jg-agent-hq 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0
4
+
5
+ - Rebuild the homepage around a native-session visual, local setup and three complete source-backed walkthroughs. Show cross-provider reviews and retained revision evidence with explicit host decisions.
6
+ - Queue local metadata-lock acquisitions in order, preventing frequent status reads from starving a revision checkpoint. Preserve exact owner checks, wait deadlines and explicit recovery.
7
+ - Coordinate journaled private writes with public document locks, explicit keep/write/remove intents and durable completion acknowledgement recovery. Prepare aggregate and milestone progress before native admission; preserve exact replay output and completion evidence.
8
+
9
+ - Use jg-plans for document observations, guarded edit preparation and explicit milestone identity assignment. Preserve complete shared requirements and JSON-safe contract metadata; report skills binding freshness without blocking the revision approval flow; require current bindings for finalization and execution.
10
+ - Keep exact body and requirement bytes in execution digests, with deterministic metadata serialization. Stop regenerating derived Overview tables.
11
+ - Add three complete public-client source examples, packed-consumer contract qualification and fixture-backed native flows. Expose the exact pending correspondence proposal ID for explicit client confirmation.
12
+
3
13
  ## 1.0.0
4
14
 
5
15
  - Use `jg-exception` with named string codes for runtime, lock, plan, provider, client and tooling failures. Preserve codes through SQLite-worker responses and publish browser-safe client codes alongside their safe messages. This changes the Node error contract; callers should handle the documented named codes.
package/README.md CHANGED
@@ -61,7 +61,7 @@ Use `jg-agent-hq request --state-root <directory>` with a closed HQ command on s
61
61
 
