Skip to content

Feat/partial update#4

Merged
vtkovapi merged 5 commits into
mainfrom
feat/partial-update
Feb 5, 2026
Merged

Feat/partial update#4
vtkovapi merged 5 commits into
mainfrom
feat/partial-update

Conversation

@vtkovapi
Copy link
Copy Markdown
Collaborator

@vtkovapi vtkovapi commented Feb 5, 2026

No description provided.

…ilters

- Added support for filtering by resource type and specific file paths in CLI commands.
- Updated `parseFlags` function to handle new `--type` flag and positional resource types.
- Improved error handling for invalid resource types and enhanced user guidance in CLI output.
- Added `getResourceTypeFromPath` to determine resource type from file paths, supporting both absolute and relative paths.
- Introduced `loadSingleResource` function to load a resource file by path, handling TypeScript, Markdown, and YAML formats.
- Implemented error handling for file loading and parsing, with detailed logging for issues encountered.
- Introduced `APPLY_FILTER` to support filtering resources by type and file paths during the apply process.
- Added utility functions to determine if a partial apply is needed and to filter resources based on specified criteria.
- Enhanced the main apply engine to load resources conditionally based on the filtering logic, improving efficiency and user control.
- Updated logging to reflect applied filters and resource loading status.
- Introduced `VALID_RESOURCE_TYPES` constant to define a comprehensive list of resource types including tools, structured outputs, assistants, squads, personalities, scenarios, simulations, and simulation suites.
- This addition supports improved resource filtering and management capabilities in the application.
…hancements

- Added new commands for selectively pushing specific resources (assistants, tools, etc.) to Vapi.
- Included examples for pushing single and multiple files, as well as combined commands for specific resource types.
- Clarified that partial applies skip deletion checks, emphasizing the need for a full apply to sync deletions.
@vtkovapi vtkovapi merged commit 3ba3faa into main Feb 5, 2026
@vtkovapi vtkovapi deleted the feat/partial-update branch February 5, 2026 20:46
dhruva-reddy added a commit that referenced this pull request May 2, 2026
## ELI5

**Problem.** The state file (`.vapi-state.<env>.json`) used to map
*name → UUID* and nothing else. So when push went to update a resource,
the engine had no way to tell whether someone had edited the resource
on the dashboard since you last pulled — there was nothing to compare
to. This is the root cause of "drift detection isn't possible," "real
rollback isn't possible," and "scoped pushes can't be precise about
what they touched": the engine has no per-resource memory of *what
was there before*.

**What this fix does.** Widens each state entry from a bare `string`
(the UUID) to a `ResourceState` object carrying:

  - `uuid`               — the platform UUID (unchanged semantics)
  - `lastPulledHash`     — sha256 of the platform payload at last pull
  - `lastPulledAt`       — ISO timestamp
  - `lastPushedHash`     — sha256 of the last pushed payload
  - `platformVersionId`  — Stack I, populated when platform exposes one

Every state-reading and state-writing call site is updated. **No new
external behavior ships in this PR alone** — strictly plumbing.
Backwards compatible: legacy state files (the old `string` shape) load
fine, just without hashes until the next pull/push populates them. The
on-disk file isn't rewritten until the next `saveState`, so a "deploy
and immediately rollback" doesn't corrupt state.

**Outcome you'll notice.** This PR alone changes nothing visible. It's
the architectural foundation that **drift detection (Stack G), snapshot
rollback (Stack H), and scoped state writes (Stack J)** all depend on.
After it lands, your next pull populates `lastPulledHash` for every
resource, and the next three PRs unlock real safety guarantees.

---

Architectural pivot. State sections move from Record<string, string>
(name → UUID) to Record<string, ResourceState> carrying:
  - uuid: string (the platform UUID, unchanged semantics)
  - lastPulledHash?: string (sha256 of canonicalized platform payload)
  - lastPulledAt?: string (ISO timestamp)
  - lastPushedHash?: string (sha256 of last pushed payload)
  - platformVersionId?: string (Stack I — populated when platform exposes one)

This is the architectural prerequisite for drift detection (Stack G),
snapshot rollback (Stack H), optimistic concurrency (Stack I), and scoped
state writes (Stack J). Every state-reading call site is updated, but
NO new external behavior ships in this PR — strictly plumbing.

