orbitmap 0.4.2 → 0.4.3

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.
Files changed (156) hide show
  1. package/README.md +60 -13
  2. package/dist/adapters/cloud.d.ts +53 -21
  3. package/dist/adapters/cloud.js +95 -29
  4. package/dist/adapters/cloud.js.map +1 -1
  5. package/dist/adapters/factory.d.ts +3 -0
  6. package/dist/adapters/factory.js +8 -1
  7. package/dist/adapters/factory.js.map +1 -1
  8. package/dist/adapters/local/adapter.d.ts +0 -20
  9. package/dist/adapters/local/adapter.js +0 -18
  10. package/dist/adapters/local/adapter.js.map +1 -1
  11. package/dist/adapters/local/context.d.ts +1 -1
  12. package/dist/adapters/local/context.js +10 -2
  13. package/dist/adapters/local/context.js.map +1 -1
  14. package/dist/adapters/local/entities/tasks.d.ts +9 -1
  15. package/dist/adapters/local/entities/tasks.js +47 -5
  16. package/dist/adapters/local/entities/tasks.js.map +1 -1
  17. package/dist/adapters/local/entities/work-items.d.ts +14 -30
  18. package/dist/adapters/local/entities/work-items.js +63 -47
  19. package/dist/adapters/local/entities/work-items.js.map +1 -1
  20. package/dist/adapters/local/rules.d.ts +4 -4
  21. package/dist/adapters/local/rules.js +4 -19
  22. package/dist/adapters/local/rules.js.map +1 -1
  23. package/dist/adapters/local/shapes.d.ts +27 -7
  24. package/dist/adapters/local/shapes.js +41 -5
  25. package/dist/adapters/local/shapes.js.map +1 -1
  26. package/dist/adapters/local/store.d.ts +55 -6
  27. package/dist/adapters/local/store.js +122 -8
  28. package/dist/adapters/local/store.js.map +1 -1
  29. package/dist/adapters/local/types.d.ts +9 -2
  30. package/dist/adapters/local/types.js +9 -2
  31. package/dist/adapters/local/types.js.map +1 -1
  32. package/dist/adapters/types.d.ts +7 -20
  33. package/dist/agent-instructions.d.ts +21 -8
  34. package/dist/agent-instructions.js +91 -35
  35. package/dist/agent-instructions.js.map +1 -1
  36. package/dist/area-directories.d.ts +75 -0
  37. package/dist/area-directories.js +162 -0
  38. package/dist/area-directories.js.map +1 -0
  39. package/dist/area-grouping.d.ts +55 -0
  40. package/dist/area-grouping.js +72 -0
  41. package/dist/area-grouping.js.map +1 -0
  42. package/dist/commands/areas.js +30 -2
  43. package/dist/commands/areas.js.map +1 -1
  44. package/dist/commands/assign.d.ts +1 -0
  45. package/dist/commands/assign.js +2 -0
  46. package/dist/commands/assign.js.map +1 -1
  47. package/dist/commands/context.d.ts +95 -0
  48. package/dist/commands/context.js +104 -2
  49. package/dist/commands/context.js.map +1 -1
  50. package/dist/commands/create.d.ts +1 -0
  51. package/dist/commands/create.js +19 -14
  52. package/dist/commands/create.js.map +1 -1
  53. package/dist/commands/dep.js +5 -8
  54. package/dist/commands/dep.js.map +1 -1
  55. package/dist/commands/doc-import.d.ts +1 -0
  56. package/dist/commands/doc-import.js +8 -26
  57. package/dist/commands/doc-import.js.map +1 -1
  58. package/dist/commands/doc-patch.js +16 -52
  59. package/dist/commands/doc-patch.js.map +1 -1
  60. package/dist/commands/doc-share.js +4 -0
  61. package/dist/commands/doc-share.js.map +1 -1
  62. package/dist/commands/doc-update.js +4 -8
  63. package/dist/commands/doc-update.js.map +1 -1
  64. package/dist/commands/doc.js +7 -12
  65. package/dist/commands/doc.js.map +1 -1
  66. package/dist/commands/docs-cache.js +23 -10
  67. package/dist/commands/docs-cache.js.map +1 -1
  68. package/dist/commands/docs.js +29 -10
  69. package/dist/commands/docs.js.map +1 -1
  70. package/dist/commands/get.js +4 -10
  71. package/dist/commands/get.js.map +1 -1
  72. package/dist/commands/ideas.d.ts +3 -1
  73. package/dist/commands/ideas.js +26 -49
  74. package/dist/commands/ideas.js.map +1 -1
  75. package/dist/commands/init.d.ts +24 -1
  76. package/dist/commands/init.js +0 -0
  77. package/dist/commands/init.js.map +1 -1
  78. package/dist/commands/intent.js +10 -14
  79. package/dist/commands/intent.js.map +1 -1
  80. package/dist/commands/issues.d.ts +3 -1
  81. package/dist/commands/issues.js +47 -72
  82. package/dist/commands/issues.js.map +1 -1
  83. package/dist/commands/log.d.ts +1 -0
  84. package/dist/commands/log.js +18 -17
  85. package/dist/commands/log.js.map +1 -1
  86. package/dist/commands/mission.js +3 -12
  87. package/dist/commands/mission.js.map +1 -1
  88. package/dist/commands/orbit.d.ts +7 -1
  89. package/dist/commands/orbit.js +13 -24
  90. package/dist/commands/orbit.js.map +1 -1
  91. package/dist/commands/setup-agent.d.ts +97 -4
  92. package/dist/commands/setup-agent.js +265 -38
  93. package/dist/commands/setup-agent.js.map +1 -1
  94. package/dist/commands/setup-mcp.d.ts +2 -0
  95. package/dist/commands/setup-mcp.js +17 -40
  96. package/dist/commands/setup-mcp.js.map +1 -1
  97. package/dist/commands/start.d.ts +43 -0
  98. package/dist/commands/start.js +158 -3
  99. package/dist/commands/start.js.map +1 -1
  100. package/dist/commands/status.d.ts +1 -0
  101. package/dist/commands/status.js +5 -15
  102. package/dist/commands/status.js.map +1 -1
  103. package/dist/commands/subtask.d.ts +1 -0
  104. package/dist/commands/subtask.js +9 -2
  105. package/dist/commands/subtask.js.map +1 -1
  106. package/dist/commands/task-edit-content.js +4 -8
  107. package/dist/commands/task-edit-content.js.map +1 -1
  108. package/dist/commands/task.d.ts +7 -0
  109. package/dist/commands/task.js +5 -2
  110. package/dist/commands/task.js.map +1 -1
  111. package/dist/commands/tasks.d.ts +35 -0
  112. package/dist/commands/tasks.js +45 -9
  113. package/dist/commands/tasks.js.map +1 -1
  114. package/dist/commands/vibes.d.ts +3 -1
  115. package/dist/commands/vibes.js +41 -31
  116. package/dist/commands/vibes.js.map +1 -1
  117. package/dist/config.d.ts +11 -0
  118. package/dist/config.js +14 -1
  119. package/dist/config.js.map +1 -1
  120. package/dist/doc-cache.d.ts +74 -5
  121. package/dist/doc-cache.js +106 -22
  122. package/dist/doc-cache.js.map +1 -1
  123. package/dist/enums.d.ts +26 -0
  124. package/dist/enums.js +53 -0
  125. package/dist/enums.js.map +1 -0
  126. package/dist/errors.d.ts +67 -0
  127. package/dist/errors.js +82 -0
  128. package/dist/errors.js.map +1 -1
  129. package/dist/index.js +134 -56
  130. package/dist/index.js.map +1 -1
  131. package/dist/mcp-config.d.ts +42 -1
  132. package/dist/mcp-config.js +82 -2
  133. package/dist/mcp-config.js.map +1 -1
  134. package/dist/oauth.js +10 -10
  135. package/dist/output.d.ts +12 -0
  136. package/dist/output.js +39 -1
  137. package/dist/output.js.map +1 -1
  138. package/dist/paths.d.ts +40 -0
  139. package/dist/paths.js +174 -9
  140. package/dist/paths.js.map +1 -1
  141. package/dist/project-config.d.ts +42 -1
  142. package/dist/project-config.js +51 -0
  143. package/dist/project-config.js.map +1 -1
  144. package/dist/workspace-resolve.d.ts +179 -9
  145. package/dist/workspace-resolve.js +288 -20
  146. package/dist/workspace-resolve.js.map +1 -1
  147. package/dist/write-target.d.ts +56 -0
  148. package/dist/write-target.js +170 -0
  149. package/dist/write-target.js.map +1 -0
  150. package/package.json +1 -1
  151. package/dist/commands/create-project.d.ts +0 -6
  152. package/dist/commands/create-project.js +0 -28
  153. package/dist/commands/create-project.js.map +0 -1
  154. package/dist/commands/projects.d.ts +0 -3
  155. package/dist/commands/projects.js +0 -28
  156. package/dist/commands/projects.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from 'commander';
