overlord-cli 0.2609221008.0 → 0.2609250853.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.47
1
+ 0.3.48
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "overlord",
4
- "version": "0.3.47",
4
+ "version": "0.3.48",
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.47",
3
+ "version": "0.3.48",
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,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.47",
3
+ "version": "0.3.48",
4
4
  "description": "Chat-driven access to Overlord mission protocol workflows with hook-driven activity capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.47",
3
+ "version": "0.3.48",
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",
@@ -10,10 +10,17 @@ ovld protocol update-artifact --mission-id $MISSION_ID --artifact-id <artifact-i
10
10
  ovld protocol attachment-list --session-key <sessionKey> --objective-id <objective-id>
11
11
  ovld protocol attachment-upload-file --session-key <sessionKey> --objective-id <objective-id> --file ./spec.pdf --content-type application/pdf
12
12
  ovld protocol attachment-download-url --session-key <sessionKey> --attachment-id <attachment-id>
13
+ ovld protocol attachment-download-url --session-key <sessionKey> --attachment-id <attachment-id> --output ./attachment.pdf
13
14
  ```
14
15
 
15
16
  The `attach` and `load-context` responses already include an `attachments` array plus `previousObjectives` and `futureObjectives` arrays — use those for `<attachment-id>` and `<objective-id>` values. The objective currently being executed is not repeated in those arrays; it is the top-level `objective`. `previousObjectives` are the objectives already worked (before the current one) and `futureObjectives` are the ones queued after it. Run `attachment-list` mid-session if new files have been uploaded since attach. `--mission-id` is optional for attachment calls when `--objective-id` is a full display ID that lets the server derive the mission; an attachment ID alone does not carry mission scope.
16
17
 
18
+ Attachment HTTPS URLs require Overlord authentication. Use `--output` to save
19
+ the bytes through the CLI's existing authenticated client; it creates a new
20
+ file and will not overwrite one. Do not read CLI credential files or pass their
21
+ contents to `curl`. Hosted MCP callers can use their authenticated tool or
22
+ client transport to retrieve the same attachment.
23
+
17
24
  ## Creating artifacts during a turn
18
25
 
19
26
  Artifacts do not require delivery. Publish a plan, notes, decision, or URL mid-session with `add-artifact` (or MCP `overlord_add_artifact`). Provide `--type`, `--label`, and at least one of `--content-text` / `--content-text-file` or `--external-url`. An optional `--session-key` (auto-injected from the attach cache when present) stamps session/objective provenance; `delivery_id` stays null. Delivery may still attach additional artifacts later.
@@ -1228,7 +1228,7 @@ process.stdin.on('data', async chunk => {
1228
1228
  result: {
1229
1229
  protocolVersion: PROTOCOL_VERSION,
1230
1230
  capabilities: { tools: { listChanged: false } },
1231
- serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.47' }
1231
+ serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.48' }
1232
1232
  }
1233
1233
  });
1234
1234
  continue;
package/dist/index.js CHANGED
@@ -3285,7 +3285,8 @@ function createBackendClient() {
3285
3285
  path: path38,
3286
3286
  body,
3287
3287
  extraHeaders,
3288
- rawBody
3288
+ rawBody,
3289
+ responseType = "json"
3289
3290
  }) {
3290
3291
  const url2 = `${baseUrl}${path38.startsWith("/") ? path38 : `/${path38}`}`;
3291
3292
  const auth = resolveAuthHeaders({ baseUrl });
@@ -3300,7 +3301,7 @@ The backend URL may have changed. Run \`ovld auth login\` to sign in to the curr
3300
3301
  response = await fetch(url2, {
3301
3302
  method,
3302
3303
  headers: {
3303
- Accept: "application/json",
3304
+ Accept: responseType === "bytes" ? "application/octet-stream" : "application/json",
3304
3305
  ...rawBody === void 0 && body !== void 0 ? { "Content-Type": "application/json" } : {},
3305
3306
  "x-overlord-device-fingerprint": clientDevice.deviceFingerprint,
3306
3307
  "x-overlord-device-label": clientDevice.deviceLabel,
@@ -3317,7 +3318,7 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3317
3318
  ` + (error51 instanceof Error ? error51.message : String(error51))
3318
3319
  });
3319
3320
  }
