jg-agent-hq 0.5.2 → 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.
Files changed (110) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +11 -1
  3. package/api/README.md +24 -8
  4. package/dist/actions/actions.d.ts +17 -17
  5. package/dist/actions/actions.js +47 -34
  6. package/dist/actions/reads.d.ts +4 -4
  7. package/dist/actions/reads.js +16 -9
  8. package/dist/cli/cli.js +80 -21
  9. package/dist/contracts/browser/types.d.ts +24 -0
  10. package/dist/contracts/constants.d.ts +9 -0
  11. package/dist/contracts/constants.js +10 -0
  12. package/dist/contracts/index.d.ts +1 -1
  13. package/dist/contracts/index.js +1 -1
  14. package/dist/contracts/plans/types.d.ts +26 -0
  15. package/dist/contracts/plans/types.js +4 -1
  16. package/dist/contracts/types.d.ts +39 -3
  17. package/dist/errors/utilities.js +2 -2
  18. package/dist/handoffs/handoffs.d.ts +25 -25
  19. package/dist/handoffs/handoffs.js +93 -77
  20. package/dist/ipc/client.d.ts +13 -13
  21. package/dist/ipc/client.js +53 -25
  22. package/dist/ipc/framing.d.ts +1 -1
  23. package/dist/ipc/framing.js +15 -5
  24. package/dist/ipc/server.d.ts +1 -1
  25. package/dist/ipc/server.js +26 -8
  26. package/dist/locks/locks.d.ts +38 -38
  27. package/dist/locks/locks.js +168 -108
  28. package/dist/plans/admission.d.ts +38 -38
  29. package/dist/plans/admission.js +184 -137
  30. package/dist/plans/authority.d.ts +1 -1
  31. package/dist/plans/authority.js +12 -5
  32. package/dist/plans/documents.d.ts +71 -0
  33. package/dist/plans/documents.js +263 -0
  34. package/dist/plans/evidence.d.ts +4 -4
  35. package/dist/plans/evidence.js +64 -29
  36. package/dist/plans/files.d.ts +26 -11
  37. package/dist/plans/files.js +146 -63
  38. package/dist/plans/finalization.d.ts +3 -3
  39. package/dist/plans/finalization.js +12 -17
  40. package/dist/plans/plans.d.ts +78 -78
  41. package/dist/plans/plans.js +305 -126
  42. package/dist/plans/projections.d.ts +2 -2
  43. package/dist/plans/projections.js +18 -7
  44. package/dist/plans/reconciliation.d.ts +4 -4
  45. package/dist/plans/reconciliation.js +33 -26
  46. package/dist/plans/revisions.d.ts +7 -7
  47. package/dist/plans/revisions.js +13 -10
  48. package/dist/plans/types.d.ts +15 -4
  49. package/dist/plans/types.js +11 -3
  50. package/dist/plans/utilities.d.ts +18 -9
  51. package/dist/plans/utilities.js +46 -157
  52. package/dist/providers/claude/claude.d.ts +6 -6
  53. package/dist/providers/claude/claude.js +27 -14
  54. package/dist/providers/claude/control/control.d.ts +19 -19
  55. package/dist/providers/claude/control/control.js +45 -33
  56. package/dist/providers/claude/control/permissions.js +5 -2
  57. package/dist/providers/claude/control/skills.d.ts +1 -1
  58. package/dist/providers/claude/control/skills.js +12 -5
  59. package/dist/providers/claude/control/stream.d.ts +1 -1
  60. package/dist/providers/claude/control/stream.js +6 -3
  61. package/dist/providers/claude/history/history.model.d.ts +2 -2
  62. package/dist/providers/claude/history/history.model.js +30 -13
  63. package/dist/providers/claude/history/types.d.ts +19 -1
  64. package/dist/providers/claude/history/utilities.d.ts +3 -3
  65. package/dist/providers/claude/history/utilities.js +34 -16
  66. package/dist/providers/claude/rpc.d.ts +3 -3
  67. package/dist/providers/claude/rpc.js +56 -19
  68. package/dist/providers/claude/transformers.d.ts +1 -1
  69. package/dist/providers/claude/transformers.js +7 -4
  70. package/dist/providers/codex/approvals/utilities.d.ts +1 -1
  71. package/dist/providers/codex/approvals/utilities.js +6 -3
  72. package/dist/providers/codex/codex.d.ts +2 -2
  73. package/dist/providers/codex/codex.js +48 -21
  74. package/dist/providers/codex/rpc.d.ts +2 -2
  75. package/dist/providers/codex/rpc.js +60 -19
  76. package/dist/providers/codex/transformers.d.ts +4 -4
  77. package/dist/providers/codex/transformers.js +4 -4
  78. package/dist/providers/codex/types.d.ts +12 -12
  79. package/dist/providers/codex/validations.d.ts +1 -1
  80. package/dist/providers/codex/validations.js +7 -3
  81. package/dist/providers/process.d.ts +1 -1
  82. package/dist/providers/process.js +16 -7
  83. package/dist/providers/types.d.ts +3 -3
  84. package/dist/runtime/browser/browser.js +14 -5
  85. package/dist/runtime/runtime.d.ts +13 -13
  86. package/dist/runtime/runtime.js +49 -24
  87. package/dist/runtime/state/state.d.ts +18 -18
  88. package/dist/runtime/state/state.js +100 -45
  89. package/dist/runtime/types.d.ts +37 -37
  90. package/dist/sessions/sessions.d.ts +4 -4
  91. package/dist/sessions/sessions.js +15 -9
  92. package/dist/sessions/utilities.d.ts +1 -1
  93. package/dist/sessions/utilities.js +16 -6
  94. package/dist/skills/skills.d.ts +10 -10
  95. package/dist/skills/skills.js +27 -17
  96. package/dist/store/browser/browser.model.d.ts +1 -1
  97. package/dist/store/browser/browser.model.js +7 -4
  98. package/dist/store/control/control.model.d.ts +4 -4
  99. package/dist/store/control/control.model.js +10 -7
  100. package/dist/store/handoffs/handoffs.model.d.ts +3 -3
  101. package/dist/store/handoffs/handoffs.model.js +9 -6
  102. package/dist/store/plans/plans.model.d.ts +3 -3
  103. package/dist/store/plans/plans.model.js +31 -15
  104. package/dist/store/store.d.ts +1 -1
  105. package/dist/store/store.js +60 -14
  106. package/dist/store/store.worker.js +8 -4
  107. package/dist/store/types.d.ts +72 -54
  108. package/dist/store/types.js +3 -1
  109. package/errors/README.md +63 -63
  110. package/package.json +6 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
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
+
13
+ ## 1.0.0
14
+
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.
16
+ - Use the shared Astro UI 0.4.0, `jg-site` metadata helpers and `jg-playwright` browser checks. Remove `error-message-utils` from the runtime and website.
17
+ - Redesign the public website around Claude Code and Codex collaboration, a copyable API example, the available runtime capabilities and section navigation for the documentation.
18
+
3
19
  ## 0.5.2