Backwards compatibility:
- src/state.ts:loadState wraps any legacy bare-string value as
  { uuid: <string> } at load time. Existing customer state files keep
  working until their next pull populates hashes. No flag-day migration.
- The on-disk file is NOT rewritten until the next saveState, so a
  "deploy and immediately rollback" scenario does NOT corrupt state.

Files:
- src/types.ts: ResourceState type, StateFile sections retyped.
- src/state-serialize.ts: hashPayload (canonicalize + sha256),
  asResourceState (legacy migration), upsertState (preserves un-touched
  fields when patching).
- src/state.ts: stateUuid helper for the common case;
  loadState wraps legacy string entries via migrateSection;
  re-exports the helpers for ergonomics.
- src/pull.ts: each pull populates lastPulledHash + lastPulledAt;
  credential entries preserve prior metadata when slug+uuid are stable.
- src/push.ts: each PATCH/POST populates lastPushedHash via upsertState.
  All `state.X[id]` reads → `?.uuid`. State assignments → upsertState.
- src/cleanup.ts, src/credentials.ts, src/delete.ts, src/eval.ts,
  src/resolver.ts, src/call.ts: mechanical updates for the new shape.
  Verified by tsc — no leaks where a bare string is still expected.
- tests/state-migration.test.ts: legacy string entries load and
  round-trip; mixed legacy + new entries; canonicalize stability;
  hashPayload determinism; upsertState preservation semantics.

Closes improvements.md #4 (architectural prerequisite). G/H/I/J unblocked.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
dhruva-reddy added a commit that referenced this pull request May 2, 2026
## ELI5

**Problem.** The state file (`.vapi-state.<env>.json`) used to map
*name → UUID* and nothing else. So when push went to update a resource,
the engine had no way to tell whether someone had edited the resource
on the dashboard since you last pulled — there was nothing to compare
to. This is the root cause of "drift detection isn't possible," "real
rollback isn't possible," and "scoped pushes can't be precise about
what they touched": the engine has no per-resource memory of *what
was there before*.

**What this fix does.** Widens each state entry from a bare `string`
(the UUID) to a `ResourceState` object carrying:

  - `uuid`               — the platform UUID (unchanged semantics)
  - `lastPulledHash`     — sha256 of the platform payload at last pull
  - `lastPulledAt`       — ISO timestamp
  - `lastPushedHash`     — sha256 of the last pushed payload
  - `platformVersionId`  — Stack I, populated when platform exposes one

Every state-reading and state-writing call site is updated. **No new
external behavior ships in this PR alone** — strictly plumbing.
Backwards compatible: legacy state files (the old `string` shape) load
fine, just without hashes until the next pull/push populates them. The
on-disk file isn't rewritten until the next `saveState`, so a "deploy
and immediately rollback" doesn't corrupt state.

**Outcome you'll notice.** This PR alone changes nothing visible. It's
the architectural foundation that **drift detection (Stack G), snapshot
rollback (Stack H), and scoped state writes (Stack J)** all depend on.
After it lands, your next pull populates `lastPulledHash` for every
resource, and the next three PRs unlock real safety guarantees.

---

Architectural pivot. State sections move from Record<string, string>
(name → UUID) to Record<string, ResourceState> carrying:
  - uuid: string (the platform UUID, unchanged semantics)
  - lastPulledHash?: string (sha256 of canonicalized platform payload)
  - lastPulledAt?: string (ISO timestamp)
  - lastPushedHash?: string (sha256 of last pushed payload)
  - platformVersionId?: string (Stack I — populated when platform exposes one)

This is the architectural prerequisite for drift detection (Stack G),
snapshot rollback (Stack H), optimistic concurrency (Stack I), and scoped
state writes (Stack J). Every state-reading call site is updated, but
NO new external behavior ships in this PR — strictly plumbing.

Backwards compatibility:
- src/state.ts:loadState wraps any legacy bare-string value as
  { uuid: <string> } at load time. Existing customer state files keep
  working until their next pull populates hashes. No flag-day migration.
- The on-disk file is NOT rewritten until the next saveState, so a
  "deploy and immediately rollback" scenario does NOT corrupt state.