62
62
  `plan-status --directory <path>` and `plan-milestones --directory <path>` inspect a selected ordinary planning directory. No project registry is required. Mutations use the existing `request` JSON command with `kind: 'plan'`; see the [plan command reference](api/README.md#plan-coordination).
63
63
 
64
- Finalization assigns milestone UUIDs and returns the complete canonical sequence when a breakdown exists. A plan without a breakdown remains one unit: finalization returns null content, plan approval suffices, and whole-plan execution uses an empty milestone selection with a null milestone ID. No milestone file is created merely to make a small plan executable. Plan approval, sequence approval and scoped execution authorization are separate explicit operator actions. None sends native input or answers tool permissions. `coordination.json` holds current records beside the plan. SQLite retains write replay identities and a replaceable, paged milestone projection. Keep both when recovering interrupted writes. A pending write blocks further mutation until its original action is reconciled.
64
+ HQ uses jg-plans to observe and prepare ordinary Markdown plans. The default profile retains unknown contractual metadata and all shared requirement sections while excluding only declared administrative fields. Status reports skills bindings as absent, current or stale. A stale binding keeps the plan readable and approvable during revision, but closes finalization and execution until jg-breakdown refreshes coverage; bindings never grant HQ approval. Finalization assigns milestone UUIDs and returns the complete canonical sequence when a breakdown exists. A plan without a breakdown remains one unit: finalization returns null content, plan approval suffices, and whole-plan execution uses an empty milestone selection with a null milestone ID. No milestone file is created merely to make a small plan executable. Plan approval, sequence approval and scoped execution authorization are separate explicit operator actions. None sends native input or answers tool permissions. `coordination.json` holds current records beside the plan. SQLite retains write replay identities and a replaceable, paged milestone projection. Keep both when recovering interrupted writes. Document locks release before the write journal is completed. Checked replacements are private (0600), and progress preserves revision while recording one prepared updated_at. A pending write blocks further mutation until its original action is reconciled.
65
65
 
66
66
  Coordinators can retain revision-bound compatibility reviews in that same file. Core operations preserve the records without assessing them or granting authority. The integrating coordinator owns review freshness and conflict gates.
67
67
 
@@ -75,6 +75,14 @@ Collect one completed reviewer message by its exact native turn/item reference.
75
75
 
76
76
  `handoff-show --id <uuid>` reads one handoff; `handoffs --workspace-root <path>` pages the inbox. The [handoff reference](api/README.md#cross-provider-handoffs) describes creation, preview, send and native findings collection through the same CLI's JSON request interface.
77
77
 
78
+ ## Source examples
79
+
80
+ Follow the [three complete walkthroughs](https://jg-agent-hq.jesusgraterol.dev/examples/), with copyable source, visual results and explicit host decisions.
81
+
82
+ `examples/control-session.ts` creates a native session and reads its actual delivery, output, permission and usage observations. `examples/review-handoff.ts` presents exact cross-provider review/feedback previews and delivers selected findings. `examples/revise-plan.ts` runs the planning skills through the revision lease, retains verified work through explicit correspondence, and obtains fresh approvals and execution scope.
83
+
84
+ These complete TypeScript examples use the public client and contracts. Start the local controller, sign in to the native CLIs, and install the required skills and supported project-local jg-plans CLI first. The host supplies actual user decisions and keeps native permission handling separate. Retain request identities before submission; after an interrupted client call, inspect those receipts instead of rerunning a whole example. Examples are development sources, not package exports or automatic website actions.
85
+
78
86
  ## Project blueprint
79
87
 
80
88
  - `src/index.ts`: the explicit public package boundary.
package/api/README.md CHANGED
@@ -6,7 +6,7 @@ Intentional Node API failures use `Exception` from `jg-exception`. The [error re
6
6
 
7
7
  ## Lock lifecycle
8
8
 
9
- - `acquireHqLock(root, command, options?)` acquires `.runtime/hq.lock` and returns an asynchronous release function. The caller owns the trusted state root and supplies a non-empty, single-line operation label. Surrounding whitespace is trimmed. The returned release function is idempotent and refuses a replaced owner.
9
+ - `acquireHqLock(root, command, options?)` acquires `.runtime/hq.lock` and returns an asynchronous release function. The caller owns the trusted state root and supplies a non-empty, single-line operation label. Surrounding whitespace is trimmed. The returned release function is idempotent and refuses a replaced owner. Acquisitions in one process queue by their normalized lock path, so later status polling cannot overtake a waiting checkpoint. Cross-process exclusion still uses the same file and exact owner; no cross-process ordering is promised. Timed-out or failed waiters leave the local queue.
10
10
  - `withHqLock(root, command, operation, options?)` runs an asynchronous operation under the lock. It releases on success or failure; operation failures propagate unchanged. If cleanup also fails, the original operation error stays primary and cleanup failure is reported on stderr.
11
11
  - `readHqLockState(root, now?)` reports free, held or unreadable without acquiring or reclaiming the lock. Held state includes the owner, liveness and age.
12
12
  - `getOwnerLiveness(pid)` reports alive, dead or unknown. An unverifiable owner is not evidence that recovery is safe.
@@ -168,13 +168,17 @@ Output is one JSON line with `schemaVersion: 1`. Read output includes the comman
168
168
 
169
169
  ## Plan coordination
170
170
 
171
- `computePlanRevision({ body, metadata, milestones })` is the pure Node API for execution identity. `metadata` contains `scope`, `repositories` and `errorReservations`. Reservation entries contain `repository`, `namespace`, inclusive `start`/`end`, `registryPath` and `purpose`; this API hashes them and does not allocate codes. Repository and reservation order is canonicalized. Plan bodies normalize line endings only. Private coordinators supply the body after parsing their own frontmatter; ordinary planning directories use the entire plan file.
171
+ `computePlanRevision({ body, metadata, milestones })` is the pure Node API for execution identity. `metadata` contains `scope`, `repositories`, `errorReservations` and JSON-safe `extensions`. Reservation entries contain `repository`, `namespace`, inclusive `start`/`end`, `registryPath` and `purpose`; this API hashes them and does not allocate codes. Repository and reservation order is canonicalized; object keys use strict deterministic JSON. The exact parsed body, including its line endings, is contractual.
172
172
 
173
- Send `{ kind: 'plan', command }` through the existing local request API. Every command selects `target: { directory }`, an absolute directory inside an allowed workspace. A private host supplies `parsePlanContract({ directory, content })` when constructing the runtime. It returns the exact body after frontmatter and its contract metadata from the current file. The core validates that exclusion boundary and metadata while leaving private frontmatter policy with its owner. With no parser, the whole ordinary plan is contractual. The private server resolves operator identity itself and never forwards browser-supplied roots, contract exclusions or metadata.
173
+ Send `{ kind: 'plan', command }` through the existing local request API. Every command selects `target: { directory }`, an absolute directory inside an allowed workspace. The default profile uses jg-plans observations: absent HQ fields default to local scope and empty repository/reservation lists; unknown fields, including plan `id`, remain in `extensions`. Only `created_at`, `updated_at`, `revision` and `status` are administrative. Malformed, non-mapping or non-JSON metadata fails closed. No preferred-document conformance gate is imposed.
174
+
175
+ A trusted private host may supply `parsePlanContract({ directory, content })`. It must return exactly the body observed by jg-plans and valid HQ metadata. That host owns its alternative metadata profile and must put its contractual extension fields in `extensions`. It cannot exclude body prose. The private server resolves operator identity itself and never forwards browser-supplied roots, contract exclusions or metadata.
176
+
177
+ Milestone contracts retain every requirement byte outside observed status/identity lines, plus preamble and all intervening/trailing shared sections. Only recognized Overview table spans and the three valid `jg_skills` binding fields are excluded; other milestone metadata remains contractual. HQ does not regenerate Overview tables. Statuses must be exactly pending, in progress or done, and milestone IDs/order participate in sequence identity. Ordinal renumbering alone does not change a milestone's identity. Missing IDs are assigned explicitly by jg-plans and saved before application. When present, a skills binding must match the current plan id, revision and fingerprint excluding exactly the four administrative keys. A matching binding never grants HQ approval or execution permission.
174
178
 
175
179
  | Command kind | Required fields and result |
176
180
  | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
177
- | `status` | `target`. Returns current execution revisions, full inspection hashes, approval state and a bounded coordination summary and retained-evidence counts. |
181
+ | `status` | `target`. Returns current execution revisions, full inspection hashes, `skillsBinding` (`absent`, `current` or `stale`), approval state and a bounded coordination summary and retained-evidence counts. |
178
182
  | `milestones` | `target`, optional `limit` (default 32, maximum 128) and `cursor`. Returns a bounded ordered seek page. |
179
183
  | `finalize` | `target`, `action`, `expected`. Assigns initial UUIDs or reconciles a checkpoint. Returns the complete canonical file, or a saved proposal needing one confirmation. Optional `confirmation: { proposalId, decisions }` resolves every unmatched source. |
180
184
  | `begin-revision` | `target`, `action`, `expected`, `intent: 'plan' \| 'breakdown'`, `threadIds`, `checkouts`. Closes execution admission and starts owned interruption/checkpoint work. |
@@ -190,13 +194,23 @@ Send `{ kind: 'plan', command }` through the existing local request API. Every c
190
194
 
191
195
  Milestones are optional. Finalizing a plan with no milestone file returns `content: null` and does not create a file. That unit needs plan approval and explicit execution authorization, with `milestoneIds: []`; execution checks, completion and native execution scopes select it with `milestoneId: null`. A real breakdown requires a nonempty selection of its stable IDs and its separate sequence approval. Null cannot select a milestone or bypass sequence approval. Whole-plan completion retains its exact plan contract/digest, actual check references and checkout evidence, with null shared-sequence digest. Completed work cannot be authorized again under that unchanged contract.
192
196
 
193
- A first-use sequence has one `**Milestone ID:** <uuid>` immediately below each `**Status:**` line. Blank lines may separate the heading from its status; no intervening requirement prose is allowed. The initial finalizer rejects duplicate, malformed or misplaced IDs and inconsistent framing. It refreshes existing Overview status rows and returns the complete canonical file for presentation before approval. A changed finalized contract goes through checkpoint reconciliation. A raw or changed sequence cannot inherit finalized status or sequence authority. A done marker remains visible but blocks execution without completion evidence.
197
+ Skills bindings are optional for generic HQ plans. When present, their syntax must be valid and their plan ID, revision and structural fingerprint must match before finalization or execution. A valid but stale binding remains visible in status: plan approval and explicit revision invocations remain available so jg-plan can retain the old sequence until jg-breakdown refreshes its coverage. Malformed bindings fail as invalid artifacts. A stale binding never supplies sequence approval or completion, even when semantic execution digests are unchanged.
194
198
 
195
- The milestone contract includes its stable UUID, title without its ordinal, all requirement prose, shared sequence requirements and the approval statement. Status and identity marker lines are excluded from the prose; only the derived Overview table is excluded from shared text. Prose next to that table remains contractual. Sequence order is significant. Renumbering preserves execution identity; changed requirements, dependencies, scope, reservations or order require applicable approval. Full-file hashes preserve exact UTF-8 bytes and are distinct from normalized execution revisions. Administrative frontmatter excluded by the trusted contract parser, session labels, status advancement and coordination receipts do not change execution digests.
199
+ A first-use sequence has one `**Milestone ID:** <uuid>` immediately below each `**Status:**` line. Blank lines may separate the heading from its status; no intervening requirement prose is allowed. The initial finalizer rejects duplicate, malformed or misplaced IDs and inconsistent framing. It preserves existing Overview text and returns the complete canonical file for presentation before approval. A changed finalized contract goes through checkpoint reconciliation. A raw or changed sequence cannot inherit finalized status or sequence authority. A done marker remains visible but blocks execution without completion evidence.
200
+
201
+ The milestone contract includes its stable UUID, title without its ordinal, all requirement prose, shared sequence requirements and the approval statement. Status and identity marker lines are excluded from the prose; only the derived Overview table is excluded from shared text. Prose next to that table remains contractual. Sequence order is significant. Renumbering preserves execution identity; changed requirements, dependencies, scope, reservations or order require applicable approval. Full-file hashes preserve exact UTF-8 bytes and are distinct from semantic execution revisions. Administrative frontmatter excluded by the trusted contract parser, session labels, status advancement and coordination receipts do not change execution digests.
196
202
 
197
203
  Plan and milestone artifacts are bounded to 1 MiB each; coordination evidence is bounded to 8 MiB and a sequence to 1,024 milestones. Reads do not scan planning trees. Milestone pages use ordinal seek ordering with unique ascending ordinals. Cursors bind the selected directory, page size, execution revisions and exact milestone inspection hash. Any changed artifact requires a fresh page; renumbering or status-only edits still preserve approval. A SQLite projection is rebuilt only when the selected milestone file's full hash changes. Every read verifies its source file; the projection is replaceable and never grants authority.
198
204
 
199
- Mutations hold the shared metadata lock at `<coordinationRoot>/.runtime/hq.lock` (`coordinationRoot` defaults to `stateRoot`), retain a durable action identity and intended write before changing files, sync temporary files and atomically replace each artifact. Use `serve --coordination-root <directory>` when the canonical coordination lock is separate from runtime storage. Repeating an action UUID with the identical payload never reapproves revoked work. A changed payload conflicts. An interrupted write remains blocked and can be retried with its original action only when files match the recorded baseline or exact intended output. Conflicting edits are preserved. Completed write bodies are removed from SQLite while replay identity remains. The current finalization receipt retains the operator event, execution revision, nullable canonical file hash and timestamp independently of write recovery bodies. Status reads expose `pendingActionId` for unresolved writes; they never approve or resume work.
205
+ Mutations acquire the HQ metadata lock at `<coordinationRoot>/.runtime/hq.lock` (`coordinationRoot` defaults to `stateRoot`), then the public jg-plans document locks in plan-before-milestones order. Use `serve --coordination-root <directory>` when coordination ownership is separate from runtime storage. Locks cover bounded observation, preparation, journaling and file application; no model turn or native stop wait holds them. A busy document lock becomes `JG_AGENT_HQ_ACTION_CONFLICT` with the safe `document-locked` reason. There is no automatic stale-lock takeover.
206
+
207
+ SQLite persists exact prepared plan/milestone sources, assigned IDs and timestamps before application. A plan source of null means keep; milestone operations are explicitly keep, write with source, or remove. A null recorded before-plan hash permits only coordination work. Replay accepts only each recorded baseline or its exact desired state. Markdown is applied before coordination. Every HQ replacement uses jg-fs checked atomic writes with explicit 0600; absent targets are created exclusively and privately before content is written. Strict bounded, same-handle, single-link reads remain in HQ. Inspection alone never changes file permissions.
208
+
209
+ After file durability succeeds, document locks must release successfully before SQLite marks the intent completed and clears its write bodies; HQ metadata ownership remains held through completion. A write, sync or release failure retains the prepared payload and closes admission. A crash after release and before completion is replayable. A failed completion acknowledgement is reconciled against the durable ledger: confirmed completion succeeds, an uncommitted intent stays pending, and an unknown outcome remains closed. Retry only the same original action and payload after inspection; changed files or payloads conflict. Nonparticipating writers still have a final comparison-to-replacement/removal race; these operations are not a multi-file transaction.
210
+
211
+ Accepted implementation input prepares aggregate and selected pending milestone progress before native admission. Message, queue and steering requests record accepted implementation scope; an in-progress marker does not assert that a provider has started or completed a turn. Progress is journaled and released before current authority is checked again for native admission. A retry of the same native action can finish its retained progress intent without regenerating timestamps; it still needs current runtime/authorization checks. Native control and permission actions do not advance progress.
212
+
213
+ Only accepted completion evidence advances a milestone to done. Aggregate done requires the complete current execution contract, applicable current approval/finalization and verified completion; administrative done markers alone do not provide them. Progress-only plan changes preserve revision and set updated_at once in the saved prepared source. An unchanged plan preserves its timestamp. The current finalization receipt retains the operator event, semantic revision, nullable canonical file hash and timestamp independently of write recovery bodies. Status reads expose pendingActionId for unresolved writes and never approve or resume work.
200
214
 
201
215
  `coordination.json` includes required `comparisons`, an array bounded to 1,024 records validated by `PlanComparisonSchema`. Each record binds `sourceRevision`, `targetDirectory`, `targetRevision`, a `compatible` or `contradiction` verdict, `reason`, `reviewedAt` and reviewer provenance (`provider`, `cliVersion`, nullable observed `model`, and native message `reference`). A trusted coordinator writes these records while holding the same metadata lock. Core operations preserve them; status exposes only `comparisonCount`. They never change execution digests or grant authority. The coordinator owns relevance, freshness, semantic judgments, bounded review reads and any execution gate, including contradictions. The standalone core does not assess compatibility.
202
216
 
@@ -208,7 +222,7 @@ Begin revision before invoking a planning skill. Execution admission closes unde
208
222
 
209
223
  The local host supplies checkout evidence as `{ repository, directory, claimReference, paths }`. Paths are exact relative task paths. The core streams their contents, records link targets without following them, includes missing paths as deletions, and captures the current Git branch/HEAD. It does not stage or reset files and rejects traversal, parent-link escapes, `.git` and excluded archive/backup directories. Check commands and references are trusted operator evidence; this primitive does not execute arbitrary submitted commands or treat an imported agent claim as verification.
210
224
 
211
- After native `jg-plan` revises the contract and an explicitly requested `jg-breakdown` regenerates a needed sequence, close the planning controller before finalization. Only unique exact normalized title and complete-contract matches retain identity automatically. Every unmatched checkpoint source, including done and partial work, appears in one saved proposal. Confirmation decisions use `sourceIds`, `targetIds`, `relation` (`equivalent`, `requirements-changed`, `omitted`, `reopened`) and explicit one-to-one `retainedPairs`. One source ID cannot be assigned to multiple targets. Grouped decisions retain split/merged evidence. A complete equivalent mapping preserves verified completion or partial status; rewording does not create new checks. A changed requirement gets fresh pending identity. Explicit reopening preserves evidence while invalidating its completion credit. Unverified done markers cannot become verified through an equivalent mapping.
225
+ After native `jg-plan` revises the contract and an explicitly requested `jg-breakdown` regenerates a needed sequence, close the planning controller before finalization. Only unique exact title and complete-contract matches retain identity automatically. Every unmatched checkpoint source, including done and partial work, appears in one saved proposal. Status exposes its nullable `coordination.revision.proposalId`; clients use the paged reconciliation reads to present correspondence and confirm that exact saved identity. Confirmation decisions use `sourceIds`, `targetIds`, `relation` (`equivalent`, `requirements-changed`, `omitted`, `reopened`) and explicit one-to-one `retainedPairs`. One source ID cannot be assigned to multiple targets. Grouped decisions retain split/merged evidence. A complete equivalent mapping preserves verified completion or partial status; rewording does not create new checks. A changed requirement gets fresh pending identity. Explicit reopening preserves evidence while invalidating its completion credit. Unverified done markers cannot become verified through an equivalent mapping.
212
226
 
213
227
  A whole-plan checkpoint retains null milestones and an empty milestone inventory. If a revision removes a sequence because the remaining scope no longer needs one, every unmatched checkpoint milestone still requires explicit omission confirmation. Its verified evidence remains available; absence alone never resets progress or authorizes whole-plan execution.
214
228
 
@@ -1183,6 +1183,11 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
1183
1183
  completed: "completed";
1184
1184
  }>;
1185
1185
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1186
+ skillsBinding: z.ZodEnum<{
1187
+ absent: "absent";
1188
+ current: "current";
1189
+ stale: "stale";
1190
+ }>;
1186
1191
  isFinalized: z.ZodBoolean;
1187
1192
  isPlanApproved: z.ZodBoolean;
1188
1193
  isSequenceApproved: z.ZodBoolean;
@@ -1375,6 +1380,7 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
1375
1380
  hasUncertainEffects: z.ZodBoolean;
1376
1381
  hasCheckpoint: z.ZodBoolean;
1377
1382
  hasProposal: z.ZodBoolean;
1383
+ proposalId: z.ZodNullable<z.ZodUUID>;
1378
1384
  unmatchedCount: z.ZodNumber;
1379
1385
  }, z.core.$strict>>;
1380
1386
  }, z.core.$strict>;
@@ -1404,6 +1410,11 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
1404
1410
  completed: "completed";
1405
1411
  }>;