4
20
 
5
21
  - Resume inactive managed Codex sessions retained as loaded by native unsubscribe, preserving explicit handoff and active/uncertain ownership guards.
package/README.md CHANGED
@@ -31,6 +31,8 @@ Short metadata operations use `withHqLock`. Long-lived runtime ownership must us
31
31
 
32
32
  See the [API reference](api/README.md) and [error contracts](errors/README.md).
33
33
 
34
+ Intentional failures use `Exception` from `jg-exception`, with the named string codes in the error reference. Local clients use `PUBLIC_ERROR_CODES` and `PUBLIC_ERROR_MESSAGES` from `jg-agent-hq/contracts` for errors translated at the IPC boundary. Safe classifications remain separate from private diagnostic causes.
35
+
34
36
  ## Local controller
35
37
 
36
38
  Install Codex and sign in through its native CLI, then start `jg-agent-hq serve --state-root .runtime --workspace-root /path/to/workspace`. Run `jg-agent-hq status --state-root .runtime` in a client. `threads`, `thread`, `turns`, `items` and `usage` read native information; `stop` waits for confirmed runtime shutdown.
@@ -59,7 +61,7 @@ Use `jg-agent-hq request --state-root <directory>` with a closed HQ command on s
59
61
 
60
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).
61
63
 
62
- 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.
63
65
 
64
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.
65
67
 
@@ -73,6 +75,14 @@ Collect one completed reviewer message by its exact native turn/item reference.
73
75
 
74
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.
75
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
+
76
86
  ## Project blueprint
77
87
 
78
88
  - `src/index.ts`: the explicit public package boundary.
package/api/README.md CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  Import the named exports from `jg-agent-hq`. Internal module paths are private.
4
4
 