Files:
- src/types.ts: ResourceState type, StateFile sections retyped.
- src/state-serialize.ts: hashPayload (canonicalize + sha256),
  asResourceState (legacy migration), upsertState (preserves un-touched
  fields when patching).
- src/state.ts: stateUuid helper for the common case;
  loadState wraps legacy string entries via migrateSection;
  re-exports the helpers for ergonomics.
- src/pull.ts: each pull populates lastPulledHash + lastPulledAt;
  credential entries preserve prior metadata when slug+uuid are stable.
- src/push.ts: each PATCH/POST populates lastPushedHash via upsertState.
  All `state.X[id]` reads → `?.uuid`. State assignments → upsertState.
- src/cleanup.ts, src/credentials.ts, src/delete.ts, src/eval.ts,
  src/resolver.ts, src/call.ts: mechanical updates for the new shape.
  Verified by tsc — no leaks where a bare string is still expected.
- tests/state-migration.test.ts: legacy string entries load and
  round-trip; mixed legacy + new entries; canonicalize stability;
  hashPayload determinism; upsertState preservation semantics.

Closes improvements.md #4 (architectural prerequisite). G/H/I/J unblocked.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
dhruva-reddy added a commit that referenced this pull request May 2, 2026
## ELI5

**Problem.** The state file (`.vapi-state.<env>.json`) used to map
*name → UUID* and nothing else. So when push went to update a resource,
the engine had no way to tell whether someone had edited the resource
on the dashboard since you last pulled — there was nothing to compare
to. This is the root cause of "drift detection isn't possible," "real
rollback isn't possible," and "scoped pushes can't be precise about
what they touched": the engine has no per-resource memory of *what
was there before*.

**What this fix does.** Widens each state entry from a bare `string`
(the UUID) to a `ResourceState` object carrying:

  - `uuid`               — the platform UUID (unchanged semantics)
  - `lastPulledHash`     — sha256 of the platform payload at last pull
  - `lastPulledAt`       — ISO timestamp
  - `lastPushedHash`     — sha256 of the last pushed payload
  - `platformVersionId`  — Stack I, populated when platform exposes one

Every state-reading and state-writing call site is updated. **No new
external behavior ships in this PR alone** — strictly plumbing.
Backwards compatible: legacy state files (the old `string` shape) load
fine, just without hashes until the next pull/push populates them. The
on-disk file isn't rewritten until the next `saveState`, so a "deploy
and immediately rollback" doesn't corrupt state.

**Outcome you'll notice.** This PR alone changes nothing visible. It's
the architectural foundation that **drift detection (Stack G), snapshot
rollback (Stack H), and scoped state writes (Stack J)** all depend on.
After it lands, your next pull populates `lastPulledHash` for every
resource, and the next three PRs unlock real safety guarantees.

---

Architectural pivot. State sections move from Record<string, string>
(name → UUID) to Record<string, ResourceState> carrying:
  - uuid: string (the platform UUID, unchanged semantics)
  - lastPulledHash?: string (sha256 of canonicalized platform payload)
  - lastPulledAt?: string (ISO timestamp)
  - lastPushedHash?: string (sha256 of last pushed payload)
  - platformVersionId?: string (Stack I — populated when platform exposes one)

This is the architectural prerequisite for drift detection (Stack G),
snapshot rollback (Stack H), optimistic concurrency (Stack I), and scoped
state writes (Stack J). Every state-reading call site is updated, but
NO new external behavior ships in this PR — strictly plumbing.

Backwards compatibility:
- src/state.ts:loadState wraps any legacy bare-string value as
  { uuid: <string> } at load time. Existing customer state files keep
  working until their next pull populates hashes. No flag-day migration.
- The on-disk file is NOT rewritten until the next saveState, so a
  "deploy and immediately rollback" scenario does NOT corrupt state.

Files:
- src/types.ts: ResourceState type, StateFile sections retyped.
- src/state-serialize.ts: hashPayload (canonicalize + sha256),
  asResourceState (legacy migration), upsertState (preserves un-touched
  fields when patching).
- src/state.ts: stateUuid helper for the common case;
  loadState wraps legacy string entries via migrateSection;
  re-exports the helpers for ergonomics.
