overlord-cli 0.2608221603.0 → 0.2608231148.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.
@@ -1 +1 @@
1
- 0.3.35
1
+ 0.3.36
@@ -1,4 +1,4 @@
1
- contractVersion: "116"
1
+ contractVersion: "117"
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.35",
4
+ "version": "0.3.36",
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.35",
3
+ "version": "0.3.36",
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: "116"
1
+ contractVersion: "117"
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.35",
3
+ "version": "0.3.36",
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: "116"
1
+ contractVersion: "117"
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.35",
3
+ "version": "0.3.36",
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",
@@ -69,5 +69,9 @@ events:
69
69
  inputPath: tool_input
70
70
  callIdPath: call_id
71
71
  fileEditKind: file.edited
72
+ # Live Cursor Write payloads use file_path; path/filePath match the write
73
+ # formatter's key order so an alternate Cursor dialect still captures.
72
74
  filePathPaths:
73
75
  - file_path
76
+ - filePath
77
+ - path
@@ -1,4 +1,4 @@
1
- contractVersion: "116"
1
+ contractVersion: "117"
2
2
  componentType: connector
3
3
  componentKey: cursor
4
4
  label: "Cursor Connector"
@@ -1,4 +1,4 @@
1
- contractVersion: "116"
1
+ contractVersion: "117"
2
2
  componentType: connector
3
3
  componentKey: opencode
4
4
  label: "OpenCode Connector"
@@ -1,4 +1,4 @@
1
- contractVersion: "116"
1
+ contractVersion: "117"
2
2
  componentType: connector
3
3
  componentKey: pi
4
4
  label: "PI Connector"
@@ -1091,7 +1091,7 @@ process.stdin.on('data', async chunk => {
1091
1091
  result: {
1092
1092
  protocolVersion: PROTOCOL_VERSION,
1093
1093
  capabilities: { tools: { listChanged: false } },
1094
- serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.35' }
1094
+ serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.36' }
1095
1095
  }
1096
1096
  });
1097
1097
  continue;
package/dist/index.js CHANGED
@@ -67,7 +67,44 @@ function isUnlinkableExecutionRequestError(error) {
67
67
  const message = error instanceof Error ? error.message : String(error);
68
68
  return message.includes("invalid_execution_request_transition");
69
69
  }
70
+ function trimmedStringField({
71
+ record,
72
+ key
73
+ }) {
74
+ const value = record[key];
75
+ return typeof value === "string" ? value.trim() : "";
76
+ }
77
+ function looksLikeAlreadyLinkedExecutionRequest({ text }) {
78
+ return text.includes(EXECUTION_REQUEST_ALREADY_LINKED_CODE) || /already linked to another(?: mission)? session/i.test(text);
79
+ }
80
+ function isExecutionRequestAlreadyLinkedPayload(payload) {
81
+ if (!payload || typeof payload !== "object") return false;
82
+ const record = payload;
83
+ if (trimmedStringField({ record, key: "code" }) === EXECUTION_REQUEST_ALREADY_LINKED_CODE) {
84
+ return true;
85
+ }
86
+ const text = [
87
+ trimmedStringField({ record, key: "error" }),
88
+ trimmedStringField({ record, key: "message" }),
89
+ trimmedStringField({ record, key: "detail" })
90
+ ].join(" ");
91
+ return looksLikeAlreadyLinkedExecutionRequest({ text });
92
+ }
93
+ function isExecutionRequestAlreadyLinkedError(error) {
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ return looksLikeAlreadyLinkedExecutionRequest({ text: message });
96
+ }
97
+ function formatExecutionRequestAlreadyLinkedDiagnostic() {
98
+ return [
99
+ "Attach was rejected because this execution request is already linked to another mission session (`execution_request_already_linked`).",
100
+ "This is a stale mission-session binding, not a user authentication failure. Do not run `ovld auth login` or `ovld auth repair`.",
101
+ "Recovery: retry `ovld protocol attach` without `--execution-request-id` (unset OVERLORD_EXECUTION_REQUEST_ID). The existing session remains bound to the request; a new attach can continue the objective without relinking it."
102
+ ].join("\n");
103
+ }
70
104
  function formatCliError(error) {
105
+ if (isExecutionRequestAlreadyLinkedError(error)) {
106
+ return redactSecrets(formatExecutionRequestAlreadyLinkedDiagnostic());
107
+ }
71
108
  if (error instanceof CliError) {
72
109
  return redactSecrets(error.message);
73
110
  }
@@ -76,7 +113,7 @@ function formatCliError(error) {
76
113
  }
77
114
  return redactSecrets(String(error));
78
115
  }
