@skrr-ai/cli 0.1.22 → 0.1.24

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 (281) hide show
  1. package/README.md +83 -73
  2. package/bin/dev-fallback.js +221 -0
  3. package/bin/run.js +96 -0
  4. package/dist/base-command.d.ts +15 -0
  5. package/dist/base-command.js +145 -11
  6. package/dist/commands/agents/attach-harness.d.ts +37 -0
  7. package/dist/commands/agents/attach-harness.js +102 -3
  8. package/dist/commands/agents/chat.d.ts +69 -1
  9. package/dist/commands/agents/chat.js +202 -22
  10. package/dist/commands/agents/create.d.ts +38 -0
  11. package/dist/commands/agents/create.js +95 -2
  12. package/dist/commands/agents/schedule-trace.js +11 -0
  13. package/dist/commands/agents/show.js +29 -1
  14. package/dist/commands/api-keys/create.d.ts +24 -0
  15. package/dist/commands/api-keys/create.js +80 -0
  16. package/dist/commands/api-keys/list.d.ts +11 -0
  17. package/dist/commands/api-keys/list.js +42 -0
  18. package/dist/commands/api-keys/revoke.d.ts +14 -0
  19. package/dist/commands/api-keys/revoke.js +33 -0
  20. package/dist/commands/api-keys/rotate.d.ts +19 -0
  21. package/dist/commands/api-keys/rotate.js +42 -0
  22. package/dist/commands/balance/index.d.ts +18 -0
  23. package/dist/commands/balance/index.js +29 -0
  24. package/dist/commands/balance/show.d.ts +25 -0
  25. package/dist/commands/balance/show.js +60 -0
  26. package/dist/commands/balance/statement.d.ts +19 -0
  27. package/dist/commands/balance/statement.js +52 -0
  28. package/dist/commands/browser/doctor.d.ts +11 -0
  29. package/dist/commands/browser/doctor.js +11 -0
  30. package/dist/commands/code/jobs/approve.d.ts +25 -0
  31. package/dist/commands/code/jobs/approve.js +52 -0
  32. package/dist/commands/code/jobs/cancel.d.ts +12 -0
  33. package/dist/commands/code/jobs/cancel.js +39 -0
  34. package/dist/commands/code/jobs/index.d.ts +19 -0
  35. package/dist/commands/code/jobs/index.js +38 -0
  36. package/dist/commands/code/jobs/list.d.ts +12 -0
  37. package/dist/commands/code/jobs/list.js +87 -0
  38. package/dist/commands/code/jobs/run.d.ts +32 -0
  39. package/dist/commands/code/jobs/run.js +151 -0
  40. package/dist/commands/code/jobs/show.d.ts +12 -0
  41. package/dist/commands/code/jobs/show.js +86 -0
  42. package/dist/commands/commitments/preflight.js +18 -4
  43. package/dist/commands/commitments/receipt-metrics.d.ts +39 -0
  44. package/dist/commands/commitments/receipt-metrics.js +78 -0
  45. package/dist/commands/convos/search.js +5 -5
  46. package/dist/commands/harnesses/leases/list.d.ts +3 -0
  47. package/dist/commands/harnesses/leases/list.js +59 -12
  48. package/dist/commands/harnesses/leases/show.js +36 -0
  49. package/dist/commands/harnesses/list.d.ts +18 -0
  50. package/dist/commands/harnesses/list.js +30 -0
  51. package/dist/commands/harnesses/products.js +49 -3
  52. package/dist/commands/harnesses/quota.d.ts +16 -0
  53. package/dist/commands/harnesses/quota.js +26 -1
  54. package/dist/commands/harnesses/usage.js +17 -0
  55. package/dist/commands/inbox/index.d.ts +2 -1
  56. package/dist/commands/inbox/index.js +27 -4
  57. package/dist/commands/login.js +4 -1
  58. package/dist/commands/machines/dedicated/create.d.ts +18 -0
  59. package/dist/commands/machines/dedicated/create.js +90 -0
  60. package/dist/commands/machines/dedicated/destroy.d.ts +14 -0
  61. package/dist/commands/machines/dedicated/destroy.js +56 -0
  62. package/dist/commands/machines/dedicated/grow.d.ts +13 -0
  63. package/dist/commands/machines/dedicated/grow.js +46 -0
  64. package/dist/commands/machines/dedicated/health-check.d.ts +12 -0
  65. package/dist/commands/machines/dedicated/health-check.js +42 -0
  66. package/dist/commands/machines/dedicated/incident-close.d.ts +12 -0
  67. package/dist/commands/machines/dedicated/incident-close.js +42 -0
  68. package/dist/commands/machines/dedicated/index.d.ts +6 -0
  69. package/dist/commands/machines/dedicated/index.js +39 -0
  70. package/dist/commands/machines/dedicated/list.d.ts +11 -0
  71. package/dist/commands/machines/dedicated/list.js +58 -0
  72. package/dist/commands/machines/dedicated/restart.d.ts +12 -0
  73. package/dist/commands/machines/dedicated/restart.js +42 -0
  74. package/dist/commands/machines/dedicated/show.d.ts +12 -0
  75. package/dist/commands/machines/dedicated/show.js +58 -0
  76. package/dist/commands/machines/dedicated/snapshot.d.ts +12 -0
  77. package/dist/commands/machines/dedicated/snapshot.js +42 -0
  78. package/dist/commands/machines/dedicated/start.d.ts +12 -0
  79. package/dist/commands/machines/dedicated/start.js +42 -0
  80. package/dist/commands/machines/dedicated/stop.d.ts +12 -0
  81. package/dist/commands/machines/dedicated/stop.js +42 -0
  82. package/dist/commands/machines/hosted/index.js +4 -1
  83. package/dist/commands/machines/list.d.ts +1 -0
  84. package/dist/commands/machines/list.js +33 -5
  85. package/dist/commands/memory/approvals/issue.d.ts +18 -0
  86. package/dist/commands/memory/approvals/issue.js +63 -0
  87. package/dist/commands/memory/commit.js +5 -2
  88. package/dist/commands/memory/context.d.ts +3 -2
  89. package/dist/commands/memory/context.js +9 -11
  90. package/dist/commands/memory/delete.d.ts +1 -1
  91. package/dist/commands/memory/list.d.ts +1 -1
  92. package/dist/commands/memory/list.js +1 -1
  93. package/dist/commands/memory/mounts/resolve.d.ts +10 -0
  94. package/dist/commands/memory/mounts/resolve.js +27 -0
  95. package/dist/commands/memory/proposals/commit.d.ts +18 -0
  96. package/dist/commands/memory/proposals/commit.js +32 -0
  97. package/dist/commands/memory/proposals/create.d.ts +18 -0
  98. package/dist/commands/memory/proposals/create.js +56 -0
  99. package/dist/commands/memory/proposals/list.d.ts +13 -0
  100. package/dist/commands/memory/proposals/list.js +31 -0
  101. package/dist/commands/memory/proposals/promote.d.ts +22 -0
  102. package/dist/commands/memory/proposals/promote.js +33 -0
  103. package/dist/commands/memory/proposals/reject.d.ts +16 -0
  104. package/dist/commands/memory/proposals/reject.js +28 -0
  105. package/dist/commands/memory/rebuild-index.d.ts +20 -0
  106. package/dist/commands/memory/rebuild-index.js +25 -0
  107. package/dist/commands/memory/save.d.ts +1 -1
  108. package/dist/commands/memory/save.js +1 -1
  109. package/dist/commands/memory/search.d.ts +6 -3
  110. package/dist/commands/memory/search.js +27 -3
  111. package/dist/commands/memory/show.d.ts +1 -1
  112. package/dist/commands/memory/stores/archive.d.ts +14 -0
  113. package/dist/commands/memory/stores/archive.js +31 -0
  114. package/dist/commands/memory/stores/create.d.ts +12 -0
  115. package/dist/commands/memory/stores/create.js +30 -0
  116. package/dist/commands/memory/stores/delete.d.ts +15 -0
  117. package/dist/commands/memory/stores/delete.js +38 -0
  118. package/dist/commands/memory/stores/list.d.ts +10 -0
  119. package/dist/commands/memory/stores/list.js +29 -0
  120. package/dist/commands/memory/stores/show.d.ts +12 -0
  121. package/dist/commands/memory/stores/show.js +14 -0
  122. package/dist/commands/memory/stores/update.d.ts +15 -0
  123. package/dist/commands/memory/stores/update.js +39 -0
  124. package/dist/commands/memory/sync/delete.d.ts +13 -0
  125. package/dist/commands/memory/sync/delete.js +35 -0
  126. package/dist/commands/memory/sync/pull.d.ts +19 -0
  127. package/dist/commands/memory/sync/pull.js +52 -0
  128. package/dist/commands/memory/sync/push.d.ts +18 -0
  129. package/dist/commands/memory/sync/push.js +115 -0
  130. package/dist/commands/memory/sync/resolve.d.ts +23 -0
  131. package/dist/commands/memory/sync/resolve.js +27 -0
  132. package/dist/commands/memory/sync/status.d.ts +9 -0
  133. package/dist/commands/memory/sync/status.js +22 -0
  134. package/dist/commands/memory/topics/archive.d.ts +20 -0
  135. package/dist/commands/memory/topics/archive.js +29 -0
  136. package/dist/commands/memory/topics/create.d.ts +23 -0
  137. package/dist/commands/memory/topics/create.js +46 -0
  138. package/dist/commands/memory/topics/delete.d.ts +22 -0
  139. package/dist/commands/memory/topics/delete.js +30 -0
  140. package/dist/commands/memory/topics/forget.d.ts +22 -0
  141. package/dist/commands/memory/topics/forget.js +29 -0
  142. package/dist/commands/memory/topics/list.d.ts +13 -0
  143. package/dist/commands/memory/topics/list.js +22 -0
  144. package/dist/commands/memory/topics/move.d.ts +22 -0
  145. package/dist/commands/memory/topics/move.js +26 -0
  146. package/dist/commands/memory/topics/show.d.ts +17 -0
  147. package/dist/commands/memory/topics/show.js +21 -0
  148. package/dist/commands/memory/topics/update.d.ts +23 -0
  149. package/dist/commands/memory/topics/update.js +27 -0
  150. package/dist/commands/memory/tree.d.ts +5 -2
  151. package/dist/commands/memory/tree.js +20 -2
  152. package/dist/commands/memory/update.d.ts +1 -1
  153. package/dist/commands/memory/versions/list.d.ts +16 -0
  154. package/dist/commands/memory/versions/list.js +22 -0
  155. package/dist/commands/memory/versions/redact.d.ts +21 -0
  156. package/dist/commands/memory/versions/redact.js +22 -0
  157. package/dist/commands/memory/versions/restore.d.ts +20 -0
  158. package/dist/commands/memory/versions/restore.js +16 -0
  159. package/dist/commands/memory/versions/show.d.ts +15 -0
  160. package/dist/commands/memory/versions/show.js +17 -0
  161. package/dist/commands/messages/list.js +25 -8
  162. package/dist/commands/messages/show.js +10 -0
  163. package/dist/commands/spaces/update.js +16 -12
  164. package/dist/commands/spaces/work-sync/reconcile.d.ts +38 -0
  165. package/dist/commands/spaces/work-sync/reconcile.js +90 -0
  166. package/dist/commands/spaces/work-sync/telemetry.d.ts +29 -0
  167. package/dist/commands/spaces/work-sync/telemetry.js +96 -0
  168. package/dist/commands/store/install.js +5 -1
  169. package/dist/commands/store/releases.js +1 -1
  170. package/dist/commands/store/update.js +5 -1
  171. package/dist/commands/subscriptions/cancel.js +5 -1
  172. package/dist/commands/subscriptions/health.js +5 -1
  173. package/dist/commands/subscriptions/status.js +5 -1
  174. package/dist/commands/subscriptions/subscribe.js +5 -1
  175. package/dist/commands/tasks/activity.d.ts +2 -3
  176. package/dist/commands/tasks/activity.js +20 -6
  177. package/dist/commands/tasks/complete.d.ts +22 -150
  178. package/dist/commands/tasks/complete.js +174 -599
  179. package/dist/commands/tasks/create.d.ts +6 -0
  180. package/dist/commands/tasks/create.js +114 -4
  181. package/dist/commands/tasks/deliverable/add.d.ts +8 -0
  182. package/dist/commands/tasks/deliverable/add.js +62 -11
  183. package/dist/commands/tasks/deliverable/confirm.d.ts +5 -5
  184. package/dist/commands/tasks/deliverable/confirm.js +9 -18
  185. package/dist/commands/tasks/deliverable/list.d.ts +12 -0
  186. package/dist/commands/tasks/deliverable/list.js +58 -0
  187. package/dist/commands/tasks/events/append.d.ts +2 -0
  188. package/dist/commands/tasks/events/append.js +41 -6
  189. package/dist/commands/tasks/events/list.d.ts +1 -0
  190. package/dist/commands/tasks/events/list.js +1 -0
  191. package/dist/commands/tasks/events/tail.d.ts +1 -0
  192. package/dist/commands/tasks/events/tail.js +1 -0
  193. package/dist/commands/tasks/expectations/assess.d.ts +21 -0
  194. package/dist/commands/tasks/expectations/assess.js +103 -0
  195. package/dist/commands/tasks/expectations.js +121 -25
  196. package/dist/commands/tasks/judge.d.ts +1 -0
  197. package/dist/commands/tasks/judge.js +2 -1
  198. package/dist/commands/tasks/output.d.ts +1 -11
  199. package/dist/commands/tasks/output.js +80 -141
  200. package/dist/commands/tasks/report.d.ts +3 -3
  201. package/dist/commands/tasks/report.js +66 -41
  202. package/dist/commands/tasks/resource/add.d.ts +23 -0
  203. package/dist/commands/tasks/resource/add.js +76 -0
  204. package/dist/commands/tasks/resource/list.d.ts +13 -0
  205. package/dist/commands/tasks/resource/list.js +41 -0
  206. package/dist/commands/tasks/result/show.d.ts +13 -0
  207. package/dist/commands/tasks/result/show.js +64 -0
  208. package/dist/commands/tasks/result/submit.d.ts +26 -0
  209. package/dist/commands/tasks/result/submit.js +134 -0
  210. package/dist/commands/tasks/resume/save.d.ts +16 -0
  211. package/dist/commands/tasks/resume/save.js +69 -0
  212. package/dist/commands/tasks/resume/show.d.ts +13 -0
  213. package/dist/commands/tasks/resume/show.js +35 -0
  214. package/dist/commands/tasks/review.d.ts +17 -0
  215. package/dist/commands/tasks/review.js +54 -0
  216. package/dist/commands/tasks/runs.js +5 -0
  217. package/dist/commands/tasks/self-schedule.js +7 -4
  218. package/dist/commands/tasks/show.js +19 -0
  219. package/dist/commands/tasks/timeline.d.ts +2 -2
  220. package/dist/commands/tasks/timeline.js +19 -24
  221. package/dist/commands/tasks/updates/add.d.ts +22 -0
  222. package/dist/commands/tasks/updates/add.js +122 -0
  223. package/dist/commands/tasks/updates/list.d.ts +15 -0
  224. package/dist/commands/tasks/updates/list.js +57 -0
  225. package/dist/commands/tasks/waive.d.ts +1 -0
  226. package/dist/commands/tasks/waive.js +2 -1
  227. package/dist/lib/agentic-stream.d.ts +257 -0
  228. package/dist/lib/agentic-stream.js +490 -33
  229. package/dist/lib/balance.d.ts +8 -0
  230. package/dist/lib/commitment-product.d.ts +10 -1
  231. package/dist/lib/commitment-product.js +66 -2
  232. package/dist/lib/commitments.d.ts +2 -1
  233. package/dist/lib/commitments.js +1 -0
  234. package/dist/lib/conversation-search.d.ts +3 -0
  235. package/dist/lib/conversation-search.js +75 -0
  236. package/dist/lib/dedicated-machines.d.ts +66 -0
  237. package/dist/lib/dedicated-machines.js +161 -0
  238. package/dist/lib/execution-target.d.ts +21 -0
  239. package/dist/lib/execution-target.js +22 -6
  240. package/dist/lib/harnesses.d.ts +87 -6
  241. package/dist/lib/harnesses.js +32 -1
  242. package/dist/lib/hosted-machines.js +9 -0
  243. package/dist/lib/inbox.d.ts +2 -1
  244. package/dist/lib/machines.d.ts +17 -0
  245. package/dist/lib/machines.js +29 -0
  246. package/dist/lib/managed-agent-keys.d.ts +104 -0
  247. package/dist/lib/managed-agent-keys.js +50 -0
  248. package/dist/lib/memory-scope.d.ts +4 -3
  249. package/dist/lib/memory-scope.js +9 -9
  250. package/dist/lib/memory-sync.d.ts +114 -0
  251. package/dist/lib/memory-sync.js +730 -0
  252. package/dist/lib/message-provenance.d.ts +42 -0
  253. package/dist/lib/message-provenance.js +89 -0
  254. package/dist/lib/scoped-memory-command.d.ts +68 -0
  255. package/dist/lib/scoped-memory-command.js +183 -0
  256. package/dist/lib/session-task-endpoints.d.ts +1 -1
  257. package/dist/lib/session-task-endpoints.js +7 -0
  258. package/dist/lib/sky-code-broker.d.ts +47 -0
  259. package/dist/lib/sky-code-broker.js +50 -0
  260. package/dist/lib/sky-code-doctor.js +10 -1
  261. package/dist/lib/task-artifact-flags.d.ts +2 -0
  262. package/dist/lib/task-artifact-flags.js +7 -0
  263. package/dist/lib/task-execution.d.ts +4 -5
  264. package/dist/lib/task-execution.js +4 -5
  265. package/dist/lib/task-extras.d.ts +1 -5
  266. package/dist/lib/task-extras.js +1 -5
  267. package/dist/lib/task-legacy.d.ts +24 -0
  268. package/dist/lib/task-legacy.js +48 -0
  269. package/dist/lib/task-transcript.d.ts +5 -7
  270. package/dist/lib/task-transcript.js +8 -16
  271. package/dist/lib/tasks.d.ts +39 -21
  272. package/dist/lib/tasks.js +64 -21
  273. package/dist/lib/triggers.d.ts +39 -1
  274. package/dist/lib/triggers.js +70 -2
  275. package/dist/lib/usage-discovery.d.ts +17 -1
  276. package/dist/lib/usage-discovery.js +17 -1
  277. package/dist/lib/work-sync.d.ts +70 -0
  278. package/dist/lib/work-sync.js +29 -0
  279. package/dist/node_modules/@skrr-ai/data-provider/index.js +3760 -3621
  280. package/oclif.manifest.json +14653 -7813
  281. package/package.json +26 -5
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STREAM_LOST_EXIT_CODE = exports.DETACH_EXIT_CODE = void 0;
4
+ exports.interruptedDetachMessage = interruptedDetachMessage;
5
+ exports.reconcileTerminalFromMessages = reconcileTerminalFromMessages;
6
+ exports.inspectTurnCommand = inspectTurnCommand;
3
7
  exports.noOutputFailureMessage = noOutputFailureMessage;
4
8
  exports.noStreamJsonPayload = noStreamJsonPayload;
5
9
  exports.chatStreamHeaderLines = chatStreamHeaderLines;
@@ -8,6 +12,104 @@ const data_provider_1 = require("@skrr-ai/data-provider");
8
12
  const base_command_1 = require("../../base-command");
9
13
  const agentic_stream_1 = require("../../lib/agentic-stream");
10
14
  const web_url_1 = require("../../lib/web-url");
15
+ /**
16
+ * Exit code for a run the USER stopped watching, by pressing Ctrl-C.
17
+ *
18
+ * OSK-2944 established that exiting 1 on a lost stream made "the run failed"
19
+ * and "we lost the view of a live run" indistinguishable, and invited duplicate
20
+ * execution. So a detach gets its own non-zero code.
21
+ *
22
+ * It must be non-zero on EVERY output mode. The `--jsonl` branch used to
23
+ * `return` here, which leaves the exit code at 0, so a script driving the CLI
24
+ * read a detached — possibly already-failed — run as a success. That is the
25
+ * mode automation actually uses.
26
+ */
27
+ exports.DETACH_EXIT_CODE = 130;
28
+ /**
29
+ * Exit code for a detach nobody asked for — the stream was lost, or could not
30
+ * be attached at all.
31
+ *
32
+ * 130 is the conventional "killed by SIGINT" code, and it was returned for a
33
+ * detach that no signal caused: a script reading it concludes the user pressed
34
+ * Ctrl-C, which is the opposite of what happened (OSK-7660). Reserving 130 for
35
+ * an actual interrupt and giving the unattended case its own code keeps both
36
+ * answers true.
37
+ */
38
+ exports.STREAM_LOST_EXIT_CODE = 75;
39
+ /**
40
+ * What to say when the user pressed Ctrl-C and the run did not stop.
41
+ *
42
+ * A cancel is REQUESTED over the session; whether the harness honours it is not
43
+ * something this process can guarantee. Measured on a local harness, where the
44
+ * answer is checkable with `ps`: the CLI exited, and the shell and the `sleep
45
+ * 200` it had spawned were still alive at +10s, +26s and +53s — while the CLI
46
+ * said nothing about it at all (OSK-7733). Three things compound there: work
47
+ * the user asked to stop keeps consuming their machine and their vendor tokens;
48
+ * they are not told, so they will not go and kill it; and the record is left
49
+ * `unfinished: true` with no error, so the cancellation is invisible in history
50
+ * too.
51
+ *
52
+ * Silence is the one unacceptable option, because the user will believe they
53
+ * cancelled. This says what was asked, what is not guaranteed, and how to look.
54
+ */
55
+ function interruptedDetachMessage(input) {
56
+ return (`Cancel requested for run ${input.sessionId}, but no terminal event arrived before the ` +
57
+ 'grace period ended. The runtime MAY STILL BE EXECUTING — a tool call already running on ' +
58
+ 'your machine is not guaranteed to stop. ' +
59
+ `Check what it did with: ${inspectTurnCommand(input.conversationId)}` +
60
+ (process.platform === 'win32'
61
+ ? ''
62
+ : ', and look for a surviving process with `ps -ef | grep -i claude`'));
63
+ }
64
+ /**
65
+ * What the durable record says about a turn, read from its messages.
66
+ *
67
+ * The stream is not the only witness and must not be the only one consulted: a
68
+ * run refused during admission writes `error: true` plus the reason on the
69
+ * response message and never closes the session stream, so a joined subscriber
70
+ * waits forever for an event that will not come (OSK-7624, OSK-7635, OSK-7720,
71
+ * OSK-7735). Exported as a pure function so the mapping from a message row to a
72
+ * terminal verdict is testable without a socket.
73
+ *
74
+ * Returns null while the row is still in flight — the caller keeps waiting,
75
+ * because a long tool call is silence, not a failure.
76
+ */
77
+ function reconcileTerminalFromMessages(messages, responseMessageId) {
78
+ const row = (responseMessageId && messages.find((m) => m?.messageId === responseMessageId)) ||
79
+ [...messages].reverse().find((m) => m && m.isCreatedByUser === false);
80
+ if (!row)
81
+ return null;
82
+ const agentic = row.metadata?.agentic;
83
+ const recordedError = typeof agentic?.error === 'string' ? agentic.error : undefined;
84
+ const text = typeof row.text === 'string' ? row.text : '';
85
+ if (row.error === true) {
86
+ return {
87
+ status: 'failed',
88
+ ...(text ? { text } : {}),
89
+ // The reason exists on the row; it simply never reached the surface. Say
90
+ // it, rather than the transport error that masked it (OSK-7595).
91
+ error: recordedError ?? 'The run failed. No reason was recorded on the message.',
92
+ };
93
+ }
94
+ // `unfinished: false` is the persister's terminal marker; an empty body with
95
+ // it set is a turn that ended having produced nothing, which is still
96
+ // terminal and still better reported than waited on.
97
+ if (row.unfinished === false)
98
+ return { status: 'completed', text };
99
+ return null;
100
+ }
101
+ /**
102
+ * How to look at a turn the CLI is no longer watching.
103
+ *
104
+ * NOT `skrr agents chat --conversation <id>`, which is what this used to print:
105
+ * that command requires the `agentId` argument and `--prompt`, so it exits with
106
+ * `Missing 1 required arg: agentId` and never reattaches. A recovery
107
+ * instruction that cannot be run is worse than none — it costs the reader a
108
+ * round trip to discover the product was wrong.
109
+ */
110
+ function inspectTurnCommand(conversationId) {
111
+ return `skrr messages list ${conversationId ?? '<conversation-id>'}`;
112
+ }
11
113
  /**
12
114
  * A terminal run that produced no text is NOT a success to report silently.
13
115
  *
@@ -23,8 +125,7 @@ function noOutputFailureMessage(input) {
23
125
  if (input.text?.trim())
24
126
  return null;
25
127
  return (`The turn ended with no output (status: ${input.status}). ` +
26
- 'It may have failed on the runtime. Inspect it with: skrr agents chat ' +
27
- `--conversation ${input.conversationId ?? '<conversation-id>'}`);
128
+ `It may have failed on the runtime. Inspect it with: ${inspectTurnCommand(input.conversationId)}`);
28
129
  }
29
130
  function noStreamJsonPayload(input) {
30
131
  const { result, conversationId, agentId, baseURL, threadRootMessageId } = input;
@@ -97,7 +198,19 @@ class AgentsChat extends base_command_1.BaseCommand {
97
198
  'agent’s runtime, tools, session, or working directory and cannot perform work — ' +
98
199
  'it is for inline text assistance. Use --no-stream for a real turn.',
99
200
  }),
100
- jsonl: core_1.Flags.boolean({ description: 'Emit one JSON event per line while streaming' }),
201
+ jsonl: core_1.Flags.boolean({
202
+ description: 'Emit one JSON event per line while streaming. Every line is a complete JSON value. ' +
203
+ 'Assistant text arrives as `text.delta` whose `text` is the CUMULATIVE answer so far, ' +
204
+ 'not a delta — take the last one, or `run.result` at the end. The same text is ' +
205
+ 'mirrored inside `session.output` envelopes for consumers that want the raw stream, ' +
206
+ 'so folding both doubles the answer: pick ONE lane. Inside a `session.output`, ' +
207
+ '`envelopes[].__seq` is the dedupe key and the ordering key — the same envelope is ' +
208
+ 'delivered by more than one room, and a re-delivery repeats its `__seq`. A ' +
209
+ '`stream.gap` event means envelopes in that seq range never arrived and the streamed ' +
210
+ 'text is short; `run.result` and the persisted message remain authoritative. Tool ' +
211
+ 'calls arrive as `tool.started` / `tool.completed`, once per `toolUseId`, on cloud ' +
212
+ 'and local-harness runs alike.',
213
+ }),
101
214
  json: core_1.Flags.boolean({
102
215
  description: 'Emit the final one-shot response as JSON (use with --no-stream)',
103
216
  }),
@@ -122,7 +235,7 @@ class AgentsChat extends base_command_1.BaseCommand {
122
235
  * canonical scope at all. Naming that at launch is cheap; discovering it
123
236
  * mid-run costs a session.
124
237
  */
