overlord-cli 0.2610261104.0 → 0.2610301407.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.
@@ -9,6 +9,7 @@ OpenCode, Antigravity, and others). A connector is what lets an agent speak the
9
9
  - [For Users](#for-users)
10
10
  - [Setting up connectors](#setting-up-connectors)
11
11
  - [Connector bundles](#connector-bundles)
12
+ - [Plugin marketplace](#plugin-marketplace)
12
13
  - [Extension point](#extension-point)
13
14
  - [For Developers](#for-developers)
14
15
  - [Contract Component](#contract-component)
@@ -41,6 +42,19 @@ connector contract version changes.
41
42
  - [Antigravity](adapters/antigravity/README.md): Antigravity plugin exposing the local mission workflow to Antigravity CLI/IDE sessions.
42
43
  - [OpenCode](adapters/opencode/README.md): control-plane connector (Shape C) driven by `ovld agent-session sidecar` — no hook scripts.
43
44
 
45
+ ### Plugin marketplace
46
+
47
+ The dedicated [Overlord ecosystem marketplace](https://github.com/cooperativ-labs/overlord-marketplace#readme)
48
+ is intended to distribute the optional Knowledgebase plugin for Codex CLI and
49
+ Claude Code. Publication and public first-install verification are pending; consult
50
+ its README for the current status and installation and refresh instructions. Knowledgebase
51
+ also supports MCP-only use; its onboarding changes are tracked in per:214.
52
+
53
+ Continue to install and refresh Overlord itself with `ovld agent-setup <agent>`.
54
+ That setup owns its existing hooks and, for Codex, rules and permission profile.
55
+ The new marketplace's v1 scope does not include Overlord or Scribe and does not
56
+ migrate existing installations.
57
+
44
58
  ### Extension point
45
59
 
46
60
  A custom agent connector is a sanctioned extension point: a new adapter plus a
@@ -1 +1 @@
1
- 0.3.57
1
+ 0.3.59
@@ -1,4 +1,4 @@
1
- contractVersion: "167"
1
+ contractVersion: "168"
2
2
  componentType: connector
3
3
  componentKey: antigravity
4
4
  label: "Antigravity Connector"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "overlord",
4
- "version": "0.3.57",
4
+ "version": "0.3.59",
5
5
  "description": "Chat-driven access to Overlord mission protocol workflows through skills and MCP.",
6
6
  "author": {
7
7
  "name": "Cooperativ",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.57",
3
+ "version": "0.3.59",
4
4
  "description": "Overlord mission protocol workflow for Claude Code — attach/update/ask/deliver, slash commands, and hook-driven activity capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -1,4 +1,4 @@
1
- contractVersion: "167"
1
+ contractVersion: "168"
2
2
  componentType: connector
3
3
  componentKey: claude
4
4
  label: "Claude Code Connector"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.57",
3
+ "version": "0.3.59",
4
4
  "description": "Chat-driven access to Overlord mission protocol workflows with hook-driven activity capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -1,4 +1,4 @@
1
- contractVersion: "167"
1
+ contractVersion: "168"
2
2
  componentType: connector
3
3
  componentKey: codex
4
4
  label: "Codex Connector"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.57",
3
+ "version": "0.3.59",
4
4
  "description": "Overlord mission protocol workflow for Cursor — attach/update/ask/deliver, slash commands, MCP bridge, and follow-up capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -1,4 +1,4 @@
1
- contractVersion: "167"
1
+ contractVersion: "168"
2
2
  componentType: connector
3
3
  componentKey: cursor
4
4
  label: "Cursor Connector"
@@ -1,4 +1,4 @@
1
- contractVersion: "167"
1
+ contractVersion: "168"
2
2
  componentType: connector
3
3
  componentKey: opencode
4
4
  label: "OpenCode Connector"
@@ -26,11 +26,10 @@ Re-running setup is idempotent. `ovld doctor` reports missing or modified manage
26
26
 
27
27
  PI accepts provider-qualified models with `--model` and an independent `--thinking` level. The built-in catalog includes:
28
28
 
29
- | Display name | PI model ID |
30
- | --------------- | ---------------------------- |
31
- | GLM 5.2 | `zai/glm-5.2` |
32
- | Claude Opus 4.8 | `anthropic/claude-opus-4-8` |
33
- | GPT-5.6 Terra | `openai-codex/gpt-5.6-terra` |
29
+ | Display name | PI model ID |
30
+ | --------------- | --------------------------- |
31
+ | GLM 5.2 | `zai/glm-5.2` |
32
+ | Claude Opus 4.8 | `anthropic/claude-opus-4-8` |
34
33
 
35
34
  Authenticate the matching PI provider through PI's login/configuration flow or its supported environment variables. Use `pi --list-models` to inspect the models available to the current PI configuration.
36
35
 
@@ -1,4 +1,4 @@
1
- contractVersion: "167"
1
+ contractVersion: "168"
2
2
  componentType: connector
3
3
  componentKey: pi
4
4
  label: "PI Connector"
@@ -186,6 +186,16 @@ with a JSON string array when a path contains a comma or the list is long. They
186
186
  Declared, never as native capture. Never use it to enumerate every changed or opened file, and
187
187
  never make a separate call just to declare paths.
188
188
 
189
+ If attach warns that its local binding or ledger is unavailable, keep the explicit
190
+ `--session-key` and `--objective-id` on `update` / `deliver` and include the known missed
191
+ paths normally. The CLI still submits them through the authenticated session as Declared;
192
+ do not omit paths or replace the file evidence with a list in the summary. Check stderr for
193
+ acceptance/sync warnings. If fallback synchronization fails, repeat those declarations on a
194
+ later update/deliver because no local retry copy exists. Re-run attach in the intended checkout
195
+ with the same `OVLD_HOME` to restore native capture. `changes` reports the local coverage gap
196
+ in `capture.healthCodes`; `objective-changes` reads synchronized evidence, including fallback
197
+ declarations, from the server.
198
+
189
199
  Artifacts and a delivery report remain optional annotations when they add review value. There
190
200
  is no per-file explanation input. Use `--payload-json` when the full delivery object fits comfortably inline
191
201
  (roughly under 8 KB). Larger inline `--*-json` values are rejected; stream them through the
@@ -233,12 +243,12 @@ human implementation follow-up such as deploy, secrets, or migrations (those bel
233
243
 
234
244
  #### Writing a deferred-work item
235
245
 
236
- | Field | Limit | What to write |
237
- | ---------- | --------- | ------------------------------------------------------------------- |
238
- | `title` | 80 chars | The work, as an imperative phrase. Shown as the row title. |
239
- | `change` | 400 chars | The specific change that is needed, in one or two sentences. |
240
- | `location` | 200 chars | Where to find it: the file, function, component, or command. |
241
- | `doneWhen` | 200 chars | The observable result, in one sentence. |
246
+ | Field | Limit | What to write |
247
+ | ---------- | --------- | ------------------------------------------------------------ |
248
+ | `title` | 80 chars | The work, as an imperative phrase. Shown as the row title. |
249
+ | `change` | 400 chars | The specific change that is needed, in one or two sentences. |
250
+ | `location` | 200 chars | Where to find it: the file, function, component, or command. |
251
+ | `doneWhen` | 200 chars | The observable result, in one sentence. |
242
252
 
243
253
  All four fields are required. A plain string item is rejected with `invalid_input`.
244
254
 
@@ -361,6 +371,9 @@ ovld protocol deliver --session-key <sessionKey> --objective-id $OBJECTIVE_ID \
361
371
  EOF
362
372
  ```
363
373
 
374
+ For spaces, quote the whole inline value, for example
375
+ `--paths "planning/demo environment.md,src/generated.ts"`, or use the JSON array form.
376
+
364
377
  Paths are normalized against the checkout. Traversal, symlinks that leave the checkout, ignored
365
378
  paths, and Overlord-managed paths are rejected with a reason on stderr and never fail the call.
366
379
 
@@ -389,7 +402,7 @@ ovld protocol create --project-id <project-id> --agent <agent-identifier> --obje
389
402
  # One call: a draft mission whose first objective is already assigned to Codex.
390
403
  ovld protocol create --agent <agent-identifier> \
391
404
  --project-id <project-id> \
392
- --objectives-json '[{"objective":"Implement the API","agent":"codex","model":"gpt-5.6-terra"},{"objective":"Add CLI docs","agent":"claude"}]'
405
+ --objectives-json '[{"objective":"Implement the API","agent":"codex","model":"gpt-6.1-terra"},{"objective":"Add CLI docs","agent":"claude"}]'
393
406
  ```
394
407
 
395
408
  ```bash
@@ -143,6 +143,15 @@ paths, and Overlord-managed paths are rejected with a reason on stderr and never
143
143
  Absent targets (deleted or renamed-away files) are valid. Never enumerate every changed or
144
144
  opened file, and when unsure, describe the coverage gap in the summary instead of guessing.
145
145
 
146
+ Quote an inline value containing spaces: `--paths "planning/demo environment.md,src/generated.ts"`.
147
+ If the local binding or ledger is unavailable, pass `--session-key` and `--objective-id`
148
+ explicitly and keep the path flags. The CLI warns and submits normalized paths through the
149
+ authenticated session as Declared; do not drop the paths from delivery. Fallback sync failures
150
+ warn and need the declarations repeated on a later update/deliver (no local retry copy).
151
+ Use `objective-changes` to read synchronized fallback evidence. Local `changes` instead reports
152
+ the missing/invalid binding in `capture.healthCodes` and stderr. Restore native capture by
153
+ re-running attach in the intended checkout with the same `OVLD_HOME` and writable storage.
154
+
146
155
  ### Shared worktree safety (critical)
147
156
 
148
157
  The working tree may contain file changes from **other agents, missions, or objectives** running concurrently in the same checkout or worktree. Those changes are **not yours to undo**.
@@ -188,7 +197,7 @@ ovld protocol create --project-id <project-id> --agent <agent-identifier> --obje
188
197
  # One call: a draft mission whose first objective is already assigned to Codex.
189
198
  ovld protocol create --agent <agent-identifier> \
190
199
  --project-id <project-id> \
191
- --objectives-json '[{"objective":"Implement the API","agent":"codex","model":"gpt-5.6-terra"},{"objective":"Add CLI docs","agent":"claude"}]'
200
+ --objectives-json '[{"objective":"Implement the API","agent":"codex","model":"gpt-6.1-terra"},{"objective":"Add CLI docs","agent":"claude"}]'
192
201
  ```
193
202
 
194
203
  ```bash
@@ -1837,7 +1837,7 @@ process.stdin.on('data', async chunk => {
1837
1837
  result: {
1838
1838
  protocolVersion: PROTOCOL_VERSION,
1839
1839
  capabilities: { tools: { listChanged: false } },
1840
- serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.57' }
1840
+ serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.59' }
1841
1841
  }
1842
1842
  });
1843
1843
  continue;
@@ -41,6 +41,7 @@ Required content:
41
41
  - Deliver last with a summary written by behavior or component, plus artifacts when they add review value.
42
42
  - Never revert, restore, or delete concurrent work from other agents or missions to deliver; ask instead.
43
43
  - Declare only known shell/script/generator outputs, deletes, and rename endpoints that capture missed (`--paths` / `--paths-file`); there is no per-file explanation input.
44
+ - Quote inline path lists containing spaces; use a JSON string array with `--paths-file <path|->` for commas or long lists. If local binding/storage is unavailable, retain the explicit session key, objective id, and path flags: the CLI warns and submits Declared evidence through the authenticated session. Read it with `objective-changes`; local `changes` explains the coverage gap. Failed fallback sync requires repeating the declarations because it has no local retry copy.
44
45
  - Use stdin/file flags for shell-special content.
45
46
  - Use stdin/file flags for oversized JSON payloads (`--*-json` values above ~8 KB are rejected; use `--*-file -`).
46
47
  - Do not continue implementation after delivery unless follow-up execution is explicitly requested.
package/dist/index.js CHANGED
@@ -5888,6 +5888,15 @@ function removeChangeLedger(input2) {
5888
5888
  return false;
5889
5889
  }
5890
5890
  }
5891
+ function prepareDeclaredChangeEvidence(input2) {
5892
+ const ledger = emptyLedger(input2);
5893
+ const result = appendEvidenceToLedger(ledger, {
5894
+ filePaths: input2.filePaths,
5895
+ source: "agent_declared",
5896
+ hookHealth: AGENT_DECLARED_HEALTH
5897
+ });
5898
+ return { evidence: ledger.evidence, rejected: result.rejected };
5899
+ }
5891
5900
  var LEDGER_SCHEMA_VERSION, MAX_PATHS_PER_APPEND, MAX_LEDGER_EVIDENCE, MAX_HEALTH_ENTRIES, STICKY_HEALTH_CODES, MAX_HEALTH_CODE_LENGTH, MAX_IGNORE_FILE_BYTES, MAX_IGNORE_LINES, MAX_IGNORE_RULES, MAX_IGNORE_LINE_LENGTH, MAX_LEDGER_FILE_BYTES, LEDGER_EVIDENCE_KEYS, LEDGER_HEALTH_KEYS, LEDGER_CAPTURE_KEYS, CAPTURE_BINDING_STATES, AGENT_DECLARED_HEALTH, LEGACY_GENERATOR_DECLARATION_HEALTH, LEGACY_WINDOW_DISCARDED_HEALTH, LEGACY_V2_EVIDENCE_KEYS;
5892
5901
  var init_change_ledger = __esm({
5893
5902
  "src/change-ledger.ts"() {
@@ -5934,6 +5943,7 @@ var init_change_ledger = __esm({
5934
5943
  var active_objective_sessions_exports = {};
5935
5944
  __export(active_objective_sessions_exports, {
5936
5945
  MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS: () => MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS,
5946
+ diagnoseObjectiveBinding: () => diagnoseObjectiveBinding,
5937
5947
  finalizeActiveSession: () => finalizeActiveSession,
5938
5948
  readActiveSessions: () => readActiveSessions,
5939
5949
  readObjectiveSessions: () => readObjectiveSessions,
@@ -5996,7 +6006,7 @@ function readManifest(workingDirectory) {
5996
6006
  const raw = readBoundedUtf8File(target, MAX_ACTIVE_SESSION_MANIFEST_BYTES);
5997
6007
  if (raw === null) return null;
5998
6008
  const value2 = JSON.parse(raw);
5999
- if (value2.schemaVersion !== 3 || value2.workingDirectory !== expected.workingDirectory || !Array.isArray(value2.entries) || value2.entries.length > MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS) {
6009
+ if (value2.schemaVersion !== 3 || value2.workingDirectory !== expected.workingDirectory || !Array.isArray(value2.entries)) {
6000
6010
  return null;
6001
6011
  }
6002
6012
  return {
@@ -6012,7 +6022,14 @@ function readManifest(workingDirectory) {
6012
6022
  }
6013
6023
  function writeManifest(workingDirectory, entries) {
6014
6024
  const manifest = { ...emptyManifest(workingDirectory), entries };
6015
- writeOwnerOnlyFileAtomically(manifestPath2(workingDirectory), JSON.stringify(manifest));
6025
+ const contents = JSON.stringify(manifest);
6026
+ if (Buffer.byteLength(contents) > MAX_ACTIVE_SESSION_MANIFEST_BYTES) {
6027
+ throw new Error("Local binding manifest exceeds its storage limit.");
6028
+ }
6029
+ writeOwnerOnlyFileAtomically(manifestPath2(workingDirectory), contents);
6030
+ }
6031
+ function manifestFits(workingDirectory, entries) {
6032
+ return Buffer.byteLength(JSON.stringify({ ...emptyManifest(workingDirectory), entries })) <= MAX_ACTIVE_SESSION_MANIFEST_BYTES;
6016
6033
  }
6017
6034
  function resolveEntry(entries, requestedObjectiveId) {
6018
6035
  const matching = entries.filter(
@@ -6052,7 +6069,7 @@ function writeActiveSession({
6052
6069
  const prior = current.find(
6053
6070
  (entry) => entry.objectiveId === trimmedObjective && !entry.deliveryPendingSync
6054
6071
  );
6055
- const entries = current.filter(
6072
+ let entries = current.filter(
6056
6073
  (entry) => entry.objectiveId !== trimmedObjective || entry.deliveryPendingSync
6057
6074
  );
6058
6075
  if (prior && prior.sessionKey !== trimmedKey) {
@@ -6063,10 +6080,6 @@ function writeActiveSession({
6063
6080
  });
6064
6081
  if (!removed) entries.push({ ...prior, deliveryPendingSync: true });
6065
6082
  }
6066
- if (entries.length >= MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS) {
6067
- if (prior && prior.sessionKey !== trimmedKey) writeManifest(workingDirectory, entries);
6068
- return false;
6069
- }
6070
6083
  const next = {
6071
6084
  missionId: trimmedMission,
6072
6085
  objectiveId: trimmedObjective,
@@ -6075,6 +6088,24 @@ function writeActiveSession({
6075
6088
  attachedAt: (/* @__PURE__ */ new Date()).toISOString(),
6076
6089
  deliveryPendingSync: false
6077
6090
  };
6091
+ const hasCapacity = () => entries.filter((entry) => entry.objectiveId === trimmedObjective).length < MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS && manifestFits(workingDirectory, [...entries, next]);
6092
+ if (!hasCapacity()) {
6093
+ const retries = entries.filter((entry) => entry.deliveryPendingSync).sort((left, right) => Date.parse(left.attachedAt) - Date.parse(right.attachedAt));
6094
+ for (const entry of retries) {
6095
+ if (hasCapacity()) break;
6096
+ if (removeChangeLedger({
6097
+ workingDirectory,
6098
+ objectiveId: entry.objectiveId,
6099
+ sessionKey: entry.sessionKey
6100
+ })) {
6101
+ entries = entries.filter((candidate) => candidate !== entry);
6102
+ }
6103
+ }
6104
+ }
6105
+ if (!hasCapacity()) {
6106
+ if (prior && prior.sessionKey !== trimmedKey) writeManifest(workingDirectory, entries);
6107
+ return false;
6108
+ }
6078
6109
  if (prior?.sessionKey !== trimmedKey) {
6079
6110
  resetChangeLedger({
6080
6111
  workingDirectory,
@@ -6224,6 +6255,17 @@ function finalizeActiveSession({
6224
6255
  return false;
6225
6256
  }
6226
6257
  }
6258
+ function diagnoseObjectiveBinding(workingDirectory, objectiveId) {
6259
+ const target = manifestPath2(workingDirectory);
6260
+ if (!existsSync11(target)) return "binding_file_missing";
6261
+ const manifest = readManifest(workingDirectory);
6262
+ if (!manifest) return "binding_file_unreadable_or_invalid";
6263
+ const matches = manifest.entries.filter((entry) => entryMatchesObjective(entry, objectiveId));
6264
+ if (matches.length >= MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS)
6265
+ return "objective_binding_capacity_reached";
6266
+ if (matches.length === 0) return "objective_binding_missing_in_working_directory";
6267
+ return "binding_or_ledger_storage_unavailable";
6268
+ }
6227
6269
  var MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS, MAX_OBJECTIVE_ALIASES, MAX_ID_LENGTH, MAX_ACTIVE_SESSION_MANIFEST_BYTES, MAX_ACTIVE_SESSION_MANIFEST_FILES;
6228
6270
  var init_active_objective_sessions = __esm({
6229
6271
  "src/active-objective-sessions.ts"() {
@@ -44619,7 +44661,8 @@ function bareHealthCode(code) {
44619
44661
  function buildLocalObjectiveChanges({
44620
44662
  objectiveId,
44621
44663
  snapshots,
44622
- syncFailed
44664
+ syncFailed,
44665
+ unavailableDiagnosis = "objective_binding_missing_in_working_directory"
44623
44666
  }) {
44624
44667
  if (snapshots.length === 0) {
44625
44668
  return {
@@ -44631,8 +44674,12 @@ function buildLocalObjectiveChanges({
44631
44674
  limit: OBJECTIVE_FILE_CHANGES_LIMIT,
44632
44675
  truncated: false,
44633
44676
  sync: { synced: 0, pending: 0, failed: syncFailed },
44634
- capture: { bindingState: "unknown", callbackObserved: false, healthCodes: [] },
44635
- warnings: []
44677
+ capture: {
44678
+ bindingState: "unknown",
44679
+ callbackObserved: false,
44680
+ healthCodes: [unavailableDiagnosis]
44681
+ },
44682
+ warnings: ["unknown_binding"]
44636
44683
  };
44637
44684
  }
44638
44685
  const byPath = /* @__PURE__ */ new Map();
@@ -45018,6 +45065,8 @@ attach:
45018
45065
  The CLI records the session's capture binding: bound when OVERLORD_OBJECTIVE_ID
45019
45066
  names the attached objective, unbound otherwise. Bound is configuration evidence
45020
45067
  only; it never claims the capture hook is installed or has run.
45068
+ Attach warns on stderr if its local binding cannot be saved. Check OVLD_HOME
45069
+ permissions and re-run attach in this checkout to restore native capture.
45021
45070
  Returns:
45022
45071
  Full JSON including session.sessionKey, mission, history, artifacts, sharedState,
45023
45072
  and agentInstructions with required workflow instructions and structured-field pointers.
@@ -45344,7 +45393,7 @@ add-objectives:
45344
45393
  --objective-model requires --objective-agent.
45345
45394
  Notes:
45346
45395
  Each item is { "objective": "...", "title": "...", "agent": "codex",
45347
- "model": "gpt-5.6-terra", "autoAdvance": true|false, "resourceKey": "..." }.
45396
+ "model": "gpt-6.1-terra", "autoAdvance": true|false, "resourceKey": "..." }.
45348
45397
  model requires agent. Per-item autoAdvance and agent win over the flags.
45349
45398
 
45350
45399
  update-objective:
@@ -45561,6 +45610,13 @@ deliver:
45561
45610
  out-of-checkout symlinks, ignored and Overlord-managed paths are rejected with a
45562
45611
  reason on stderr), and absent targets are valid. Never enumerate opened files or a
45563
45612
  shared-worktree diff; when unsure, describe the coverage limitation instead.
45613
+ Quote the whole --paths value when a path contains spaces. Use --paths-file -
45614
+ with a JSON string array on stdin for paths containing commas or a long list.
45615
+ If the local binding or ledger is missing, keep --session-key and --objective-id:
45616
+ declarations still synchronize through the authenticated session as Declared.
45617
+ A warning explains the local capture gap. Failed fallback sync has no local retry
45618
+ copy: repeat those declarations on update/deliver. objective-changes reads the
45619
+ synchronized server evidence; changes reads only this checkout's ledgers.
45564
45620
  Inline --*-json values larger than ~8 KB are rejected; use --payload-file - and
45565
45621
  stream JSON on stdin. Keep --summary inline.
45566
45622
 
@@ -45598,6 +45654,8 @@ changes:
45598
45654
  syncState synced | pending } sorted by path and capped at 200; total counts distinct
45599
45655
  local paths. coverage "unavailable" means no local session matched, not "no files
45600
45656
  changed". This is not complete cross-device history: use objective-changes.
45657
+ capture.healthCodes and stderr explain missing bindings or unreadable local storage.
45658
+ Re-run attach in the intended checkout with the same OVLD_HOME to restore capture.
45601
45659
 
45602
45660
  sync-changes:
45603
45661
  Purpose:
@@ -46943,10 +47001,14 @@ function declaredOutputPathInputs({
46943
47001
  }
46944
47002
  return paths;
46945
47003
  }
46946
- function appendDeclaredOutputPaths({
47004
+ async function appendDeclaredOutputPaths({
46947
47005
  flags,
46948
47006
  fileInputs,
46949
47007
  active,
47008
+ runtime,
47009
+ missionId,
47010
+ objectiveRef,
47011
+ sessionKey,
46950
47012
  workingDirectory
46951
47013
  }) {
46952
47014
  const paths = declaredOutputPathInputs({ flags, fileInputs });
@@ -46954,19 +47016,63 @@ function appendDeclaredOutputPaths({
46954
47016
  delete flags["--paths-file"];
46955
47017
  delete fileInputs["--paths-file"];
46956
47018
  if (paths === null) return;
46957
- if (!active) {
47019
+ if (!sessionKey || !active && !objectiveRef) {
46958
47020
  throw new CliError({
46959
- message: "--paths/--paths-file requires the attached objective session in this working directory."
47021
+ message: "--paths/--paths-file requires --session-key and --objective-id (or a cached attached session). Run protocol attach from this checkout."
46960
47022
  });
46961
47023
  }
46962
- const result = declareChangePaths({
47024
+ const identity = {
46963
47025
  workingDirectory,
46964
- objectiveId: active.objectiveId,
46965
- sessionKey: active.sessionKey,
46966
- filePaths: paths
46967
- });
46968
- if (!result.recorded) {
46969
- console.error("[overlord] Declared paths could not be recorded in the local change ledger.");
47026
+ objectiveId: active?.objectiveId ?? objectiveRef,
47027
+ sessionKey
47028
+ };
47029
+ const result = active ? declareChangePaths({ ...identity, filePaths: paths }) : null;
47030
+ if (!result?.recorded) {
47031
+ const prepared = prepareDeclaredChangeEvidence({ ...identity, filePaths: paths });
47032
+ console.error(
47033
+ `[overlord] ${diagnoseObjectiveBinding(workingDirectory, identity.objectiveId)}. Submitting declared paths directly through the authenticated session. Re-run protocol attach in this checkout; check OVLD_HOME permissions if capture remains unavailable.`
47034
+ );
47035
+ for (const rejected of prepared.rejected.slice(0, 20)) {
47036
+ console.error(
47037
+ `[overlord] Ignored declared path ${JSON.stringify(rejected.path)}: ${rejected.reason}`
47038
+ );
47039
+ }
47040
+ for (let offset = 0; offset < prepared.evidence.length; offset += 25) {
47041
+ const batch = prepared.evidence.slice(offset, offset + 25);
47042
+ try {
47043
+ const response = asRecord5(
47044
+ await runtime.backend.post({
47045
+ path: "/api/protocol/sync-changes",
47046
+ body: {
47047
+ args: [],
47048
+ positional: [],
47049
+ fileInputs: {},
47050
+ externalSessionId: null,
47051
+ flags: {
47052
+ "--mission-id": missionId,
47053
+ "--objective-id": identity.objectiveId,
47054
+ "--session-key": sessionKey,
47055
+ "--changes-json": JSON.stringify(batch)
47056
+ }
47057
+ }
47058
+ })
47059
+ );
47060
+ const outcomes = Array.isArray(response.outcomes) ? response.outcomes.map(asRecord5) : [];
47061
+ if (batch.some(
47062
+ (entry) => !outcomes.some(
47063
+ (outcome) => outcome.idempotencyKey === entry.idempotencyKey && outcome.filePath === entry.filePath && (outcome.status === "accepted" || outcome.status === "ignored")
47064
+ )
47065
+ )) {
47066
+ console.error(
47067
+ "[overlord] Some declared paths were not accepted. Retry --paths on update/deliver; no local retry copy is available."
47068
+ );
47069
+ }
47070
+ } catch {
47071
+ console.error(
47072
+ "[overlord] Declared path synchronization failed. Retry --paths on update/deliver; no local retry copy is available."
47073
+ );
47074
+ }
47075
+ }
46970
47076
  return;
46971
47077
  }
46972
47078
  for (const rejected of result.rejected.slice(0, 20)) {
@@ -47168,8 +47274,14 @@ Run \`${primaryCommand} protocol help\` for usage.`
47168
47274
  const local = buildLocalObjectiveChanges({
47169
47275
  objectiveId: objectiveSessions[0]?.objectiveId ?? objectiveRef,
47170
47276
  snapshots,
47171
- syncFailed
47277
+ syncFailed,
47278
+ unavailableDiagnosis: diagnoseObjectiveBinding(workingDirectory, objectiveRef)
47172
47279
  });
47280
+ if (local.coverage === "unavailable") {
47281
+ console.error(
47282
+ `[overlord] ${local.capture.healthCodes[0]}. Run protocol attach for this objective in this checkout and check OVLD_HOME permissions. Explicit --paths with a valid session key can still synchronize declarations.`
47283
+ );
47284
+ }
47173
47285
  for (const entry of objectiveSessions.filter((candidate) => candidate.deliveryPendingSync)) {
47174
47286
  const stillUnsynced = readUnsyncedChangeEvidence({
47175
47287
  workingDirectory,
@@ -47240,7 +47352,16 @@ Run \`${primaryCommand} protocol help\` for usage.`
47240
47352
  const sessionKey = typeof flags["--session-key"] === "string" ? flags["--session-key"] : null;
47241
47353
  const active = sessionKey ? readActiveSessions(workingDirectory).find((entry) => entry.sessionKey === sessionKey) : void 0;
47242
47354
  lifecycleActive = active;
47243
- appendDeclaredOutputPaths({ flags, fileInputs, active, workingDirectory });
47355
+ await appendDeclaredOutputPaths({
47356
+ flags,
47357
+ fileInputs,
47358
+ active,
47359
+ workingDirectory,
47360
+ runtime,
47361
+ missionId,
47362
+ objectiveRef,
47363
+ sessionKey
47364
+ });
47244
47365
  if (sessionKey && active) {
47245
47366
  await syncObjectiveLedger({ runtime, workingDirectory, missionId, sessionKey, active });
47246
47367
  }
@@ -47361,6 +47482,11 @@ Run \`${primaryCommand} protocol help\` for usage.`
47361
47482
  objectiveAliases: [...objectiveAliases],
47362
47483
  sessionKey: resultRecord.sessionKey
47363
47484
  });
47485
+ if (!bound) {
47486
+ console.error(
47487
+ `[overlord] Attach succeeded, but native file capture is unavailable: ${diagnoseObjectiveBinding(workingDirectory, objectiveIdentity)}. Check OVLD_HOME storage/permissions and re-run attach in this checkout. Explicit --paths can still synchronize through the session key.`
47488
+ );
47489
+ }
47364
47490
  if (bound) {
47365
47491
  recordChangeLedgerBinding({
47366
47492
  workingDirectory,