1406
1412
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1413
+ skillsBinding: z.ZodEnum<{
1414
+ absent: "absent";
1415
+ current: "current";
1416
+ stale: "stale";
1417
+ }>;
1407
1418
  isFinalized: z.ZodBoolean;
1408
1419
  isPlanApproved: z.ZodBoolean;
1409
1420
  isSequenceApproved: z.ZodBoolean;
@@ -1596,6 +1607,7 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
1596
1607
  hasUncertainEffects: z.ZodBoolean;
1597
1608
  hasCheckpoint: z.ZodBoolean;
1598
1609
  hasProposal: z.ZodBoolean;
1610
+ proposalId: z.ZodNullable<z.ZodUUID>;
1599
1611
  unmatchedCount: z.ZodNumber;
1600
1612
  }, z.core.$strict>>;
1601
1613
  }, z.core.$strict>;
@@ -1624,6 +1636,11 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
1624
1636
  completed: "completed";
1625
1637
  }>;
1626
1638
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1639
+ skillsBinding: z.ZodEnum<{
1640
+ absent: "absent";
1641
+ current: "current";
1642
+ stale: "stale";
1643
+ }>;
1627
1644
  isFinalized: z.ZodBoolean;
1628
1645
  isPlanApproved: z.ZodBoolean;