- src/pull.ts: each pull populates lastPulledHash + lastPulledAt;
  credential entries preserve prior metadata when slug+uuid are stable.
- src/push.ts: each PATCH/POST populates lastPushedHash via upsertState.
  All `state.X[id]` reads → `?.uuid`. State assignments → upsertState.
- src/cleanup.ts, src/credentials.ts, src/delete.ts, src/eval.ts,
  src/resolver.ts, src/call.ts: mechanical updates for the new shape.
  Verified by tsc — no leaks where a bare string is still expected.
- tests/state-migration.test.ts: legacy string entries load and
  round-trip; mixed legacy + new entries; canonicalize stability;
  hashPayload determinism; upsertState preservation semantics.

Closes improvements.md #4 (architectural prerequisite). G/H/I/J unblocked.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
dhruva-reddy added a commit that referenced this pull request May 5, 2026
## ELI5

**Problem.** The state file (`.vapi-state.<env>.json`) used to map
*name → UUID* and nothing else. So when push went to update a resource,
the engine had no way to tell whether someone had edited the resource
on the dashboard since you last pulled — there was nothing to compare
to. This is the root cause of "drift detection isn't possible," "real
rollback isn't possible," and "scoped pushes can't be precise about
what they touched": the engine has no per-resource memory of *what
was there before*.

**What this fix does.** Widens each state entry from a bare `string`
(the UUID) to a `ResourceState` object carrying:

  - `uuid`               — the platform UUID (unchanged semantics)
  - `lastPulledHash`     — sha256 of the platform payload at last pull
  - `lastPulledAt`       — ISO timestamp
  - `lastPushedHash`     — sha256 of the last pushed payload
  - `platformVersionId`  — Stack I, populated when platform exposes one

Every state-reading and state-writing call site is updated. **No new
external behavior ships in this PR alone** — strictly plumbing.
Backwards compatible: legacy state files (the old `string` shape) load
fine, just without hashes until the next pull/push populates them. The
on-disk file isn't rewritten until the next `saveState`, so a "deploy
and immediately rollback" doesn't corrupt state.

**Outcome you'll notice.** This PR alone changes nothing visible. It's
the architectural foundation that **drift detection (Stack G), snapshot
rollback (Stack H), and scoped state writes (Stack J)** all depend on.
After it lands, your next pull populates `lastPulledHash` for every
resource, and the next three PRs unlock real safety guarantees.

---

Architectural pivot. State sections move from Record<string, string>
(name → UUID) to Record<string, ResourceState> carrying:
  - uuid: string (the platform UUID, unchanged semantics)
  - lastPulledHash?: string (sha256 of canonicalized platform payload)
  - lastPulledAt?: string (ISO timestamp)
  - lastPushedHash?: string (sha256 of last pushed payload)
  - platformVersionId?: string (Stack I — populated when platform exposes one)

This is the architectural prerequisite for drift detection (Stack G),
snapshot rollback (Stack H), optimistic concurrency (Stack I), and scoped
state writes (Stack J). Every state-reading call site is updated, but
NO new external behavior ships in this PR — strictly plumbing.

Backwards compatibility:
- src/state.ts:loadState wraps any legacy bare-string value as
  { uuid: <string> } at load time. Existing customer state files keep
  working until their next pull populates hashes. No flag-day migration.
- The on-disk file is NOT rewritten until the next saveState, so a
  "deploy and immediately rollback" scenario does NOT corrupt state.

Files:
- src/types.ts: ResourceState type, StateFile sections retyped.
- src/state-serialize.ts: hashPayload (canonicalize + sha256),
  asResourceState (legacy migration), upsertState (preserves un-touched
  fields when patching).
- src/state.ts: stateUuid helper for the common case;
  loadState wraps legacy string entries via migrateSection;
  re-exports the helpers for ergonomics.
- src/pull.ts: each pull populates lastPulledHash + lastPulledAt;
  credential entries preserve prior metadata when slug+uuid are stable.
- src/push.ts: each PATCH/POST populates lastPushedHash via upsertState.
  All `state.X[id]` reads → `?.uuid`. State assignments → upsertState.