3320
- const payload = await readResponseJson2(response);
3321
+ const payload = response.ok && responseType === "bytes" ? Buffer.from(await response.arrayBuffer()) : await readResponseJson2(response);
3321
3322
  if (!response.ok) {
3322
3323
  if (isExecutionRequestAlreadyLinkedPayload(payload)) {
3323
3324
  throw new CliError({ message: formatExecutionRequestAlreadyLinkedDiagnostic() });
@@ -3339,6 +3340,7 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3339
3340
  baseUrl,
3340
3341
  health: () => request({ method: "GET", path: "/api/health" }),
3341
3342
  get: (path38) => request({ method: "GET", path: path38 }),
3343
+ getBytes: (path38) => request({ method: "GET", path: path38, responseType: "bytes" }),
3342
3344
  post: ({ path: path38, body }) => request({ method: "POST", path: path38, body }),
3343
3345
  patch: ({ path: path38, body }) => request({ method: "PATCH", path: path38, body }),
3344
3346
  delete: (path38) => request({ method: "DELETE", path: path38 }),
@@ -37397,12 +37399,21 @@ async function loadMissionContext({
37397
37399
  const id = objective.id;
37398
37400
  if (typeof id !== "string" || id.length === 0) return;
37399
37401
  const attachments = await runtime.backend.get(`/api/objectives/${encodeURIComponent(id)}/attachments`).catch(() => []);
37400
- const label = objectiveDisplayRef(objective) ?? "objective";
37402
+ const label = objectiveDisplayRef(objective) ?? id;
37401
37403
  for (const attachment of attachments) {
37402
37404
  const record2 = asRecord4(attachment);
37403
37405
  const filename = String(record2.filename ?? "attachment");
37404
37406
  const contentType = record2.contentType ? ` (${String(record2.contentType)})` : "";
37405
- attachmentLines.push(`- [${label}] ${filename}${contentType}`);
37407
+ const attachmentId = typeof record2.id === "string" ? record2.id : null;
37408
+ const storageKey = typeof record2.storageKey === "string" ? record2.storageKey : null;
37409
+ const url2 = storageKey ? `${runtime.backend.baseUrl}/api/storage/attachments/${encodeURIComponent(storageKey)}` : null;
37410
+ attachmentLines.push(`- [${label}] ${filename}${contentType}${url2 ? ` \u2014 ${url2}` : ""}`);
37411
+ if (attachmentId) {
37412
+ const output = `./.overlord/tmp/attachment-${attachmentId}-${path31.basename(filename)}`;
37413
+ attachmentLines.push(
37414
+ ` Download: \`ovld protocol attachment-download-url --objective-id ${shellQuote2(label)} --attachment-id ${shellQuote2(attachmentId)} --output ${shellQuote2(output)}\``
37415
+ );
37416
+ }
37406
37417
  }
37407
37418
  })
37408
37419
  );
@@ -37425,7 +37436,7 @@ async function loadMissionContext({
37425
37436
  "",
37426
37437
  ...attachmentLines.length > 0 ? [
37427
37438
  "## Attachments",
37428
- "Files attached to the objective(s) below. Use `ovld protocol attachment-list` and `ovld protocol attachment-download-url` to retrieve them.",
37439
+ "Attachment URLs require Overlord authentication. Use the download commands below; the CLI supplies its own credentials. Use `ovld protocol attachment-list` to refresh this list.",
37429
37440
  ...attachmentLines,
37430
37441
  ""
37431
37442
  ] : [],
@@ -38832,12 +38843,14 @@ attachment-list:
38832
38843
 
38833
38844
  attachment-download-url:
38834
38845
  Purpose:
38835
- Return the download URL for a specific attachment on the mission.
38846
+ Return the authenticated download URL for a specific attachment, or save it
38847
+ to a new file using the CLI's existing authentication.
38836
38848
  Required:
38837
38849
  --mission-id <id>
38838
38850
  --attachment-id <id> (use the id from attachment-list output)
38839
38851
  Optional:
38840
38852
  --objective-id <id> Restrict the lookup to one objective
38853
+ --output <path> Download to a new local file (never overwrites)
38841
38854
 
38842
38855
  list-organizations:
38843
38856
  Purpose:
@@ -39670,6 +39683,7 @@ __export(commands_exports, {
39670
39683
  firstObjectiveId: () => firstObjectiveId,
39671
39684
  launchFailureMessage: () => launchFailureMessage,
39672
39685
  queueableObjectiveId: () => queueableObjectiveId,
39686
+ readWorktreeBranchAutomationEnabled: () => readWorktreeBranchAutomationEnabled,
39673
39687
  resolveActiveObjectiveId: () => resolveActiveObjectiveId,
39674
39688
  resolveProtocolFileInputs: () => resolveProtocolFileInputs,
39675
39689
  runManagementCommand: () => runManagementCommand,
@@ -39678,7 +39692,7 @@ __export(commands_exports, {
39678
39692
  sanitizeRunnerFailureMessage: () => sanitizeRunnerFailureMessage,
39679
39693
  shouldRefuseInlineRunnerLaunch: () => shouldRefuseInlineRunnerLaunch
39680
39694
  });
39681
- import { readFileSync as readFileSync21 } from "node:fs";
39695
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "node:fs";
39682
39696
  import path37 from "node:path";
39683
39697
  function resourceAccessModeBody(value) {
39684
39698
  if (typeof value !== "string") return {};
@@ -39910,10 +39924,14 @@ function parseLaunchEnvVarsValue(value) {
39910
39924
  }
39911
39925
  return vars;
39912
39926
  }
39913
- async function readWorktreeBranchAutomationEnabled(runtime) {
39927
+ async function readWorktreeBranchAutomationEnabled({
39928
+ runtime,
39929
+ workspaceId
39930
+ }) {
39914
39931
  try {
39915
39932
  const settings = await fetchLaunchSettings({
39916
- backend: runtime.backend
39933
+ backend: runtime.backend,
39934
+ workspaceId
39917
39935
  });
39918
39936
  return settings.worktreeBranchAutomationEnabled === true;
39919
39937
  } catch (error51) {
@@ -40450,6 +40468,30 @@ Run \`${primaryCommand} protocol help\` for usage.`
40450
40468
  if (subcommand === "attachment-download-url") {
40451
40469
  const relUrl = resultRecord.url;
40452
40470
  if (typeof relUrl === "string" && relUrl.startsWith("/")) {
40471
+ const output = flags["--output"];
40472
+ if (output !== void 0) {
40473
+ if (typeof output !== "string" || !output.trim()) {
40474
+ throw new CliError({ message: "--output requires a file path." });
40475
+ }
40476
+ if (!relUrl.startsWith("/api/storage/attachments/")) {
40477
+ throw new CliError({ message: "Unexpected attachment download path." });
40478
+ }
40479
+ const bytes = await runtime.backend.getBytes(relUrl);
40480
+ try {
40481
+ writeFileSync13(output, bytes, { flag: "wx", mode: 384 });
40482
+ } catch (error51) {
40483
+ throw new CliError({
40484
+ message: `Could not create attachment file ${output}: ${String(error51)}`
40485
+ });
40486
+ }
40487
+ printJson({
40488
+ id: resultRecord.id,
40489
+ filename: resultRecord.filename,
40490
+ output,
40491
+ sizeBytes: bytes.length
40492
+ });
40493
+ return;
40494
+ }
40453
40495
  printJson({ ...resultRecord, url: `${runtime.backend.baseUrl}${relUrl}` });
40454
40496
  return;
40455
40497
  }
@@ -40747,7 +40789,10 @@ async function runManagementCommand({
40747
40789
  missionId,
40748
40790
  workingDirectory,
40749
40791
  objectiveId: objectiveId ?? void 0,
40750
- automationEnabled: await readWorktreeBranchAutomationEnabled(scopedRuntime),
40792
+ automationEnabled: await readWorktreeBranchAutomationEnabled({
40793
+ runtime: scopedRuntime,
40794
+ workspaceId: missionWorkspaceId
40795
+ }),
40751
40796
  dryRun,
40752
40797
  overrideBranch: flagValue(parsed.flags, "--branch"),
40753
40798
  noWorktree: flagBoolean(parsed.flags, "--no-worktree")
@@ -41144,7 +41189,10 @@ The runner will not register a target for you \u2014 declare this machine first,
41144
41189
  missionId,
41145
41190
  workingDirectory: String(requestRecord.workingDirectory ?? process.cwd()),
41146
41191
  objectiveId: String(requestRecord.objectiveId ?? ""),
41147
- automationEnabled: await readWorktreeBranchAutomationEnabled(runtime),
41192
+ automationEnabled: await readWorktreeBranchAutomationEnabled({
41193
+ runtime,
41194
+ workspaceId: requestWorkspaceId
41195
+ }),
41148
41196
  dryRun,
41149
41197
  overrideBranch: flagValue(parsed.flags, "--branch"),
41150
41198
  noWorktree: flagBoolean(parsed.flags, "--no-worktree")