@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
@@ -387,5 +387,20 @@ type IncompatibleCliCredentialScope = 'daemon' | 'daemon-install';
387
387
  export declare function isDaemonScopedCredential(token?: string | null): boolean;
388
388
  /** The one repair for a machine-only token passed to a human CLI command. */
389
389
  export declare function describeDaemonScopedCredential(bin: string, scope?: IncompatibleCliCredentialScope, source?: ResolvedCredential['source']): string;
390
+ /**
391
+ * Did the server MEAN this 5xx, or did it fall over?
392
+ *
393
+ * An outage and a designed refusal arrive with the same status and want
394
+ * opposite reactions — wait for recovery, versus act on a condition. The
395
+ * discriminator is whether the server authored an answer: a typed `code` plus
396
+ * either an explanation it wrote (`cause` / `remedy`, both of which the 5xx
397
+ * redaction boundary deliberately lets through) or an explicit verdict that
398
+ * retrying will not help.
399
+ *
400
+ * Deliberately NOT folded into `isOutageFailure`: that predicate also gates the
401
+ * outbox queue decision and `noteControlPlaneOutage`, and those ask a different
402
+ * question. Merging the two is the mistake its own comment warns about.
403
+ */
404
+ export declare function isTypedServerRefusal(body: Record<string, unknown> | null): boolean;
390
405
  export declare function isRetryableFailure(status: number | undefined, body: Record<string, unknown> | null): boolean;
391
406
  export { Flags };
@@ -10,6 +10,7 @@ exports.describeAssigneeNotInSpace = describeAssigneeNotInSpace;
10
10
  exports.describeForbidden = describeForbidden;
11
11
  exports.isDaemonScopedCredential = isDaemonScopedCredential;
12
12
  exports.describeDaemonScopedCredential = describeDaemonScopedCredential;
13
+ exports.isTypedServerRefusal = isTypedServerRefusal;
13
14
  exports.isRetryableFailure = isRetryableFailure;
14
15
  const core_1 = require("@oclif/core");
15
16
  Object.defineProperty(exports, "Flags", { enumerable: true, get: function () { return core_1.Flags; } });
@@ -751,6 +752,14 @@ class BaseCommand extends core_1.Command {
751
752
  if (isOclifExitError(err)) {
752
753
  return super.catch(err);
753
754
  }
755
+ // Canonical Task Model v1 removed several `tasks complete` flags outright,
756
+ // so a caller following older instructions — including the managed block the
757
+ // platform itself installed — got a bare `Nonexistent flags:` with no hint
758
+ // that the capability moved rather than vanished. Name where each went.
759
+ const retiredHint = retiredFlagHint(err.message || '');
760
+ if (retiredHint) {
761
+ err.message = `${err.message}\n\n${retiredHint}`;
762
+ }
754
763
  if (this.wantsJsonOutput()) {
755
764
  const exit = err.exitCode ?? err.oclif?.exit ?? 1;
756
765
  process.exitCode = exit;
@@ -936,6 +945,29 @@ class BaseCommand extends core_1.Command {
936
945
  retryable: true,
937
946
  });
938
947
  }