- src/cleanup.ts, src/credentials.ts, src/delete.ts, src/eval.ts,
  src/resolver.ts, src/call.ts: mechanical updates for the new shape.
  Verified by tsc — no leaks where a bare string is still expected.
- tests/state-migration.test.ts: legacy string entries load and
  round-trip; mixed legacy + new entries; canonicalize stability;
  hashPayload determinism; upsertState preservation semantics.

Closes improvements.md #4 (architectural prerequisite). G/H/I/J unblocked.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
dhruva-reddy added a commit that referenced this pull request May 5, 2026
## ELI5

**Problem.** The state file (`.vapi-state.<env>.json`) used to map
*name → UUID* and nothing else. So when push went to update a resource,
the engine had no way to tell whether someone had edited the resource
on the dashboard since you last pulled — there was nothing to compare
to. This is the root cause of "drift detection isn't possible," "real
rollback isn't possible," and "scoped pushes can't be precise about
what they touched": the engine has no per-resource memory of *what
was there before*.

**What this fix does.** Widens each state entry from a bare `string`
(the UUID) to a `ResourceState` object carrying:

  - `uuid`               — the platform UUID (unchanged semantics)
  - `lastPulledHash`     — sha256 of the platform payload at last pull
  - `lastPulledAt`       — ISO timestamp
  - `lastPushedHash`     — sha256 of the last pushed payload
  - `platformVersionId`  — Stack I, populated when platform exposes one

Every state-reading and state-writing call site is updated. **No new
external behavior ships in this PR alone** — strictly plumbing.
Backwards compatible: legacy state files (the old `string` shape) load
fine, just without hashes until the next pull/push populates them. The
on-disk file isn't rewritten until the next `saveState`, so a "deploy
and immediately rollback" doesn't corrupt state.

**Outcome you'll notice.** This PR alone changes nothing visible. It's
the architectural foundation that **drift detection (Stack G), snapshot
rollback (Stack H), and scoped state writes (Stack J)** all depend on.
After it lands, your next pull populates `lastPulledHash` for every
resource, and the next three PRs unlock real safety guarantees.

---

Architectural pivot. State sections move from Record<string, string>
(name → UUID) to Record<string, ResourceState> carrying:
  - uuid: string (the platform UUID, unchanged semantics)
  - lastPulledHash?: string (sha256 of canonicalized platform payload)
  - lastPulledAt?: string (ISO timestamp)
  - lastPushedHash?: string (sha256 of last pushed payload)
  - platformVersionId?: string (Stack I — populated when platform exposes one)

This is the architectural prerequisite for drift detection (Stack G),
snapshot rollback (Stack H), optimistic concurrency (Stack I), and scoped
state writes (Stack J). Every state-reading call site is updated, but
NO new external behavior ships in this PR — strictly plumbing.

Backwards compatibility:
- src/state.ts:loadState wraps any legacy bare-string value as
  { uuid: <string> } at load time. Existing customer state files keep
  working until their next pull populates hashes. No flag-day migration.
- The on-disk file is NOT rewritten until the next saveState, so a
  "deploy and immediately rollback" scenario does NOT corrupt state.

Files:
- src/types.ts: ResourceState type, StateFile sections retyped.
- src/state-serialize.ts: hashPayload (canonicalize + sha256),
  asResourceState (legacy migration), upsertState (preserves un-touched
  fields when patching).
- src/state.ts: stateUuid helper for the common case;
  loadState wraps legacy string entries via migrateSection;
  re-exports the helpers for ergonomics.
- src/pull.ts: each pull populates lastPulledHash + lastPulledAt;
  credential entries preserve prior metadata when slug+uuid are stable.
- src/push.ts: each PATCH/POST populates lastPushedHash via upsertState.
  All `state.X[id]` reads → `?.uuid`. State assignments → upsertState.
- src/cleanup.ts, src/credentials.ts, src/delete.ts, src/eval.ts,
  src/resolver.ts, src/call.ts: mechanical updates for the new shape.
  Verified by tsc — no leaks where a bare string is still expected.
- tests/state-migration.test.ts: legacy string entries load and
  round-trip; mixed legacy + new entries; canonicalize stability;
  hashPayload determinism; upsertState preservation semantics.

Closes improvements.md #4 (architectural prerequisite). G/H/I/J unblocked.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant