@skrr-ai/cli 0.1.36 → 0.1.38

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 (266) hide show
  1. package/README.md +17 -4
  2. package/bin/dev-fallback.js +167 -4
  3. package/dist/base-command.js +46 -2
  4. package/dist/commands/agents/actions/create.d.ts +5 -0
  5. package/dist/commands/agents/actions/create.js +42 -5
  6. package/dist/commands/agents/actions/delete.d.ts +1 -0
  7. package/dist/commands/agents/actions/delete.js +7 -0
  8. package/dist/commands/agents/actions/update.d.ts +5 -0
  9. package/dist/commands/agents/actions/update.js +27 -1
  10. package/dist/commands/agents/api-actions/add.d.ts +41 -0
  11. package/dist/commands/agents/api-actions/add.js +205 -0
  12. package/dist/commands/agents/api-actions/index.d.ts +39 -0
  13. package/dist/commands/agents/api-actions/index.js +103 -0
  14. package/dist/commands/agents/api-actions/remove.d.ts +14 -0
  15. package/dist/commands/agents/api-actions/remove.js +36 -0
  16. package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
  17. package/dist/commands/agents/avatar/default/apply.js +56 -0
  18. package/dist/commands/agents/avatar/default/index.d.ts +29 -0
  19. package/dist/commands/agents/avatar/default/index.js +61 -0
  20. package/dist/commands/agents/avatar/default/set.d.ts +24 -0
  21. package/dist/commands/agents/avatar/default/set.js +120 -0
  22. package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
  23. package/dist/commands/agents/avatar/library/delete.js +47 -0
  24. package/dist/commands/agents/avatar/library/index.d.ts +16 -0
  25. package/dist/commands/agents/avatar/library/index.js +56 -0
  26. package/dist/commands/agents/avatar/presets.d.ts +19 -0
  27. package/dist/commands/agents/avatar/presets.js +56 -0
  28. package/dist/commands/agents/avatar/upload.js +7 -1
  29. package/dist/commands/agents/categories/create.d.ts +14 -0
  30. package/dist/commands/agents/categories/create.js +46 -0
  31. package/dist/commands/agents/categories/delete.d.ts +13 -0
  32. package/dist/commands/agents/categories/delete.js +41 -0
  33. package/dist/commands/agents/categories/index.d.ts +36 -0
  34. package/dist/commands/agents/categories/index.js +135 -0
  35. package/dist/commands/agents/categories/update.d.ts +22 -0
  36. package/dist/commands/agents/categories/update.js +59 -0
  37. package/dist/commands/agents/chat.d.ts +21 -0
  38. package/dist/commands/agents/chat.js +94 -7
  39. package/dist/commands/agents/create.d.ts +10 -0
  40. package/dist/commands/agents/create.js +64 -3
  41. package/dist/commands/agents/ensure-default.d.ts +27 -0
  42. package/dist/commands/agents/ensure-default.js +65 -0
  43. package/dist/commands/agents/list.d.ts +15 -0
  44. package/dist/commands/agents/list.js +31 -1
  45. package/dist/commands/agents/mute.d.ts +16 -0
  46. package/dist/commands/agents/mute.js +38 -0
  47. package/dist/commands/agents/pin.d.ts +16 -0
  48. package/dist/commands/agents/pin.js +38 -0
  49. package/dist/commands/agents/scene-background/upload.d.ts +30 -0
  50. package/dist/commands/agents/scene-background/upload.js +97 -0
  51. package/dist/commands/agents/show.js +13 -0
  52. package/dist/commands/agents/tools/auth.d.ts +19 -0
  53. package/dist/commands/agents/tools/auth.js +41 -0
  54. package/dist/commands/agents/tools/calls.d.ts +36 -0
  55. package/dist/commands/agents/tools/calls.js +117 -0
  56. package/dist/commands/agents/tools/index.d.ts +20 -0
  57. package/dist/commands/agents/tools/index.js +77 -0
  58. package/dist/commands/agents/unmute.d.ts +16 -0
  59. package/dist/commands/agents/unmute.js +38 -0
  60. package/dist/commands/agents/unpin.d.ts +16 -0
  61. package/dist/commands/agents/unpin.js +38 -0
  62. package/dist/commands/agents/update.d.ts +12 -0
  63. package/dist/commands/agents/update.js +74 -3
  64. package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
  65. package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
  66. package/dist/commands/convos/messages.d.ts +13 -0
  67. package/dist/commands/convos/messages.js +40 -16
  68. package/dist/commands/daemon/index.js +8 -1
  69. package/dist/commands/daemon/logs.d.ts +26 -0
  70. package/dist/commands/daemon/logs.js +56 -0
  71. package/dist/commands/daemon/uninstall.js +1 -1
  72. package/dist/commands/followups/act.d.ts +22 -0
  73. package/dist/commands/followups/act.js +103 -0
  74. package/dist/commands/followups/cancel.d.ts +20 -0
  75. package/dist/commands/followups/cancel.js +50 -0
  76. package/dist/commands/followups/checkin.d.ts +27 -0
  77. package/dist/commands/followups/checkin.js +107 -0
  78. package/dist/commands/followups/list.d.ts +24 -0
  79. package/dist/commands/followups/list.js +90 -0
  80. package/dist/commands/followups/observability.d.ts +23 -0
  81. package/dist/commands/followups/observability.js +114 -0
  82. package/dist/commands/followups/remind.d.ts +26 -0
  83. package/dist/commands/followups/remind.js +106 -0
  84. package/dist/commands/followups/reschedule.d.ts +15 -0
  85. package/dist/commands/followups/reschedule.js +48 -0
  86. package/dist/commands/followups/resolve.d.ts +23 -0
  87. package/dist/commands/followups/resolve.js +54 -0
  88. package/dist/commands/followups/show.d.ts +12 -0
  89. package/dist/commands/followups/show.js +46 -0
  90. package/dist/commands/followups/watch.d.ts +51 -0
  91. package/dist/commands/followups/watch.js +211 -0
  92. package/dist/commands/goals/labels/add.js +19 -2
  93. package/dist/commands/goals/labels/remove.js +22 -2
  94. package/dist/commands/harnesses/forget.js +28 -0
  95. package/dist/commands/harnesses/install.d.ts +41 -0
  96. package/dist/commands/harnesses/install.js +165 -0
  97. package/dist/commands/harnesses/installers.d.ts +45 -0
  98. package/dist/commands/harnesses/installers.js +155 -0
  99. package/dist/commands/harnesses/list.d.ts +82 -1
  100. package/dist/commands/harnesses/list.js +104 -12
  101. package/dist/commands/harnesses/models.js +10 -1
  102. package/dist/commands/harnesses/show.d.ts +15 -0
  103. package/dist/commands/harnesses/show.js +44 -3
  104. package/dist/commands/harnesses/update.js +1 -1
  105. package/dist/commands/harnesses/usage.d.ts +25 -0
  106. package/dist/commands/harnesses/usage.js +24 -2
  107. package/dist/commands/instructions/status.js +13 -1
  108. package/dist/commands/labels/list.d.ts +24 -1
  109. package/dist/commands/labels/list.js +62 -19
  110. package/dist/commands/machines/dedicated/catalog.js +4 -15
  111. package/dist/commands/machines/dedicated/create.d.ts +8 -0
  112. package/dist/commands/machines/dedicated/create.js +58 -1
  113. package/dist/commands/machines/dedicated/destroy.js +18 -4
  114. package/dist/commands/machines/dedicated/list.js +9 -6
  115. package/dist/commands/machines/hosted/list.js +12 -0
  116. package/dist/commands/machines/list.js +11 -0
  117. package/dist/commands/machines/show.d.ts +1 -0
  118. package/dist/commands/machines/show.js +40 -11
  119. package/dist/commands/memory/governance/index.d.ts +21 -0
  120. package/dist/commands/memory/governance/index.js +64 -0
  121. package/dist/commands/memory/governance/set.d.ts +24 -0
  122. package/dist/commands/memory/governance/set.js +95 -0
  123. package/dist/commands/memory/provenance.d.ts +18 -0
  124. package/dist/commands/memory/provenance.js +66 -0
  125. package/dist/commands/profiles/list.d.ts +23 -0
  126. package/dist/commands/profiles/list.js +96 -0
  127. package/dist/commands/search/skills.d.ts +11 -1
  128. package/dist/commands/search/skills.js +26 -8
  129. package/dist/commands/skills/details.d.ts +2 -0
  130. package/dist/commands/skills/details.js +24 -1
  131. package/dist/commands/skills/import-as-actions.d.ts +32 -0
  132. package/dist/commands/skills/import-as-actions.js +175 -0
  133. package/dist/commands/skills/install.d.ts +2 -0
  134. package/dist/commands/skills/install.js +24 -1
  135. package/dist/commands/skills/invocable.js +6 -2
  136. package/dist/commands/skills/local.d.ts +40 -0
  137. package/dist/commands/skills/local.js +160 -0
  138. package/dist/commands/skills/search.d.ts +11 -1
  139. package/dist/commands/skills/search.js +29 -8
  140. package/dist/commands/spaces/actions/add.js +23 -5
  141. package/dist/commands/spaces/actions/available.js +3 -0
  142. package/dist/commands/spaces/actions/list.d.ts +5 -0
  143. package/dist/commands/spaces/actions/list.js +49 -3
  144. package/dist/commands/spaces/actions/run.d.ts +28 -0
  145. package/dist/commands/spaces/actions/run.js +146 -0
  146. package/dist/commands/spaces/actions/update.js +27 -5
  147. package/dist/commands/spaces/create.d.ts +3 -0
  148. package/dist/commands/spaces/create.js +32 -2
  149. package/dist/commands/spaces/label-summaries.d.ts +27 -0
  150. package/dist/commands/spaces/label-summaries.js +64 -0
  151. package/dist/commands/spaces/labels/add.js +19 -2
  152. package/dist/commands/spaces/labels/remove.js +22 -2
  153. package/dist/commands/spaces/show.js +2 -0
  154. package/dist/commands/spaces/task-rollups.d.ts +5 -0
  155. package/dist/commands/spaces/task-rollups.js +15 -4
  156. package/dist/commands/spaces/update.d.ts +5 -0
  157. package/dist/commands/spaces/update.js +41 -4
  158. package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
  159. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +105 -0
  160. package/dist/commands/tasks/actions/attach.js +32 -7
  161. package/dist/commands/tasks/complete.d.ts +1 -0
  162. package/dist/commands/tasks/complete.js +21 -1
  163. package/dist/commands/tasks/create.d.ts +3 -0
  164. package/dist/commands/tasks/create.js +34 -2
  165. package/dist/commands/tasks/events/append.js +29 -6
  166. package/dist/commands/tasks/expectations/assess.d.ts +12 -0
  167. package/dist/commands/tasks/expectations/assess.js +123 -14
  168. package/dist/commands/tasks/expectations.js +95 -17
  169. package/dist/commands/tasks/follow-up.js +2 -2
  170. package/dist/commands/tasks/labels/attach.js +20 -3
  171. package/dist/commands/tasks/labels/detach.js +21 -3
  172. package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
  173. package/dist/commands/tasks/lifecycle/attach.js +47 -0
  174. package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
  175. package/dist/commands/tasks/lifecycle/definitions.js +59 -0
  176. package/dist/commands/tasks/lifecycle/detach.d.ts +19 -0
  177. package/dist/commands/tasks/lifecycle/detach.js +72 -0
  178. package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
  179. package/dist/commands/tasks/lifecycle/history.js +38 -0
  180. package/dist/commands/tasks/lifecycle/migrate.d.ts +14 -0
  181. package/dist/commands/tasks/lifecycle/migrate.js +68 -0
  182. package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
  183. package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
  184. package/dist/commands/tasks/lifecycle/reopen.d.ts +15 -0
  185. package/dist/commands/tasks/lifecycle/reopen.js +71 -0
  186. package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
  187. package/dist/commands/tasks/lifecycle/show.js +27 -0
  188. package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
  189. package/dist/commands/tasks/lifecycle/start.js +30 -0
  190. package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
  191. package/dist/commands/tasks/lifecycle/transition.js +109 -0
  192. package/dist/commands/tasks/list.js +16 -9
  193. package/dist/commands/tasks/move.d.ts +1 -0
  194. package/dist/commands/tasks/move.js +29 -0
  195. package/dist/commands/tasks/result/submit.js +11 -1
  196. package/dist/commands/tasks/review-queue.d.ts +44 -0
  197. package/dist/commands/tasks/review-queue.js +314 -0
  198. package/dist/commands/tasks/show.d.ts +11 -0
  199. package/dist/commands/tasks/show.js +139 -4
  200. package/dist/commands/tasks/trust.js +7 -2
  201. package/dist/commands/tasks/update.d.ts +1 -0
  202. package/dist/commands/tasks/update.js +83 -0
  203. package/dist/commands/tasks/updates/add.js +1 -1
  204. package/dist/commands/token/list.d.ts +22 -0
  205. package/dist/commands/token/list.js +68 -0
  206. package/dist/commands/token/revoke.d.ts +23 -0
  207. package/dist/commands/token/revoke.js +53 -0
  208. package/dist/lib/agent-actions.d.ts +92 -11
  209. package/dist/lib/agent-actions.js +171 -25
  210. package/dist/lib/agent-config.d.ts +11 -0
  211. package/dist/lib/agent-config.js +85 -3
  212. package/dist/lib/agent-pin-mute.d.ts +29 -0
  213. package/dist/lib/agent-pin-mute.js +30 -0
  214. package/dist/lib/agent-visual-refs.d.ts +33 -0
  215. package/dist/lib/agent-visual-refs.js +267 -0
  216. package/dist/lib/agentic-stream.d.ts +6 -0
  217. package/dist/lib/agentic-stream.js +34 -3
  218. package/dist/lib/assignee-resolver.d.ts +1 -1
  219. package/dist/lib/assignee-resolver.js +8 -0
  220. package/dist/lib/bulk-task-targets.d.ts +12 -0
  221. package/dist/lib/bulk-task-targets.js +34 -1
  222. package/dist/lib/cli-installers.d.ts +130 -0
  223. package/dist/lib/cli-installers.js +145 -0
  224. package/dist/lib/command-miss.js +55 -7
  225. package/dist/lib/dedicated-lease-command.d.ts +13 -0
  226. package/dist/lib/dedicated-lease-command.js +22 -1
  227. package/dist/lib/dedicated-machines.d.ts +95 -1
  228. package/dist/lib/dedicated-machines.js +236 -2
  229. package/dist/lib/failed-lookup.d.ts +3 -0
  230. package/dist/lib/failed-lookup.js +40 -0
  231. package/dist/lib/first-party-harness-agent.js +16 -2
  232. package/dist/lib/first-party-harness-doctor.d.ts +15 -0
  233. package/dist/lib/first-party-harness-doctor.js +126 -27
  234. package/dist/lib/followups.d.ts +115 -0
  235. package/dist/lib/followups.js +127 -0
  236. package/dist/lib/harnesses.d.ts +8 -0
  237. package/dist/lib/instruction-input.d.ts +19 -1
  238. package/dist/lib/instruction-input.js +52 -1
  239. package/dist/lib/label-ref.d.ts +95 -0
  240. package/dist/lib/label-ref.js +163 -0
  241. package/dist/lib/label-scope.d.ts +17 -2
  242. package/dist/lib/label-scope.js +27 -7
  243. package/dist/lib/local-skills.d.ts +98 -0
  244. package/dist/lib/local-skills.js +195 -0
  245. package/dist/lib/machines.d.ts +10 -10
  246. package/dist/lib/machines.js +23 -1
  247. package/dist/lib/search-query.d.ts +19 -0
  248. package/dist/lib/search-query.js +35 -0
  249. package/dist/lib/space-custom-actions.d.ts +72 -0
  250. package/dist/lib/space-custom-actions.js +117 -0
  251. package/dist/lib/space-resolver.d.ts +1 -21
  252. package/dist/lib/space-resolver.js +19 -10
  253. package/dist/lib/task-closure.d.ts +33 -0
  254. package/dist/lib/task-closure.js +104 -0
  255. package/dist/lib/task-lifecycle-output.d.ts +14 -0
  256. package/dist/lib/task-lifecycle-output.js +209 -0
  257. package/dist/lib/task-ref-resolver.d.ts +1 -17
  258. package/dist/lib/task-ref-resolver.js +18 -8
  259. package/dist/lib/tasks.d.ts +3 -0
  260. package/dist/lib/tasks.js +40 -3
  261. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
  262. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
  263. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  264. package/dist/node_modules/@skrr-ai/data-provider/index.js +5559 -4897
  265. package/oclif.manifest.json +33890 -28690
  266. package/package.json +24 -6