1629
1646
  isSequenceApproved: z.ZodBoolean;
@@ -1816,6 +1833,7 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
1816
1833
  hasUncertainEffects: z.ZodBoolean;
1817
1834
  hasCheckpoint: z.ZodBoolean;
1818
1835
  hasProposal: z.ZodBoolean;
1836
+ proposalId: z.ZodNullable<z.ZodUUID>;
1819
1837
  unmatchedCount: z.ZodNumber;
1820
1838
  }, z.core.$strict>>;
1821
1839
  }, z.core.$strict>;
@@ -1968,6 +1986,11 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
1968
1986
  completed: "completed";
1969
1987
  }>;
1970
1988
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1989
+ skillsBinding: z.ZodEnum<{
1990
+ absent: "absent";
1991
+ current: "current";
1992
+ stale: "stale";
1993
+ }>;
1971
1994
  isFinalized: z.ZodBoolean;
1972
1995
  isPlanApproved: z.ZodBoolean;
1973
1996
  isSequenceApproved: z.ZodBoolean;
@@ -2160,6 +2183,7 @@ export declare const BrowserPlanDetailSchema: z.ZodObject<{
2160
2183
  hasUncertainEffects: z.ZodBoolean;
2161
2184
  hasCheckpoint: z.ZodBoolean;
2162
2185
  hasProposal: z.ZodBoolean;
2186
+ proposalId: z.ZodNullable<z.ZodUUID>;
2163
2187
  unmatchedCount: z.ZodNumber;
2164
2188
  }, z.core.$strict>>;