2
+ import { Command, Option } from 'commander';
3
3
  import { initCommand } from './commands/init.js';
4
4
  import { contextCommand } from './commands/context.js';
5
5
  import { areasCommand } from './commands/areas.js';
@@ -35,7 +35,7 @@ import { depAddCommand, depRemoveCommand } from './commands/dep.js';
35
35
  import { getCommand } from './commands/get.js';
36
36
  import { createRequire } from 'node:module';
37
37
  import { createAreaCommand } from './commands/create-area.js';
38
- import { setWorkspaceFlag } from './workspace-resolve.js';
38
+ import { setWorkspaceFlag, setWorkspaceIdFlag } from './workspace-resolve.js';
39
39
  const program = new Command();
40
40
  /**
41
41
  * `--version` reads the real package version instead of a hardcoded literal, which had gone
@@ -50,19 +50,35 @@ program
50
50
  .version(version)
51
51
  .option('--json', 'Output in JSON format', false)
52
52
  .option('--area <id>', 'Area ID or slug to use')
53
- .option('--workspace <path>', 'Local workspace directory to use (local mode)');
54
- // The workspace flag is program-level and consumed by the resolver, not by the
55
- // command modules, so capture it once before any action runs.
56
- program.hook('preAction', (thisCommand) => {
53
+ .option('--workspace <path>', 'Local workspace directory to use (local mode)')
54
+ .option('--workspace-id <slug-or-uuid>', 'Workspace to use (slug or UUID)')
55
+ // Satisfies the write-target confirmation non-interactively (see src/write-target.ts).
56
+ .option('--yes', 'Accept the resolved target area for writes without confirming', false);
57
+ // Both workspace flags are consumed by the resolver, not by the command modules, so
58
+ // capture them once before any action runs. They are different things: `--workspace` is a
59
+ // directory on this disk (and forces local mode), `--workspace-id` names a workspace in the
60
+ // backend and does not touch the mode.
61
+ //
62
+ // `--workspace-id` is read from the SUBCOMMAND first and only then from the program level.
63
+ // Previously only `thisCommand` (the program) was consulted, so `create-area --workspace-id`,
64
+ // `doc-import --workspace-id` and `init --workspace-id` put the value in the request body
65
+ // but never sent `X-Orbitmap-Workspace` — the same flag reached the header ladder or not
66
+ // purely depending on where the user typed it.
67
+ program.hook('preAction', (thisCommand, actionCommand) => {
57
68
  setWorkspaceFlag(thisCommand.opts()['workspace']);
69
+ const subcommandWorkspaceId = actionCommand.opts()['workspaceId'];
70
+ setWorkspaceIdFlag(subcommandWorkspaceId ?? thisCommand.opts()['workspaceId']);
58
71
  });
59
72
  program
60
73
  .command('init')
61
74
  .description('Set up OrbitMap (cloud account or local files) and install the agent skills')
62
75
  .option('--key <api-key>', 'Agent API key (enables non-interactive mode)')
63
76
  .option('--token <api-key>', 'Alias for --key')
64
- .option('--area <id>', 'Default area ID (cloud) or first area name (local)')
77
+ .option('--area <id>', 'Area this directory is (cloud) or first area name (local)')
78
+ .option('--workspace-id <slug-or-uuid>', 'Cloud: workspace to set up (skips the workspace question)')
65
79
  .option('--profile <profile>', 'MCP profile: full, lite, manager (default: full)')
80
+ .option('--allow-nested', 'Cloud: set up a workspace here even though another workspace root sits above or below ' +
81
+ 'this directory')
66
82
  .option('--advanced', 'Show advanced options (e.g. custom API URL)')
67
83
  .option('--local', 'Set up local-files mode without the interactive question')
68
84
  .option('--workspace <path>', 'Local workspace directory (default: ./.orbitmap)')
@@ -70,6 +86,8 @@ program
70
86
  .option('--no-skills', 'Skip installing the OrbitMap agent skills')
71
87
  .option('--agent <type>', 'Coding agent to install the skills for: claude, gemini, codex, cursor, windsurf, generic ' +
72
88
  '(default: detected from this directory, or asked)')
89
+ .option('--scope <scope>', 'Where to install the skills: user (default, ~/.claude/skills — visible from every ' +
90
+ 'directory) or project (this directory only)')
73
91
  .option('--global', 'Cloud: write to ~/.orbitmap/config.json instead of ./.orbitmap/config.json')
74
92
  .action(async (opts, command) => {
75
93
  // `--workspace` also exists as a program-level flag, and Commander binds it there;
@@ -80,12 +98,17 @@ program
80
98
  key: opts.key,
81
99
  token: opts.token,
82
100
  area: opts.area ?? all['area'],
101
+ // `--workspace-id` is also a program-level flag; take it from whichever position it
102
+ // was given in (same pattern as `--workspace` above).
103
+ workspaceId: opts.workspaceId ?? all['workspaceId'],
83
104
  profile: opts.profile,
105
+ allowNested: opts.allowNested,
84
106
  local: opts.local,
85
107
  workspace: opts.workspace ?? all['workspace'],
86
108
  workspaceName: opts.workspaceName,
87
109
  skills: opts.skills,
88
110
  agent: opts.agent,
111
+ scope: opts.scope,
89
112
  global: opts.global,
90
113
  });
91
114
  });
@@ -121,7 +144,7 @@ program
121
144
  .description('Create a new area')
122
145
  .option('--desc <description>', 'Area description')
123
146
  .option('--slug <slug>', 'Area slug (auto-generated from name if omitted)')
124
- .option('--workspace-id <uuid>', 'Workspace to create the area in')
147
+ .option('--workspace-id <slug-or-uuid>', 'Workspace to create the area in (slug or UUID)')
125
148
  .action(async (name, opts, cmd) => {
126
149
  const globalOpts = cmd.optsWithGlobals();
127
150
  await createAreaCommand(name, {
@@ -129,7 +152,9 @@ program
129
152
  area: globalOpts.area,
130
153
  desc: opts.desc,
131
154
  slug: opts.slug,
132
- workspaceId: opts.workspaceId,
155
+ // `--workspace-id` also exists as a program-level flag; `optsWithGlobals()` picks it
156
+ // up whichever position it was given in (same pattern as `--workspace` on `init`).
157
+ workspaceId: opts.workspaceId ?? globalOpts.workspaceId,
133
158
  });
134
159
  });
135
160
  program
@@ -148,7 +173,8 @@ program
148
173
  });
149
174
  program
150
175
  .command('tasks')
151
- .description('List your assigned tasks')
176
+ .description('List tasks in the current area — or, when the context is workspace-scoped, every ' +
177
+ 'area in the workspace grouped by area')
152
178
  .option('--status <statuses>', 'Filter by status (comma-separated)', 'todo,in_progress')
153
179
  .option('--priority <priority>', 'Filter by priority')
154
180
  .option('--orbit <id-or-slug>', 'Filter by orbit (UUID or slug)')
@@ -209,6 +235,7 @@ program
209
235
  await statusCommand(taskId, status, {
210
236
  json: globalOpts.json,
211
237
  area: globalOpts.area,
238
+ yes: globalOpts.yes,
212
239
  delivery: opts.delivery,
213
240
  force: opts.force,
214
241
  });
@@ -220,17 +247,18 @@ program
220
247
  .option('--priority <priority>', 'Priority (critical, high, medium, low)')
221
248
  .option('--status <status>', 'Initial status')
222
249
  .option('--effort <effort>', 'Estimated effort (e.g. 4h, 2d)')
223
- .option('--agent-id <id>', 'Assign to agent')
250
+ .option('--agent-id <id-or-slug>', 'Assign to agent (UUID or slug)')
224
251
  .option('--branch <name>', 'Git branch name')
225
252
  .option('--instructions <text>', 'Agent instructions')
226
- .option('--from-issue <id-or-number>', 'Link task to an existing issue (UUID, number, or IS-prefixed)')
227
- .option('--intent <id>', 'Link task to an intent')
228
- .option('--orbit <id>', 'Attach task to an orbit (omit to inherit the intent orbit)')
253
+ .option('--from-issue <id-or-number>', 'Link task to an existing issue (UUID or display number, e.g. IS-8hv2wn)')
254
+ .option('--intent <id-or-number>', 'Link task to an intent (UUID or display number, e.g. IN-rwb5qu)')
255
+ .option('--orbit <id-or-slug>', 'Attach task to an orbit (UUID or slug; omit to inherit the intent orbit)')
229
256
  .action(async (title, opts, cmd) => {
230
257
  const globalOpts = cmd.optsWithGlobals();
231
258
  await createCommand(title, {
232
259
  json: globalOpts.json,
233
260
  area: globalOpts.area,
261
+ yes: globalOpts.yes,
234
262
  desc: opts.desc,
235
263
  priority: opts.priority,
236
264
  status: opts.status,
@@ -254,14 +282,15 @@ program
254
282
  await subtaskCommand(parentId, title, {
255
283
  json: globalOpts.json,
256
284
  area: globalOpts.area,
285
+ yes: globalOpts.yes,
257
286
  desc: opts.desc,
258
287
  priority: opts.priority,
259
288
  effort: opts.effort,
260
289
  });
261
290
  });
262
291
  program
263
- .command('assign <id-or-number> [agent-id]')
264
- .description('Assign a task, issue, idea, or intent to an agent or user')
292
+ .command('assign <id-or-number> [agent-id-or-slug]')
293
+ .description('Assign a task, issue, idea, or intent to an agent (UUID or slug) or user')
265
294
  .option('--user-id <id>', 'Assign to a user (by user ID) instead of an agent')
266
295
  .option('--type <type>', 'Object type: task, issue, idea, intent (auto-detected from prefixed IDs; default task)')
267
296
  .action(async (objectId, agentId, opts, cmd) => {
@@ -269,6 +298,7 @@ program
269
298
  await assignCommand(objectId, agentId, {
270
299
  json: globalOpts.json,
271
300
  area: globalOpts.area,
301
+ yes: globalOpts.yes,
272
302
  userId: opts.userId,
273
303
  type: opts.type,
274
304
  });
@@ -276,13 +306,14 @@ program
276
306
  program
277
307
  .command('log <id-or-number> <message>')
278
308
  .description('Log work on a task')
279
- .option('--type <type>', 'Log type: note, code_change, decision, blocker, discovery, exploration, fix', 'note')
309
+ .option('--type <type>', 'Log type: note, code_change, decision, blocker', 'note')
280
310
  .option('--meta <json>', 'JSON metadata (e.g. \'{"files":["..."]}\')')
281
311
  .action(async (taskId, message, opts, cmd) => {
282
312
  const globalOpts = cmd.optsWithGlobals();
283
313
  await logCommand(taskId, message, {
284
314
  json: globalOpts.json,
285
315
  area: globalOpts.area,
316
+ yes: globalOpts.yes,
286
317
  type: opts.type,
287
318
  meta: opts.meta,
288
319
  });
@@ -343,17 +374,20 @@ program
343
374
  .requiredOption('--file <path>', 'Path to markdown file')
344
375
  .option('--source-path <path>', 'Original source path for reference')
345
376
  .option('--context <text>', 'Short description of when this document is relevant')
346
- .option('--workspace-id <uuid>', 'Create as workspace-level document (cross-area knowledge)')
377
+ .option('--workspace-id <slug-or-uuid>', 'Create as workspace-level document (cross-area knowledge); slug or UUID')
347
378
  .action(async (title, opts, cmd) => {
348
379
  const globalOpts = cmd.optsWithGlobals();
349
380
  await docImportCommand(title, {
350
381
  json: globalOpts.json,
351
382
  area: globalOpts.area,
383
+ yes: globalOpts.yes,
352
384
  type: opts.type,
353
385
  file: opts.file,
354
386
  sourcePath: opts.sourcePath,
355
387
  context: opts.context,
356
- workspaceId: opts.workspaceId,
388
+ // Program-level `--workspace-id` is the fallback when it was given before the
389
+ // subcommand name (see `create-area`).
390
+ workspaceId: opts.workspaceId ?? globalOpts.workspaceId,
357
391
  });
358
392
  });
359
393
  program
@@ -437,21 +471,33 @@ program
437
471
  .description('Refresh the OrbitMap agent instructions/skills, or add another agent type ' +
438
472
  '(`init` already installs them once)')
439
473
  .option('--agent <type>', 'Agent type: claude, gemini, codex, cursor, windsurf, generic')
474
+ .option('--scope <scope>', 'Where to install: user (default, ~/.claude/skills — visible from every directory) ' +
475
+ 'or project (this directory only)')
476
+ .option('--clean-project', 'With --scope user: remove an older project-scope install in this directory ' +
477
+ '(its four OrbitMap skill dirs + the OrbitMap block in the config file) without asking')
440
478
  .action(async (opts) => {
441
- await setupAgentCommand({ agent: opts.agent });
479
+ await setupAgentCommand({
480
+ agent: opts.agent,
481
+ scope: opts.scope,
482
+ cleanProject: opts.cleanProject,
483
+ });
442
484
  });
443
485
  program
444
486
  .command('setup-mcp')
445
487
  .description('Install OrbitMap MCP entry into .mcp.json in the current directory (no API calls)')
446
488
  .option('--token <api-key>', 'Agent API key (Bearer auth)')
447
489
  .option('--oauth', 'Use OAuth (no Authorization header; auth happens on first MCP use)')
448
- .option('--area <slug>', 'Area slug or UUID (required for --token, optional for --oauth)')
490
+ .option('--workspace-id <slug-or-uuid>', 'Workspace to pin in the generated block (X-Orbitmap-Workspace)')
491
+ .option('--area <slug>', 'Area slug or UUID to pin as well (X-Orbitmap-Area, optional)')
449
492
  .option('--profile <profile>', 'MCP profile: full, lite, manager (default: full)')
450
493
  .action(async (opts, cmd) => {
494
+ // `--workspace-id` also exists as a program-level flag; `optsWithGlobals()` picks it up
495
+ // whichever position it was given in (same pattern as `--area`).
451
496
  const globalOpts = cmd.optsWithGlobals();
452
497
  await setupMcpCommand({
453
498
  token: opts.token,
454
499
  oauth: opts.oauth,
500
+ workspaceId: opts.workspaceId || globalOpts.workspaceId,
455
501
  area: opts.area || globalOpts.area,
456
502
  profile: opts.profile,
457
503
  });
@@ -538,19 +584,26 @@ const issue = program
538
584
  .command('issue')
539
585
  .description('Manage issues');
540
586
  issue
541
- .command('register')
587
+ .command('register [title]')
542
588
  .description('Register a new issue')
543
- .requiredOption('--title <title>', 'Issue title')
589
+ // Title is positional, like `create`, `intent create`, `mission create` and `orbit create`.
590
+ // `--title` stays as a hidden back-compat alias.
591
+ .addOption(new Option('--title <title>', 'Deprecated: pass the title positionally').hideHelp())
544
592
  .requiredOption('--description <text>', 'Issue description')
545
593
  .option('--severity <level>', 'Severity: critical, high, medium, low')
546
- .option('--related-task <id>', 'Related task UUID')
547
- .option('--intent <id>', 'Link issue to an intent')
548
- .action(async (opts, cmd) => {
594
+ // These two stay UUID-only: TS-av6332 relaxed `intent_id`/`orbit_id`/`source_issue_id` on
595
+ // POST /tasks to `App\Rules\EntityRef`, but IssueController still validates
596
+ // `related_task_id` and `intent_id` as `uuid`. Do not translate client-side — see the
597
+ // OrbitMap issue linked from TS-zhmvnc.
598
+ .option('--related-task <uuid>', 'Related task UUID (this endpoint does not accept display numbers)')
599
+ .option('--intent <uuid>', 'Link issue to an intent, by UUID (no display numbers here)')
600
+ .action(async (title, opts, cmd) => {
549
601
  const globalOpts = cmd.optsWithGlobals();
550
602
  await issueRegisterCommand({
551
603
  json: globalOpts.json,
552
604
  area: globalOpts.area,
553
- title: opts.title,
605
+ yes: globalOpts.yes,
606
+ title: title ?? opts.title,
554
607
  description: opts.description,
555
608
  severity: opts.severity,
556
609
  relatedTask: opts.relatedTask,
@@ -586,9 +639,11 @@ issue
586
639
  issue
587
640
  .command('resolve <id-or-number>')
588
641
  .description('Resolve an issue')
589
- .requiredOption('--status <status>', 'Resolve status: resolved, wont_fix, duplicate')
642
+ // The command is named `resolve`, so `resolved` is the obvious default; --status stays
643
+ // available for the other two terminal states (wont_fix, duplicate).
644
+ .option('--status <status>', 'Resolve status: resolved, wont_fix, duplicate', 'resolved')
590
645
  .option('--resolution <text>', 'Resolution description (required for resolved/wont_fix)')
591
- .option('--resolved-task <id>', 'Task UUID that resolved this issue')
646
+ .option('--resolved-task <uuid>', 'Task UUID that resolved this issue (no display numbers here)')
592
647
  .action(async (idOrNumber, opts, cmd) => {
593
648
  const globalOpts = cmd.optsWithGlobals();
594
649
  await issueResolveCommand(idOrNumber, {
@@ -601,9 +656,11 @@ issue
601
656
  });
602
657
  issue
603
658
  .command('status <id-or-number> <status>')
604
- .description('Update issue status (open, investigating, backlog, resolved, wont_fix, duplicate)')
659
+ .description('Update issue status. Which move is legal depends on the current status ' +
660
+ '(open <-> investigating <-> backlog, any of them -> resolved/wont_fix/duplicate, ' +
661
+ 'and those back to open); the server rejects anything else with INVALID_TRANSITION')
605
662
  .option('--resolution <text>', 'Resolution description (required for resolved/wont_fix)')
606
- .option('--resolved-task <id>', 'Task UUID that resolved this issue')
663
+ .option('--resolved-task <uuid>', 'Task UUID that resolved this issue (no display numbers here)')
607
664
  .action(async (idOrNumber, status, opts, cmd) => {
608
665
  const globalOpts = cmd.optsWithGlobals();
609
666
  await issueStatusCommand(idOrNumber, status, {
@@ -618,18 +675,21 @@ const vibe = program
618
675
  .command('vibe')
619
676
  .description('Manage vibes');
620
677
  vibe
621
- .command('log')
678
+ .command('log [content]')
622
679
  .description('Log a new vibe')
623
- .requiredOption('--content <text>', 'Vibe content')
624
- .requiredOption('--type <type>', 'Type: note, code_change, decision, discovery, idea, exploration, fix')
680
+ // Content is positional, matching every other "create something" command.
681
+ // `--content` stays as a hidden back-compat alias.
682
+ .addOption(new Option('--content <text>', 'Deprecated: pass the content positionally').hideHelp())
683
+ .requiredOption('--type <type>', 'Type: note, code_change, decision, discovery, exploration, fix')
625
684
  .option('--title <title>', 'Optional title')
626
- .option('--task <id>', 'Related task UUID')
627
- .action(async (opts, cmd) => {
685
+ .option('--task <uuid>', 'Related task UUID (this endpoint does not accept display numbers)')
686
+ .action(async (content, opts, cmd) => {
628
687
  const globalOpts = cmd.optsWithGlobals();
629
688
  await vibeLogCommand({
630
689
  json: globalOpts.json,
631
690
  area: globalOpts.area,
632
- content: opts.content,
691
+ yes: globalOpts.yes,
692
+ content: content ?? opts.content,
633
693
  type: opts.type,
634
694
  title: opts.title,
635
695
  task: opts.task,
@@ -652,8 +712,8 @@ vibe
652
712
  });
653
713
  });
654
714
  vibe
655
- .command('show <id>')
656
- .description('Show full vibe details')
715
+ .command('show <id-or-number>')
716
+ .description('Show full vibe details (UUID or display number, e.g. VB-a1b2c3)')
657
717
  .action(async (id, _opts, cmd) => {
658
718
  const globalOpts = cmd.optsWithGlobals();
659
719
  await vibeShowCommand(id, {
@@ -662,8 +722,8 @@ vibe
662
722
  });
663
723
  });
664
724
  vibe
665
- .command('update <id>')
666
- .description('Update a vibe')
725
+ .command('update <id-or-number>')
726
+ .description('Update a vibe (UUID or display number, e.g. VB-a1b2c3)')
667
727
  .option('--type <type>', 'New type')
668
728
  .option('--title <title>', 'New title')
669
729
  .option('--content <text>', 'New content')
@@ -710,17 +770,20 @@ idea
710
770
  });
711
771
  });
712
772
  idea
713
- .command('add')
773
+ .command('add [content]')
714
774
  .description('Add a new idea')
715
- .requiredOption('--content <text>', 'Idea content')
775
+ // Content is positional, matching every other "create something" command.
776
+ // `--content` stays as a hidden back-compat alias.
777
+ .addOption(new Option('--content <text>', 'Deprecated: pass the content positionally').hideHelp())
716
778
  .option('--title <title>', 'Optional short title')
717
779
  .option('--priority <priority>', 'Priority (critical, high, medium, low)')
718
- .action(async (opts, cmd) => {
780
+ .action(async (content, opts, cmd) => {
719
781
  const globalOpts = cmd.optsWithGlobals();
720
782
  await ideaAddCommand({
721
783
  json: globalOpts.json,
722
784
  area: globalOpts.area,
723
- content: opts.content,
785
+ yes: globalOpts.yes,
786
+ content: content ?? opts.content,
724
787
  title: opts.title,
725
788
  priority: opts.priority,
726
789
  });
@@ -744,13 +807,23 @@ const orbit = program
744
807
  orbit
745
808
  .command('list')
746
809
  .description('List orbits (workspace-scoped from the area context)')
747
- .option('--workspace <id>', 'Filter by workspace UUID')
810
+ .option('--workspace-id <slug-or-uuid>', 'Filter by workspace (slug or UUID)')
811
+ // Back-compat: `--workspace <id>` was this filter's original spelling, which collided with
812
+ // the program-level `--workspace <path>` (a local directory that forces local mode).
813
+ // Hidden, still accepted, warns once.
814
+ .addOption(new Option('--workspace <slug-or-uuid>', 'Deprecated alias for --workspace-id').hideHelp())
748
815
  .action(async (opts, cmd) => {
749
816
  const globalOpts = cmd.optsWithGlobals();
817
+ if (opts.workspace && !opts.workspaceId) {
818
+ console.error('Warning: `orbit list --workspace` is deprecated (it collides with the global ' +
819
+ '`--workspace <path>`). Use `--workspace-id` instead.');
820
+ }
750
821
  await orbitListCommand({
751
822
  json: globalOpts.json,
752
823
  area: globalOpts.area,
753
- workspace: opts.workspace,
824
+ // Only the *subcommand* flags are considered: the global `--workspace` is a directory,
825
+ // never a filter. The global `--workspace-id` is picked up as the last fallback.
826
+ workspaceId: opts.workspaceId ?? opts.workspace ?? globalOpts.workspaceId,
754
827
  });
755
828
  });
756
829
  orbit
@@ -813,7 +886,10 @@ orbit
813
886
  .command('attach <orbit-id-or-slug>')
814
887
  .description('Attach an object to an orbit')
815
888
  .requiredOption('--type <type>', 'Object type: task, issue, vibe, idea, document')
816
- .requiredOption('--id <uuid>', 'Object UUID')
889
+ // OrbitController::findOrbitItemObject now resolves display numbers via entityRefColumn()
890
+ // for the numbered types (task/issue/vibe/idea). Documents have no display number, so
891
+ // `--type document` still requires a UUID.
892
+ .requiredOption('--id <id-or-number>', 'Object UUID or display number (TS-/IS-/VB-/ID-); documents are UUID-only')
817
893
  .option('--note <text>', 'Optional note for the attachment')
818
894
  .action(async (orbitIdOrSlug, opts, cmd) => {
819
895
  const globalOpts = cmd.optsWithGlobals();
@@ -829,7 +905,7 @@ orbit
829
905
  .command('detach <orbit-id-or-slug>')
830
906
  .description('Detach an object from an orbit')
831
907
  .requiredOption('--type <type>', 'Object type: task, issue, vibe, idea, document')
832
- .requiredOption('--id <uuid>', 'Object UUID')
908
+ .requiredOption('--id <id-or-number>', 'Object UUID or display number (TS-/IS-/VB-/ID-); documents are UUID-only')
833
909
  .action(async (orbitIdOrSlug, opts, cmd) => {
834
910
  const globalOpts = cmd.optsWithGlobals();
835
911
  await orbitDetachCommand(orbitIdOrSlug, {
@@ -907,7 +983,9 @@ intent
907
983
  .description('Create a new intent')
908
984
  .option('--outcome <text>', 'Desired outcome')
909
985
  .option('--status <status>', 'Initial status: new, design, plan, build, done, cancelled (default new)')
910
- .option('--orbit <id>', 'Attach the intent to an orbit after creation')
986
+ // PUT /intents/{id}/orbit validates `orbit_id` as `uuid|exists:orbits,id` unlike
987
+ // POST /tasks it takes no slug. `orbit list` prints the UUID (TS-adanc8).
988
+ .option('--orbit <uuid>', 'Attach the intent to an orbit after creation (UUID, not a slug)')
911
989
  .action(async (title, opts, cmd) => {
912
990
  const globalOpts = cmd.optsWithGlobals();
913
991
  await intentCreateCommand(title, {
@@ -938,7 +1016,7 @@ intent
938
1016
  .command('link <id-or-number>')
939
1017
  .description('Link a task or issue to an intent')
940
1018
  .requiredOption('--type <type>', 'Object type: task, issue')
941
- .requiredOption('--id <uuid>', 'Object UUID')
1019
+ .requiredOption('--id <uuid>', 'Object UUID (this endpoint does not accept display numbers)')
942
1020
  .action(async (idOrNumber, opts, cmd) => {
943
1021
  const globalOpts = cmd.optsWithGlobals();
944
1022
  await intentLinkCommand(idOrNumber, {
@@ -952,7 +1030,7 @@ intent
952
1030
  .command('unlink <id-or-number>')
953
1031
  .description('Unlink a task or issue from an intent')
954
1032
  .requiredOption('--type <type>', 'Object type: task, issue')
955
- .requiredOption('--id <uuid>', 'Object UUID')
1033
+ .requiredOption('--id <uuid>', 'Object UUID (this endpoint does not accept display numbers)')
956
1034
  .action(async (idOrNumber, opts, cmd) => {
957
1035
  const globalOpts = cmd.optsWithGlobals();
958
1036
  await intentUnlinkCommand(idOrNumber, {
@@ -963,8 +1041,8 @@ intent
963
1041
  });
964
1042
  });
965
1043
  intent
966
- .command('orbit <id-or-number> [orbit-id]')
967
- .description('Set or clear the orbit of an intent')
1044
+ .command('orbit <id-or-number> [orbit-uuid]')
1045
+ .description('Set or clear the orbit of an intent (the orbit is named by UUID, not by slug)')
968
1046
  .option('--clear', 'Clear the orbit instead of setting one')
969
1047
  .action(async (idOrNumber, orbitId, opts, cmd) => {
970
1048
  const globalOpts = cmd.optsWithGlobals();
@@ -1052,7 +1130,7 @@ mission
1052
1130
  .command('link <id-or-number>')
1053
1131
  .description('Link a task, issue, idea, or intent to a mission (clears intent_id on tasks/issues)')
1054
1132
  .requiredOption('--type <type>', 'Object type: task, issue, idea, intent')
1055
- .requiredOption('--id <uuid>', 'Object UUID')
1133
+ .requiredOption('--id <uuid>', 'Object UUID (this endpoint does not accept display numbers)')
1056
1134
  .action(async (idOrNumber, opts, cmd) => {
1057
1135
  const globalOpts = cmd.optsWithGlobals();
1058
1136
  await missionLinkCommand(idOrNumber, {
@@ -1066,7 +1144,7 @@ mission
1066
1144
  .command('unlink <id-or-number>')
1067
1145
  .description('Unlink a directly-linked item from a mission')
1068
1146
  .requiredOption('--type <type>', 'Object type: task, issue, idea, intent')
1069
- .requiredOption('--id <uuid>', 'Object UUID')
1147
+ .requiredOption('--id <uuid>', 'Object UUID (this endpoint does not accept display numbers)')
1070
1148
  .action(async (idOrNumber, opts, cmd) => {
1071
1149
  const globalOpts = cmd.optsWithGlobals();
1072
1150
  await missionUnlinkCommand(idOrNumber, {