overlord-cli 0.2609221008.0 → 0.2609270909.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -202,6 +202,8 @@ Notes for headless use:
202
202
  - `ovld agent-setup` accepts `--home <dir>` to target a specific `OVLD_HOME`,
203
203
  `--dry-run` to preview, and `--json` for machine-readable output. List
204
204
  installable connectors with `ovld agent-setup --json`.
205
+ - `ovld agent-setup codex --export <dir>` renders the self-contained plugin
206
+ package into an empty directory without changing the user's Codex setup.
205
207
  - Set `OVLD_HOME=/some/writable/dir` if the default `~/.ovld` is not writable in
206
208
  your container; it relocates the entire CLI data directory.
207
209
  - Interactive `ovld auth login` / `ovld config set` (no args) and `ovld setup`
@@ -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
@@ -2952,13 +2952,25 @@ function setupConnector({
2952
2952
  agentKey,
2953
2953
  home,
2954
2954
  configureCodexPermissions = true,
2955
- dryRun = false
2955
+ dryRun = false,
2956
+ exportPath
2956
2957
  }) {
2958
+ if (exportPath && agentKey !== "codex") {
2959
+ throw new CliError({
2960
+ message: "Export mode is currently supported only for the Codex connector."
2961
+ });
2962
+ }
2957
2963
  const manifest = readConnectorManifest(agentKey);
2958
2964
  const resolvedHome = resolveHome(home);
2959
- const installPath = expandInstallPath(manifest.connector.installPath, resolvedHome);
2965
+ const installPath = exportPath ? path6.resolve(exportPath) : expandInstallPath(manifest.connector.installPath, resolvedHome);
2960
2966
  const sourceDir = connectorDir(agentKey);
2961
2967
  const warnings = [];
2968
+ if (exportPath) {
2969
+ mkdirSync3(installPath, { recursive: true });
2970
+ if (readdirSync(installPath).length > 0) {
2971
+ throw new CliError({ message: `Export destination must be empty: ${installPath}` });
2972
+ }
2973
+ }
2962
2974
  const files = [];
2963
2975
  const stateFiles = [];
2964
2976
  const previousState = readInstallState(agentKey, resolvedHome);
@@ -3032,10 +3044,10 @@ function setupConnector({
3032
3044
  `Agent binary "${binaryName}" not found on PATH. The connector is installed; install ${binaryName} to launch this agent.`
3033
3045
  );
3034
3046
  }
3035
- if (agentKey === "cursor") {
3047
+ if (!exportPath && agentKey === "cursor") {
3036
3048
  warnings.push(...configureCursorHarness({ home: resolvedHome, dryRun }));
3037
3049
  }
3038
- if (agentKey === "codex") {
3050
+ if (!exportPath && agentKey === "codex") {
3039
3051
  warnings.push(
3040
3052
  ...configureCodexHarness({
3041
3053
  home: resolvedHome,
@@ -3045,10 +3057,10 @@ function setupConnector({
3045
3057
  })
3046
3058
  );
3047
3059
  }
3048
- if (agentKey === "claude") {
3060
+ if (!exportPath && agentKey === "claude") {
3049
3061
  warnings.push(...configureClaudeHarness({ home: resolvedHome, installPath, dryRun }));
3050
3062
  }
3051
- if (!dryRun) {
3063
+ if (!dryRun && !exportPath) {
3052
3064
  const installedStateFiles = manifest.connector.managedFiles.map((relativePath) => {
3053
3065
  const target = path6.join(installPath, relativePath);
3054
3066
  if (!existsSync6(target)) return null;
@@ -3285,7 +3297,8 @@ function createBackendClient() {
3285
3297
  path: path38,
3286
3298
  body,
3287
3299
  extraHeaders,
3288
- rawBody
3300
+ rawBody,
3301
+ responseType = "json"
3289
3302
  }) {
3290
3303
  const url2 = `${baseUrl}${path38.startsWith("/") ? path38 : `/${path38}`}`;
3291
3304
  const auth = resolveAuthHeaders({ baseUrl });
@@ -3300,7 +3313,7 @@ The backend URL may have changed. Run \`ovld auth login\` to sign in to the curr
3300
3313
  response = await fetch(url2, {
3301
3314
  method,
3302
3315
  headers: {
3303
- Accept: "application/json",
3316
+ Accept: responseType === "bytes" ? "application/octet-stream" : "application/json",
3304
3317
  ...rawBody === void 0 && body !== void 0 ? { "Content-Type": "application/json" } : {},
3305
3318
  "x-overlord-device-fingerprint": clientDevice.deviceFingerprint,
3306
3319
  "x-overlord-device-label": clientDevice.deviceLabel,
@@ -3317,7 +3330,7 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3317
3330
  ` + (error51 instanceof Error ? error51.message : String(error51))
3318
3331
  });
3319
3332
  }
3320
- const payload = await readResponseJson2(response);
3333
+ const payload = response.ok && responseType === "bytes" ? Buffer.from(await response.arrayBuffer()) : await readResponseJson2(response);
3321
3334
  if (!response.ok) {
3322
3335
  if (isExecutionRequestAlreadyLinkedPayload(payload)) {
3323
3336
  throw new CliError({ message: formatExecutionRequestAlreadyLinkedDiagnostic() });
@@ -3339,6 +3352,7 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3339
3352
  baseUrl,
3340
3353
  health: () => request({ method: "GET", path: "/api/health" }),
3341
3354
  get: (path38) => request({ method: "GET", path: path38 }),
3355
+ getBytes: (path38) => request({ method: "GET", path: path38, responseType: "bytes" }),
3342
3356
  post: ({ path: path38, body }) => request({ method: "POST", path: path38, body }),
3343
3357
  patch: ({ path: path38, body }) => request({ method: "PATCH", path: path38, body }),
3344
3358
  delete: (path38) => request({ method: "DELETE", path: path38 }),
@@ -4024,8 +4038,12 @@ async function runAgentSetupCommand({
4024
4038
  const target = parsed.positional[0];
4025
4039
  const dryRun = flagBoolean(parsed.flags, "--dry-run");
4026
4040
  const home = flagValue(parsed.flags, "--home");
4041
+ const exportPath = flagValue(parsed.flags, "--export");
4042
+ if (exportPath && target !== "codex") {
4043
+ throw new CliError({ message: "`--export` requires `agent-setup codex`." });
4044
+ }
4027
4045
  const shouldConfigureCodexPermissions = async (agentKey) => {
4028
- if (agentKey !== "codex" || dryRun || json2 || !process.stdin.isTTY) return true;
4046
+ if (agentKey !== "codex" || exportPath || dryRun || json2 || !process.stdin.isTTY) return true;
4029
4047
  return promptYesNo(
4030
4048
  "Configure Codex permissions to allow it to communicate with the Overlord server?",
4031
4049
  true
@@ -4053,15 +4071,21 @@ async function runAgentSetupCommand({
4053
4071
  setupConnector({
4054
4072
  agentKey: target,
4055
4073
  home,
4074
+ exportPath,
4056
4075
  dryRun,
4057
4076
  configureCodexPermissions: await shouldConfigureCodexPermissions(target)
4058
4077
  })
4059
4078
  ];
4060
4079
  if (json2) {
4061
- printJson({ ok: true, dryRun, results });
4080
+ printJson({ ok: true, dryRun, exported: Boolean(exportPath), results });
4062
4081
  } else {
4063
4082
  for (const result of results) {
4064
- printHumanResult(result);
4083
+ if (exportPath) {
4084
+ printLine(`Exported connector "${result.agentKey}" \u2192 ${result.installPath}`);
4085
+ for (const file2 of result.files) printLine(` + ${file2.path}`);
4086
+ } else {
4087
+ printHumanResult(result);
4088
+ }
4065
4089
  }
4066
4090
  }
4067
4091
  }
@@ -20362,6 +20386,23 @@ var init_errors2 = __esm({
20362
20386
  }
20363
20387
  });
20364
20388
 
20389
+ // ../packages/core/dist/service/worker-jobs.js
20390
+ var init_worker_jobs = __esm({
20391
+ "../packages/core/dist/service/worker-jobs.js"() {
20392
+ "use strict";
20393
+ init_util2();
20394
+ }
20395
+ });
20396
+
20397
+ // ../packages/core/dist/service/live-activity-jobs.js
20398
+ var init_live_activity_jobs = __esm({
20399
+ "../packages/core/dist/service/live-activity-jobs.js"() {
20400
+ "use strict";
20401
+ init_util2();
20402
+ init_worker_jobs();
20403
+ }
20404
+ });
20405
+
20365
20406
  // ../database/dist/better-sqlite3-loader.js
20366
20407
  var init_better_sqlite3_loader = __esm({
20367
20408
  "../database/dist/better-sqlite3-loader.js"() {
@@ -35711,6 +35752,7 @@ var init_requests = __esm({
35711
35752
  "use strict";
35712
35753
  init_change_feed();
35713
35754
  init_errors2();
35755
+ init_live_activity_jobs();
35714
35756
  init_util2();
35715
35757
  init_webhook_events();
35716
35758
  init_window();
@@ -37397,12 +37439,21 @@ async function loadMissionContext({
37397
37439
  const id = objective.id;
37398
37440
  if (typeof id !== "string" || id.length === 0) return;
37399
37441
  const attachments = await runtime.backend.get(`/api/objectives/${encodeURIComponent(id)}/attachments`).catch(() => []);
37400
- const label = objectiveDisplayRef(objective) ?? "objective";
37442
+ const label = objectiveDisplayRef(objective) ?? id;
37401
37443
  for (const attachment of attachments) {
37402
37444
  const record2 = asRecord4(attachment);
37403
37445
  const filename = String(record2.filename ?? "attachment");
37404
37446
  const contentType = record2.contentType ? ` (${String(record2.contentType)})` : "";
37405
- attachmentLines.push(`- [${label}] ${filename}${contentType}`);
37447
+ const attachmentId = typeof record2.id === "string" ? record2.id : null;
37448
+ const storageKey = typeof record2.storageKey === "string" ? record2.storageKey : null;
37449
+ const url2 = storageKey ? `${runtime.backend.baseUrl}/api/storage/attachments/${encodeURIComponent(storageKey)}` : null;
37450
+ attachmentLines.push(`- [${label}] ${filename}${contentType}${url2 ? ` \u2014 ${url2}` : ""}`);
37451
+ if (attachmentId) {
37452
+ const output = `./.overlord/tmp/attachment-${attachmentId}-${path31.basename(filename)}`;
37453
+ attachmentLines.push(
37454
+ ` Download: \`ovld protocol attachment-download-url --objective-id ${shellQuote2(label)} --attachment-id ${shellQuote2(attachmentId)} --output ${shellQuote2(output)}\``
37455
+ );
37456
+ }
37406
37457
  }
37407
37458
  })
37408
37459
  );
@@ -37425,7 +37476,7 @@ async function loadMissionContext({
37425
37476
  "",
37426
37477
  ...attachmentLines.length > 0 ? [
37427
37478
  "## Attachments",
37428
- "Files attached to the objective(s) below. Use `ovld protocol attachment-list` and `ovld protocol attachment-download-url` to retrieve them.",
37479
+ "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
37480
  ...attachmentLines,
37430
37481
  ""
37431
37482
  ] : [],
@@ -38832,12 +38883,14 @@ attachment-list:
38832
38883
 
38833
38884
  attachment-download-url:
38834
38885
  Purpose:
38835
- Return the download URL for a specific attachment on the mission.
38886
+ Return the authenticated download URL for a specific attachment, or save it
38887
+ to a new file using the CLI's existing authentication.
38836
38888
  Required:
38837
38889
  --mission-id <id>
38838
38890
  --attachment-id <id> (use the id from attachment-list output)
38839
38891
  Optional:
38840
38892
  --objective-id <id> Restrict the lookup to one objective
38893
+ --output <path> Download to a new local file (never overwrites)
38841
38894
 
38842
38895
  list-organizations:
38843
38896
  Purpose:
@@ -39670,6 +39723,7 @@ __export(commands_exports, {
39670
39723
  firstObjectiveId: () => firstObjectiveId,
39671
39724
  launchFailureMessage: () => launchFailureMessage,
39672
39725
  queueableObjectiveId: () => queueableObjectiveId,
39726
+ readWorktreeBranchAutomationEnabled: () => readWorktreeBranchAutomationEnabled,
39673
39727
  resolveActiveObjectiveId: () => resolveActiveObjectiveId,
39674
39728
  resolveProtocolFileInputs: () => resolveProtocolFileInputs,
39675
39729
  runManagementCommand: () => runManagementCommand,
@@ -39678,7 +39732,7 @@ __export(commands_exports, {
39678
39732
  sanitizeRunnerFailureMessage: () => sanitizeRunnerFailureMessage,
39679
39733
  shouldRefuseInlineRunnerLaunch: () => shouldRefuseInlineRunnerLaunch
39680
39734
  });
39681
- import { readFileSync as readFileSync21 } from "node:fs";
39735
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "node:fs";
39682
39736
  import path37 from "node:path";
39683
39737
  function resourceAccessModeBody(value) {
39684
39738
  if (typeof value !== "string") return {};
@@ -39910,10 +39964,14 @@ function parseLaunchEnvVarsValue(value) {
39910
39964
  }
39911
39965
  return vars;
39912
39966
  }
39913
- async function readWorktreeBranchAutomationEnabled(runtime) {
39967
+ async function readWorktreeBranchAutomationEnabled({
39968
+ runtime,
39969
+ workspaceId
39970
+ }) {
39914
39971
  try {
39915
39972
  const settings = await fetchLaunchSettings({
39916
- backend: runtime.backend
39973
+ backend: runtime.backend,
39974
+ workspaceId
39917
39975
  });
39918
39976
  return settings.worktreeBranchAutomationEnabled === true;
39919
39977
  } catch (error51) {
@@ -40450,6 +40508,30 @@ Run \`${primaryCommand} protocol help\` for usage.`
40450
40508
  if (subcommand === "attachment-download-url") {
40451
40509
  const relUrl = resultRecord.url;
40452
40510
  if (typeof relUrl === "string" && relUrl.startsWith("/")) {
40511
+ const output = flags["--output"];
40512
+ if (output !== void 0) {
40513
+ if (typeof output !== "string" || !output.trim()) {
40514
+ throw new CliError({ message: "--output requires a file path." });
40515
+ }
40516
+ if (!relUrl.startsWith("/api/storage/attachments/")) {
40517
+ throw new CliError({ message: "Unexpected attachment download path." });
40518
+ }
40519
+ const bytes = await runtime.backend.getBytes(relUrl);
40520
+ try {
40521
+ writeFileSync13(output, bytes, { flag: "wx", mode: 384 });
40522
+ } catch (error51) {
40523
+ throw new CliError({
40524
+ message: `Could not create attachment file ${output}: ${String(error51)}`
40525
+ });
40526
+ }
40527
+ printJson({
40528
+ id: resultRecord.id,
40529
+ filename: resultRecord.filename,
40530
+ output,
40531
+ sizeBytes: bytes.length
40532
+ });
40533
+ return;
40534
+ }
40453
40535
  printJson({ ...resultRecord, url: `${runtime.backend.baseUrl}${relUrl}` });
40454
40536
  return;
40455
40537
  }
@@ -40747,7 +40829,10 @@ async function runManagementCommand({
40747
40829
  missionId,
40748
40830
  workingDirectory,
40749
40831
  objectiveId: objectiveId ?? void 0,
40750
- automationEnabled: await readWorktreeBranchAutomationEnabled(scopedRuntime),
40832
+ automationEnabled: await readWorktreeBranchAutomationEnabled({
40833
+ runtime: scopedRuntime,
40834
+ workspaceId: missionWorkspaceId
40835
+ }),
40751
40836
  dryRun,
40752
40837
  overrideBranch: flagValue(parsed.flags, "--branch"),
40753
40838
  noWorktree: flagBoolean(parsed.flags, "--no-worktree")
@@ -41144,7 +41229,10 @@ The runner will not register a target for you \u2014 declare this machine first,
41144
41229
  missionId,
41145
41230
  workingDirectory: String(requestRecord.workingDirectory ?? process.cwd()),
41146
41231
  objectiveId: String(requestRecord.objectiveId ?? ""),
41147
- automationEnabled: await readWorktreeBranchAutomationEnabled(runtime),
41232
+ automationEnabled: await readWorktreeBranchAutomationEnabled({
41233
+ runtime,
41234
+ workspaceId: requestWorkspaceId
41235
+ }),
41148
41236
  dryRun,
41149
41237
  overrideBranch: flagValue(parsed.flags, "--branch"),
41150
41238
  noWorktree: flagBoolean(parsed.flags, "--no-worktree")
@@ -41602,7 +41690,7 @@ var COMMAND_FLAGS = {
41602
41690
  init: [],
41603
41691
  doctor: [],
41604
41692
  setup: [],
41605
- "agent-setup": ["--dry-run", "--home"],
41693
+ "agent-setup": ["--dry-run", "--home", "--export"],
41606
41694
  config: ["--path", "--url"],
41607
41695
  auth: ["--token", "--organization-id"],
41608
41696
  "user-token": ["--label", "--expires-in", "--no-expiry", "--scope", "--id"],
@@ -41753,8 +41841,9 @@ General:
41753
41841
 
41754
41842
  Connectors:
41755
41843
  ${primaryCommand} agent-setup [--json] List installable agent connectors
41756
- ${primaryCommand} agent-setup <agent> [--dry-run]
41757
- Install/repair one connector (e.g. claude)
41844
+ ${primaryCommand} agent-setup <agent> [--dry-run] [--export <dir>]
41845
+ Install/repair one connector; Codex --export
41846
+ writes a package without installing it
41758
41847
  ${primaryCommand} agent-setup all [--dry-run] Install/repair all supported connectors
41759
41848
  ${primaryCommand} agent-session capabilities [<agent>] [--json]
41760
41849
  What a harness can really do on the agent-session