2165
2189
  }, z.core.$strict>;
@@ -16,6 +16,7 @@ export declare const PlanMetadataSchema: z.ZodObject<{
16
16
  registryPath: z.ZodString;
17
17
  purpose: z.ZodString;
18
18
  }, z.core.$strict>>;
19
+ extensions: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
19
20
  }, z.core.$strict>;
20
21
  export type IPlanMetadata = z.infer<typeof PlanMetadataSchema>;
21
22
  export declare const PlanTargetSchema: z.ZodObject<{
@@ -1404,6 +1405,7 @@ export declare const PlanCoordinationSummarySchema: z.ZodObject<{
1404
1405
  hasUncertainEffects: z.ZodBoolean;
1405
1406
  hasCheckpoint: z.ZodBoolean;
1406
1407
  hasProposal: z.ZodBoolean;
1408
+ proposalId: z.ZodNullable<z.ZodUUID>;
1407
1409
  unmatchedCount: z.ZodNumber;
1408
1410
  }, z.core.$strict>>;
1409
1411
  }, z.core.$strict>;
@@ -1429,6 +1431,11 @@ export declare const PlanStatusSchema: z.ZodObject<{
1429
1431
  completed: "completed";
1430
1432
  }>;
1431
1433
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1434
+ skillsBinding: z.ZodEnum<{
1435
+ absent: "absent";
1436
+ current: "current";
1437
+ stale: "stale";
1438
+ }>;
1432
1439
  isFinalized: z.ZodBoolean;