5
+ Intentional Node API failures use `Exception` from `jg-exception`. The [error reference](../errors/README.md) defines their named string codes and stable messages. `PUBLIC_ERROR_CODES` and `PUBLIC_ERROR_MESSAGES` are available from `jg-agent-hq/contracts` for the seven safe client classifications. SQLite-worker responses retain the originating application code; arbitrary worker failures become `JG_AGENT_HQ_STORE_FAILED`. Browser and IPC error bodies expose only their established safe classification and message.
6
+
5
7
  ## Lock lifecycle
6
8
 
7
- - `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.
8
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.
9
11
  - `readHqLockState(root, now?)` reports free, held or unreadable without acquiring or reclaiming the lock. Held state includes the owner, liveness and age.
10
12
  - `getOwnerLiveness(pid)` reports alive, dead or unknown. An unverifiable owner is not evidence that recovery is safe.
@@ -166,13 +168,17 @@ Output is one JSON line with `schemaVersion: 1`. Read output includes the comman
166
168
 
167
169
  ## Plan coordination
168
170
 
169
- `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
+
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.
170
174
 
171
- 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.
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.
172
178
 
173
179
  | Command kind | Required fields and result |
174
180
  | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
175
- | `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. |
176
182
  | `milestones` | `target`, optional `limit` (default 32, maximum 128) and `cursor`. Returns a bounded ordered seek page. |
177
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. |
178
184
  | `begin-revision` | `target`, `action`, `expected`, `intent: 'plan' \| 'breakdown'`, `threadIds`, `checkouts`. Closes execution admission and starts owned interruption/checkpoint work. |
@@ -188,13 +194,23 @@ Send `{ kind: 'plan', command }` through the existing local request API. Every c
188
194
 
189
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.
190
196
 
191
- 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.
198
+
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.
192
200
 
193
- 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.
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.
194
202
 
195
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.
196
204
 
197
- 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.
198
214
 
199
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.
200
216
 
@@ -206,7 +222,7 @@ Begin revision before invoking a planning skill. Execution admission closes unde
206
222
 
207
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.
208
224
 
209
- 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.
210
226
 
211
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.
212
228
 
@@ -14,14 +14,14 @@ export declare const createActions: (native: ICodexProvider, claude: ReturnType<
14
14
  * Returns after durable admission; the native operation outlives this client request.
15
15
  * @returns The durable admission receipt after validation.
16
16
  * @throws
17
- * - -1: The HQ action conflicts with its recorded state
18
- * - -1: The HQ skill is unavailable
19
- * - -1: The HQ request is invalid
20
- * - -1: The HQ target is outside the allowed workspaces
21
- * - -1: The Codex integration failed
22
- * - -1: The Claude integration failed
23
- * - -1: The Claude history is unavailable
24
- * - -1: The HQ store failed
17
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
18
+ * - JG_AGENT_HQ_SKILL_UNAVAILABLE: The HQ skill is unavailable
19
+ * - JG_AGENT_HQ_REQUEST_INVALID: The HQ request is invalid
20
+ * - JG_AGENT_HQ_TARGET_FORBIDDEN: The HQ target is outside the allowed workspaces
21
+ * - JG_AGENT_HQ_CODEX_FAILED: The Codex integration failed
22
+ * - JG_AGENT_HQ_CLAUDE_FAILED: The Claude integration failed
23
+ * - JG_AGENT_HQ_CLAUDE_HISTORY_UNAVAILABLE: The Claude history is unavailable
24
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
25
25
  */
26
26
  submit(action: IActionEnvelope): Promise<IActionReceipt>;
27
27
  /** Reads only current in-memory prompts for the selected managed thread. */
@@ -30,21 +30,21 @@ export declare const createActions: (native: ICodexProvider, claude: ReturnType<
30
30
  * Quiesces the selected managed cohort without stopping unrelated controllers.
31
31
  * @returns A promise resolved only after interruption, background cleanup and release evidence.
32
32
  * @throws
33
- * - -1: The HQ action conflicts with its recorded state
34
- * - -1: The HQ target is outside the allowed workspaces
35
- * - -1: The HQ store failed
36
- * - -1: The Codex integration failed
37
- * - -1: The Claude integration failed
33
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
34
+ * - JG_AGENT_HQ_TARGET_FORBIDDEN: The HQ target is outside the allowed workspaces
35
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
36
+ * - JG_AGENT_HQ_CODEX_FAILED: The Codex integration failed
37
+ * - JG_AGENT_HQ_CLAUDE_FAILED: The Claude integration failed
38
38
  */
39
39
  quiescePlan(controls: IPlanRevisionWorkflow["controls"]): Promise<void>;
40
40
  /**
41
41
  * Stops admission, interrupts active work, cleans native terminals and confirms shutdown.
42
42
  * @returns A promise resolved after native exit and release of durable control ownership.
43
43
  * @throws
44
- * - -1: The Codex integration failed
45
- * - -1: The Claude integration failed
46
- * - -1: The HQ transport failed
47
- * - -1: The HQ store failed
44
+ * - JG_AGENT_HQ_CODEX_FAILED: The Codex integration failed
45
+ * - JG_AGENT_HQ_CLAUDE_FAILED: The Claude integration failed
46
+ * - JG_AGENT_HQ_TRANSPORT_FAILED: The HQ transport failed
47
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
48
48
  */
49
49
  close(): Promise<void>;
50
50
  };
@@ -1,5 +1,5 @@
1
1
  import { createHmac, randomUUID } from 'node:crypto';
2
- import { Exception, extractMessage } from 'error-message-utils';
2
+ import { Exception, extractMessage, isException } from 'jg-exception';
3
3
  import { z } from 'zod';
4
4
  import { setTimeout as wait } from 'node:timers/promises';
5
5
  import { getErrorKind } from '../errors/index.js';
@@ -40,12 +40,18 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
40
40
  let unavailable = false;
41
41
  let eventFailure;
42
42
  const conflict = () => {
43
- throw new Exception('The HQ action conflicts with its recorded state', undefined, {
44
- kind: 'state-conflict',
43
+ throw new Exception('The HQ action conflicts with its recorded state', {
44
+ code: 'JG_AGENT_HQ_ACTION_CONFLICT',
45
+ data: {
46
+ kind: 'state-conflict',
47
+ },
45
48
  });
46
49
  };
47
50
  const agentUnavailable = () => {
48
- throw new Exception('The Codex integration failed', undefined, { kind: 'agent-unavailable' });
51
+ throw new Exception('The Codex integration failed', {
52
+ code: 'JG_AGENT_HQ_CODEX_FAILED',
53
+ data: { kind: 'agent-unavailable' },
54
+ });
49
55
  };
50
56
  /** Quarantines controls after a lifecycle gap and stops the native transport. */
51
57
  const failEvents = (cause) => {
@@ -111,7 +117,10 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
111
117
  if (unavailable)
112
118
  return;
113
119
  if (eventCount >= 128) {
114
- failEvents(new Exception('The Codex integration failed', undefined, { kind: 'agent-unavailable' }));
120
+ failEvents(new Exception('The Codex integration failed', {
121
+ code: 'JG_AGENT_HQ_CODEX_FAILED',
122
+ data: { kind: 'agent-unavailable' },
123
+ }));
115
124
  return;
116
125
  }
117
126
  eventCount += 1;
@@ -179,8 +188,8 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
179
188
  * Dispatches one admitted intent once and records delivery without replaying it.
180
189
  * @returns A promise resolved after delivery evidence or uncertainty is persisted.
181
190
  * @throws
182
- * - -1: The HQ action conflicts with its recorded state
183
- * - -1: The HQ store failed
191
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
192
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
184
193
  */
185
194
  const dispatch = async (initial, originalThread, command, input) => {
186
195
  let receipt = initial;
@@ -295,7 +304,7 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
295
304
  }
296
305
  catch (error) {
297
306
  // Only a matching native error response proves rejection. Transport loss and malformed results remain uncertain.
298
- const explicit = error instanceof Exception && NativeRejectionSchema.safeParse(error.data).success;
307
+ const explicit = isException(error) && NativeRejectionSchema.safeParse(error.data).success;
299
308
  const kind = getErrorKind(error);
300
309
  const failure = kind === 'state-conflict' || kind === 'access-denied' || kind === 'agent-unavailable'
301
310
  ? kind
@@ -620,14 +629,14 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
620
629
  * Validates the current target and separates new dispatch from idempotent receipt reads.
621
630
  * @returns The durable admission receipt; native work runs independently.
622
631
  * @throws
623
- * - -1: The HQ action conflicts with its recorded state
624
- * - -1: The HQ skill is unavailable
625
- * - -1: The HQ request is invalid
626
- * - -1: The HQ target is outside the allowed workspaces
627
- * - -1: The Codex integration failed
628
- * - -1: The Claude integration failed
629
- * - -1: The Claude history is unavailable
630
- * - -1: The HQ store failed
632
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
633
+ * - JG_AGENT_HQ_SKILL_UNAVAILABLE: The HQ skill is unavailable
634
+ * - JG_AGENT_HQ_REQUEST_INVALID: The HQ request is invalid
635
+ * - JG_AGENT_HQ_TARGET_FORBIDDEN: The HQ target is outside the allowed workspaces
636
+ * - JG_AGENT_HQ_CODEX_FAILED: The Codex integration failed
637
+ * - JG_AGENT_HQ_CLAUDE_FAILED: The Claude integration failed
638
+ * - JG_AGENT_HQ_CLAUDE_HISTORY_UNAVAILABLE: The Claude history is unavailable
639
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
631
640
  */
632
641
  const admitAndDispatch = async (action) => {
633
642
  // The worker verifies the complete digest before returning any existing receipt.
@@ -810,14 +819,14 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
810
819
  * Returns after durable admission; the native operation outlives this client request.
811
820
  * @returns The durable admission receipt after validation.
812
821
  * @throws
813
- * - -1: The HQ action conflicts with its recorded state
814
- * - -1: The HQ skill is unavailable
815
- * - -1: The HQ request is invalid
816
- * - -1: The HQ target is outside the allowed workspaces
817
- * - -1: The Codex integration failed
818
- * - -1: The Claude integration failed
819
- * - -1: The Claude history is unavailable
820
- * - -1: The HQ store failed
822
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
823
+ * - JG_AGENT_HQ_SKILL_UNAVAILABLE: The HQ skill is unavailable
824
+ * - JG_AGENT_HQ_REQUEST_INVALID: The HQ request is invalid
825
+ * - JG_AGENT_HQ_TARGET_FORBIDDEN: The HQ target is outside the allowed workspaces
826
+ * - JG_AGENT_HQ_CODEX_FAILED: The Codex integration failed
827
+ * - JG_AGENT_HQ_CLAUDE_FAILED: The Claude integration failed
828
+ * - JG_AGENT_HQ_CLAUDE_HISTORY_UNAVAILABLE: The Claude history is unavailable
829
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
821
830
  */
822
831
  async submit(action) {
823
832
  const admission = admitAndDispatch(action);
@@ -839,11 +848,11 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
839
848
  * Quiesces the selected managed cohort without stopping unrelated controllers.
840
849
  * @returns A promise resolved only after interruption, background cleanup and release evidence.
841
850
  * @throws
842
- * - -1: The HQ action conflicts with its recorded state
843
- * - -1: The HQ target is outside the allowed workspaces
844
- * - -1: The HQ store failed
845
- * - -1: The Codex integration failed
846
- * - -1: The Claude integration failed
851
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
852
+ * - JG_AGENT_HQ_TARGET_FORBIDDEN: The HQ target is outside the allowed workspaces
853
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
854
+ * - JG_AGENT_HQ_CODEX_FAILED: The Codex integration failed
855
+ * - JG_AGENT_HQ_CLAUDE_FAILED: The Claude integration failed
847
856
  */
848
857
  async quiescePlan(controls) {
849
858
  const failures = [];
@@ -860,10 +869,10 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
860
869
  * Stops admission, interrupts active work, cleans native terminals and confirms shutdown.
861
870
  * @returns A promise resolved after native exit and release of durable control ownership.
862
871
  * @throws
863
- * - -1: The Codex integration failed
864
- * - -1: The Claude integration failed
865
- * - -1: The HQ transport failed
866
- * - -1: The HQ store failed
872
+ * - JG_AGENT_HQ_CODEX_FAILED: The Codex integration failed
873
+ * - JG_AGENT_HQ_CLAUDE_FAILED: The Claude integration failed
874
+ * - JG_AGENT_HQ_TRANSPORT_FAILED: The HQ transport failed
875
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
867
876
  */
868
877
  async close() {
869
878
  closing = true;
@@ -902,7 +911,11 @@ export const createActions = (native, claude, readClaudeThread, store, roots, ep
902
911
  await lane.catch(() => undefined);
903
912
  const failedExit = nativeExit.find((result) => result.status === 'rejected');
904
913
  if (failedExit?.status === 'rejected')
905
- throw new Exception(`The HQ transport failed: ${extractMessage(failedExit.reason)}`, undefined, { kind: 'operation-failed' }, { cause: cleanupFailure ?? failedExit.reason });
914
+ throw new Exception(`The HQ transport failed: ${extractMessage(failedExit.reason)}`, {
915
+ code: 'JG_AGENT_HQ_TRANSPORT_FAILED',
916
+ data: { kind: 'operation-failed' },
917
+ cause: cleanupFailure ?? failedExit.reason,
918
+ });
906
919
  }
907
920
  if (cleanupFailure)
908
921
  throw cleanupFailure;
@@ -8,10 +8,10 @@ type IControlRead = Extract<IHqRequest, {
8
8
  * Authorizes bounded control reads and binds seek positions to their exact query.
9
9
  * @returns The selected record or bounded page.
10
10
  * @throws
11
- * - -1: The HQ action conflicts with its recorded state
12
- * - -1: The HQ cursor does not match this request
13
- * - -1: The HQ target is outside the allowed workspaces
14
- * - -1: The HQ store failed
11
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
12
+ * - JG_AGENT_HQ_CURSOR_INVALID: The HQ cursor does not match this request
13
+ * - JG_AGENT_HQ_TARGET_FORBIDDEN: The HQ target is outside the allowed workspaces
14
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
15
15
  */
16
16
  export declare const readControl: (command: IControlRead, store: IStore, actions: ReturnType<typeof createActions>, roots: string[]) => Promise<IHqResponse>;
17
17
  export {};
@@ -1,4 +1,4 @@
1
- import { Exception } from 'error-message-utils';
1
+ import { Exception } from 'jg-exception';
2
2
  import { z } from 'zod';
3
3
  import { resolveWorkspaceTarget } from '../runtime/state/index.js';
4
4
  import { decodeHistoryCursor, encodeHistoryCursor } from '../sessions/index.js';
@@ -6,7 +6,7 @@ const PositionSchema = z.strictObject({ createdAt: z.number().int(), id: z.uuid(
6
6
  /**
7
7
  * Validates the application-owned seek position after the shared query-binding check.
8
8
  * @throws
9
- * - -1: The HQ cursor does not match this request
9
+ * - JG_AGENT_HQ_CURSOR_INVALID: The HQ cursor does not match this request
10
10
  */
11
11
  const readPosition = (cursor, filters) => {
12
12
  const decoded = decodeHistoryCursor(cursor, filters);
@@ -16,7 +16,11 @@ const readPosition = (cursor, filters) => {
16
16
  return PositionSchema.parse(JSON.parse(decoded));
17
17
  }
18
18
  catch (cause) {
19
- throw new Exception('The HQ cursor does not match this request', undefined, { kind: 'invalid-request' }, { cause });
19
+ throw new Exception('The HQ cursor does not match this request', {
20
+ code: 'JG_AGENT_HQ_CURSOR_INVALID',
21
+ data: { kind: 'invalid-request' },
22
+ cause,
23
+ });
20
24
  }
21
25
  };
22
26
  /** Encodes the final row's complete ordering tuple only when another page exists. */
@@ -28,10 +32,10 @@ const nextPageCursor = (page, filters) => {
28
32
  * Authorizes bounded control reads and binds seek positions to their exact query.
29
33
  * @returns The selected record or bounded page.
30
34
  * @throws
31
- * - -1: The HQ action conflicts with its recorded state
32
- * - -1: The HQ cursor does not match this request
33
- * - -1: The HQ target is outside the allowed workspaces
34
- * - -1: The HQ store failed
35
+ * - JG_AGENT_HQ_ACTION_CONFLICT: The HQ action conflicts with its recorded state
36
+ * - JG_AGENT_HQ_CURSOR_INVALID: The HQ cursor does not match this request
37
+ * - JG_AGENT_HQ_TARGET_FORBIDDEN: The HQ target is outside the allowed workspaces
38
+ * - JG_AGENT_HQ_STORE_FAILED: The HQ store failed
35
39
  */
36
40
  export const readControl = async (command, store, actions, roots) => {
37
41
  const authorize = async (thread) => {
@@ -80,8 +84,11 @@ export const readControl = async (command, store, actions, roots) => {
80
84
  if (command.kind === 'managed-thread')
81
85
  return { kind: command.kind, result: thread };
82
86
  if (!thread)
83
- throw new Exception('The HQ action conflicts with its recorded state', undefined, {
84
- kind: 'state-conflict',
87
+ throw new Exception('The HQ action conflicts with its recorded state', {
88
+ code: 'JG_AGENT_HQ_ACTION_CONFLICT',
89
+ data: {
90
+ kind: 'state-conflict',
91
+ },
85
92
  });
86
93
  if (command.kind === 'events')
87
94
  return {