948
+ else if (isTypedServerRefusal(body)) {
949
+ // A 5xx the server DELIBERATELY produced and described in its own
950
+ // words. Reaching the outage branch below made the CLI announce a
951
+ // platform outage for a per-conversation condition: "https://skrr.ai is
952
+ // not serving requests right now. This is a service outage, not a
953
+ // problem with your account or this command" — for
954
+ // `CONVERSATION_ADMISSION_OUTCOME_UNCONFIRMED`, while skrr.ai served
955
+ // every other command in the same minute, with the outer `retryable`
956
+ // reading true over an inner `false` (retrying was futile for ~35
957
+ // minutes). The reader is sent to a status page instead of learning
958
+ // that one conversation is parked (OSK-7719).
959
+ //
960
+ // So: the server's code, the server's words, and the server's verdict
961
+ // on whether retrying can help.
962
+ this.failWithCliError({
963
+ message: say(bodyMessage || e.message),
964
+ code: bodyCode || `HTTP_${e.status}`,
965
+ status: e.status,
966
+ exit: 1,
967
+ retryable: isRetryableFailure(e.status, body),
968
+ details: body ?? undefined,
969
+ });
970
+ }
939
971
  else if ((0, outbox_1.isOutageFailure)(e)) {
940
972
  // A gateway/unavailable status is an OUTAGE, and saying so is the whole
941
973
  // point. During the OSK-2806 incident these surfaced as bare
@@ -955,11 +987,17 @@ class BaseCommand extends core_1.Command {
955
987
  // predicate is what made a single route's 500 read as a platform
956
988
  // outage.
957
989
  this.noteControlPlaneOutage(e.status);
990
+ const method = e.method?.toUpperCase();
991
+ const readOnlyRequest = method === 'GET' || method === 'HEAD' || method === 'OPTIONS';
992
+ const outcome = readOnlyRequest
993
+ ? 'No write was attempted by this request; retry once the service recovers.'
994
+ : 'For a write, the gateway may have timed out after the server committed it. ' +
995
+ 'The outcome is unknown — check the target or reconcile by idempotency key before retrying.';
958
996
  this.failWithCliError({
959
997
  message: say(`${this.cliConfig.baseURL} is not serving requests right now` +
960
998
  `${e.status ? ` (HTTP ${e.status})` : ''}. ` +
961
999
  'This is a service outage, not a problem with your account or this command. ' +
962
- 'Nothing was changed — retry once it recovers.'),
1000
+ outcome),
963
1001
  code: 'CONTROL_PLANE_UNAVAILABLE',
964
1002
  status: e.status,
965
1003
  exit: 5,
@@ -1093,15 +1131,16 @@ class BaseCommand extends core_1.Command {
1093
1131
  });
1094
1132
  }
1095
1133
  // Same discipline as `handleApiError`: only a real outage gets outage
1096
- // wording, and only an outage lets us say nothing was written. A 500 is
1097
- // queued too, but the server ran our request before failing, so what it did
1098
- // with it is unknown and a replay is safe on the idempotency key rather
1099
- // than on an assumption that nothing landed.
1134
+ // wording. Even an edge 504 can arrive AFTER the application committed a
1135
+ // write, so neither branch claims nothing landed. A replay is safe because
1136
+ // the queued record carries an idempotency key, not because the first
1137
+ // attempt is assumed absent.
1100
1138
  const outage = (0, outbox_1.isOutageFailure)(err);
1101
1139
  const statusSuffix = e.status ? ` (HTTP ${e.status})` : '';
1102
1140
  const lead = outage
1103
1141
  ? `${this.cliConfig.baseURL} is not serving requests right now${statusSuffix}. ` +
1104
- `Your ${write.summary} was queued locally as ${queuedId} nothing has been written yet.`
1142
+ `Your ${write.summary} was queued locally as ${queuedId}; whether the server already ` +
1143
+ 'applied the timed-out attempt is unknown, so verify before replaying.'
1105
1144
  : `${this.cliConfig.baseURL} did not accept this write${statusSuffix}. ` +
1106
1145
  `Your ${write.summary} was queued locally as ${queuedId}; whether the server applied ` +
1107
1146
  'any of it is not reported, so verify before replaying.';
@@ -1132,7 +1171,10 @@ class BaseCommand extends core_1.Command {
1132
1171
  // terminal refusal or a 500. oclif's pretty-printer renders a `code` on a
1133
1172
  // CLIError as its own `Code: <code>` line, so passing it through gives
1134
1173
  // every skrr command a greppable failure line at no other cost.
1135
- this.error(message, { exit, code });
1174
+ //
1175
+ // Field-level validation is appended for the same reason: the server names
1176
+ // the offending field and only `--json` callers could read it.
1177
+ this.error(`${message}${formatValidationIssues(details)}`, { exit, code });
1136
1178
  }
1137
1179
  writeJsonCliError({ message, code, status, exit, retryable, details, }) {
1138
1180
  this.log(JSON.stringify({
@@ -1341,15 +1383,23 @@ function describeAssigneeNotInSpace(serverMessage, bin = 'skrr') {
1341
1383
  * Server-declared TERMINAL refusals: a state conflict the caller must resolve
1342
1384
  * by doing something DIFFERENT, never by repeating the identical request.
1343
1385
  *
1344
- * `skrr tasks move --status done` on a checked-out task with no approved
1345
- * TASK_OUTPUT returns 409 `task_output_required`. 409 used to be in the
1386
+ * `skrr tasks move --status done` with no current Result or independent Review
1387
+ * returns a typed 409. 409 used to be in the
1346
1388
  * transient set below, so the JSON envelope said `retryable: true` — and
1347
1389
  * `daemon/CLAUDE.md` tells daemon-hosted agents to retry retryable errors, so
1348
1390
  * they looped on a refusal that can never succeed on retry. The refusal names
1349
- * the supported path (`POST /:taskId/complete` / `skrr tasks complete`); the
1391
+ * the supported path (`skrr tasks complete`, Result, then Review); the
1350
1392
  * envelope has to agree that the ONLY way forward is that path.
1351
1393
  */
1352
- const TERMINAL_ERROR_CODES = new Set(['task_output_required', 'task_output_not_approved']);
1394
+ const TERMINAL_ERROR_CODES = new Set([
1395
+ 'TASK_RESULT_REQUIRED',
1396
+ 'TASK_CURRENT_RESULT_MISSING',
1397
+ 'TASK_RESULT_SPEC_VERSION_MISMATCH',
1398
+ 'TASK_EXPECTATIONS_NOT_MET',
1399
+ 'TASK_RESULT_CHANGES_REQUESTED',
1400
+ 'TASK_RESULT_REVIEW_REQUIRED',
1401
+ 'TASK_DELIVERY_NOT_INTEGRATED',
1402
+ ]);
1353
1403
  /**
1354
1404
  * Whether an automated retry of the IDENTICAL request could plausibly succeed.
1355
1405
  *
@@ -1451,6 +1501,28 @@ function describeDaemonScopedCredential(bin, scope = 'daemon', source) {
1451
1501
  return (`${subject}, which cannot access user API commands. ` +
1452
1502
  `Run \`${bin} login\` to create a CLI credential. For the local runtime itself, use \`${bin} daemon login\`.`);
1453
1503
  }
1504
+ /**
1505
+ * Did the server MEAN this 5xx, or did it fall over?
1506
+ *
1507
+ * An outage and a designed refusal arrive with the same status and want
1508
+ * opposite reactions — wait for recovery, versus act on a condition. The
1509
+ * discriminator is whether the server authored an answer: a typed `code` plus
1510
+ * either an explanation it wrote (`cause` / `remedy`, both of which the 5xx
1511
+ * redaction boundary deliberately lets through) or an explicit verdict that
1512
+ * retrying will not help.
1513
+ *
1514
+ * Deliberately NOT folded into `isOutageFailure`: that predicate also gates the
1515
+ * outbox queue decision and `noteControlPlaneOutage`, and those ask a different
1516
+ * question. Merging the two is the mistake its own comment warns about.
1517
+ */
1518
+ function isTypedServerRefusal(body) {
1519
+ if (!body || typeof body !== 'object')
1520
+ return false;
1521
+ const code = stringProp(body, 'code') || stringProp(body, 'errorType');
1522
+ if (!code)
1523
+ return false;
1524
+ return (typeof body.cause === 'string' || typeof body.remedy === 'string' || body.retryable === false);
1525
+ }
1454
1526
  function isRetryableFailure(status, body) {
1455
1527
  const declared = body?.retryable;
1456
1528
  if (typeof declared === 'boolean')
@@ -1460,6 +1532,42 @@ function isRetryableFailure(status, body) {
1460
1532
  return false;
1461
1533
  return status === 408 || status === 425 || status === 429 || !!(status && status >= 500);
1462
1534
  }
1535
+ /**
1536
+ * Render server-supplied field validation into the human error.
1537
+ *
1538
+ * The canonical Task routes answer a schema rejection with
1539
+ * `{error: 'Invalid request data', details: <zod issues>}` — which names the
1540
+ * exact field — but the human path used to print only the generic sentence, so
1541
+ * `tasks updates add --type finding` failed with `Invalid request data` and the
1542
+ * operator had to re-run the identical command with `--json` to learn that
1543
+ * `data.evidenceRefs` was missing. The answer was already on the wire; only the
1544
+ * renderer threw it away.
1545
+ *
1546
+ * Shape-sniffed rather than typed against zod: `details` also carries unrelated
1547
+ * payloads (outbox ids, oclif suggestions), and those must pass through
1548
+ * untouched rather than render as pseudo-fields.
1549
+ */
1550
+ function formatValidationIssues(details) {
1551
+ const issues = Array.isArray(details)
1552
+ ? details
1553
+ : Array.isArray(details?.details)
1554
+ ? details.details
1555
+ : Array.isArray(details?.issues)
1556
+ ? details.issues
1557
+ : [];
1558
+ const lines = [];
1559
+ for (const issue of issues) {
1560
+ const row = issue;
1561
+ const message = typeof row?.message === 'string' ? row.message : '';
1562
+ if (!message)
1563
+ continue;
1564
+ const path = Array.isArray(row.path) ? row.path.join('.') : '';
1565
+ lines.push(path ? ` ${path}: ${message}` : ` ${message}`);
1566
+ if (lines.length === 10)
1567
+ break;
1568
+ }
1569
+ return lines.length > 0 ? `\n${lines.join('\n')}` : '';
1570
+ }
1463
1571
  function detailsFromPrettyError(options) {
1464
1572
  const details = {};
1465
1573
  for (const key of ['suggestions', 'ref', 'showHelp']) {
@@ -1476,6 +1584,32 @@ function detailsFromCaughtError(err) {
1476
1584
  details.exit = err.oclif.exit;
1477
1585
  return Object.keys(details).length > 0 ? details : undefined;
1478
1586
  }
1587
+ /**
1588
+ * Where a removed flag's capability went. Keyed by flag name so it fires on
1589
+ * oclif's own `Nonexistent flags:` message without parsing its grammar.
1590
+ */
1591
+ const RETIRED_FLAG_REPLACEMENTS = {
1592
+ '--verdict': '--verdict is gone: a review decision and a domain conclusion are different facts. ' +
1593
+ 'Use `tasks review --decision accepted|changes_requested` for acceptance, and ' +
1594
+ '--conclusion-type/--conclusion-json for a conclusion such as NO-SHIP.',
1595
+ '--outcome': '--outcome is now --summary.',
1596
+ '--finding': '--finding is gone: record findings as `tasks updates add --type finding`.',
1597
+ '--evidence': '--evidence is now --evidence-ref on the Result, or an evidenceRefs entry.',
1598
+ '--next': '--next is now --remaining.',
1599
+ '--deliverables': '--deliverables is now --deliverable <task-resource-link-id>, recorded first with ' +
1600
+ '`tasks deliverable add`.',
1601
+ '--artifact': '--artifact is now --deliverable <task-resource-link-id>, recorded first with ' +
1602
+ '`tasks deliverable add`.',
1603
+ '--supersede': '--supersede is implicit: submitting again creates a new Result version.',
1604
+ };
1605
+ function retiredFlagHint(message) {
1606
+ if (!/nonexistent flag/i.test(message))
1607
+ return null;
1608
+ const hits = Object.keys(RETIRED_FLAG_REPLACEMENTS).filter((flag) => new RegExp(`${flag}(?![\\w-])`).test(message));
1609
+ if (hits.length === 0)
1610
+ return null;
1611
+ return hits.map((flag) => ` ${RETIRED_FLAG_REPLACEMENTS[flag]}`).join('\n');
1612
+ }
1479
1613
  function parseCliErrorCode(err) {
1480
1614
  if (err.name && err.name !== 'Error') {
1481
1615
  return err.name.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase();
@@ -1,15 +1,52 @@
1
1
  import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * Sort two positionals into (harness, agent), whichever order they were typed.
4
+ *
5
+ * The discriminator is the id SHAPE, not the position: an agent id is
6
+ * `agent_…`, and nothing else this command accepts is. That covers the reported
7
+ * mistake exactly — `attach-harness <agent> <harness>` — without guessing when
8
+ * neither value looks like an agent.
9
+ *
10
+ * Returns `{ error }` rather than picking, when the two sources disagree.
11
+ */
12
+ export declare function resolveAttachPositionals(first: string, second: string | undefined, agentFlag: string | undefined): {
13
+ harness: string;
14
+ agent?: string;
15
+ error?: undefined;
16
+ } | {
17
+ error: string;
18
+ harness?: undefined;
19
+ };
2
20
  export default class AgentsAttachHarness extends BaseCommand {
3
21
  static description: string;
4
22
  static examples: string[];
23
+ /**
24
+ * Which positional is which, when a caller gave two.
25
+ *
26
+ * This is the ONLY command in the `agents` topic whose positional is not the
27
+ * agent — every neighbour is `agents <verb> <agent-id> [args]`, and the
28
+ * space's own Execution Map documents `attach-harness <agent> <harness>`. A
29
+ * caller writing that shape had their agent id silently accepted AS THE
30
+ * HARNESS and the real harness rejected with `Unexpected argument:
31
+ * 6a985ed2…` — an error that names the argument it does not want, never says
32
+ * what it does want, and does not notice that the value it accepted is
33
+ * obviously an `agent_…` id (OSK-7686).
34
+ *
35
+ * So both orders work, decided by the shape of the ids rather than by
36
+ * position. An explicit `--agent` still wins, and a conflict is refused
37
+ * rather than silently resolved — being attached to the wrong machine is the
38
+ * wrong way to find out which one was meant.
39
+ */
5
40
  static args: {
6
41
  harness: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
42
+ agent: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
43
  };
8
44
  static flags: {
9
45
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
46
  agent: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
47
  'next-target': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
48
  'advance-on': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
49
+ 'strict-order': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
50
  'rebind-tasks': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
51
  };
15
52
  run(): Promise<void>;
@@ -1,10 +1,50 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveAttachPositionals = resolveAttachPositionals;
3
4
  const core_1 = require("@oclif/core");
4
5
  const data_provider_1 = require("@skrr-ai/data-provider");
5
6
  const base_command_1 = require("../../base-command");
6
7
  const execution_target_1 = require("../../lib/execution-target");
7
8
  const agent_resolver_1 = require("../../lib/agent-resolver");
9
+ /**
10
+ * Sort two positionals into (harness, agent), whichever order they were typed.
11
+ *
12
+ * The discriminator is the id SHAPE, not the position: an agent id is
13
+ * `agent_…`, and nothing else this command accepts is. That covers the reported
14
+ * mistake exactly — `attach-harness <agent> <harness>` — without guessing when
15
+ * neither value looks like an agent.
16
+ *
17
+ * Returns `{ error }` rather than picking, when the two sources disagree.
18
+ */
19
+ function resolveAttachPositionals(first, second, agentFlag) {
20
+ const isAgentId = (value) => !!value && value.startsWith('agent_');
21
+ let harness = first;
22
+ let agent = second;
23
+ if (second && isAgentId(first) && !isAgentId(second)) {
24
+ harness = second;
25
+ agent = first;
26
+ }
27
+ else if (second && isAgentId(first) && isAgentId(second)) {
28
+ return {
29
+ error: `Both positionals look like agent ids ("${first}", "${second}"). ` +
30
+ 'Pass one agent and one harness: `agents attach-harness <harness> --agent <agent>`.',
31
+ };
32
+ }
33
+ if (agent && agentFlag && agent !== agentFlag) {
34
+ return {
35
+ error: `Conflicting agents: "${agent}" (positional) and "${agentFlag}" (--agent). Pass one. ` +
36
+ 'Attaching to the wrong machine is the wrong way to find out which was meant.',
37
+ };
38
+ }
39
+ if (isAgentId(harness)) {
40
+ return {
41
+ error: `"${harness}" is an agent id, not a harness. This command takes the harness first: ` +
42
+ '`agents attach-harness <harness> --agent <agent>`. ' +
43
+ 'List harnesses with `skrr harnesses list --all`.',
44
+ };
45
+ }
46
+ return { harness, ...(agent ? { agent } : {}) };
47
+ }
8
48
  class AgentsAttachHarness extends base_command_1.BaseCommand {
9
49
  static description = 'Attach a harness to an agent';
10
50
  static examples = [
@@ -18,6 +58,23 @@ class AgentsAttachHarness extends base_command_1.BaseCommand {
18
58
  // local-daemon user — a dead end at the exact moment the id is needed.
19
59
  // `harnesses list` is the command that surfaces daemon-registered harness
20
60
  // _ids (see cli/src/commands/harnesses/list.ts).
61
+ /**
62
+ * Which positional is which, when a caller gave two.
63
+ *
64
+ * This is the ONLY command in the `agents` topic whose positional is not the
65
+ * agent — every neighbour is `agents <verb> <agent-id> [args]`, and the
66
+ * space's own Execution Map documents `attach-harness <agent> <harness>`. A
67
+ * caller writing that shape had their agent id silently accepted AS THE
68
+ * HARNESS and the real harness rejected with `Unexpected argument:
69
+ * 6a985ed2…` — an error that names the argument it does not want, never says
70
+ * what it does want, and does not notice that the value it accepted is
71
+ * obviously an `agent_…` id (OSK-7686).
72
+ *
73
+ * So both orders work, decided by the shape of the ids rather than by
74
+ * position. An explicit `--agent` still wins, and a conflict is refused
75
+ * rather than silently resolved — being attached to the wrong machine is the
76
+ * wrong way to find out which one was meant.
77
+ */
21
78
  static args = {
22
79
  harness: core_1.Args.string({
23
80
  description: 'Harness id. Use sbs_... for a Hosted Machine session, hosted-machine for the default Hosted Machine product, agent-worker for the cloud worker, or a harness id. ' +
@@ -25,6 +82,12 @@ class AgentsAttachHarness extends base_command_1.BaseCommand {
25
82
  required: true,
26
83
  ignoreStdin: true,
27
84
  }),
85
+ agent: core_1.Args.string({
86
+ description: 'Optional second positional, so `agents attach-harness <agent> <harness>` — the shape ' +
87
+ 'every other agents command uses — works. Equivalent to --agent.',
88
+ required: false,
89
+ ignoreStdin: true,
90
+ }),
28
91
  };
29
92
  static flags = {
30
93
  json: core_1.Flags.boolean({ description: 'Output the attachment result as JSON' }),
@@ -36,10 +99,23 @@ class AgentsAttachHarness extends base_command_1.BaseCommand {
36
99
  multiple: true,
37
100
  }),
38
101
  'advance-on': core_1.Flags.string({
39
- description: 'Failure category that permits the current target to advance to the next target.',
102
+ description: 'Failure category that permits EACH non-final target to advance to the next one. ' +
103
+ // The flag read as an explicit opt-in, so omitting it looked like
104
+ // opting into nothing — and the server was writing
105
+ // `["offline","unavailable"]` on a target the caller had explicitly
106
+ // pinned, with nothing in --help or in either command's output saying
107
+ // so (OSK-7669).
108
+ 'Defaults to `offline unavailable` when omitted and a next target exists; ' +
109
+ 'pass --strict-order for a chain no failure may advance. ' +
110
+ 'Applies to every non-final target, not only the one named here.',
40
111
  multiple: true,
41
112
  options: [...execution_target_1.EXECUTION_TARGET_ADVANCE_REASONS],
42
113
  }),
114
+ 'strict-order': core_1.Flags.boolean({
115
+ description: 'No failure category permits an advance. The declared next targets stay recorded but ' +
116
+ 'the chain never moves — previously only expressible by hand-writing executionPolicy ' +
117
+ 'through --from-json.',
118
+ }),
43
119
  'rebind-tasks': core_1.Flags.boolean({
44
120
  description: 'Publish the updated agent release and migrate dormant assigned task pins to it. Running, review, and completed tasks are never changed.',
45
121
  }),
@@ -47,9 +123,20 @@ class AgentsAttachHarness extends base_command_1.BaseCommand {
47
123
  async run() {
48
124
  this.requireAuth();
49
125
  const { args, flags } = await this.parse(AgentsAttachHarness);
126
+ const positional = resolveAttachPositionals(args.harness, args.agent, flags.agent);
127
+ if (positional.error) {
128
+ this.failWithCliError({
129
+ message: positional.error,
130
+ code: 'ATTACH_HARNESS_ARGUMENTS',
131
+ exit: 2,
132
+ retryable: false,
133
+ });
134
+ }
135
+ const harnessArg = positional.harness;
136
+ const agentArg = positional.agent;
50
137
  let agentIdentity;
51
138
  try {
52
- agentIdentity = await (0, agent_resolver_1.resolveAgentIdentity)(flags.agent);
139
+ agentIdentity = await (0, agent_resolver_1.resolveAgentIdentity)(flags.agent || agentArg);
53
140
  }
54
141
  catch (err) {
55
142
  const failure = (0, agent_resolver_1.agentResolutionFailure)(err);
@@ -66,8 +153,9 @@ class AgentsAttachHarness extends base_command_1.BaseCommand {
66
153
  let patch;
67
154
  try {
68
155
  patch = (0, execution_target_1.buildExecutionOrderPatch)({
69
- selectors: [args.harness, ...(flags['next-target'] || [])],
156
+ selectors: [harnessArg, ...(flags['next-target'] || [])],
70
157
  advanceOn: flags['advance-on'],
158
+ strict: flags['strict-order'],
71
159
  });
72
160
  }
73
161
  catch (err) {
@@ -110,6 +198,17 @@ class AgentsAttachHarness extends base_command_1.BaseCommand {
110
198
  this.log(`Agent resolved from ${agentIdentity.source}.`);
111
199
  }
112
200
  this.log(`Execution order: ${targets.map(executionTargetSelector).join(' → ')}`);
201
+ // Print the policy that was actually written. A default the operator did
202
+ // not ask for and cannot see is one they will not know they have — the
203
+ // only way to find it was to diff the returned JSON against what was typed
204
+ // (OSK-7669).
205
+ for (const [index, target] of targets.entries()) {
206
+ const advance = Array.isArray(target.advanceOn) ? target.advanceOn : [];
207
+ this.log(` ${index + 1}. ${executionTargetSelector(target)} — ` +
208
+ (advance.length > 0
209
+ ? `may advance on: ${advance.join(', ')}`
210
+ : 'strict: no failure permits an advance'));
211
+ }
113
212
  const migration = updated?.harnessAttachment;
114
213
  if (migration) {
115
214
  this.log(`Published release ${migration.releaseId || 'unknown'} and rebound ` +
@@ -1,5 +1,73 @@
1
1
  import { BaseCommand } from '../../base-command';
2
- import { type AgenticStreamResult } from '../../lib/agentic-stream';
2
+ import { type AgenticStreamResult, type ReconciledTerminal } from '../../lib/agentic-stream';
3
+ /**
4
+ * Exit code for a run the USER stopped watching, by pressing Ctrl-C.
5
+ *
6
+ * OSK-2944 established that exiting 1 on a lost stream made "the run failed"
7
+ * and "we lost the view of a live run" indistinguishable, and invited duplicate
8
+ * execution. So a detach gets its own non-zero code.
9
+ *
10
+ * It must be non-zero on EVERY output mode. The `--jsonl` branch used to
11
+ * `return` here, which leaves the exit code at 0, so a script driving the CLI
12
+ * read a detached — possibly already-failed — run as a success. That is the
13
+ * mode automation actually uses.
14
+ */
15
+ export declare const DETACH_EXIT_CODE = 130;
16
+ /**
17
+ * Exit code for a detach nobody asked for — the stream was lost, or could not
18
+ * be attached at all.
19
+ *
20
+ * 130 is the conventional "killed by SIGINT" code, and it was returned for a
21
+ * detach that no signal caused: a script reading it concludes the user pressed
22
+ * Ctrl-C, which is the opposite of what happened (OSK-7660). Reserving 130 for
23
+ * an actual interrupt and giving the unattended case its own code keeps both
24
+ * answers true.
25
+ */
26
+ export declare const STREAM_LOST_EXIT_CODE = 75;
27
+ /**
28
+ * What to say when the user pressed Ctrl-C and the run did not stop.
29
+ *
30
+ * A cancel is REQUESTED over the session; whether the harness honours it is not
31
+ * something this process can guarantee. Measured on a local harness, where the
32
+ * answer is checkable with `ps`: the CLI exited, and the shell and the `sleep
33
+ * 200` it had spawned were still alive at +10s, +26s and +53s — while the CLI
34
+ * said nothing about it at all (OSK-7733). Three things compound there: work
35
+ * the user asked to stop keeps consuming their machine and their vendor tokens;
36
+ * they are not told, so they will not go and kill it; and the record is left
37
+ * `unfinished: true` with no error, so the cancellation is invisible in history
38
+ * too.
39
+ *
40
+ * Silence is the one unacceptable option, because the user will believe they
41
+ * cancelled. This says what was asked, what is not guaranteed, and how to look.
42
+ */
43
+ export declare function interruptedDetachMessage(input: {
44
+ sessionId: string;
45
+ conversationId?: string | null;
46
+ }): string;
47
+ /**
48
+ * What the durable record says about a turn, read from its messages.
49
+ *
50
+ * The stream is not the only witness and must not be the only one consulted: a
51
+ * run refused during admission writes `error: true` plus the reason on the
52
+ * response message and never closes the session stream, so a joined subscriber
53
+ * waits forever for an event that will not come (OSK-7624, OSK-7635, OSK-7720,
54
+ * OSK-7735). Exported as a pure function so the mapping from a message row to a
55
+ * terminal verdict is testable without a socket.
56
+ *
57
+ * Returns null while the row is still in flight — the caller keeps waiting,
58
+ * because a long tool call is silence, not a failure.
59
+ */
60
+ export declare function reconcileTerminalFromMessages(messages: ReadonlyArray<Record<string, unknown>>, responseMessageId?: string): ReconciledTerminal | null;
61
+ /**
62
+ * How to look at a turn the CLI is no longer watching.
63
+ *
64
+ * NOT `skrr agents chat --conversation <id>`, which is what this used to print:
65
+ * that command requires the `agentId` argument and `--prompt`, so it exits with
66
+ * `Missing 1 required arg: agentId` and never reattaches. A recovery
67
+ * instruction that cannot be run is worse than none — it costs the reader a
68
+ * round trip to discover the product was wrong.
69
+ */
70
+ export declare function inspectTurnCommand(conversationId?: string | null): string;
3
71
  /**
4
72
  * A terminal run that produced no text is NOT a success to report silently.
5
73
  *