1433
1440
  isPlanApproved: z.ZodBoolean;
1434
1441
  isSequenceApproved: z.ZodBoolean;
@@ -1621,6 +1628,7 @@ export declare const PlanStatusSchema: z.ZodObject<{
1621
1628
  hasUncertainEffects: z.ZodBoolean;
1622
1629
  hasCheckpoint: z.ZodBoolean;
1623
1630
  hasProposal: z.ZodBoolean;
1631
+ proposalId: z.ZodNullable<z.ZodUUID>;
1624
1632
  unmatchedCount: z.ZodNumber;
1625
1633
  }, z.core.$strict>>;
1626
1634
  }, z.core.$strict>;
@@ -1814,6 +1822,11 @@ export declare const PlanResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1814
1822
  completed: "completed";
1815
1823
  }>;
1816
1824
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1825
+ skillsBinding: z.ZodEnum<{
1826
+ absent: "absent";
1827
+ current: "current";
1828
+ stale: "stale";
1829
+ }>;
1817
1830
  isFinalized: z.ZodBoolean;
1818
1831
  isPlanApproved: z.ZodBoolean;
1819
1832
  isSequenceApproved: z.ZodBoolean;
@@ -2006,6 +2019,7 @@ export declare const PlanResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
2006
2019
  hasUncertainEffects: z.ZodBoolean;
2007
2020
  hasCheckpoint: z.ZodBoolean;
2008
2021
  hasProposal: z.ZodBoolean;
2022
+ proposalId: z.ZodNullable<z.ZodUUID>;
2009
2023
  unmatchedCount: z.ZodNumber;
2010
2024
  }, z.core.$strict>>;
2011
2025
  }, z.core.$strict>;
@@ -2034,6 +2048,11 @@ export declare const PlanResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
2034
2048
  completed: "completed";
2035
2049
  }>;
2036
2050
  pendingActionId: z.ZodNullable<z.ZodUUID>;
2051
+ skillsBinding: z.ZodEnum<{
2052
+ absent: "absent";
2053
+ current: "current";
2054
+ stale: "stale";
2055
+ }>;
2037
2056
  isFinalized: z.ZodBoolean;
2038
2057
  isPlanApproved: z.ZodBoolean;
2039
2058
  isSequenceApproved: z.ZodBoolean;
@@ -2226,6 +2245,7 @@ export declare const PlanResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
2226
2245
  hasUncertainEffects: z.ZodBoolean;
2227
2246
  hasCheckpoint: z.ZodBoolean;
2228
2247
  hasProposal: z.ZodBoolean;
2248
+ proposalId: z.ZodNullable<z.ZodUUID>;
2229
2249
  unmatchedCount: z.ZodNumber;
2230
2250
  }, z.core.$strict>>;
2231
2251
  }, z.core.$strict>;
@@ -2378,6 +2398,11 @@ export declare const PlanResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
2378
2398
  completed: "completed";
2379
2399
  }>;
2380
2400
  pendingActionId: z.ZodNullable<z.ZodUUID>;
2401
+ skillsBinding: z.ZodEnum<{
2402
+ absent: "absent";
2403
+ current: "current";
2404
+ stale: "stale";
2405
+ }>;
2381
2406
  isFinalized: z.ZodBoolean;
2382
2407
  isPlanApproved: z.ZodBoolean;
2383
2408
  isSequenceApproved: z.ZodBoolean;