79
- var CliError;
116
+ var CliError, EXECUTION_REQUEST_ALREADY_LINKED_CODE;
80
117
  var init_errors = __esm({
81
118
  "src/errors.ts"() {
82
119
  "use strict";
@@ -89,6 +126,7 @@ var init_errors = __esm({
89
126
  this.exitCode = exitCode;
90
127
  }
91
128
  };
129
+ EXECUTION_REQUEST_ALREADY_LINKED_CODE = "execution_request_already_linked";
92
130
  }
93
131
  });
94
132
 
@@ -2593,7 +2631,7 @@ function configureCursorHarness({
2593
2631
  event: "postToolUse",
2594
2632
  command: CURSOR_HOOK_COMMANDS.postToolUse,
2595
2633
  marker: "overlord-post-tool-use",
2596
- extra: { matcher: "Shell|Write|Edit|MultiEdit|NotebookEdit" }
2634
+ extra: { matcher: "Shell|Write|Edit|MultiEdit|NotebookEdit|StrReplace" }
2597
2635
  }) && "postToolUse",
2598
2636
  mergeHook({
2599
2637
  event: "stop",
@@ -3186,6 +3224,9 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3186
3224
  }
3187
3225
  const payload = await readResponseJson2(response);
3188
3226
  if (!response.ok) {
3227
+ if (isExecutionRequestAlreadyLinkedPayload(payload)) {
3228
+ throw new CliError({ message: formatExecutionRequestAlreadyLinkedDiagnostic() });
3229
+ }
3189
3230
  if (response.status === 401 && auth.headers.Authorization) {
3190
3231
  const detail = errorMessageFromJson2(payload) ?? `Backend request failed: ${method} ${path36} (${response.status})`;
3191
3232
  throw new CliError({
@@ -7492,6 +7533,8 @@ var init_tool_normalize = __esm({
7492
7533
  editfile: "edit",
7493
7534
  edit_file: "edit",
7494
7535
  str_replace: "edit",
7536
+ // Cursor/IDE lowercases StrReplace → "strreplace" (no underscore).
7537
+ strreplace: "edit",
7495
7538
  str_replace_editor: "edit",
7496
7539
  apply_patch: "edit",
7497
7540
  applypatch: "edit",
@@ -8074,7 +8117,9 @@ var init_codec_registry_generated = __esm({
8074
8117
  "callIdPath": "call_id",
8075
8118
  "fileEditKind": "file.edited",
8076
8119
  "filePathPaths": [
8077
- "file_path"
8120
+ "file_path",
8121
+ "filePath",
8122
+ "path"
8078
8123
  ]
8079
8124
  }
8080
8125
  ]
@@ -19366,7 +19411,7 @@ var init_change_ledger = __esm({
19366
19411
 
19367
19412
  // src/active-objective-sessions.ts
19368
19413
  import { createHash as createHash9 } from "node:crypto";
19369
- import { existsSync as existsSync24 } from "node:fs";
19414
+ import { existsSync as existsSync24, readdirSync as readdirSync4 } from "node:fs";
19370
19415
  import path22 from "node:path";
19371
19416
  function normalizeIdentifier(value) {
19372
19417
  return typeof value === "string" ? value.trim() : "";
@@ -19529,6 +19574,63 @@ function readObjectiveSessions({
19529
19574
  const aliases = entries.filter((entry) => entry.objectiveAliases.includes(requested));
19530
19575
  return new Set(aliases.map((entry) => entry.objectiveId)).size === 1 ? aliases : [];
19531
19576
  }
19577
+ function pathIsUnderWorkingDirectory({
19578
+ absolutePath,
19579
+ workingDirectory
19580
+ }) {
19581
+ const root = canonicalDirectory(workingDirectory);
19582
+ const resolved = path22.resolve(absolutePath);
19583
+ return resolved === root || resolved.startsWith(`${root}${path22.sep}`);
19584
+ }
19585
+ function resolveWorkingDirectoryForObjective({
19586
+ objectiveId,
19587
+ candidateWorkingDirectory,
19588
+ pathHints = []
19589
+ }) {
19590
+ const requested = normalizeIdentifier(objectiveId);
19591
+ if (!isValidIdentifier(requested)) return null;
19592
+ const candidate = path22.resolve(candidateWorkingDirectory);
19593
+ const local = readManifest2(candidate);
19594
+ if (local && resolveEntry(local.entries, requested)) {
19595
+ return local.workingDirectory;
19596
+ }
19597
+ const matches = [];
19598
+ const root = path22.join(resolveGlobalDataDir(), "active-objective-sessions");
19599
+ try {
19600
+ if (!existsSync24(root)) return null;
19601
+ for (const name of readdirSync4(root).slice(0, MAX_ACTIVE_SESSION_MANIFEST_FILES)) {
19602
+ if (!name.endsWith(".json")) continue;
19603
+ try {
19604
+ const raw = readBoundedUtf8File(path22.join(root, name), MAX_ACTIVE_SESSION_MANIFEST_BYTES);
19605
+ if (raw === null) continue;
19606
+ const value = JSON.parse(raw);
19607
+ if (value.schemaVersion !== 3 || typeof value.workingDirectory !== "string" || !Array.isArray(value.entries)) {
19608
+ continue;
19609
+ }
19610
+ const entries = value.entries.flatMap((entry) => {
19611
+ const normalized = normalizeEntry(entry);
19612
+ return normalized ? [normalized] : [];
19613
+ });
19614
+ if (!resolveEntry(entries, requested)) continue;
19615
+ const workingDirectory = canonicalDirectory(value.workingDirectory);
19616
+ if (!matches.includes(workingDirectory)) matches.push(workingDirectory);
19617
+ } catch {
19618
+ }
19619
+ }
19620
+ } catch {
19621
+ return null;
19622
+ }
19623
+ if (matches.length === 0) return null;
19624
+ if (matches.length === 1) return matches[0] ?? null;
19625
+ const absoluteHints = pathHints.filter((hint) => typeof hint === "string" && path22.isAbsolute(hint)).map((hint) => path22.resolve(hint));
19626
+ if (absoluteHints.length === 0) return null;
19627
+ const hinted = matches.filter(
19628
+ (workingDirectory) => absoluteHints.some(
19629
+ (absolutePath) => pathIsUnderWorkingDirectory({ absolutePath, workingDirectory })
19630
+ )
19631
+ );
19632
+ return hinted.length === 1 ? hinted[0] ?? null : null;
19633
+ }
19532
19634
  function withActiveObjectiveSession({
19533
19635
  workingDirectory,
19534
19636
  objectiveId,
@@ -19591,7 +19693,7 @@ function finalizeActiveSession({
19591
19693
  return false;
19592
19694
  }
19593
19695
  }
19594
- var MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS, MAX_OBJECTIVE_ALIASES, MAX_ID_LENGTH, MAX_ACTIVE_SESSION_MANIFEST_BYTES;
19696
+ var MAX_ACTIVE_OBJECTIVE_SESSION_BINDINGS, MAX_OBJECTIVE_ALIASES, MAX_ID_LENGTH, MAX_ACTIVE_SESSION_MANIFEST_BYTES, MAX_ACTIVE_SESSION_MANIFEST_FILES;
19595
19697
  var init_active_objective_sessions = __esm({
19596
19698
  "src/active-objective-sessions.ts"() {
19597
19699
  "use strict";
@@ -19602,6 +19704,7 @@ var init_active_objective_sessions = __esm({
19602
19704
  MAX_OBJECTIVE_ALIASES = 16;
19603
19705
  MAX_ID_LENGTH = 200;
19604
19706
  MAX_ACTIVE_SESSION_MANIFEST_BYTES = 512 * 1024;
19707
+ MAX_ACTIVE_SESSION_MANIFEST_FILES = 256;
19605
19708
  }
19606
19709
  });
19607
19710
 
@@ -20156,6 +20259,42 @@ function resolveHookWorkingDirectory({
20156
20259
  }
20157
20260
  return path26.resolve(fallbackCwd);
20158
20261
  }
20262
+ function withProjectRootFallback({
20263
+ payload,
20264
+ projectRootPaths,
20265
+ workingDirectory
20266
+ }) {
20267
+ const rootKey = projectRootPaths?.[0];
20268
+ if (!rootKey || rootKey.includes(".") || !payload || typeof payload !== "object") {
20269
+ return payload;
20270
+ }
20271
+ if (Array.isArray(payload)) return payload;
20272
+ const record = payload;
20273
+ if (exactProjectDirectory(record[rootKey])) return payload;
20274
+ return { ...record, [rootKey]: workingDirectory };
20275
+ }
20276
+ function collectAbsolutePathHints(payload) {
20277
+ const hints = [];
20278
+ const visit = (value, depth) => {
20279
+ if (hints.length >= MAX_PATH_HINTS || depth > 4) return;
20280
+ if (typeof value === "string") {
20281
+ if (path26.isAbsolute(value) && value.length <= 4096 && !hasControlCharacters(value)) {
20282
+ hints.push(path26.resolve(value));
20283
+ }
20284
+ return;
20285
+ }
20286
+ if (!value || typeof value !== "object") return;
20287
+ if (Array.isArray(value)) {
20288
+ for (const entry of value.slice(0, 8)) visit(entry, depth + 1);
20289
+ return;
20290
+ }
20291
+ for (const entry of Object.values(value).slice(0, 16)) {
20292
+ visit(entry, depth + 1);
20293
+ }
20294
+ };
20295
+ visit(payload, 0);
20296
+ return hints;
20297
+ }
20159
20298
  function captureChangeFromPayload({
20160
20299
  agent,
20161
20300
  rawPayload,
@@ -20185,12 +20324,22 @@ function captureChangeFromPayload({
20185
20324
  payloadFailure = "invalid JSON payload";
20186
20325
  }
20187
20326
  }
20188
- const workingDirectory = resolveHookWorkingDirectory({
20327
+ const candidateWorkingDirectory = resolveHookWorkingDirectory({
20189
20328
  payload: nativePayload,
20190
20329
  projectRootPaths: codec.projectRootPaths,
20191
20330
  fallbackCwd
20192
20331
  });
20193
- const normalized = payloadFailure ? null : normalizeForAdapter({ codec, payload: nativePayload });
20332
+ const workingDirectory = resolveWorkingDirectoryForObjective({
20333
+ objectiveId,
20334
+ candidateWorkingDirectory,
20335
+ pathHints: collectAbsolutePathHints(nativePayload)
20336
+ }) ?? candidateWorkingDirectory;
20337
+ const payloadForNormalize = withProjectRootFallback({
20338
+ payload: nativePayload,
20339
+ projectRootPaths: codec.projectRootPaths,
20340
+ workingDirectory
20341
+ });
20342
+ const normalized = payloadFailure ? null : normalizeForAdapter({ codec, payload: payloadForNormalize });
20194
20343
  const directPaths = normalized?.kind === "file.edited" && Array.isArray(normalized.payload.paths) ? normalized.payload.paths.filter((value) => typeof value === "string") : [];
20195
20344
  const confidentlyNonMutating = normalized?.kind === "tool.completed" && (normalized.payload.tool === "read" || normalized.payload.tool === "search" || normalized.payload.tool === "fetch");
20196
20345
  return withActiveObjectiveSession({
@@ -20239,6 +20388,7 @@ function captureChangeFromPayload({
20239
20388
  }
20240
20389
  });
20241
20390
  }
20391
+ var MAX_PATH_HINTS;
20242
20392
  var init_capture_change = __esm({
20243
20393
  "src/capture-change.ts"() {
20244
20394
  "use strict";
@@ -20248,6 +20398,7 @@ var init_capture_change = __esm({
20248
20398
  init_event();
20249
20399
  init_active_objective_sessions();
20250
20400
  init_change_ledger();
20401
+ MAX_PATH_HINTS = 16;
20251
20402
  }
20252
20403
  });
20253
20404
 
@@ -21464,7 +21615,7 @@ var init_launch = __esm({
21464
21615
  });
21465
21616
 
21466
21617
  // src/launch-bootstrap.ts
21467
- import { existsSync as existsSync26, readdirSync as readdirSync4, readFileSync as readFileSync16, statSync as statSync7 } from "node:fs";
21618
+ import { existsSync as existsSync26, readdirSync as readdirSync5, readFileSync as readFileSync16, statSync as statSync7 } from "node:fs";
21468
21619
  import path30 from "node:path";
21469
21620
  function firstCapture(match) {
21470
21621
  if (!match) return null;
@@ -21491,7 +21642,7 @@ function recoverLaunchBootstrapFromProjectTmp({
21491
21642
  const prefix = `launch-${safeMissionPart(trimmedMission)}-`;
21492
21643
  let newest = null;
21493
21644
  try {
21494
- for (const name of readdirSync4(tmpDir)) {
21645
+ for (const name of readdirSync5(tmpDir)) {
21495
21646
  if (!name.startsWith(prefix) || !name.endsWith(".sh")) continue;
21496
21647
  const filePath = path30.join(tmpDir, name);
21497
21648
  try {
@@ -23655,6 +23806,8 @@ async function runProtocolCommand({
23655
23806
  path: protocolPath,
23656
23807
  body: { ...protocolBody, flags }
23657
23808
  });
23809
+ } else if (isExecutionRequestAlreadyLinkedError(error)) {
23810
+ throw new CliError({ message: formatExecutionRequestAlreadyLinkedDiagnostic() });
23658
23811
  } else {
23659
23812
  throw error;
23660
23813
  }