overlord-cli 0.2608181528.0 → 0.2608191134.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.27
1
+ 0.3.28
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "overlord",
4
- "version": "0.3.27",
4
+ "version": "0.3.28",
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.27",
3
+ "version": "0.3.28",
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.27",
3
+ "version": "0.3.28",
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.27",
3
+ "version": "0.3.28",
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",
@@ -84,7 +84,7 @@ Use this mode when the conversation starts normally and the user asks the agent
84
84
  When you open or discuss an existing mission that has a draft objective, submit it with `ovld protocol discuss-objective --mission-id <mission_id>`.
85
85
  4. If the user wants to route the current session onto an existing mission by ID, run `ovld protocol connect --mission-id <mission_id>` (add `--objective-id <objective_id>` to pin the session to a specific objective).
86
86
  5. If the user wants to establish a persistent session with a mission by ID, run `ovld protocol attach --mission-id <mission_id>`.
87
- 6. If the user wants to find a mission but does not know the ID, run `ovld protocol search-missions --query "..." --status next-up,execute` and ask the user to confirm.
87
+ 6. If the user wants to find a mission but does not know the ID, run `ovld protocol search-missions --query "..." --status execute,review` and ask the user to confirm.
88
88
  7. If you need to understand project routing before prompting, use `ovld protocol discover-project`.
89
89
  8. If the user wants to **record work that is already finished** in this chat (for example, something you just built in a chat app) as a completed mission, run `ovld protocol record-work` (or the hosted `overlord_record_work` MCP tool). This creates a mission with one completed objective, records the file changes with rationales, lands it in the review column, and runs the standard Gemini delivery summary — all in one call, with no `attach`/`deliver`. Do **not** use it for in-progress work. The exact submission format is in [reference/record-work.md](reference/record-work.md).
90
90
  9. If you need other lifecycle commands or flags, run `ovld protocol help` and use the real subcommand list instead of guessing.
@@ -12,7 +12,7 @@ ovld protocol attachment-upload-file --session-key <sessionKey> --objective-id <
12
12
  ovld protocol attachment-download-url --session-key <sessionKey> --attachment-id <attachment-id>
13
13
  ```
14
14
 
15
- 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` or `--attachment-id` lets the server derive the mission.
15
+ 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
16
 
17
17
  ## Creating artifacts during a turn
18
18
 
@@ -31,4 +31,3 @@ For large artifacts such as planning documents, architecture decisions, research
31
31
  - Prefer `add-artifact` mid-turn (or a delivery artifact) with a `note` or `decision` type, a concise summary, and the repository file path — not the full document content.
32
32
 
33
33
  This keeps the mission feed readable while preserving the full document in version control where it can be reviewed, diffed, and referenced later. If that summary artifact already exists on the mission, revise it with `update-artifact` rather than creating another copy.
34
-
@@ -110,13 +110,27 @@ const tools = [
110
110
  ['name']
111
111
  )
112
112
  },