@@ -2570,6 +2595,7 @@ export declare const PlanResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
2570
2595
  hasUncertainEffects: z.ZodBoolean;
2571
2596
  hasCheckpoint: z.ZodBoolean;
2572
2597
  hasProposal: z.ZodBoolean;
2598
+ proposalId: z.ZodNullable<z.ZodUUID>;
2573
2599
  unmatchedCount: z.ZodNumber;
2574
2600
  }, z.core.$strict>>;
2575
2601
  }, z.core.$strict>;
@@ -5,7 +5,7 @@ export const PlanRevisionSchema = z.strictObject({
5
5
  planDigest: PlanDigestSchema,
6
6
  breakdownDigest: PlanDigestSchema.nullable(),
7
7
  });
8
- // private coordinators supply parsed frontmatter boundaries and contract metadata
8
+ // JSON-only contract metadata remains safe in the browser contracts entry point.
9
9
  export const PlanMetadataSchema = z.strictObject({
10
10
  scope: z.string().min(1).max(128),
11
11
  repositories: z.array(z.string().min(1).max(128)).max(128),
@@ -21,6 +21,7 @@ export const PlanMetadataSchema = z.strictObject({
21
21
  })
22
22
  .refine((reservation) => reservation.end >= reservation.start))
23
23
  .max(128),
24
+ extensions: z.record(z.string(), z.json()).default({}),
24
25
  });
25
26
  export const PlanTargetSchema = z.strictObject({
26
27
  directory: z.string().min(1).max(4096),
@@ -328,6 +329,7 @@ export const PlanCoordinationSummarySchema = PlanCoordinationSchema.omit({
328
329
  .extend({
329
330
  hasCheckpoint: z.boolean(),
330
331
  hasProposal: z.boolean(),
332
+ proposalId: z.uuid().nullable(),
331
333
  unmatchedCount: z.number().int().nonnegative(),
332
334
  })
333
335
  .nullable(),
@@ -351,6 +353,7 @@ export const PlanStatusSchema = z.object({
351
353
  'completed',
352
354
  ]),
353
355
  pendingActionId: z.uuid().nullable(),
356
+ skillsBinding: z.enum(['absent', 'current', 'stale']),
354
357
  isFinalized: z.boolean(),
355
358
  isPlanApproved: z.boolean(),
356
359
  isSequenceApproved: z.boolean(),
@@ -644,8 +644,8 @@ export declare const UsageSnapshotSchema: z.ZodObject<{
644
644
  state: z.ZodEnum<{
645
645
  unavailable: "unavailable";
646
646
  available: "available";
647
- exhausted: "exhausted";
648
647
  stale: "stale";
648
+ exhausted: "exhausted";
649
649
  }>;
650
650
  source: z.ZodLiteral<"native">;
651
651
  observedAt: z.ZodNullable<z.ZodNumber>;
@@ -772,6 +772,11 @@ export declare const HqResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
772
772
  completed: "completed";
773
773
  }>;
774
774
  pendingActionId: z.ZodNullable<z.ZodUUID>;
775
+ skillsBinding: z.ZodEnum<{
776
+ absent: "absent";
777
+ current: "current";
778
+ stale: "stale";
779
+ }>;
775
780
  isFinalized: z.ZodBoolean;
776
781
  isPlanApproved: z.ZodBoolean;
777
782
  isSequenceApproved: z.ZodBoolean;
@@ -964,6 +969,7 @@ export declare const HqResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
964
969
  hasUncertainEffects: z.ZodBoolean;
965
970
  hasCheckpoint: z.ZodBoolean;
966
971
  hasProposal: z.ZodBoolean;
972
+ proposalId: z.ZodNullable<z.ZodUUID>;
967
973
  unmatchedCount: z.ZodNumber;
968
974
  }, z.core.$strict>>;
969
975
  }, z.core.$strict>;
@@ -992,6 +998,11 @@ export declare const HqResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
992
998
  completed: "completed";
993
999
  }>;
994
1000
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1001
+ skillsBinding: z.ZodEnum<{
1002
+ absent: "absent";
1003
+ current: "current";
1004
+ stale: "stale";
1005
+ }>;
995
1006
  isFinalized: z.ZodBoolean;
996
1007
  isPlanApproved: z.ZodBoolean;
997
1008
  isSequenceApproved: z.ZodBoolean;
@@ -1184,6 +1195,7 @@ export declare const HqResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1184
1195
  hasUncertainEffects: z.ZodBoolean;
1185
1196
  hasCheckpoint: z.ZodBoolean;
1186
1197
  hasProposal: z.ZodBoolean;
1198
+ proposalId: z.ZodNullable<z.ZodUUID>;
1187
1199
  unmatchedCount: z.ZodNumber;
1188
1200
  }, z.core.$strict>>;
1189
1201
  }, z.core.$strict>;
@@ -1336,6 +1348,11 @@ export declare const HqResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1336
1348
  completed: "completed";
1337
1349
  }>;
1338
1350
  pendingActionId: z.ZodNullable<z.ZodUUID>;