125
- static TASK_REF_IN_PROMPT = /\b(?:[A-Z][A-Z0-9]*-\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b/;
238
+ static TASK_REF_IN_PROMPT = /\b(?:OSK-\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b/;
126
239
  async run() {
127
240
  this.requireAuth();
128
241
  const { args, flags } = await this.parse(AgentsChat);
@@ -131,6 +244,15 @@ class AgentsChat extends base_command_1.BaseCommand {
131
244
  exit: 2,
132
245
  });
133
246
  }
247
+ if (flags.quick && flags.jsonl) {
248
+ // Accepted-and-ignored is worse than rejected: the caller had a parser
249
+ // waiting, got prose, and read the `JSONDecodeError` as the quick path
250
+ // having failed — which it had not (OSK-7647). `--quick` is a single
251
+ // one-shot response, so there is no event stream for `--jsonl` to carry.
252
+ this.error('--jsonl has no meaning with --quick: the persona-only summarizer returns one ' +
253
+ 'response and streams no events. Use --quick --json for a machine-readable ' +
254
+ 'one-shot, or drop --quick for a real streamed turn.', { exit: 2 });
255
+ }
134
256
  if (flags['approve-tools'] && !process.stdin.isTTY) {
135
257
  this.error('--approve-tools requires an interactive terminal.', { exit: 2 });
136
258
  }
@@ -171,7 +293,12 @@ class AgentsChat extends base_command_1.BaseCommand {
171
293
  'Address every task operation with this id explicitly, e.g.',
172
294
  ` skrr tasks show ${taskId} --json`,
173
295
  ` skrr tasks comments add ${taskId} --body "<progress>"`,
174
- ` skrr tasks complete ${taskId} --summary "<what you did>" --artifacts "<refs>"`,
296
+ // `--deliverables`, not `--artifacts`: the flag was renamed with the
297
+ // domain and this line was not, so an agent following it verbatim got
298
+ // `Nonexistent flag: --artifacts` and had to reason its way out —
299
+ // costing a tool call, a model turn, and a paragraph of apology in the
300
+ // user-visible task output (OSK-7683).
301
+ ` skrr tasks complete ${taskId} --summary "<what you did>" --deliverables "<refs>"`,
175
302
  '',
176
303
  'This is a chat turn, not a managed task run: the task is NOT checked out and its ' +
177
304
  'status is not managed for you. Do not go looking for an implicit task context — ' +
@@ -181,11 +308,22 @@ class AgentsChat extends base_command_1.BaseCommand {
181
308
  this.log(`Bound to task ${task.identifier ?? taskId} (chat turn — task not checked out)`);
182
309
  }
183
310
  }
184
- else if (AgentsChat.TASK_REF_IN_PROMPT.test(flags.prompt)) {
185
- this.warn('The prompt names what looks like a task reference, but this turn is NOT bound to a ' +
186
- 'task: the session will report OVERSKY_SESSION_TASK_CONTEXT=main_chat and ' +
187
- '`skrr tasks show` without an id will fail with TASK_CONTEXT_MISSING. Pass ' +
188
- '--task <id> to inject the canonical scope, or use `skrr tasks start` for a managed run.');
311
+ else {
312
+ // Quote what matched. The warning states as fact that a task reference is
313
+ // present, and the old pattern `[A-Z][A-Z0-9]*-\d+` matched any uppercase
314
+ // token followed by a hyphen and digits `UTF-8`, `GPT-4`, `RFC-2119`,
315
+ // `ERROR-500`, and every marker string a probe used so it fired on
316
+ // prompts naming no task and gave the reader nothing to check it against.
317
+ // A warning that cries wolf on ordinary text is a warning people stop
318
+ // reading, and this one guards a genuinely expensive mistake (OSK-7736).
319
+ const match = AgentsChat.TASK_REF_IN_PROMPT.exec(flags.prompt);
320
+ if (match) {
321
+ this.warn(`The prompt names what looks like a task reference ("${match[0]}"), but this turn is ` +
322
+ 'NOT bound to a task: the session will report ' +
323
+ 'OVERSKY_SESSION_TASK_CONTEXT=main_chat and `skrr tasks show` without an id will ' +
324
+ 'fail with TASK_CONTEXT_MISSING. Pass --task <id> to inject the canonical scope, ' +
325
+ 'or use `skrr tasks start` for a managed run.');
326
+ }
189
327
  }
190
328
  // OSK-2936 — `--quick` is the ONLY route to the non-executing summarizer,
191
329
  // and it says so.
@@ -253,7 +391,10 @@ class AgentsChat extends base_command_1.BaseCommand {
253
391
  // `--no-stream` runs the SAME turn; it only withholds the live output.
254
392
  const quiet = !!flags['no-stream'];
255
393
  if (flags.jsonl) {
256
- this.log(JSON.stringify({
394
+ // Written through the one JSONL helper, not `this.log`: oclif routes that
395
+ // through `util.format`, which rewrites `%s`-shaped sequences that appear
396
+ // in ordinary agent output (OSK-7629).
397
+ (0, agentic_stream_1.writeJsonLine)(process.stdout, {
257
398
  type: 'run.accepted',
258
399
  sessionId: started.sessionId,
259
400
  conversationId: started.conversationId,
@@ -261,7 +402,7 @@ class AgentsChat extends base_command_1.BaseCommand {
261
402
  responseMessageId: started.responseMessageId,
262
403
  agentId: args.agentId,
263
404
  url: (0, web_url_1.agentUrlFrom)(this.cliConfig.baseURL, { id: args.agentId }),
264
- }));
405
+ });
265
406
  }
266
407
  else if (!quiet) {
267
408
  for (const line of chatStreamHeaderLines({
@@ -274,6 +415,20 @@ class AgentsChat extends base_command_1.BaseCommand {
274
415
  this.log(line);
275
416
  }
276
417
  }
418
+ // The durable record, consulted when the stream goes quiet. Without this
419
+ // the CLI has no terminal condition for a run-level failure at all: the
420
+ // refusal is written to the message and the session stream is never closed,
421
+ // so an interactive user waits forever and a script that shells out to
422
+ // `agents chat` never returns (OSK-7735).
423
+ const conversationId = started.conversationId;
424
+ const reconcileTerminal = conversationId
425
+ ? async () => {
426
+ const messages = (await data_provider_1.dataService.getMessagesByConvoId(conversationId));
427
+ if (!Array.isArray(messages))
428
+ return null;
429
+ return reconcileTerminalFromMessages(messages, started.responseMessageId);
430
+ }
431
+ : undefined;
277
432
  const client = new agentic_stream_1.AgenticStreamClient({
278
433
  baseURL: this.cliConfig.baseURL,
279
434
  token: this.resolvedCredential.token,
@@ -282,6 +437,7 @@ class AgentsChat extends base_command_1.BaseCommand {
282
437
  jsonl: flags.jsonl,
283
438
  quiet,
284
439
  approveTools: flags['approve-tools'],
440
+ reconcileTerminal,
285
441
  });
286
442
  // OSK-2938 — Ctrl-C must be bounded, visible, and honest about what it
287
443
  // did NOT stop.
@@ -311,7 +467,8 @@ class AgentsChat extends base_command_1.BaseCommand {
311
467
  client.cancel();
312
468
  if (!flags.jsonl) {
313
469
  this.log(`\nCancelling run ${started.sessionId}… (waiting up to ${CANCEL_GRACE_MS / 1000}s; ` +
314
- 'press Ctrl-C again to detach)');
470
+ 'press Ctrl-C again to detach). A tool call already running on the runtime is ' +
471
+ 'not guaranteed to stop.');
315
472
  }
316
473
  graceTimer = setTimeout(() => detach?.(), CANCEL_GRACE_MS);
317
474
  graceTimer.unref?.();
@@ -333,28 +490,51 @@ class AgentsChat extends base_command_1.BaseCommand {
333
490
  }),
334
491
  detached,
335
492
  ]);
493
+ // Ask the record before saying the run may still be running. That was
494
+ // said of a turn which had completed thirteen seconds earlier, and of
495
+ // turns the server had already finalised as errors — "it may still be
496
+ // executing" is the most expensive thing to be wrong about here, because
497
+ // it is what stops a caller retrying or alerting (OSK-7595, OSK-7660).
498
+ let reconciled = null;
336
499
  if (outcome === 'detached') {
337
- // Never claim the run stopped — we only stopped watching it.
338
- const message = `Detached from run ${started.sessionId} before it reached a terminal state. ` +
339
- 'It may still be executing on the runtime. ' +
340
- `Check with: skrr agents chat --conversation ${started.conversationId ?? '<conversation-id>'}`;
500
+ if (await client.probeTerminal('detach'))
501
+ reconciled = client.settledResult();
502
+ }
503
+ if (outcome === 'detached' && !reconciled) {
504
+ const message = interrupts > 0
505
+ ? interruptedDetachMessage({
506
+ sessionId: started.sessionId,
507
+ conversationId: started.conversationId,
508
+ })
509
+ : `Detached from run ${started.sessionId} before it reached a terminal state. ` +
510
+ 'It may still be executing on the runtime. ' +
511
+ `Check with: ${inspectTurnCommand(started.conversationId)}`;
512
+ // 130 only when a signal actually caused this; otherwise the stream was
513
+ // lost and claiming SIGINT lies to every script reading the code
514
+ // (OSK-7660).
515
+ const exit = interrupts > 0 ? exports.DETACH_EXIT_CODE : exports.STREAM_LOST_EXIT_CODE;
341
516
  if (flags.jsonl) {
342
- this.log(JSON.stringify({
517
+ (0, agentic_stream_1.writeJsonLine)(process.stdout, {
343
518
  type: 'run.detached',
344
519
  sessionId: started.sessionId,
345
520
  conversationId: started.conversationId,
521
+ interrupted: interrupts > 0,
346
522
  message,
347
- }));
523
+ });
524
+ // A detach is not a success in any output mode. `--jsonl` is the mode
525
+ // automation drives, so leaving this at 0 is the one that actually
526
+ // costs someone a wrong decision.
527
+ process.exitCode = exit;
348
528
  return;
349
529
  }
350
- this.error(message, { exit: 130 });
530
+ this.error(message, { exit });
351
531
  }
352
- const result = outcome;
532
+ const result = reconciled ?? outcome;
353
533
  if (flags.jsonl) {
354
534
  // The event stream already contains the terminal event. This summary
355
535
  // makes shell consumers able to find the final text without replaying
356
536
  // the event reducer.
357
- this.log(JSON.stringify({ type: 'run.result', ...result }));
537
+ (0, agentic_stream_1.writeJsonLine)(process.stdout, { type: 'run.result', ...result });
358
538
  }
359
539
  else if (quiet && flags.json) {
360
540
  // A real executed turn — the metadata says so, unlike `--quick`.
@@ -27,6 +27,44 @@ export declare function agentCreateMissingFieldsMessage(missing: string[]): stri
27
27
  * be reported.
28
28
  */
29
29
  export declare function agentCreateMissingFields(payload: Record<string, unknown>): string[];
30
+ /**
31
+ * OSK-7680 — what creating ONE agent also starts.
32
+ *
33
+ * Within ~10 seconds of `agents create`, the new agent owns five
34
+ * system-managed commitments, four of them already active, on 30m/1h/2h/12h/1d
35
+ * cadences, three of them in Execute mode. Nothing in the create output said
36
+ * so: it carried only `proactiveProvisioning: {status: 'pending'}`, which does
37
+ * not read as "I am about to enrol this agent in four recurring autonomous
38
+ * loops". The person who asked for one agent got a standing workload, and the
39
+ * default `commitments list --agent <id>` then answered "No commitments."
40
+ *
41
+ * Said at creation because that is the moment the decision is being made and
42
+ * the moment `--no-relationship-loops` is still available. The opt-out already
43
+ * existed; only the disclosure was missing, and an opt-out nobody is told about
44
+ * is not one.
45
+ */
46
+ /**
47
+ * KEYS THE SERVER DID NOT KEEP.
48
+ *
49
+ * OSK-7704 — a `--from-json` body carrying
50
+ * `"machineRequirements": {"capabilities": ["daemonTools"]}` created the agent
51
+ * and dropped the field: no warning, no 400, and `agents show --json` has no
52
+ * such key. The escape hatch the help points at for anything the flags do not
53
+ * cover accepts arbitrary keys and silently discards the ones the server does
54
+ * not model, so a caller who declares a requirement believes they declared it.
55
+ *
56
+ * Compared against the CREATED AGENT rather than a hard-coded field list: the
57
+ * server owns which keys it models, that set changes, and a list here would
58
+ * drift into warning about fields that now work. A key that came back — under
59
+ * any value, including `null` where the server deliberately stores one — is
60
+ * kept; anything absent from the response was not.
61
+ *
62
+ * A warning, never a refusal. Some keys legitimately do not round-trip (a
63
+ * write-only secret, a field the read projection omits), and turning those into
64
+ * a failed create would be worse than the silence.
65
+ */
66
+ export declare function unappliedPayloadKeys(sent: Record<string, unknown>, created: unknown, ignore?: readonly string[]): string[];
67
+ export declare function backgroundLoopLines(agentId: string, relationshipLoopsSkipped: boolean): string[];
30
68
  export default class AgentsCreate extends BaseCommand {
31
69
  static description: string;
32
70
  static examples: string[];
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.agentCreateMissingFieldsMessage = agentCreateMissingFieldsMessage;
4
4
  exports.agentCreateMissingFields = agentCreateMissingFields;
5
+ exports.unappliedPayloadKeys = unappliedPayloadKeys;
6
+ exports.backgroundLoopLines = backgroundLoopLines;
5
7
  const core_1 = require("@oclif/core");
6
8
  const data_provider_1 = require("@skrr-ai/data-provider");
7
9
  const base_command_1 = require("../../base-command");
@@ -55,6 +57,72 @@ function agentCreateMissingFields(payload) {
55
57
  missing.push('--target');
56
58
  return missing;
57
59
  }
60
+ /**
61
+ * OSK-7680 — what creating ONE agent also starts.
62
+ *
63
+ * Within ~10 seconds of `agents create`, the new agent owns five
64
+ * system-managed commitments, four of them already active, on 30m/1h/2h/12h/1d
65
+ * cadences, three of them in Execute mode. Nothing in the create output said
66
+ * so: it carried only `proactiveProvisioning: {status: 'pending'}`, which does
67
+ * not read as "I am about to enrol this agent in four recurring autonomous
68
+ * loops". The person who asked for one agent got a standing workload, and the
69
+ * default `commitments list --agent <id>` then answered "No commitments."
70
+ *
71
+ * Said at creation because that is the moment the decision is being made and
72
+ * the moment `--no-relationship-loops` is still available. The opt-out already
73
+ * existed; only the disclosure was missing, and an opt-out nobody is told about
74
+ * is not one.
75
+ */
76
+ /**
77
+ * KEYS THE SERVER DID NOT KEEP.
78
+ *
79
+ * OSK-7704 — a `--from-json` body carrying
80
+ * `"machineRequirements": {"capabilities": ["daemonTools"]}` created the agent
81
+ * and dropped the field: no warning, no 400, and `agents show --json` has no
82
+ * such key. The escape hatch the help points at for anything the flags do not
83
+ * cover accepts arbitrary keys and silently discards the ones the server does
84
+ * not model, so a caller who declares a requirement believes they declared it.
85
+ *
86
+ * Compared against the CREATED AGENT rather than a hard-coded field list: the
87
+ * server owns which keys it models, that set changes, and a list here would
88
+ * drift into warning about fields that now work. A key that came back — under
89
+ * any value, including `null` where the server deliberately stores one — is
90
+ * kept; anything absent from the response was not.
91
+ *
92
+ * A warning, never a refusal. Some keys legitimately do not round-trip (a
93
+ * write-only secret, a field the read projection omits), and turning those into
94
+ * a failed create would be worse than the silence.
95
+ */
96
+ function unappliedPayloadKeys(sent, created, ignore = []) {
97
+ if (!created || typeof created !== 'object' || Array.isArray(created))
98
+ return [];
99
+ const back = created;
100
+ const skip = new Set(ignore);
101
+ return Object.keys(sent)
102
+ .filter((key) => !skip.has(key))
103
+ .filter((key) => sent[key] !== undefined)
104
+ .filter((key) => !Object.prototype.hasOwnProperty.call(back, key))
105
+ .sort();
106
+ }
107
+ function backgroundLoopLines(agentId, relationshipLoopsSkipped) {
108
+ if (relationshipLoopsSkipped) {
109
+ return [
110
+ 'Background loops: relationship portfolio skipped (--no-relationship-loops). ' +
111
+ 'Self-reflection is still seeded and runs on its own cadence.',
112
+ ` skrr commitments list --agent ${agentId} --include-system # what it still runs`,
113
+ ];
114
+ }
115
+ return [
116
+ 'Background loops: this agent is being enrolled in system-managed commitments — ' +
117
+ 'self-reflection, conversation continuity, relationship pulse, commitment incubator ' +
118
+ 'and open-loop closer. They run on their own cadence, unprompted, and are hidden ' +
119
+ 'from the default commitments list.',
120
+ ` skrr commitments list --agent ${agentId} --include-system # see them`,
121
+ ` skrr commitments operating-review ${agentId} # what they are doing`,
122
+ ' skrr commitments pause <commitment-id> # stop one',
123
+ ' skrr agents create --no-relationship-loops # a single-purpose agent next time',
124
+ ];
125
+ }
58
126
  class AgentsCreate extends base_command_1.BaseCommand {
59
127
  static description = 'Create a new agent in the selected workspace, or in your default workspace when --workspace is omitted (`skrr workspaces list` names it)';
60
128
  static examples = [
@@ -91,7 +159,17 @@ class AgentsCreate extends base_command_1.BaseCommand {
91
159
  }),
92
160
  category: core_1.Flags.string({ description: 'Agent category' }),
93
161
  target: core_1.Flags.string({
94
- description: 'Required execution target. Use a Harness id, Hosted Machine session, or Agent Worker. Use hosted-machine, sbs_..., agent-worker, or a connected Harness id.',
162
+ description: 'Required execution target. Use a Harness id, Hosted Machine session, or Agent Worker. ' +
163
+ 'Use hosted-machine, sbs_..., agent-worker, or a connected Harness id. ' +
164
+ // There is no "unplaced" agent to create: a body that reaches the API
165
+ // without one is given an explicit `agent-worker` target server-side,
166
+ // so an operator who expected an unset field gets a real, visible
167
+ // placement they did not choose (OSK-7654). This command refuses the
168
+ // omission rather than letting that happen silently — say so, so the
169
+ // refusal reads as a contract rather than a missing feature.
170
+ 'There is no unplaced agent: a create that omits this is given an ' +
171
+ '`agent-worker` target by the server, so this command asks instead of ' +
172
+ 'letting a placement be chosen for you.',
95
173
  }),
96
174
  'next-target': core_1.Flags.string({
97
175
  description: 'Next execution target in exact execution order after --target. Repeat in the order it should be tried.',
@@ -229,17 +307,32 @@ class AgentsCreate extends base_command_1.BaseCommand {
229
307
  catch (err) {
230
308
  this.handleApiError(err);
231
309
  }
310
+ // Said before anything else, and in both output modes: a caller who
311
+ // declared a requirement the server does not model has NOT declared it, and
312
+ // finding that out later — from a run that landed somewhere it should not
313
+ // have — is the expensive way (OSK-7704).
314
+ // relationshipLoops is an input-only provisioning control. The server
315
+ // applies it by deciding which system commitments to seed, so it is not an
316
+ // Agent document field and is intentionally absent from the response.
317
+ const unapplied = unappliedPayloadKeys(payload, created, ['relationshipLoops']);
318
+ if (unapplied.length > 0) {
319
+ this.warn(`The server did not keep ${unapplied.join(', ')} — ${unapplied.length === 1 ? 'that field is' : 'those fields are'} not part of the agent it created. Check \`skrr agents show <id> --json\`.`);
320
+ }
232
321
  if (flags.json) {
233
322
  this.log(JSON.stringify((0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, created), null, 2));
234
323
  return;
235
324
  }
236
325
  const a = created;
237
- this.log(`Created agent ${a.id ?? a._id ?? '?'} — ${a.name ?? '(no name)'}`);
326
+ const agentId = String(a.id ?? a._id ?? '?');
327
+ this.log(`Created agent ${agentId} — ${a.name ?? '(no name)'}`);
238
328
  // Chosen for the user, so say so: a silent default is the kind of thing
239
329
  // people discover much later, when it matters.
240
330
  if (appliedDefaults.length > 0) {
241
331
  this.log(`Defaults applied: ${appliedDefaults.join(', ')}`);
242
332
  }
333
+ for (const line of backgroundLoopLines(agentId, flags['no-relationship-loops'] === true)) {
334
+ this.log(line);
335
+ }
243
336
  this.log(`URL: ${(0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, a).url ?? '-'}`);
244
337
  }
245
338
  }
@@ -77,7 +77,18 @@ class AgentsScheduleTrace extends base_command_1.BaseCommand {
77
77
  if (events.length === 0) {
78
78
  // An empty trace is a real answer — nothing touched this day's schedule —
79
79
  // and must not read as a failed lookup.
80
+ //
81
+ // It is also a CLAIM, and it was wrong once (OSK-7658): the trace saw only
82
+ // triggers the smart-schedule planner had minted, so a one-shot from
83
+ // `skrr agents schedule --at` that fired and replied rendered as "nothing
84
+ // happened". The server-side filter is fixed; the sentence now names the
85
+ // two surfaces that would disagree, because a reader who has just been
86
+ // told nothing happened on a day they watched something happen should not
87
+ // have to guess where to look next.
80
88
  this.log('No schedule events for this day.');
89
+ this.log('');
90
+ this.log(` ${this.config.bin} agents schedule-overview ${args.agent} # what is armed, and recent fires`);
91
+ this.log(` ${this.config.bin} agents activity ${args.agent} # what the agent actually did`);
81
92
  return;
82
93
  }
83
94
  (0, format_1.renderTable)(events.map((e) => ({
@@ -57,6 +57,10 @@ function agentExecutionOrderLines(agent) {
57
57
  const entries = projected.length > 0 ? projected : fallback;
58
58
  if (entries.length === 0)
59
59
  return ['Execution order: automatic (no configured target)'];
60
+ // Only the SERVER's projection knows whether a selector resolves. The local
61
+ // fallback is built from the stored policy and has no resolution information
62
+ // at all, so it must not claim one either way.
63
+ const resolved = projected.length > 0;
60
64
  return [
61
65
  'Execution order:',
62
66
  ...entries.map((entry, index) => {
@@ -64,10 +68,34 @@ function agentExecutionOrderLines(agent) {
64
68
  const target = typeof entry.name === 'string' && entry.name ? entry.name : entry.selector;
65
69
  const label = typeof entry.label === 'string' && entry.label ? ` — ${entry.label}` : '';
66
70
  const status = typeof entry.status === 'string' ? ` (${entry.status})` : '';
67
- return ` ${position}. ${target || '(invalid target)'}${status}${label}`;
71
+ // An UNRESOLVABLE target used to render as an absence — no name, no
72
+ // `(online)`/`(offline)` marker — on a line that otherwise looks like a
73
+ // normal one. `attach-harness` accepts an id that resolves to nothing
74
+ // with `ok: true`, so the typo persists silently, and an operator
75
+ // reviewing someone else's config reads entry 2 as a harness whose
76
+ // status is momentarily unknown. Entry 2 in a chain is by definition the
77
+ // one you have not looked at recently. An unresolvable target is a
78
+ // strictly worse condition than an offline one, and offline is loud
79
+ // (OSK-7677). An absence becomes a statement.
80
+ const unresolvable = resolved &&
81
+ !status &&
82
+ !(typeof entry.name === 'string' && entry.name) &&
83
+ !isSynthetic(entry)
84
+ ? ' [!] no such harness — nothing is registered under this id'
85
+ : '';
86
+ return ` ${position}. ${target || '(invalid target)'}${status}${label}${unresolvable}`;
68
87
  }),
69
88
  ];
70
89
  }
90
+ /** The platform's own products resolve by name, not by a harness lookup. */
91
+ function isSynthetic(entry) {
92
+ const kind = typeof entry.kind === 'string' ? entry.kind : '';
93
+ if (kind === 'agent-worker' || kind === 'hosted-machine' || kind === 'hosted-job-machine') {
94
+ return true;
95
+ }
96
+ const selector = typeof entry.selector === 'string' ? entry.selector : '';
97
+ return selector.startsWith('__oversky_') || selector.startsWith('sbs_');
98
+ }
71
99
  class AgentsShow extends base_command_1.BaseCommand {
72
100
  static description = 'Show details for a single agent';
73
101
  static examples = [
@@ -0,0 +1,24 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * Mint a Managed Agents API key for a Space.
4
+ *
5
+ * The secret is displayed EXACTLY ONCE. There is no endpoint that reveals it
6
+ * again, so this command says that where the value is printed rather than in a
7
+ * footnote — a caller that scrolls past it has to rotate.
8
+ */
9
+ export default class ApiKeysCreate extends BaseCommand {
10
+ static description: string;
11
+ static examples: string[];
12
+ static args: {
13
+ name: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
14
+ };
15
+ static flags: {
16
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ env: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
+ scope: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
+ 'expires-at': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
21
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
+ };
23
+ run(): Promise<void>;
24
+ }