113
+ {
114
+ name: 'overlord_list_project_statuses',
115
+ title: 'List Overlord project statuses',
116
+ description:
117
+ "Read one project's board columns. Status names and order are defined per project, so two projects in the same workspace can label the same lifecycle differently; each status also carries a stable type (draft, next, execute, review, complete, blocked, cancelled) that does not vary by project.",
118
+ inputSchema: objectSchema(
119
+ {
120
+ projectId: stringProperty('Overlord project id, slug, or name.')
121
+ },
122
+ ['projectId']
123
+ )
124
+ },
113
125
  {
114
126
  name: 'overlord_search_missions',
115
127
  title: 'Search Overlord missions',
116
128
  description: 'Search missions in the OAuth-bound workspace.',
117
129
  inputSchema: objectSchema({
118
130
  query: stringProperty('Search query text.'),
119
- status: stringProperty('Comma-separated status types, such as draft,execute,review.'),
131
+ status: stringProperty(
132
+ 'Comma-separated status TYPES, such as draft,next,execute,review. Types are workspace-invariant (draft, next, execute, review, complete, blocked, cancelled). Project-defined status names are not accepted here.'
133
+ ),
120
134
  projectId: stringProperty('Optional project id, slug, or name.'),
121
135
  limit: {
122
136
  type: 'number',
@@ -164,7 +178,9 @@ const tools = [
164
178
  'Load structured mission context, objectives, history, artifacts, and shared context.',
165
179
  inputSchema: objectSchema(
166
180
  {
167
- missionId: stringProperty('Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'),
181
+ missionId: stringProperty(
182
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
183
+ ),
168
184
  objectiveId: stringProperty(
169
185
  'Objective UUID or display id such as coo:756.k7xm. Returns that objective as the current one instead of rediscovering the mission active objective.'
170
186
  ),
@@ -181,7 +197,9 @@ const tools = [
181
197
  description: 'Append one or more draft objectives to an existing mission.',
182
198
  inputSchema: objectSchema(
183
199
  {
184
- missionId: stringProperty('Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'),
200
+ missionId: stringProperty(
201
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
202
+ ),
185
203
  objectiveId: stringProperty(
186
204
  'Objective UUID or display id such as coo:756.k7xm. Used only to supply missionId when it is omitted.'
187
205
  ),
@@ -227,7 +245,9 @@ const tools = [
227
245
  'Attach an MCP-hosted agent session to a mission before update/ask/deliver. Pass objectiveId when the caller already knows which objective to execute.',
228
246
  inputSchema: objectSchema(
229
247
  {
230
- missionId: stringProperty('Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'),
248
+ missionId: stringProperty(
249
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
250
+ ),
231
251
  objectiveId: stringProperty(
232
252
  'Optional objective UUID or display id (e.g. coo:756.k7xm). Pins attach to that objective.'
233
253
  ),
@@ -246,7 +266,9 @@ const tools = [
246
266
  description: 'Post an update, alert, decision, or discussion summary for an attached session.',
247
267
  inputSchema: objectSchema(
248
268
  {
249
- missionId: stringProperty('Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'),
269
+ missionId: stringProperty(
270
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
271
+ ),
250
272
  objectiveId: stringProperty(
251
273
  'Objective UUID or display id such as coo:756.k7xm. Supplies missionId when it is omitted; the session key still determines which objective the event lands on.'
252
274
  ),
@@ -265,7 +287,9 @@ const tools = [
265
287
  'Deliver an attached session with explicit summary, optional change rationales, and optional human-action/tradeoff evidence.',
266
288
  inputSchema: objectSchema(
267
289
  {
268
- missionId: stringProperty('Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'),
290
+ missionId: stringProperty(
291
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
292
+ ),
269
293
  objectiveId: stringProperty(
270
294
  'Objective UUID or display id such as coo:756.k7xm. Supplies missionId when it is omitted; the session key still determines which objective is delivered.'
271
295
  ),
@@ -306,7 +330,9 @@ const tools = [
306
330
  'Create a mission artifact during a turn without delivering (plan, notes, decision, URL). Provide type, label, and at least one of contentText or externalUrl. Optional sessionKey stamps provenance. Revise later with overlord_update_artifact.',
307
331
  inputSchema: objectSchema(
308
332
  {
309
- missionId: stringProperty('Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'),
333
+ missionId: stringProperty(
334
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
335
+ ),
310
336
  objectiveId: stringProperty(
311
337
  'Objective UUID or display id such as coo:756.k7xm. Stamps objective provenance when no live sessionKey is available.'
312
338
  ),
@@ -328,7 +354,9 @@ const tools = [
328
354
  'Revise an existing mission artifact in place (label, Markdown content, and/or URL) using optimistic concurrency via expectedRevision.',
329
355
  inputSchema: objectSchema(
330
356
  {
331
- missionId: stringProperty('Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'),
357
+ missionId: stringProperty(
358
+ 'Mission UUID or workspace display id. Optional when objectiveId is a display id such as coo:756.k7xm, which already names its mission.'
359
+ ),
332
360
  objectiveId: stringProperty(
333
361
  'Objective UUID or display id such as coo:756.k7xm. Used only to supply missionId when it is omitted.'
334
362
  ),
@@ -357,7 +385,8 @@ const tools = [
357
385
  title: stringProperty('Optional mission title.'),
358
386
  changeRationales: {
359
387
  type: 'array',
360
- description: 'One entry per meaningful file change (filePath, label, summary, why, impact).'
388
+ description:
389
+ 'One entry per meaningful file change (filePath, label, summary, why, impact).'
361
390
  },
362
391
  changedFiles: {
363
392
  type: 'array',
@@ -384,28 +413,22 @@ function requiredString(args, name) {
384
413
  return value;
385
414
  }
386
415
 
387
- /** Mission display id spelled inside an objective display id (`coo:756.k7xm`). */
388
- function missionFromObjectiveRef(ref) {
389
- const match =
390
- typeof ref === 'string' ? /^(.+:\d+)\.[0-9a-hjkmnp-tv-z]{4,5}$/i.exec(ref.trim()) : null;
391
- return match ? match[1] : null;
392
- }
393
-
394
416
  /**
395
- * Mission/objective addressing shared by every mission-scoped tool: an objective
396
- * display id already names its mission, so a caller holding only that identifier
397
- * can address the tool with it. Mirrors `missionScopeFlags` in mcp/server.ts.
417
+ * Forward mission/objective addressing to the CLI. The CLI owns the shared
418
+ * `@overlord/contract` parser and derives a mission from a display id before it
419
+ * performs local bookkeeping or calls the backend, so this standalone shim
420
+ * does not carry a second copy of the public-id regex.
398
421
  */
399
422
  function missionScopeFlags(args) {
400
423
  const objectiveId = optionalString(args, 'objectiveId');
401
- const missionId = optionalString(args, 'missionId') ?? missionFromObjectiveRef(objectiveId);
402
- if (!missionId) {
424
+ const missionId = optionalString(args, 'missionId');
425
+ if (!missionId && !objectiveId) {
403
426
  throw new Error(
404
427
  'Missing required argument: missionId (pass it, or an objective display id such as coo:756.k7xm as objectiveId)'
405
428
  );
406
429
  }
407
430
  return {
408
- 'mission-id': missionId,
431
+ ...(missionId ? { 'mission-id': missionId } : {}),
409
432
  ...(objectiveId ? { 'objective-id': objectiveId } : {})
410
433
  };
411
434
  }
@@ -431,6 +454,11 @@ function callOverlordTool(name, args) {
431
454
  ...(optionalString(args, 'slug') ? { slug: requiredString(args, 'slug') } : {})
432
455
  });
433
456
  }
457
+ if (name === 'overlord_list_project_statuses') {
458
+ return runProtocol('statuses', {
459
+ 'project-id': requiredString(args, 'projectId')
460
+ });
461
+ }
434
462
  if (name === 'overlord_search_missions') {
435
463
  return runProtocol('search-missions', {
436
464
  ...(optionalString(args, 'query') ? { query: requiredString(args, 'query') } : {}),
@@ -478,8 +506,7 @@ function callOverlordTool(name, args) {
478
506
  if (name === 'overlord_add_objectives') {
479
507
  if (!Array.isArray(args.objectives)) throw new Error('objectives must be an array');
480
508
  return runProtocol('add-objectives', {
481
- // objectiveId here only names the mission; the new objectives are appended.
482
- 'mission-id': missionScopeFlags(args)['mission-id'],
509
+ ...missionScopeFlags(args),
483
510
  'objectives-json': args.objectives
484
511
  });
485
512
  }
@@ -491,7 +518,11 @@ function callOverlordTool(name, args) {
491
518
  }
492
519
  return runProtocol('update-objective', {
493
520
  'objective-id': requiredString(args, 'objectiveId'),
494
- ...(hasAutoAdvance ? (args.autoAdvance ? { 'auto-advance': true } : { 'no-auto-advance': true }) : {}),
521
+ ...(hasAutoAdvance
522
+ ? args.autoAdvance
523
+ ? { 'auto-advance': true }
524
+ : { 'no-auto-advance': true }
525
+ : {}),
495
526
  ...(hasInstructionText ? { 'instruction-text': requiredString(args, 'instructionText') } : {})
496
527
  });
497
528
  }
@@ -578,8 +609,7 @@ function callOverlordTool(name, args) {
578
609
  throw new Error('Provide at least one of label, contentText, or externalUrl');
579
610
  }
580
611
  return runProtocol('update-artifact', {
581
- // The artifact is addressed by its own id; objectiveId only scopes the mission.
582
- 'mission-id': missionScopeFlags(args)['mission-id'],
612
+ ...missionScopeFlags(args),
583
613
  'artifact-id': requiredString(args, 'artifactId'),
584
614
  'expected-revision': String(Math.trunc(args.expectedRevision)),
585
615
  ...(hasLabel ? { label: args.label } : {}),
@@ -633,7 +663,7 @@ process.stdin.on('data', async chunk => {
633
663
  result: {
634
664
  protocolVersion: PROTOCOL_VERSION,
635
665
  capabilities: { tools: { listChanged: false } },
636
- serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.27' }
666
+ serverInfo: { name: 'overlord-__OVERLORD_ADAPTER_KEY__', version: '0.3.28' }
637
667
  }
638
668
  });
639
669
  continue;
package/dist/index.js CHANGED
@@ -18725,6 +18725,13 @@ var init_migration_ledger = __esm({
18725
18725
  }
18726
18726
  });
18727
18727
 
18728
+ // ../database/dist/next-status-type-migration-runtime.js
18729
+ var init_next_status_type_migration_runtime = __esm({
18730
+ "../database/dist/next-status-type-migration-runtime.js"() {
18731
+ "use strict";
18732
+ }
18733
+ });
18734
+
18728
18735
  // ../database/dist/objective-display-key.js
18729
18736
  var init_objective_display_key = __esm({
18730
18737
  "../database/dist/objective-display-key.js"() {
@@ -18749,6 +18756,13 @@ var init_project_resources_resource_key_migration_runtime = __esm({
18749
18756
  }
18750
18757
  });
18751
18758
 
18759
+ // ../database/dist/project-statuses-migration-runtime.js
18760
+ var init_project_statuses_migration_runtime = __esm({
18761
+ "../database/dist/project-statuses-migration-runtime.js"() {
18762
+ "use strict";
18763
+ }
18764
+ });
18765
+
18752
18766
  // ../database/dist/connection.js
18753
18767
  var init_connection = __esm({
18754
18768
  "../database/dist/connection.js"() {
@@ -18758,8 +18772,10 @@ var init_connection = __esm({
18758
18772
  init_ext_everhour_migration_runtime();
18759
18773
  init_local_paths();
18760
18774
  init_migration_ledger();
18775
+ init_next_status_type_migration_runtime();
18761
18776
  init_objective_display_key_migration_runtime();
18762
18777
  init_project_resources_resource_key_migration_runtime();
18778
+ init_project_statuses_migration_runtime();
18763
18779
  }
18764
18780
  });
18765
18781
 
@@ -18787,6 +18803,7 @@ var init_migrate_postgres = __esm({
18787
18803
  init_ext_everhour_migration_runtime();
18788
18804
  init_migration_ledger();
18789
18805
  init_objective_display_key_migration_runtime();
18806
+ init_project_statuses_migration_runtime();
18790
18807
  }
18791
18808
  });
18792
18809
 
@@ -20806,7 +20823,8 @@ function printProtocolHelp({ primaryCommand }) {
20806
20823
  Use this for mission lifecycle work from an agent runtime: create a standalone
20807
20824
  draft with \`${primaryCommand} protocol create\`, create-and-attach with
20808
20825
  \`${primaryCommand} protocol prompt\`, or attach to an existing mission with
20809
- \`${primaryCommand} protocol attach --mission-id <mission_id>\`.
20826
+ \`${primaryCommand} protocol attach --mission-id <mission_id>\` or
20827
+ \`${primaryCommand} protocol attach --objective-id <mission_id.objective_key>\`.
20810
20828
 
20811
20829
  Backend and auth:
20812
20830
  Configure the REST backend before protocol calls:
@@ -20831,7 +20849,8 @@ Project discovery:
20831
20849
  projects with \`${primaryCommand} create-project --name "<name>"\`.
20832
20850
 
20833
20851
  Agent workflow (required):
20834
- 1. Attach first with \`${primaryCommand} protocol attach --mission-id <id> [--objective-id <id>]\`.
20852
+ 1. Attach first with \`${primaryCommand} protocol attach --mission-id <id>\` or a full
20853
+ objective display id via \`--objective-id <id>\`.
20835
20854
  2. Post progress with \`${primaryCommand} protocol update\` or liveness with
20836
20855
  \`${primaryCommand} protocol heartbeat\`.
20837
20856
  3. Ask blocking questions with \`${primaryCommand} protocol ask\` and stop work.
@@ -20958,15 +20977,30 @@ load-context:
20958
20977
 
20959
20978
  search-missions:
20960
20979
  Purpose:
20961
- Find missions by keyword, status, or project.
20980
+ Find missions by keyword, status type, or project.
20962
20981
  Optional:
20963
20982
  --query <text> Free-text search
20964
- --status <csv> Comma-separated statuses (e.g. next-up,execute)
20983
+ --status <csv> Comma-separated status TYPES (e.g. execute,review).
20984
+ Types are workspace-invariant: draft, next, execute, review,
20985
+ complete, blocked, cancelled. Project-defined status
20986
+ names (board column labels) are not accepted here \u2014
20987
+ use \`statuses\` to read one project's names.
20965
20988
  --project-id <id> Restrict to one project
20966
20989
  --limit <n> Max results (default: 25)
20967
20990
  Returns:
20968
20991
  JSON with matching missions.
20969
20992
 
20993
+ statuses:
20994
+ Purpose:
20995
+ List one project's board columns. Statuses are defined per project, so their
20996
+ names and order vary between projects in the same workspace; the status TYPE
20997
+ of each column does not.
20998
+ Required:
20999
+ --project-id <id> Project id, slug, or name
21000
+ Returns:
21001
+ JSON array of statuses ordered by position, each with id, projectId, key,
21002
+ name, type, position, isDefault, and isTerminal.
21003
+
20970
21004
  discuss-objective:
20971
21005
  Purpose:
20972
21006
  Mark the latest draft objective as submitted. Does not start execution \u2014 use attach.
@@ -22784,7 +22818,7 @@ var init_select_prompt = __esm({
22784
22818
 
22785
22819
  // src/session-key.ts
22786
22820
  import { createHash as createHash10 } from "node:crypto";
22787
- import { existsSync as existsSync28, mkdirSync as mkdirSync15, readFileSync as readFileSync23, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "node:fs";
22821
+ import { existsSync as existsSync28, mkdirSync as mkdirSync15, readdirSync as readdirSync6, readFileSync as readFileSync23, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "node:fs";
22788
22822
  import path32 from "node:path";
22789
22823
  function sessionKeyCachePath({
22790
22824
  missionId,
@@ -22811,10 +22845,7 @@ function readCachedSessionKey({
22811
22845
  objectiveId
22812
22846
  }) {
22813
22847
  if (objectiveId?.trim()) {
22814
- const keyed = readSessionKeyFile(
22815
- sessionKeyCachePath({ missionId, workingDirectory, objectiveId })
22816
- );
22817
- if (keyed) return keyed;
22848
+ return readSessionKeyFile(sessionKeyCachePath({ missionId, workingDirectory, objectiveId }));
22818
22849
  }
22819
22850
  return readSessionKeyFile(sessionKeyCachePath({ missionId, workingDirectory }));
22820
22851
  }
@@ -22852,12 +22883,25 @@ function writeCachedSessionKey({
22852
22883
  function clearCachedSessionKey({
22853
22884
  missionId,
22854
22885
  workingDirectory,
22855
- objectiveId
22886
+ objectiveId,
22887
+ sessionKey
22856
22888
  }) {
22857
22889
  try {
22858
- const files = [sessionKeyCachePath({ missionId, workingDirectory })];
22859
- if (objectiveId?.trim()) {
22860
- files.push(sessionKeyCachePath({ missionId, workingDirectory, objectiveId }));
22890
+ const files = /* @__PURE__ */ new Set();
22891
+ const trimmedSessionKey = sessionKey?.trim();
22892
+ if (trimmedSessionKey) {
22893
+ const cacheDir = path32.join(resolveGlobalDataDir(), "protocol-session-keys");
22894
+ if (existsSync28(cacheDir)) {
22895
+ for (const name of readdirSync6(cacheDir)) {
22896
+ const filePath = path32.join(cacheDir, name);
22897
+ if (readSessionKeyFile(filePath) === trimmedSessionKey) files.add(filePath);
22898
+ }
22899
+ }
22900
+ } else {
22901
+ files.add(sessionKeyCachePath({ missionId, workingDirectory }));
22902
+ if (objectiveId?.trim()) {
22903
+ files.add(sessionKeyCachePath({ missionId, workingDirectory, objectiveId }));
22904
+ }
22861
22905
  }
22862
22906
  for (const filePath of files) {
22863
22907
  if (existsSync28(filePath)) rmSync7(filePath);
@@ -23536,12 +23580,30 @@ async function runProtocolCommand({
23536
23580
  const attachedObjective = asRecord5(resultRecord.objective);
23537
23581
  const attachedObjectiveId = typeof attachedObjective.displayId === "string" && attachedObjective.displayId.trim() || typeof attachedObjective.id === "string" && attachedObjective.id.trim() || // `connect` returns a flat result rather than the full objective record.
23538
23582
  typeof resultRecord.objectiveDisplayId === "string" && resultRecord.objectiveDisplayId.trim() || typeof resultRecord.objectiveId === "string" && resultRecord.objectiveId.trim() || objectiveRef || null;
23539
- writeCachedSessionKey({
23540
- missionId,
23541
- workingDirectory,
23542
- sessionKey: resultRecord.sessionKey,
23543
- objectiveId: attachedObjectiveId
23544
- });
23583
+ const objectiveAliases = new Set(
23584
+ [
23585
+ attachedObjectiveId,
23586
+ typeof attachedObjective.id === "string" ? attachedObjective.id.trim() : null,
23587
+ typeof attachedObjective.displayId === "string" ? attachedObjective.displayId.trim() : null,
23588
+ objectiveRef ?? null
23589
+ ].filter((value) => Boolean(value))
23590
+ );
23591
+ if (objectiveAliases.size === 0) {
23592
+ writeCachedSessionKey({
23593
+ missionId,
23594
+ workingDirectory,
23595
+ sessionKey: resultRecord.sessionKey
23596
+ });
23597
+ } else {
23598
+ for (const objectiveAlias of objectiveAliases) {
23599
+ writeCachedSessionKey({
23600
+ missionId,
23601
+ workingDirectory,
23602
+ sessionKey: resultRecord.sessionKey,
23603
+ objectiveId: objectiveAlias
23604
+ });
23605
+ }
23606
+ }
23545
23607
  if (subcommand === "attach" || subcommand === "resume-follow-up") {
23546
23608
  writeActiveSession({
23547
23609
  workingDirectory,
@@ -23566,7 +23628,12 @@ async function runProtocolCommand({
23566
23628
  }
23567
23629
  }
23568
23630
  if (subcommand === "deliver" && missionId) {
23569
- clearCachedSessionKey({ missionId, workingDirectory });
23631
+ clearCachedSessionKey({
23632
+ missionId,
23633
+ workingDirectory,
23634
+ objectiveId: objectiveRef,
23635
+ sessionKey: typeof flags["--session-key"] === "string" ? flags["--session-key"] : null
23636
+ });
23570
23637
  removeActiveSession({ workingDirectory, missionId });
23571
23638
  clearActiveMissionPointer(workingDirectory);
23572
23639
  const connectorInstallsEditHook = existsSync29(path33.join(os6.homedir(), ".claude")) || existsSync29(
@@ -23953,8 +24020,10 @@ async function runManagementCommand({
23953
24020
  const query = flagValue(parsed.flags, "--query");
23954
24021
  const projectId = flagValue(parsed.flags, "--project-id");
23955
24022
  const limit = flagValue(parsed.flags, "--limit");
24023
+ const statusTypes = (flagValue(parsed.flags, "--status") ?? "").split(",").map((value) => value.trim()).filter((value) => value !== "");
23956
24024
  if (query) params.set("q", query);
23957
24025
  if (projectId) params.set("projectId", projectId);
24026
+ if (statusTypes.length > 0) params.set("statusTypes", statusTypes.join(","));
23958
24027
  if (limit) params.set("limit", limit);
23959
24028
  let missions;
23960
24029
  const result = await runtime.backend.get(
@@ -23972,10 +24041,57 @@ async function runManagementCommand({
23972
24041
  }
23973
24042
  return;
23974
24043
  }
24044
+ // Board columns are project-scoped (coo:752): two projects in one workspace
24045
+ // may name and order their statuses differently, so the only way to discover
24046
+ // a board's columns is to ask the project that owns them. Read-only —
24047
+ // status definitions are edited in project settings.
24048
+ case "statuses": {
24049
+ const sub = parsed.positional[0];
24050
+ if (sub !== "list") {
24051
+ throw new CliError({
24052
+ message: "Usage: ovld statuses list --project-id <id|slug|name> [--json]"
24053
+ });
24054
+ }
24055
+ const projectRef = flagValue(parsed.flags, "--project-id");
24056
+ if (!projectRef) {
24057
+ throw new CliError({
24058
+ message: "Missing --project-id (accepts a project id, slug, or name)"
24059
+ });
24060
+ }
24061
+ const project = await resolveProjectByIdOrName({
24062
+ backend: runtime.backend,
24063
+ projectRef
24064
+ });
24065
+ const statuses = await runtime.backend.get(
24066
+ `/api/projects/${encodeURIComponent(project.id)}/statuses`
24067
+ );
24068
+ if (json) printJson({ projectId: project.id, statuses });
24069
+ else {
24070
+ for (const status of statuses) {
24071
+ const record = asRecord5(status);
24072
+ const flags = [
24073
+ record.isDefault === true ? "default" : null,
24074
+ record.isTerminal === true ? "terminal" : null
24075
+ ].filter(Boolean).join(",");
24076
+ console.log(
24077
+ `${record.position ?? ""} ${record.key ?? ""} ${record.name ?? ""} ${record.type ?? ""} ${flags}`
24078
+ );
24079
+ }
24080
+ }
24081
+ return;
24082
+ }
23975
24083
  case "requests": {
23976
24084
  const sub = parsed.positional[0];
23977
24085
  if (!sub) {
23978
- const result2 = await runtime.backend.get("/api/agent-requests");
24086
+ const objectiveRef = flagValue(parsed.flags, "--objective-id");
24087
+ const missionId = flagValue(parsed.flags, "--mission-id") ?? missionDisplayIdFromObjectiveRef(objectiveRef);
24088
+ const params = new URLSearchParams();
24089
+ if (missionId) params.set("missionId", missionId);
24090
+ if (objectiveRef) params.set("objectiveId", objectiveRef);
24091
+ const query = params.size > 0 ? `?${params.toString()}` : "";
24092
+ const result2 = await runtime.backend.get(
24093
+ `/api/agent-requests${query}`
24094
+ );
23979
24095
  if (json) printJson(result2);
23980
24096
  else {
23981
24097
  for (const item of result2.requests) {
@@ -24026,8 +24142,11 @@ async function runManagementCommand({
24026
24142
  message: "Usage: ovld inputs list --mission-id <id> [--json] | ovld inputs send --channel-id <id> --body <text> [--json]"
24027
24143
  });
24028
24144
  }
24145
+ const objectiveRef = flagValue(parsed.flags, "--objective-id");
24146
+ const params = new URLSearchParams({ missionId });
24147
+ if (objectiveRef) params.set("objectiveId", objectiveRef);
24029
24148
  const result = await runtime.backend.get(
24030
- `/api/agent-session-inputs?missionId=${encodeURIComponent(missionId)}`
24149
+ `/api/agent-session-inputs?${params.toString()}`
24031
24150
  );
24032
24151
  if (json) printJson(result);
24033
24152
  else {
@@ -24692,7 +24811,8 @@ var COMMAND_FLAGS = {
24692
24811
  "--no-start"
24693
24812
  ],
24694
24813
  missions: ["--status", "--query", "--project-id", "--limit"],
24695
- requests: ["--revision", "--decision", "--text"],
24814
+ statuses: ["--project-id"],
24815
+ requests: ["--mission-id", "--objective-id", "--revision", "--decision", "--text"],
24696
24816
  inputs: ["--mission-id", "--objective-id", "--channel-id", "--body", "--kind"],
24697
24817
  mission: [],
24698
24818
  changes: ["--mission-id", "--objective-id"]
@@ -24811,9 +24931,19 @@ Missions:
24811
24931
  ${primaryCommand} prompt "<objective>" [--json]
24812
24932
  ${primaryCommand} attach <missionId> [agent] [--json]
24813
24933
  ${primaryCommand} missions list [--status <csv>] [--project-id <id>] [--json]
24934
+ --status filters status TYPES
24935
+ (draft,execute,review,complete,blocked,cancelled),
24936
+ not the project-defined status names on a board
24937
+ ${primaryCommand} statuses list --project-id <id|slug|name> [--json]
24938
+ List one project's board columns (key, name, type,
24939
+ position, default/terminal). Statuses are defined
24940
+ per project, so they vary between projects.
24814
24941
  ${primaryCommand} mission context|events|deliveries|artifacts|rationales <missionId> [--json]
24815
- ${primaryCommand} requests [--json] List open and recent agent decisions
24942
+ ${primaryCommand} requests [--mission-id <id>] [--objective-id <id>] [--json]
24943
+ List open and recent agent decisions
24816
24944
  ${primaryCommand} requests resolve <id> --revision <n> --decision allow|deny|ask [--text <text>]
24945
+ ${primaryCommand} inputs list [--mission-id <id>] [--objective-id <id>] [--json]
24946
+ List instructions for one mission or objective
24817
24947
 
24818
24948
  Launch and runner:
24819
24949
  ${primaryCommand} launch <agent> --mission-id <missionId> [--branch <name>] [--no-worktree] [--dry-run] [--json]
@@ -24832,12 +24962,13 @@ Agents:
24832
24962
  connect, load-context, update, heartbeat, ask, deliver.
24833
24963
 
24834
24964
  Protocol (JSON output by default):
24835
- ${primaryCommand} protocol attach --mission-id <id> [--objective-id <id>]
24836
- ${primaryCommand} protocol update --mission-id <id> --session-key <key> --summary "..."
24965
+ ${primaryCommand} protocol attach --mission-id <id> | --objective-id <display-id>
24966
+ ${primaryCommand} protocol update --objective-id <display-id> --session-key <key> --summary "..."
24837
24967
  ${primaryCommand} protocol heartbeat --mission-id <id> --session-key <key>
24838
24968
  ${primaryCommand} protocol ask --mission-id <id> --session-key <key> --question "..."
24839
24969
  ${primaryCommand} protocol deliver --mission-id <id> --session-key <key> --summary "..."
24840
- ${primaryCommand} protocol search-missions --query "<text>" --status next-up,execute
24970
+ ${primaryCommand} protocol search-missions --query "<text>" --status execute,review
24971
+ ${primaryCommand} protocol statuses --project-id <id|slug|name>
24841
24972
  ${primaryCommand} protocol load-context --mission-id <id>
24842
24973
  ${primaryCommand} protocol help
24843
24974
 
@@ -24890,6 +25021,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
24890
25021
  "resume",
24891
25022
  "runner",
24892
25023
  "missions",
25024
+ "statuses",
24893
25025
  "requests",
24894
25026
  "inputs",
24895
25027
  "inbox",