1351
+ skillsBinding: z.ZodEnum<{
1352
+ absent: "absent";
1353
+ current: "current";
1354
+ stale: "stale";
1355
+ }>;
1339
1356
  isFinalized: z.ZodBoolean;
1340
1357
  isPlanApproved: z.ZodBoolean;
1341
1358
  isSequenceApproved: z.ZodBoolean;
@@ -1528,6 +1545,7 @@ export declare const HqResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1528
1545
  hasUncertainEffects: z.ZodBoolean;
1529
1546
  hasCheckpoint: z.ZodBoolean;
1530
1547
  hasProposal: z.ZodBoolean;
1548
+ proposalId: z.ZodNullable<z.ZodUUID>;
1531
1549
  unmatchedCount: z.ZodNumber;
1532
1550
  }, z.core.$strict>>;
1533
1551
  }, z.core.$strict>;
@@ -1951,8 +1969,8 @@ export declare const HqResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1951
1969
  state: z.ZodEnum<{
1952
1970
  unavailable: "unavailable";
1953
1971
  available: "available";
1954
- exhausted: "exhausted";
1955
1972
  stale: "stale";
1973
+ exhausted: "exhausted";
1956
1974
  }>;
1957
1975
  source: z.ZodLiteral<"native">;
1958
1976
  observedAt: z.ZodNullable<z.ZodNumber>;
@@ -3103,6 +3121,11 @@ export declare const IpcResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3103
3121
  completed: "completed";
3104
3122
  }>;
3105
3123
  pendingActionId: z.ZodNullable<z.ZodUUID>;
3124
+ skillsBinding: z.ZodEnum<{
3125
+ absent: "absent";
3126
+ current: "current";
3127
+ stale: "stale";
3128
+ }>;
3106
3129
  isFinalized: z.ZodBoolean;
3107
3130
  isPlanApproved: z.ZodBoolean;
3108
3131
  isSequenceApproved: z.ZodBoolean;
@@ -3295,6 +3318,7 @@ export declare const IpcResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3295
3318
  hasUncertainEffects: z.ZodBoolean;
3296
3319
  hasCheckpoint: z.ZodBoolean;
3297
3320
  hasProposal: z.ZodBoolean;
3321
+ proposalId: z.ZodNullable<z.ZodUUID>;
3298
3322
  unmatchedCount: z.ZodNumber;
3299
3323
  }, z.core.$strict>>;
3300
3324
  }, z.core.$strict>;
@@ -3323,6 +3347,11 @@ export declare const IpcResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3323
3347
  completed: "completed";
3324
3348
  }>;
3325
3349
  pendingActionId: z.ZodNullable<z.ZodUUID>;
3350
+ skillsBinding: z.ZodEnum<{
3351
+ absent: "absent";
3352
+ current: "current";
3353
+ stale: "stale";
3354
+ }>;
3326
3355
  isFinalized: z.ZodBoolean;
3327
3356
  isPlanApproved: z.ZodBoolean;
3328
3357
  isSequenceApproved: z.ZodBoolean;
@@ -3515,6 +3544,7 @@ export declare const IpcResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3515
3544
  hasUncertainEffects: z.ZodBoolean;
3516
3545
  hasCheckpoint: z.ZodBoolean;
3517
3546
  hasProposal: z.ZodBoolean;
3547
+ proposalId: z.ZodNullable<z.ZodUUID>;
3518
3548
  unmatchedCount: z.ZodNumber;
3519
3549
  }, z.core.$strict>>;
3520
3550
  }, z.core.$strict>;
@@ -3667,6 +3697,11 @@ export declare const IpcResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3667
3697
  completed: "completed";
3668
3698
  }>;
3669
3699
  pendingActionId: z.ZodNullable<z.ZodUUID>;
3700
+ skillsBinding: z.ZodEnum<{
3701
+ absent: "absent";
3702
+ current: "current";
3703
+ stale: "stale";
3704
+ }>;
3670
3705
  isFinalized: z.ZodBoolean;
3671
3706
  isPlanApproved: z.ZodBoolean;
3672
3707
  isSequenceApproved: z.ZodBoolean;
@@ -3859,6 +3894,7 @@ export declare const IpcResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3859
3894
  hasUncertainEffects: z.ZodBoolean;
3860
3895
  hasCheckpoint: z.ZodBoolean;
3861
3896
  hasProposal: z.ZodBoolean;
3897
+ proposalId: z.ZodNullable<z.ZodUUID>;
3862
3898
  unmatchedCount: z.ZodNumber;
3863
3899
  }, z.core.$strict>>;
3864
3900
  }, z.core.$strict>;
@@ -4282,8 +4318,8 @@ export declare const IpcResponseSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4282
4318
  state: z.ZodEnum<{
4283
4319
  unavailable: "unavailable";
4284
4320
  available: "available";
4285
- exhausted: "exhausted";
4286
4321
  stale: "stale";
4322
+ exhausted: "exhausted";
4287
4323
  }>;
4288
4324
  source: z.ZodLiteral<"native">;
4289
4325
  observedAt: z.ZodNullable<z.ZodNumber>;