@@ -42,6 +42,9 @@ class TasksUpdate extends base_command_1.BaseCommand {
42
42
  description: 'Path to a JSON file (or "-" for stdin) to use as the patch body; may include taskId',
43
43
  }),
44
44
  title: core_1.Flags.string({ description: 'New title' }),
45
+ yes: core_1.Flags.boolean({
46
+ description: 'Skip the confirmation when changing Expectations revokes assessments already recorded',
47
+ }),
45
48
  expect: core_1.Flags.string({
46
49
  multiple: true,
47
50
  description: tasks_1.EXPECT_FLAG_HELP +
@@ -227,6 +230,86 @@ class TasksUpdate extends base_command_1.BaseCommand {
227
230
  }
228
231
  }
229
232
  }
233
+ /**
234
+ * Say what the edit costs BEFORE making it.
235
+ *
236
+ * `expectations` is a TaskSpecFence field, and assessments are matched by
237
+ * exact `specVersion` — so rewriting the list bumps the version and every
238
+ * judgement already recorded against the old one stops counting. Assess
239
+ * five, fix a typo in the sixth, and the five are gone.
240
+ *
241
+ * Disclosure, not a block: the edit is legitimate and must stay possible.
242
+ * The point is only that its price should not be discovered afterwards, by
243
+ * a Task that will not close. `--yes` states the intent in the command line
244
+ * where it can be reviewed, which is also what a non-TTY caller needs.
245
+ */
246
+ /*
247
+ * The trigger is the PAYLOAD, not the flag that produced it.
248
+ *
249
+ * The first version guarded only `--expect`, so `--from-json
250
+ * '{"expectations": [...]}'` — exactly what an agent batching edits uses —
251
+ * rewrote the list and revoked the assessments with no warning at all.
252
+ * Same write, same price: the disclosure belongs on the effective change.
253
+ */
254
+ /*
255
+ * The DESCRIPTION is a spec field too.
256
+ *
257
+ * `TaskSpecFence.TASK_SPEC_FIELDS` is `['description', 'expectations']`, and
258
+ * both advance `specVersion` — which revokes every assessment, because they
259
+ * are matched by exact version. The disclosure was wired to the Expectations
260
+ * payload alone, so fixing a typo in the prose voided a reviewer's sign-off
261
+ * with no warning and no receipt. Same write, same price, same disclosure.
262
+ */
263
+ const changesSpec = expectationsPatch !== undefined ||
264
+ body.expectations !== undefined ||
265
+ flags.description !== undefined ||
266
+ body.description !== undefined;
267
+ if (changesSpec) {
268
+ let settled = [];
269
+ let unreadable = false;
270
+ try {
271
+ const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskIdentity.id);
272
+ settled = acceptance.expectations.filter((e) => e.assessmentId);
273
+ }
274
+ catch {
275
+ // An unreadable acceptance is not a reason to refuse the edit. Warn
276
+ // without a number rather than inventing one or blocking the write.
277
+ unreadable = true;
278
+ }
279
+ if ((unreadable || settled.length > 0) && !flags.yes) {
280
+ const noun = settled.length === 1 ? 'assessment' : 'assessments';
281
+ const count = unreadable ? 'Any existing' : `${settled.length} existing`;
282
+ const field = expectationsPatch !== undefined || body.expectations !== undefined
283
+ ? 'Changing Expectations'
284
+ : 'Changing the description';
285
+ this.log(`${field} advances the Task specification, so ${count} ${noun} ` +
286
+ 'will stop counting and must be recorded again.');
287
+ /*
288
+ * NAME them. The count alone made the warning unactionable — and it is
289
+ * task-WIDE, so Expectations you are not touching lose their judgements
290
+ * too, which a bare number actively hides.
291
+ */
292
+ for (const row of settled) {
293
+ this.log(` ${row.id} ${row.sentence || row.text || ''}`);
294
+ }
295
+ if (settled.length > 0) {
296
+ this.log('Revocation covers every Expectation on this Task, including ones this edit ' +
297
+ 'does not touch.');
298
+ }
299
+ const ok = await this.confirm('Continue? [y/N] ');
300
+ if (!ok) {
301
+ /*
302
+ * Non-zero, because the edit did NOT happen.
303
+ *
304
+ * This printed "No change made." and exited 0, so `skrr tasks update
305
+ * … && echo applied` printed `applied`. The guard exists to protect
306
+ * the non-interactive path, and the non-interactive path is precisely
307
+ * the one that cannot see a message — it can only read the exit code.
308
+ */
309
+ this.error('No change made — re-run with `--yes` to accept the revocation.', { exit: 2 });
310
+ }
311
+ }
312
+ }
230
313
  const payload = (0, prompt_1.mergeDefined)((0, task_resolver_1.stripTaskIdentityFields)(body), {
231
314
  title: flags.title,
232
315
  expectations: expectationsPatch === null ? [] : (expectationsPatch ?? undefined),
@@ -42,7 +42,7 @@ class TasksUpdatesAdd extends base_command_1.BaseCommand {
42
42
  'fields are required even when empty. ' +
43
43
  'progress {completedSinceLast:[],nextActions:[],currentFocus?} · ' +
44
44
  'finding {finding,evidenceRefs:[],impact?,severity?} · ' +
45
- 'decision {decision,rationale,alternativesConsidered?} · ' +
45
+ 'decision {decision,rationale,alternativesConsidered?:[]} · ' +
46
46
  'blocker {cause,requiredAction,nextOwner} · ' +
47
47
  'verification {claim,result:passed|failed|inconclusive,evidenceRefs:[]}. ' +
48
48
  'nextOwner is a principal object like {"kind":"human","userId":"..."}, not a name. ' +
@@ -0,0 +1,22 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr token list`
4
+ *
5
+ * The other half of `token mint`. Minting binds a long-lived refresh session to
6
+ * a machine and records the `--label` with it — which reads as a promise that
7
+ * the credential can be found again — and there was no way to see it: `token`
8
+ * had only `mint`, and `list-tokens` shows CI tokens, a different credential
9
+ * type, so `revoke-token` had nothing to aim at. The only remedy was
10
+ * `logout --all-devices`, which signs every machine out.
11
+ *
12
+ * `GET /api/auth/sessions/refresh` has served exactly this list all along; it
13
+ * was simply not reachable from the CLI.
14
+ */
15
+ export default class TokenList extends BaseCommand {
16
+ static description: string;
17
+ static examples: string[];
18
+ static flags: {
19
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
+ };
21
+ run(): Promise<void>;
22
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_command_1 = require("../../base-command");
5
+ const api_fetch_1 = require("../../lib/api-fetch");
6
+ const format_1 = require("../../lib/format");
7
+ /**
8
+ * `skrr token list`
9
+ *
10
+ * The other half of `token mint`. Minting binds a long-lived refresh session to
11
+ * a machine and records the `--label` with it — which reads as a promise that
12
+ * the credential can be found again — and there was no way to see it: `token`
13
+ * had only `mint`, and `list-tokens` shows CI tokens, a different credential
14
+ * type, so `revoke-token` had nothing to aim at. The only remedy was
15
+ * `logout --all-devices`, which signs every machine out.
16
+ *
17
+ * `GET /api/auth/sessions/refresh` has served exactly this list all along; it
18
+ * was simply not reachable from the CLI.
19
+ */
20
+ class TokenList extends base_command_1.BaseCommand {
21
+ static description = 'List the active sessions a minted token belongs to — the other half of `token mint`';
22
+ static examples = [
23
+ '<%= config.bin %> token list',
24
+ '<%= config.bin %> token list --json',
25
+ ];
26
+ static flags = { json: core_1.Flags.boolean({ description: 'Output JSON' }) };
27
+ async run() {
28
+ this.requireAuth();
29
+ const { flags } = await this.parse(TokenList);
30
+ let data = null;
31
+ try {
32
+ data = await (0, api_fetch_1.apiFetch)('/api/auth/sessions/refresh', {
33
+ method: 'GET',
34
+ credential: this.resolvedCredential,
35
+ });
36
+ }
37
+ catch (err) {
38
+ this.handleApiError(err);
39
+ }
40
+ const sessions = data?.sessions || [];
41
+ if (flags.json)
42
+ return this.log(JSON.stringify({ sessions, count: sessions.length }, null, 2));
43
+ if (!sessions.length)
44
+ return this.log('No active sessions.');
45
+ (0, format_1.renderTable)(sessions.map((session) => ({
46
+ id: session.id,
47
+ kind: session.kind,
48
+ // The operator's own name for the credential wins over a derived
49
+ // device string — it is what they would search by.
50
+ device: session.label || session.device || '-',
51
+ ip: session.ip || '-',
52
+ lastActive: session.lastActiveAt || session.createdAt || '-',
53
+ // The session you are typing in. Revoking it signs THIS machine out,
54
+ // which is the one outcome nobody means when they revoke a credential.
55
+ current: session.current ? 'yes' : '',
56
+ })), [
57
+ { key: 'id', header: 'ID' },
58
+ { key: 'kind', header: 'KIND' },
59
+ { key: 'device', header: 'DEVICE', maxWidth: 34 },
60
+ { key: 'ip', header: 'IP' },
61
+ { key: 'lastActive', header: 'LAST ACTIVE' },
62
+ { key: 'current', header: 'CURRENT' },
63
+ ], (line) => this.log(line));
64
+ this.log('');
65
+ this.log('Retire one with: skrr token revoke <id>');
66
+ }
67
+ }
68
+ exports.default = TokenList;
@@ -0,0 +1,23 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr token revoke <id>`
4
+ *
5
+ * Retire ONE session — the credential `token mint` handed to one machine —
6
+ * without signing every other machine out. `logout --all-devices` was the only
7
+ * way to do this, which is a blunt instrument for "that one CI box is
8
+ * decommissioned".
9
+ *
10
+ * Owner-gated server-side: a row that is not the caller's returns
11
+ * `{ revoked: false }` rather than an error, so ids cannot be enumerated.
12
+ */
13
+ export default class TokenRevoke extends BaseCommand {
14
+ static description: string;
15
+ static examples: string[];
16
+ static args: {
17
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
18
+ };
19
+ static flags: {
20
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
+ };
22
+ run(): Promise<void>;
23
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_command_1 = require("../../base-command");
5
+ const api_fetch_1 = require("../../lib/api-fetch");
6
+ /**
7
+ * `skrr token revoke <id>`
8
+ *
9
+ * Retire ONE session — the credential `token mint` handed to one machine —
10
+ * without signing every other machine out. `logout --all-devices` was the only
11
+ * way to do this, which is a blunt instrument for "that one CI box is
12
+ * decommissioned".
13
+ *
14
+ * Owner-gated server-side: a row that is not the caller's returns
15
+ * `{ revoked: false }` rather than an error, so ids cannot be enumerated.
16
+ */
17
+ class TokenRevoke extends base_command_1.BaseCommand {
18
+ static description = 'Revoke one session by id — see `skrr token list` for the ids';
19
+ static examples = ['<%= config.bin %> token revoke 665f1c2e9a4b3d0011aa77bc'];
20
+ static args = {
21
+ id: core_1.Args.string({
22
+ required: true,
23
+ ignoreStdin: true,
24
+ description: 'Session id from `skrr token list`',
25
+ }),
26
+ };
27
+ static flags = { json: core_1.Flags.boolean({ description: 'Output JSON' }) };
28
+ async run() {
29
+ this.requireAuth();
30
+ const { args, flags } = await this.parse(TokenRevoke);
31
+ let data = null;
32
+ try {
33
+ data = await (0, api_fetch_1.apiFetch)(`/api/auth/sessions/refresh/${encodeURIComponent(args.id)}/revoke`, {
34
+ method: 'POST',
35
+ credential: this.resolvedCredential,
36
+ body: {},
37
+ });
38
+ }
39
+ catch (err) {
40
+ this.handleApiError(err);
41
+ }
42
+ if (flags.json)
43
+ return this.log(JSON.stringify(data, null, 2));
44
+ if (data?.revoked)
45
+ return this.log(`Revoked session ${args.id}. Other machines stay signed in.`);
46
+ // The server does not distinguish "already gone" from "not yours" on
47
+ // purpose, so neither does this — saying "not found" would leak the
48
+ // difference and let somebody probe for ids.
49
+ this.log(`Nothing to revoke for ${args.id} — it is already revoked, or it is not one of your sessions.`);
50
+ this.log('List what is active with: skrr token list');
51
+ }
52
+ }
53
+ exports.default = TokenRevoke;
@@ -1,34 +1,115 @@
1
- import type { Agent, AgentAction, BuiltinActionConfig, BuiltinActionType, BuiltinAgentAction, EmbeddedActionRef, PromptAgentAction } from '@skrr-ai/data-provider';
2
- export declare const BUILTIN_ACTION_TYPES: readonly ["slack_send_message", "slack_tool", "group_chat_message", "space_create_task", "space_post_update", "task_create", "task_mark_done", "task_assign", "goal_create", "goal_mark_done", "smart_schedule_plan", "smart_schedule_delta_watch"];
1
+ import type { Agent, AgentAction, AgentActionOutcome, AgentActionScope, BuiltinActionConfig, BuiltinActionType, BuiltinAgentAction, EmbeddedActionRef, PromptAgentAction } from '@skrr-ai/data-provider';
2
+ export { BUILTIN_ACTION_TYPES } from '@skrr-ai/data-provider';
3
3
  export declare const ACTION_TARGET_TYPES: readonly ["group-chats", "spaces", "tasks", "goals", "slack-channels", "slack-users"];
4
4
  export type ActionTargetType = (typeof ACTION_TARGET_TYPES)[number];
5
5
  export declare function parseJsonObjectFlag(value: string | undefined, flagName: string): Record<string, unknown> | undefined;
6
6
  export declare function fetchAgentForActionEdit(agentId: string): Promise<Agent>;
7
7
  export declare function getAgentActions(agent: Agent): AgentAction[];
8
8
  export declare function findAgentAction(agent: Agent, actionId: string): AgentAction | undefined;
9
+ /**
10
+ * The row as the SERVER stored it, not as we sent it.
11
+ *
12
+ * `updateAgentActions` returns the updated Agent, and both editors used to
13
+ * discard it and print the object they had just built — so the output was the
14
+ * input, restated. That is not a cosmetic difference: the server normalizes
15
+ * `agentActions` through an allowlist before persisting, so a field it drops is
16
+ * echoed back by the CLI as though it had been saved. A `label` scope and
17
+ * `outcome: durable` were both silently discarded that way and the CLI reported
18
+ * success with the values the caller had typed (OSK-9628).
19
+ *
20
+ * Falling back to the local object keeps the command working if the write
21
+ * succeeds but the response is unexpectedly shaped; it cannot make the output
22
+ * wrong in a way it was not already.
23
+ */
24
+ export declare function storedActionOrLocal(agent: Agent | null | undefined, local: AgentAction): AgentAction;
25
+ export type AppendedAgentAction = {
26
+ /** The action as the server stored it. */
27
+ action: AgentAction;
28
+ /** False when this id was already in the library — a replayed request. */
29
+ created: boolean;
30
+ total: number;
31
+ };
32
+ /**
33
+ * Append ONE action atomically.
34
+ *
35
+ * `agents actions create` used to read the agent, append in memory and write
36
+ * the whole library back through `updateAgentActions`. Two concurrent creates
37
+ * therefore each read the same library and the later write erased the earlier
38
+ * action — six parallel creates all printed success and left one (OSK-9673).
39
+ * This endpoint appends with a single conditional `$push` on the server, so
40
+ * concurrent creates all land, the cap is enforced at the instant of the write,
41
+ * and a retried request whose id already landed returns `created: false`
42
+ * instead of adding a second copy. The client-generated id is what makes that
43
+ * retry safe, so it is sent rather than left for the server to assign.
44
+ *
45
+ * Update and delete still use `updateAgentActions` and still read-modify-write.
46
+ */
47
+ export declare function appendAgentAction(agentId: string, action: AgentAction): Promise<AppendedAgentAction>;
9
48
  export declare function updateAgentActions(agentId: string, actions: AgentAction[]): Promise<Agent>;
10
- export declare function makePromptAction(input: {
49
+ /**
50
+ * Fields every action shape carries regardless of kind.
51
+ *
52
+ * `scope` and `outcome` are listed HERE rather than threaded through each
53
+ * factory's own parameter list, because the previous version enumerated the
54
+ * fields it copied and simply omitted `scope` — so a space-scoped action was
55
+ * unauthorable from the CLI even via `--from-json`, and the omission was
56
+ * invisible (the row wrote fine, it was just offered everywhere).
57
+ */
58
+ export type AgentActionCommonInput = {
11
59
  title: string;
12
60
  description?: string;
13
- prompt: string;
14
61
  order: number;
15
62
  enabled: boolean;
16
63
  id?: string;
17
64
  sourceListingId?: string;
65
+ scope?: AgentActionScope;
66
+ outcome?: AgentActionOutcome;
67
+ };
68
+ export declare function makePromptAction(input: AgentActionCommonInput & {
69
+ prompt: string;
18
70
  /** Structured built-in actions embedded in the prompt — the chip source of truth. */
19
71
  embeddedActions?: EmbeddedActionRef[];
20
72
  }): PromptAgentAction;
21
- export declare function makeBuiltinAction(input: {
22
- title: string;
23
- description?: string;
73
+ export declare function makeBuiltinAction(input: AgentActionCommonInput & {
24
74
  builtinType: BuiltinActionType;
25
75
  config: BuiltinActionConfig | Record<string, unknown>;
26
76
  prompt?: string;
27
- order: number;
28
- enabled: boolean;
29
- id?: string;
30
- sourceListingId?: string;
31
77
  }): BuiltinAgentAction;
78
+ export declare const AGENT_ACTION_SCOPE_CHOICES: readonly ["general", "space", "label"];
79
+ export declare const AGENT_ACTION_OUTCOME_CHOICES: readonly ["ephemeral", "durable"];
80
+ export type AgentActionScopeFlags = {
81
+ scope?: string;
82
+ space?: string;
83
+ 'space-title'?: string;
84
+ label?: string[];
85
+ };
86
+ /**
87
+ * Turn the scope flags into a stored scope, or `undefined` when the caller said
88
+ * nothing about scope (so an update leaves the existing one alone).
89
+ *
90
+ * `--space <id>` and `--label <id>` imply their kind, because typing
91
+ * `--scope space --space s1` twice is the kind of ceremony people skip and then
92
+ * wonder why the action is everywhere. An explicit `--scope general` clears it.
93
+ */
94
+ /**
95
+ * `--label` accepts an id OR a name, like every other `--label` in the CLI.
96
+ *
97
+ * It used to take the value verbatim as a `labelId`. A name was therefore
98
+ * stored as though it were an id, matched no space's `labelIds`, and produced
99
+ * an action offered NOWHERE — silently, with the create reporting success. That
100
+ * is exactly the "an action that disappears reads as deletion" hazard the label
101
+ * tier was designed around, arriving through the CLI instead of through a card
102
+ * that forgot to pass its labels. An unknown name was accepted too, so a typo
103
+ * was indistinguishable from a working scope.
104
+ *
105
+ * `resolveLabelRefs` is the same resolver `spaces create --label` uses: it
106
+ * short-circuits when every value already looks like an id (so a scripted
107
+ * caller pays no request), refuses an unknown name with the near misses named,
108
+ * and refuses an ambiguous one rather than guessing.
109
+ */
110
+ export declare function resolveAgentActionScopeFlags(flags: AgentActionScopeFlags): Promise<AgentActionScope | undefined>;
111
+ /** Human-readable one-liner for a scope, used by list/show renderers. */
112
+ export declare function describeAgentActionScope(scope?: AgentActionScope | null): string;
32
113
  export declare function nextActionOrder(actions: AgentAction[]): number;
33
114
  export declare function actionKind(action: AgentAction): 'prompt' | 'builtin';
34
115
  export declare function renderActions(actions: AgentAction[], log: (line: string) => void): void;
@@ -1,13 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ACTION_TARGET_TYPES = exports.BUILTIN_ACTION_TYPES = void 0;
3
+ exports.AGENT_ACTION_OUTCOME_CHOICES = exports.AGENT_ACTION_SCOPE_CHOICES = exports.ACTION_TARGET_TYPES = exports.BUILTIN_ACTION_TYPES = void 0;
4
4
  exports.parseJsonObjectFlag = parseJsonObjectFlag;
5
5
  exports.fetchAgentForActionEdit = fetchAgentForActionEdit;
6
6
  exports.getAgentActions = getAgentActions;
7
7
  exports.findAgentAction = findAgentAction;
8
+ exports.storedActionOrLocal = storedActionOrLocal;
9
+ exports.appendAgentAction = appendAgentAction;
8
10
  exports.updateAgentActions = updateAgentActions;
9
11
  exports.makePromptAction = makePromptAction;
10
12
  exports.makeBuiltinAction = makeBuiltinAction;
13
+ exports.resolveAgentActionScopeFlags = resolveAgentActionScopeFlags;
14
+ exports.describeAgentActionScope = describeAgentActionScope;
11
15
  exports.nextActionOrder = nextActionOrder;
12
16
  exports.actionKind = actionKind;
13
17
  exports.renderActions = renderActions;
@@ -15,22 +19,13 @@ exports.renderAction = renderAction;
15
19
  const node_crypto_1 = require("node:crypto");
16
20
  const data_provider_1 = require("@skrr-ai/data-provider");
17
21
  const format_1 = require("./format");
18
- exports.BUILTIN_ACTION_TYPES = [
19
- 'slack_send_message',
20
- 'slack_tool',
21
- 'group_chat_message',
22
- 'space_create_task',
23
- 'space_post_update',
24
- 'task_create',
25
- 'task_mark_done',
26
- 'task_assign',
27
- 'goal_create',
28
- 'goal_mark_done',
29
- 'smart_schedule_plan',
30
- 'smart_schedule_delta_watch',
31
- ];
32
- const _builtinActionTypesAreExhaustive = true;
33
- void _builtinActionTypesAreExhaustive;
22
+ const label_ref_1 = require("./label-ref");
23
+ const api_fetch_1 = require("./api-fetch");
24
+ // The vocabulary is owned by `@skrr-ai/data-provider`, which also proves it
25
+ // complete against `BuiltinActionType`. This file used to hold a second copy
26
+ // with its own guard (OSK-9668).
27
+ var data_provider_2 = require("@skrr-ai/data-provider");
28
+ Object.defineProperty(exports, "BUILTIN_ACTION_TYPES", { enumerable: true, get: function () { return data_provider_2.BUILTIN_ACTION_TYPES; } });
34
29
  exports.ACTION_TARGET_TYPES = [
35
30
  'group-chats',
36
31
  'spaces',
@@ -64,40 +59,182 @@ function getAgentActions(agent) {
64
59
  function findAgentAction(agent, actionId) {
65
60
  return getAgentActions(agent).find((action) => action.id === actionId);
66
61
  }
62
+ /**
63
+ * The row as the SERVER stored it, not as we sent it.
64
+ *
65
+ * `updateAgentActions` returns the updated Agent, and both editors used to
66
+ * discard it and print the object they had just built — so the output was the
67
+ * input, restated. That is not a cosmetic difference: the server normalizes
68
+ * `agentActions` through an allowlist before persisting, so a field it drops is
69
+ * echoed back by the CLI as though it had been saved. A `label` scope and
70
+ * `outcome: durable` were both silently discarded that way and the CLI reported
71
+ * success with the values the caller had typed (OSK-9628).
72
+ *
73
+ * Falling back to the local object keeps the command working if the write
74
+ * succeeds but the response is unexpectedly shaped; it cannot make the output
75
+ * wrong in a way it was not already.
76
+ */
77
+ function storedActionOrLocal(agent, local) {
78
+ if (!agent)
79
+ return local;
80
+ return findAgentAction(agent, local.id) ?? local;
81
+ }
82
+ /**
83
+ * Append ONE action atomically.
84
+ *
85
+ * `agents actions create` used to read the agent, append in memory and write
86
+ * the whole library back through `updateAgentActions`. Two concurrent creates
87
+ * therefore each read the same library and the later write erased the earlier
88
+ * action — six parallel creates all printed success and left one (OSK-9673).
89
+ * This endpoint appends with a single conditional `$push` on the server, so
90
+ * concurrent creates all land, the cap is enforced at the instant of the write,
91
+ * and a retried request whose id already landed returns `created: false`
92
+ * instead of adding a second copy. The client-generated id is what makes that
93
+ * retry safe, so it is sent rather than left for the server to assign.
94
+ *
95
+ * Update and delete still use `updateAgentActions` and still read-modify-write.
96
+ */
97
+ async function appendAgentAction(agentId, action) {
98
+ try {
99
+ return await (0, api_fetch_1.apiFetch)(`/api/agents/${encodeURIComponent(agentId)}/agent-actions`, { method: 'POST', body: { action } });
100
+ }
101
+ catch (err) {
102
+ if (!isMissingRoute(err))
103
+ throw err;
104
+ return appendAgentActionByRewrite(agentId, action);
105
+ }
106
+ }
107
+ /**
108
+ * The server predates the append route.
109
+ *
110
+ * A released CLI is not guaranteed a server that has every route it knows —
111
+ * a self-hosted instance, or production mid-rollout — and without this,
112
+ * `agents actions create` against such a server simply failed. A missing ROUTE
113
+ * answers 404 with no `code` and a "No API route matches" message; a missing
114
+ * AGENT answers 404 with `code: 'agent_not_found'`, which must NOT fall back.
115
+ */
116
+ function isMissingRoute(err) {
117
+ return (err instanceof api_fetch_1.ApiFetchError &&
118
+ err.status === 404 &&
119
+ !err.code &&
120
+ typeof err.body === 'string' &&
121
+ err.body.includes('No API route matches'));
122
+ }
123
+ /**
124
+ * The pre-append behaviour, kept only for servers without the route: read the
125
+ * library, append in memory, write it back. It is NOT safe under concurrency —
126
+ * that is the defect the route exists to fix — but it is correct for a single
127
+ * writer, which beats refusing to create anything.
128
+ */
129
+ async function appendAgentActionByRewrite(agentId, action) {
130
+ const agent = await fetchAgentForActionEdit(agentId);
131
+ const actions = getAgentActions(agent);
132
+ const earlier = actions.find((candidate) => candidate.id === action.id);
133
+ if (earlier) {
134
+ return { action: earlier, created: false, total: actions.length };
135
+ }
136
+ const placed = typeof action.order === 'number' ? action : { ...action, order: nextActionOrder(actions) };
137
+ const saved = await updateAgentActions(agentId, [...actions, placed]);
138
+ return {
139
+ action: storedActionOrLocal(saved, placed),
140
+ created: true,
141
+ total: getAgentActions(saved).length || actions.length + 1,
142
+ };
143
+ }
67
144
  async function updateAgentActions(agentId, actions) {
68
145
  return data_provider_1.dataService.updateAgent({
69
146
  agent_id: agentId,
70
147
  data: { agentActions: actions },
71
148
  });
72
149
  }
73
- function makePromptAction(input) {
150
+ function commonActionFields(input) {
74
151
  return {
75
152
  id: input.id ?? (0, node_crypto_1.randomUUID)(),
76
153
  title: input.title,
77
154
  description: input.description,
78
155
  order: input.order,
79
156
  enabled: input.enabled,
157
+ ...(input.scope ? { scope: input.scope } : {}),
158
+ ...(input.outcome ? { outcome: input.outcome } : {}),
159
+ ...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
160
+ };
161
+ }
162
+ function makePromptAction(input) {
163
+ return {
164
+ ...commonActionFields(input),
80
165
  prompt: input.prompt,
81
166
  ...(input.embeddedActions && input.embeddedActions.length > 0
82
167
  ? { embeddedActions: input.embeddedActions }
83
168
  : {}),
84
- ...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
85
169
  };
86
170
  }
87
171
  function makeBuiltinAction(input) {
88
172
  return {
89
- id: input.id ?? (0, node_crypto_1.randomUUID)(),
173
+ ...commonActionFields(input),
90
174
  kind: 'builtin',
91
- title: input.title,
92
- description: input.description,
93
- order: input.order,
94
- enabled: input.enabled,
95
175
  builtinType: input.builtinType,
96
176
  config: input.config,
97
177
  ...(input.prompt ? { prompt: input.prompt } : {}),
98
- ...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
99
178
  };
100
179
  }
180
+ /* ── scope + outcome flags (shared by `create` and `update`) ─────────────── */
181
+ exports.AGENT_ACTION_SCOPE_CHOICES = ['general', 'space', 'label'];
182
+ exports.AGENT_ACTION_OUTCOME_CHOICES = ['ephemeral', 'durable'];
183
+ /**
184
+ * Turn the scope flags into a stored scope, or `undefined` when the caller said
185
+ * nothing about scope (so an update leaves the existing one alone).
186
+ *
187
+ * `--space <id>` and `--label <id>` imply their kind, because typing
188
+ * `--scope space --space s1` twice is the kind of ceremony people skip and then
189
+ * wonder why the action is everywhere. An explicit `--scope general` clears it.
190
+ */
191
+ /**
192
+ * `--label` accepts an id OR a name, like every other `--label` in the CLI.
193
+ *
194
+ * It used to take the value verbatim as a `labelId`. A name was therefore
195
+ * stored as though it were an id, matched no space's `labelIds`, and produced
196
+ * an action offered NOWHERE — silently, with the create reporting success. That
197
+ * is exactly the "an action that disappears reads as deletion" hazard the label
198
+ * tier was designed around, arriving through the CLI instead of through a card
199
+ * that forgot to pass its labels. An unknown name was accepted too, so a typo
200
+ * was indistinguishable from a working scope.
201
+ *
202
+ * `resolveLabelRefs` is the same resolver `spaces create --label` uses: it
203
+ * short-circuits when every value already looks like an id (so a scripted
204
+ * caller pays no request), refuses an unknown name with the near misses named,
205
+ * and refuses an ambiguous one rather than guessing.
206
+ */
207
+ async function resolveAgentActionScopeFlags(flags) {
208
+ const labelRefs = (flags.label ?? []).map((value) => value.trim()).filter(Boolean);
209
+ const spaceId = flags.space?.trim();
210
+ const declared = flags.scope?.trim();
211
+ const kind = declared ?? (spaceId ? 'space' : labelRefs.length ? 'label' : undefined);
212
+ if (!kind)
213
+ return undefined;
214
+ if (kind === 'general')
215
+ return { kind: 'general' };
216
+ if (kind === 'space') {
217
+ if (!spaceId)
218
+ throw new Error('--scope space requires --space <space-id>.');
219
+ const spaceTitle = flags['space-title']?.trim();
220
+ return { kind: 'space', spaceId, ...(spaceTitle ? { spaceTitle } : {}) };
221
+ }
222
+ if (kind === 'label') {
223
+ if (!labelRefs.length)
224
+ throw new Error('--scope label requires at least one --label <label-id-or-name>.');
225
+ const labelIds = await (0, label_ref_1.resolveLabelRefs)(labelRefs, { applicableTo: 'space' });
226
+ return { kind: 'label', labelIds };
227
+ }
228
+ throw new Error(`--scope must be one of ${exports.AGENT_ACTION_SCOPE_CHOICES.join(', ')}.`);
229
+ }
230
+ /** Human-readable one-liner for a scope, used by list/show renderers. */
231
+ function describeAgentActionScope(scope) {
232
+ if (scope?.kind === 'space')
233
+ return `space:${scope.spaceId}`;
234
+ if (scope?.kind === 'label')
235
+ return `label:${scope.labelIds.join('|')}`;
236
+ return 'general';
237
+ }
101
238
  function nextActionOrder(actions) {
102
239
  if (actions.length === 0)
103
240
  return 0;
@@ -122,12 +259,19 @@ function renderActions(actions, log) {
122
259
  target: action.kind === 'builtin'
123
260
  ? action.builtinType
124
261
  : `${(action.prompt || '').trim().length} chars`,
262
+ // Where an action is offered and what it leaves behind decide whether
263
+ // a person ever sees it fire. A listing that omits both makes a
264
+ // mis-scoped action indistinguishable from a working one.
265
+ scope: describeAgentActionScope(action.scope),
266
+ outcome: action.outcome ?? 'ephemeral',
125
267
  order: String(action.order),
126
268
  })), [
127
269
  { key: 'id', header: 'ID', verbatim: true },
128
270
  { key: 'title', header: 'Title', maxWidth: 30 },
129
271
  { key: 'kind', header: 'Kind' },
130
272
  { key: 'target', header: 'Target', maxWidth: 24 },
273
+ { key: 'scope', header: 'Scope', maxWidth: 24 },
274
+ { key: 'outcome', header: 'Outcome' },
131
275
  { key: 'enabled', header: 'On' },
132
276
  { key: 'order', header: 'Order' },
133
277
  ], log);
@@ -137,6 +281,8 @@ function renderAction(action, log) {
137
281
  log(`Title: ${action.title}`);
138
282
  log(`Kind: ${actionKind(action)}`);
139
283
  log(`Enabled: ${action.enabled === false ? 'no' : 'yes'}`);
284
+ log(`Scope: ${describeAgentActionScope(action.scope)}`);
285
+ log(`Outcome: ${action.outcome ?? 'ephemeral'}`);
140
286
  log(`Order: ${action.order}`);
141
287
  if (action.description) {
142
288
  log(`Description: ${action.description}`);