@skrr-ai/cli 0.1.47 → 0.1.49

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 (286) hide show
  1. package/README.md +1 -1
  2. package/dist/base-command.d.ts +18 -0
  3. package/dist/base-command.js +61 -1
  4. package/dist/commands/agent-worker.d.ts +12 -0
  5. package/dist/commands/agent-worker.js +140 -0
  6. package/dist/commands/agents/chat.d.ts +21 -0
  7. package/dist/commands/agents/chat.js +26 -9
  8. package/dist/commands/balance/usage/breakdown.d.ts +14 -0
  9. package/dist/commands/balance/usage/breakdown.js +68 -0
  10. package/dist/commands/balance/usage.js +24 -0
  11. package/dist/commands/commerce/entitlements/explain.d.ts +22 -0
  12. package/dist/commands/commerce/entitlements/explain.js +40 -0
  13. package/dist/commands/commerce/incidents/audit.d.ts +20 -0
  14. package/dist/commands/commerce/incidents/audit.js +37 -0
  15. package/dist/commands/commerce/incidents/list.d.ts +22 -0
  16. package/dist/commands/commerce/incidents/list.js +49 -0
  17. package/dist/commands/commerce/incidents/resolve.d.ts +23 -0
  18. package/dist/commands/commerce/incidents/resolve.js +45 -0
  19. package/dist/commands/commerce/incidents/retry.d.ts +22 -0
  20. package/dist/commands/commerce/incidents/retry.js +45 -0
  21. package/dist/commands/commerce/incidents/show.d.ts +13 -0
  22. package/dist/commands/commerce/incidents/show.js +30 -0
  23. package/dist/commands/commerce/offers/approve.d.ts +17 -0
  24. package/dist/commands/commerce/offers/approve.js +33 -0
  25. package/dist/commands/commerce/offers/create.d.ts +18 -0
  26. package/dist/commands/commerce/offers/create.js +34 -0
  27. package/dist/commands/commerce/offers/publish.d.ts +13 -0
  28. package/dist/commands/commerce/offers/publish.js +28 -0
  29. package/dist/commands/commerce/offers/retire.d.ts +17 -0
  30. package/dist/commands/commerce/offers/retire.js +32 -0
  31. package/dist/commands/commerce/offers/validate.d.ts +18 -0
  32. package/dist/commands/commerce/offers/validate.js +33 -0
  33. package/dist/commands/commerce/products/create.d.ts +10 -0
  34. package/dist/commands/commerce/products/create.js +25 -0
  35. package/dist/commands/commerce/promotions/redeem.d.ts +13 -0
  36. package/dist/commands/commerce/promotions/redeem.js +32 -0
  37. package/dist/commands/commerce/terms/accept.d.ts +18 -0
  38. package/dist/commands/commerce/terms/accept.js +39 -0
  39. package/dist/commands/commerce/terms/show.d.ts +10 -0
  40. package/dist/commands/commerce/terms/show.js +34 -0
  41. package/dist/commands/commerce/trials/conversion-preview.d.ts +18 -0
  42. package/dist/commands/commerce/trials/conversion-preview.js +39 -0
  43. package/dist/commands/commerce/trials/start.d.ts +23 -0
  44. package/dist/commands/commerce/trials/start.js +58 -0
  45. package/dist/commands/commitments/accounting.d.ts +39 -0
  46. package/dist/commands/commitments/accounting.js +116 -0
  47. package/dist/commands/commitments/action-history.d.ts +1 -0
  48. package/dist/commands/commitments/action-history.js +8 -1
  49. package/dist/commands/commitments/case.d.ts +1 -0
  50. package/dist/commands/commitments/case.js +19 -3
  51. package/dist/commands/commitments/cases.d.ts +1 -0
  52. package/dist/commands/commitments/cases.js +11 -1
  53. package/dist/commands/commitments/checks.d.ts +1 -0
  54. package/dist/commands/commitments/checks.js +5 -1
  55. package/dist/commands/commitments/cost.d.ts +62 -0
  56. package/dist/commands/commitments/cost.js +130 -0
  57. package/dist/commands/commitments/create.js +1 -1
  58. package/dist/commands/commitments/delete.d.ts +1 -0
  59. package/dist/commands/commitments/delete.js +56 -6
  60. package/dist/commands/commitments/feedback.js +9 -1
  61. package/dist/commands/commitments/handover.js +16 -0
  62. package/dist/commands/commitments/hypotheses.d.ts +1 -0
  63. package/dist/commands/commitments/hypotheses.js +17 -2
  64. package/dist/commands/commitments/links/list.js +4 -1
  65. package/dist/commands/commitments/liveness.d.ts +18 -0
  66. package/dist/commands/commitments/liveness.js +80 -0
  67. package/dist/commands/commitments/metrics.d.ts +1 -0
  68. package/dist/commands/commitments/metrics.js +8 -1
  69. package/dist/commands/commitments/next-tick.d.ts +39 -0
  70. package/dist/commands/commitments/next-tick.js +122 -0
  71. package/dist/commands/commitments/observations.d.ts +1 -0
  72. package/dist/commands/commitments/observations.js +19 -2
  73. package/dist/commands/commitments/pause.js +12 -0
  74. package/dist/commands/commitments/receipt.d.ts +2 -0
  75. package/dist/commands/commitments/receipt.js +16 -2
  76. package/dist/commands/commitments/remediation-proposal.js +6 -2
  77. package/dist/commands/commitments/remediation-proposals.js +5 -1
  78. package/dist/commands/commitments/restore.d.ts +25 -0
  79. package/dist/commands/commitments/restore.js +46 -0
  80. package/dist/commands/commitments/show.js +32 -0
  81. package/dist/commands/commitments/trigger-status.js +33 -0
  82. package/dist/commands/commitments/update.d.ts +1 -0
  83. package/dist/commands/commitments/update.js +31 -5
  84. package/dist/commands/commitments/wake-capabilities.d.ts +0 -1
  85. package/dist/commands/commitments/wake-capabilities.js +8 -4
  86. package/dist/commands/enterprise/budgets/create.d.ts +11 -0
  87. package/dist/commands/enterprise/budgets/create.js +27 -0
  88. package/dist/commands/enterprise/budgets/evaluate.d.ts +17 -0
  89. package/dist/commands/enterprise/budgets/evaluate.js +32 -0
  90. package/dist/commands/enterprise/budgets/publish.d.ts +14 -0
  91. package/dist/commands/enterprise/budgets/publish.js +30 -0
  92. package/dist/commands/enterprise/contracts/activate.d.ts +14 -0
  93. package/dist/commands/enterprise/contracts/activate.js +30 -0
  94. package/dist/commands/enterprise/contracts/create.d.ts +14 -0
  95. package/dist/commands/enterprise/contracts/create.js +32 -0
  96. package/dist/commands/enterprise/contracts/issue.d.ts +18 -0
  97. package/dist/commands/enterprise/contracts/issue.js +34 -0
  98. package/dist/commands/enterprise/domains/begin.d.ts +20 -0
  99. package/dist/commands/enterprise/domains/begin.js +39 -0
  100. package/dist/commands/enterprise/domains/verify.d.ts +14 -0
  101. package/dist/commands/enterprise/domains/verify.js +32 -0
  102. package/dist/commands/enterprise/external-config/activate.d.ts +22 -0
  103. package/dist/commands/enterprise/external-config/activate.js +49 -0
  104. package/dist/commands/enterprise/external-config/set.d.ts +25 -0
  105. package/dist/commands/enterprise/external-config/set.js +123 -0
  106. package/dist/commands/enterprise/external-config/show.d.ts +12 -0
  107. package/dist/commands/enterprise/external-config/show.js +39 -0
  108. package/dist/commands/enterprise/external-config/suspend.d.ts +13 -0
  109. package/dist/commands/enterprise/external-config/suspend.js +41 -0
  110. package/dist/commands/enterprise/finance/close-snapshot.d.ts +11 -0
  111. package/dist/commands/enterprise/finance/close-snapshot.js +28 -0
  112. package/dist/commands/enterprise/finance/record-document.d.ts +18 -0
  113. package/dist/commands/enterprise/finance/record-document.js +35 -0
  114. package/dist/commands/enterprise/profile.d.ts +20 -0
  115. package/dist/commands/enterprise/profile.js +38 -0
  116. package/dist/commands/login.d.ts +13 -0
  117. package/dist/commands/login.js +77 -0
  118. package/dist/commands/machines/dedicated/index.js +3 -0
  119. package/dist/commands/machines/dedicated/service/apply.d.ts +23 -0
  120. package/dist/commands/machines/dedicated/service/apply.js +99 -0
  121. package/dist/commands/machines/dedicated/service/approve.d.ts +23 -0
  122. package/dist/commands/machines/dedicated/service/approve.js +52 -0
  123. package/dist/commands/machines/dedicated/service/create.d.ts +55 -0
  124. package/dist/commands/machines/dedicated/service/create.js +222 -0
  125. package/dist/commands/machines/dedicated/service/edit.d.ts +30 -0
  126. package/dist/commands/machines/dedicated/service/edit.js +146 -0
  127. package/dist/commands/machines/dedicated/service/exec.d.ts +26 -0
  128. package/dist/commands/machines/dedicated/service/exec.js +92 -0
  129. package/dist/commands/machines/dedicated/service/export.d.ts +29 -0
  130. package/dist/commands/machines/dedicated/service/export.js +106 -0
  131. package/dist/commands/machines/dedicated/service/index.d.ts +14 -0
  132. package/dist/commands/machines/dedicated/service/index.js +49 -0
  133. package/dist/commands/machines/dedicated/service/logs.d.ts +33 -0
  134. package/dist/commands/machines/dedicated/service/logs.js +148 -0
  135. package/dist/commands/machines/dedicated/service/ls.d.ts +20 -0
  136. package/dist/commands/machines/dedicated/service/ls.js +80 -0
  137. package/dist/commands/machines/dedicated/service/restart.d.ts +14 -0
  138. package/dist/commands/machines/dedicated/service/restart.js +29 -0
  139. package/dist/commands/machines/dedicated/service/rm.d.ts +20 -0
  140. package/dist/commands/machines/dedicated/service/rm.js +33 -0
  141. package/dist/commands/machines/dedicated/service/secret/index.d.ts +14 -0
  142. package/dist/commands/machines/dedicated/service/secret/index.js +25 -0
  143. package/dist/commands/machines/dedicated/service/secret/rm.d.ts +22 -0
  144. package/dist/commands/machines/dedicated/service/secret/rm.js +54 -0
  145. package/dist/commands/machines/dedicated/service/secret/set.d.ts +22 -0
  146. package/dist/commands/machines/dedicated/service/secret/set.js +93 -0
  147. package/dist/commands/machines/dedicated/service/start.d.ts +14 -0
  148. package/dist/commands/machines/dedicated/service/start.js +29 -0
  149. package/dist/commands/machines/dedicated/service/status.d.ts +21 -0
  150. package/dist/commands/machines/dedicated/service/status.js +85 -0
  151. package/dist/commands/machines/dedicated/service/stop.d.ts +20 -0
  152. package/dist/commands/machines/dedicated/service/stop.js +35 -0
  153. package/dist/commands/machines/dedicated/service/top.d.ts +22 -0
  154. package/dist/commands/machines/dedicated/service/top.js +120 -0
  155. package/dist/commands/machines/dedicated/sign-in-status.d.ts +22 -0
  156. package/dist/commands/machines/dedicated/sign-in-status.js +79 -0
  157. package/dist/commands/machines/dedicated/ssh-config.d.ts +28 -0
  158. package/dist/commands/machines/dedicated/ssh-config.js +66 -0
  159. package/dist/commands/machines/dedicated/ssh-proxy.d.ts +22 -0
  160. package/dist/commands/machines/dedicated/ssh-proxy.js +62 -0
  161. package/dist/commands/machines/dedicated/ssh.d.ts +29 -0
  162. package/dist/commands/machines/dedicated/ssh.js +121 -0
  163. package/dist/commands/native/allow-all.d.ts +14 -0
  164. package/dist/commands/native/allow-all.js +25 -0
  165. package/dist/commands/native/allow.d.ts +24 -0
  166. package/dist/commands/native/allow.js +45 -0
  167. package/dist/commands/native/deny.d.ts +24 -0
  168. package/dist/commands/native/deny.js +43 -0
  169. package/dist/commands/native/disable.d.ts +17 -0
  170. package/dist/commands/native/disable.js +28 -0
  171. package/dist/commands/native/enable.d.ts +12 -0
  172. package/dist/commands/native/enable.js +29 -0
  173. package/dist/commands/native/list-apps.d.ts +19 -0
  174. package/dist/commands/native/list-apps.js +30 -0
  175. package/dist/commands/native/restrict-to.d.ts +22 -0
  176. package/dist/commands/native/restrict-to.js +41 -0
  177. package/dist/commands/native/status.d.ts +19 -0
  178. package/dist/commands/native/status.js +33 -0
  179. package/dist/commands/native.d.ts +39 -0
  180. package/dist/commands/native.js +76 -0
  181. package/dist/commands/service/index.d.ts +14 -0
  182. package/dist/commands/service/index.js +31 -0
  183. package/dist/commands/service/logs.d.ts +18 -0
  184. package/dist/commands/service/logs.js +53 -0
  185. package/dist/commands/service/ls.d.ts +13 -0
  186. package/dist/commands/service/ls.js +48 -0
  187. package/dist/commands/service/propose.d.ts +34 -0
  188. package/dist/commands/service/propose.js +113 -0
  189. package/dist/commands/service/status.d.ts +17 -0
  190. package/dist/commands/service/status.js +56 -0
  191. package/dist/commands/spaces/auto-executor/runs.d.ts +13 -0
  192. package/dist/commands/spaces/auto-executor/runs.js +56 -0
  193. package/dist/commands/store/governance/artifacts.d.ts +25 -0
  194. package/dist/commands/store/governance/artifacts.js +55 -0
  195. package/dist/commands/store/governance/assign.d.ts +16 -0
  196. package/dist/commands/store/governance/assign.js +54 -0
  197. package/dist/commands/store/governance/create-license.d.ts +18 -0
  198. package/dist/commands/store/governance/create-license.js +35 -0
  199. package/dist/commands/store/governance/install-plan.d.ts +25 -0
  200. package/dist/commands/store/governance/install-plan.js +56 -0
  201. package/dist/commands/store/governance/license-policy.d.ts +30 -0
  202. package/dist/commands/store/governance/license-policy.js +69 -0
  203. package/dist/commands/store/governance/policy.d.ts +25 -0
  204. package/dist/commands/store/governance/policy.js +65 -0
  205. package/dist/commands/store/governance/publish-release.d.ts +17 -0
  206. package/dist/commands/store/governance/publish-release.js +34 -0
  207. package/dist/commands/tasks/deliverable/add.d.ts +15 -0
  208. package/dist/commands/tasks/deliverable/add.js +174 -0
  209. package/dist/commands/tasks/deliverable/archive.d.ts +35 -0
  210. package/dist/commands/tasks/deliverable/archive.js +205 -0
  211. package/dist/commands/tasks/labels/detach.js +3 -0
  212. package/dist/commands/tasks/labels/suggest.d.ts +24 -0
  213. package/dist/commands/tasks/labels/suggest.js +69 -0
  214. package/dist/commands/tasks/list.d.ts +16 -2
  215. package/dist/commands/tasks/list.js +100 -24
  216. package/dist/commands/tasks/show.d.ts +23 -0
  217. package/dist/commands/tasks/show.js +51 -1
  218. package/dist/commands/wiki/rm.d.ts +22 -1
  219. package/dist/commands/wiki/rm.js +52 -3
  220. package/dist/lib/agentic-stream.js +10 -2
  221. package/dist/lib/balance.d.ts +6 -1
  222. package/dist/lib/balance.js +15 -0
  223. package/dist/lib/commerce-command.d.ts +48 -0
  224. package/dist/lib/commerce-command.js +70 -0
  225. package/dist/lib/commerce.d.ts +93 -0
  226. package/dist/lib/commerce.js +129 -0
  227. package/dist/lib/commitment-product.js +1 -1
  228. package/dist/lib/commitments.d.ts +202 -29
  229. package/dist/lib/commitments.js +300 -33
  230. package/dist/lib/daemon-installer.d.ts +6 -5
  231. package/dist/lib/daemon-installer.js +4 -17
  232. package/dist/lib/dedicated-lease-command.js +10 -0
  233. package/dist/lib/dedicated-machines.d.ts +37 -0
  234. package/dist/lib/dedicated-machines.js +47 -0
  235. package/dist/lib/dedicated-service-command.d.ts +60 -0
  236. package/dist/lib/dedicated-service-command.js +182 -0
  237. package/dist/lib/dedicated-service.d.ts +342 -0
  238. package/dist/lib/dedicated-service.js +741 -0
  239. package/dist/lib/dedicated-ssh.d.ts +136 -0
  240. package/dist/lib/dedicated-ssh.js +387 -0
  241. package/dist/lib/delegated-cli.js +51 -13
  242. package/dist/lib/enterprise-commerce.d.ts +67 -0
  243. package/dist/lib/enterprise-commerce.js +112 -0
  244. package/dist/lib/enterprise-external-configuration.d.ts +60 -0
  245. package/dist/lib/enterprise-external-configuration.js +58 -0
  246. package/dist/lib/first-party-harness.js +17 -3
  247. package/dist/lib/governed-store.d.ts +110 -0
  248. package/dist/lib/governed-store.js +79 -0
  249. package/dist/lib/guest-service-command.d.ts +16 -0
  250. package/dist/lib/guest-service-command.js +32 -0
  251. package/dist/lib/guest-service.d.ts +67 -0
  252. package/dist/lib/guest-service.js +112 -0
  253. package/dist/lib/prompt.d.ts +1 -0
  254. package/dist/lib/prompt.js +1 -0
  255. package/dist/lib/task-asset-upload.d.ts +20 -0
  256. package/dist/lib/task-asset-upload.js +30 -8
  257. package/dist/lib/task-extras.d.ts +23 -0
  258. package/dist/lib/task-extras.js +6 -0
  259. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonScopes.d.ts +9 -3
  260. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonScopes.js +10 -3
  261. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +1 -1
  262. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +1 -1
  263. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -2
  264. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +8 -5
  265. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.d.ts +16 -0
  266. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +21 -4
  267. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseManifest.d.ts +38 -0
  268. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseManifest.js +66 -1
  269. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +1 -1
  270. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +24 -2
  271. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonScopes.d.ts +9 -3
  272. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonScopes.js +10 -3
  273. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +1 -1
  274. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +1 -1
  275. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -2
  276. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -2
  277. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.d.ts +16 -0
  278. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +20 -4
  279. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseManifest.d.ts +38 -0
  280. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseManifest.js +64 -0
  281. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +1 -1
  282. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +24 -2
  283. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  284. package/dist/node_modules/@skrr-ai/data-provider/index.js +5060 -4827
  285. package/oclif.manifest.json +35194 -29157
  286. package/package.json +43 -1
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveCostWindow = resolveCostWindow;
4
+ exports.formatCostWindow = formatCostWindow;
5
+ const core_1 = require("@oclif/core");
6
+ const base_command_1 = require("../../base-command");
7
+ const commitments_1 = require("../../lib/commitments");
8
+ const DAY_MS = 24 * 60 * 60 * 1000;
9
+ const DEFAULT_WINDOW_DAYS = 7;
10
+ /**
11
+ * Resolve a cost window to UTC day boundaries.
12
+ *
13
+ * `CommitmentPeriodClose.readCostWindow` REFUSES a window that is not exactly
14
+ * on UTC day starts (`RangeError: cost windows must use UTC day boundaries`),
15
+ * because the closed daily metrics it sums are bucketed that way — a window
16
+ * that started mid-day would silently include or exclude a whole bucket. So the
17
+ * CLI snaps to the boundary itself rather than forwarding a wall-clock time and
18
+ * letting the operator meet a 500 they cannot act on.
19
+ *
20
+ * Snapping is a real change to what was asked for, so it is deliberately
21
+ * TRUNCATION in both directions — `--to 2026-09-19T18:00Z` reports through the
22
+ * start of the 19th, not the end of it. The command prints the window it
23
+ * actually used for that reason.
24
+ *
25
+ * The default window ends at TODAY's UTC day start, not now: today's metrics
26
+ * are not closed yet, so including the partial day would report a cost that
27
+ * changes when you re-run the same command.
28
+ */
29
+ function resolveCostWindow(input = {}, now = new Date()) {
30
+ const dayStart = (date) => new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
31
+ const parse = (value, flag) => {
32
+ const parsed = new Date(value);
33
+ if (Number.isNaN(parsed.getTime())) {
34
+ throw new Error(`${flag} is not a date: ${value}`);
35
+ }
36
+ return parsed;
37
+ };
38
+ const to = input.to ? dayStart(parse(input.to, '--to')) : dayStart(now);
39
+ const from = input.from
40
+ ? dayStart(parse(input.from, '--from'))
41
+ : new Date(to.getTime() - DEFAULT_WINDOW_DAYS * DAY_MS);
42
+ if (to.getTime() <= from.getTime()) {
43
+ throw new Error('--to must be a later UTC day than --from.');
44
+ }
45
+ return { from: from.toISOString(), to: to.toISOString() };
46
+ }
47
+ /**
48
+ * `skrr commitments cost <id>` — closed-period spend for one commitment.
49
+ *
50
+ * Money on this path has no other bound the operator can read: a Commitment's
51
+ * agent turns are `AgentOutcome` rows carrying no cost fields, so
52
+ * `spendLimitDailyUsd` cannot see them and `maxRunsPerDay` IS the spend control
53
+ * (see `autonomyEnvelope.maxRunsPerDay` in the API's own schema note). This is
54
+ * the read that says what those runs actually cost.
55
+ *
56
+ * `metrics` shows the daily rows; this sums the closed ones over a window and,
57
+ * critically, reports how much of the window was ATTRIBUTABLE.
58
+ */
59
+ class CommitmentsCost extends base_command_1.BaseCommand {
60
+ static description = "Sum a commitment's closed-period run cost over a UTC day window";
61
+ static examples = [
62
+ '<%= config.bin %> commitments cost obj_abc123',
63
+ '<%= config.bin %> commitments cost obj_abc123 --from 2026-09-01 --to 2026-09-15',
64
+ '<%= config.bin %> commitments cost obj_abc123 --json',
65
+ ];
66
+ static args = {
67
+ id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
68
+ };
69
+ static flags = {
70
+ from: core_1.Flags.string({
71
+ description: `Window start, truncated to its UTC day (default: ${DEFAULT_WINDOW_DAYS} days before --to)`,
72
+ }),
73
+ to: core_1.Flags.string({
74
+ description: "Window end, truncated to its UTC day (default: today's UTC day start)",
75
+ }),
76
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
77
+ };
78
+ async run() {
79
+ this.requireAuth();
80
+ const { args, flags } = await this.parse(CommitmentsCost);
81
+ let window;
82
+ try {
83
+ window = resolveCostWindow({ from: flags.from, to: flags.to });
84
+ }
85
+ catch (err) {
86
+ this.error(err.message, { exit: 1 });
87
+ }
88
+ let data;
89
+ try {
90
+ data = await commitments_1.commitmentApi.cost(args.id, window);
91
+ }
92
+ catch (err) {
93
+ this.handleApiError(err);
94
+ }
95
+ if (flags.json) {
96
+ this.log(JSON.stringify(data, null, 2));
97
+ return;
98
+ }
99
+ for (const line of formatCostWindow(data))
100
+ this.log(line);
101
+ }
102
+ }
103
+ exports.default = CommitmentsCost;
104
+ /**
105
+ * Pure renderer for the cost window.
106
+ *
107
+ * `costStatus` is printed BEFORE the dollar figure, on purpose. `partial` and
108
+ * `unavailable` mean some runs reported no cost attribution at all, so the
109
+ * total understates the spend; a reader who sees the number first has already
110
+ * formed a belief by the time they reach the caveat.
111
+ */
112
+ function formatCostWindow(data) {
113
+ const micros = Number(data.costUsdMicros || 0);
114
+ const runs = Number(data.runCount || 0);
115
+ const unattributed = Number(data.unavailableRunCount || 0);
116
+ const status = data.costStatus ?? 'not_applicable';
117
+ const caveat = {
118
+ reported: 'every run in the window reported a cost',
119
+ partial: 'some runs reported no cost — the total below is a FLOOR',
120
+ unavailable: 'no run in the window reported a cost — the total below is meaningless',
121
+ not_applicable: 'no closed runs in the window',
122
+ };
123
+ return [
124
+ `Cost for ${data.commitmentId ?? '-'}`,
125
+ `Window: ${data.from ?? '-'} → ${data.to ?? '-'} (${Number(data.dayCount || 0)} closed day(s))`,
126
+ `Attribution: ${status} — ${caveat[status] ?? 'unrecognized cost status'}`,
127
+ `Cost: $${(micros / 1_000_000).toFixed(4)}`,
128
+ `Runs: ${runs} (${Number(data.reportedRunCount || 0)} with cost, ${unattributed} without)`,
129
+ ];
130
+ }
@@ -197,7 +197,7 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
197
197
  agent: core_1.Flags.string({ description: 'Agent that owns and watches this commitment (required)' }),
198
198
  kind: core_1.Flags.string({
199
199
  description: 'Lifecycle kind: achieve is terminal-capable; maintain is perpetual',
200
- options: ['achieve', 'maintain'],
200
+ options: [...commitments_1.COMMITMENT_KIND_VALUES],
201
201
  }),
202
202
  title: core_1.Flags.string({ description: 'Short commitment title (required)' }),
203
203
  outcome: core_1.Flags.string({
@@ -22,6 +22,7 @@ export default class CommitmentsDelete extends BaseCommand {
22
22
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
23
  reason: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
24
  yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ 'stop-open-work': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
26
  };
26
27
  run(): Promise<void>;
27
28
  }
@@ -30,16 +30,43 @@ class CommitmentsDelete extends base_command_1.BaseCommand {
30
30
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
31
31
  reason: core_1.Flags.string({ description: 'Why it was deleted (recorded on the boundary ledger)' }),
32
32
  yes: core_1.Flags.boolean({ char: 'y', description: 'Skip confirmation prompt' }),
33
+ 'stop-open-work': core_1.Flags.boolean({
34
+ description: 'Cancel the open Tasks this Commitment produced. Without it they KEEP RUNNING — deleting the producer has never stopped the product.',
35
+ allowNo: true,
36
+ }),
33
37
  };
34
38
  async run() {
35
39
  this.requireAuth();
36
40
  const { args, flags } = await this.parse(CommitmentsDelete);
37
- // The repo's own destructive-confirm helper rather than a second prompt:
38
- // it also refuses to hang on a non-TTY, exiting 7 with an instruction to
39
- // pass --yes, which is what makes this safe to call from a script.
41
+ let preview = null;
42
+ try {
43
+ preview = (await commitments_1.commitmentApi.deletionPreview(args.id));
44
+ }
45
+ catch {
46
+ // An older server has no preview route. Proceed — the delete itself
47
+ // still refuses to guess when there is open work.
48
+ }
49
+ // The API refuses to delete an active Commitment, and rightly so. But a
50
+ // deliberate step is not the same as a dead end: the person has already
51
+ // said what they want, so the step becomes part of THIS gesture rather
52
+ // than a second command they have to go and find. Same rule the web
53
+ // dialog applies, so the two surfaces cannot drift.
54
+ const mustPauseFirst = preview?.requiresStopFirst === true;
55
+ const openTasks = Number(preview?.openTaskCount || 0);
56
+ if (openTasks > 0 && flags['stop-open-work'] === undefined) {
57
+ this.error(`${args.id} has ${openTasks} open task(s), and deleting it does NOT stop them.\n` +
58
+ ` skrr commitments delete ${args.id} --stop-open-work # cancel them too\n` +
59
+ ` skrr commitments delete ${args.id} --no-stop-open-work # leave them running`, { exit: 1 });
60
+ }
61
+ const fate = openTasks === 0
62
+ ? 'Its checks, runs and cases stay readable.'
63
+ : flags['stop-open-work']
64
+ ? `Its ${openTasks} open task(s) will be CANCELLED.`
65
+ : `Its ${openTasks} open task(s) will KEEP RUNNING.`;
66
+ const verb = mustPauseFirst ? 'Pause and delete' : 'Delete';
40
67
  let confirmed;
41
68
  try {
42
- confirmed = await (0, prompt_1.confirmDestructive)(`Delete commitment ${args.id}? Its checks, runs and cases stay readable.`, flags.yes);
69
+ confirmed = await (0, prompt_1.confirmDestructive)(`${verb} commitment ${args.id}? ${fate}`, flags.yes);
43
70
  }
44
71
  catch (err) {
45
72
  if (err.exit === 7) {
@@ -51,9 +78,23 @@ class CommitmentsDelete extends base_command_1.BaseCommand {
51
78
  this.log('Cancelled.');
52
79
  return;
53
80
  }
81
+ if (mustPauseFirst) {
82
+ try {
83
+ await commitments_1.commitmentApi.pause(args.id);
84
+ this.log(`Paused ${args.id}.`);
85
+ }
86
+ catch (err) {
87
+ // Report WHICH half failed. "Could not delete" would be wrong and
88
+ // would send the reader looking in the wrong place.
89
+ this.log(`Could not pause ${args.id} — it was not deleted.`);
90
+ this.handleApiError(err);
91
+ }
92
+ }
54
93
  let result;
55
94
  try {
56
- result = await commitments_1.commitmentApi.remove(args.id, flags.reason);
95
+ result = await commitments_1.commitmentApi.remove(args.id, flags.reason, {
96
+ stopOpenWork: flags['stop-open-work'],
97
+ });
57
98
  }
58
99
  catch (err) {
59
100
  this.handleApiError(err);
@@ -66,7 +107,16 @@ class CommitmentsDelete extends base_command_1.BaseCommand {
66
107
  this.log(`Deleted ${String(commitment.id ?? args.id)}.`);
67
108
  if (commitment.title)
68
109
  this.log(` ${String(commitment.title)}`);
69
- this.log(' Its checks, runs, cases and linked Tasks remain readable.');
110
+ const work = (result.work ?? {});
111
+ // Lead with what still ACTS. What remains readable is reassurance; what
112
+ // remains running is the fact the reader needs.
113
+ if (work.openTasksStopped)
114
+ this.log(` ${work.openTasksStopped} open task(s) cancelled.`);
115
+ if (work.openTasksLeftRunning) {
116
+ this.log(` ${work.openTasksLeftRunning} open task(s) are STILL RUNNING.`);
117
+ }
118
+ this.log(' Its checks, runs and cases remain readable.');
119
+ this.log(` Restore it with: skrr commitments restore ${String(commitment.id ?? args.id)}`);
70
120
  }
71
121
  }
72
122
  exports.default = CommitmentsDelete;
@@ -53,7 +53,15 @@ class CommitmentsFeedback extends base_command_1.BaseCommand {
53
53
  this.log(JSON.stringify(result, null, 2));
54
54
  return;
55
55
  }
56
- this.log(`Recorded "${flags.kind}" on ${args.checkId}. Reflection will weigh it next cycle.`);
56
+ // A contradictory click used to acknowledge identically to a fresh verdict
57
+ // (OSK-10955) — the server reports what already stands on the check, and
58
+ // this copy keeps it visible.
59
+ const prior = Array.isArray(result?.priorFeedbackKinds)
60
+ ? result.priorFeedbackKinds.filter(Boolean)
61
+ : [];
62
+ const priorClause = prior.length ? ` Earlier feedback on this check: ${prior.join(', ')}.` : '';
63
+ const reaffirmClause = result?.reaffirmed ? ' (reaffirmed — same verdict as before)' : '';
64
+ this.log(`Recorded "${flags.kind}" on ${args.checkId}.${reaffirmClause} Reflection will weigh it next cycle.${priorClause}`);
57
65
  }
58
66
  }
59
67
  exports.default = CommitmentsFeedback;
@@ -78,6 +78,22 @@ class CommitmentsHandover extends base_command_1.BaseCommand {
78
78
  }
79
79
  const agentLabel = target.name ? `${target.name} (${target.id})` : target.id;
80
80
  this.log(`Handed commitment ${args.id} over to ${agentLabel}`);
81
+ // The transition summary — without it a mid-check/mid-run handover reads
82
+ // as a silent success and the operator cannot tell whether in-flight work
83
+ // kept the old executor or was fenced.
84
+ const inFlight = result?.inFlight;
85
+ if (inFlight) {
86
+ const claimed = Number(inFlight.claimedRuns) || 0;
87
+ const fencedRuns = Number(inFlight.fencedRuns) || 0;
88
+ const fencedChecks = Number(inFlight.fencedChecks) || 0;
89
+ if (claimed > 0) {
90
+ this.log(` ${claimed} claimed run(s) keep the old executor until they finish`);
91
+ }
92
+ if (fencedRuns > 0 || fencedChecks > 0) {
93
+ this.log(` fenced ${fencedRuns} unclaimed run(s) and ${fencedChecks} in-flight check(s) — cancelled before start`);
94
+ }
95
+ this.log(` the new executor takes over from the next wake`);
96
+ }
81
97
  // The audit entry the server appended — echo it so "from whom" is answered
82
98
  // without a second call. Absent on a server that predates the trail.
83
99
  const commitment = result?.commitment ??
@@ -22,6 +22,7 @@ export default class CommitmentsHypotheses extends BaseCommand {
22
22
  limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
23
  status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
24
  'investigation-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ cursor: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
26
  };
26
27
  run(): Promise<void>;
27
28
  }
@@ -35,6 +35,9 @@ class CommitmentsHypotheses extends base_command_1.BaseCommand {
35
35
  'investigation-key': core_1.Flags.string({
36
36
  description: 'Narrow to one investigation (an open loop subject key)',
37
37
  }),
38
+ cursor: core_1.Flags.string({
39
+ description: 'Continue from the next_cursor emitted by a previous page',
40
+ }),
38
41
  };
39
42
  async run() {
40
43
  this.requireAuth();
@@ -45,6 +48,7 @@ class CommitmentsHypotheses extends base_command_1.BaseCommand {
45
48
  limit: flags.limit,
46
49
  status: flags.status,
47
50
  investigationKey: flags['investigation-key'],
51
+ cursor: flags.cursor,
48
52
  });
49
53
  }
50
54
  catch (err) {
@@ -52,9 +56,20 @@ class CommitmentsHypotheses extends base_command_1.BaseCommand {
52
56
  }
53
57
  if (flags.json) {
54
58
  this.log(JSON.stringify(response, null, 2));
55
- return;
56
59
  }
57
- (0, commitments_1.renderCommitmentHypotheses)(response, (line) => this.log(line));
60
+ else {
61
+ // A filtered-out list is not an empty ledger — say which filter did it
62
+ // (OSK-10953).
63
+ const filters = [
64
+ flags.status ? `--status ${flags.status}` : null,
65
+ flags['investigation-key'] ? `--investigation-key ${flags['investigation-key']}` : null,
66
+ ].filter(Boolean);
67
+ const emptyMessage = filters.length
68
+ ? `No hypotheses match ${filters.join(' ')}.`
69
+ : 'No hypotheses recorded.';
70
+ (0, commitments_1.renderCommitmentHypotheses)(response, (line) => this.log(line), { emptyMessage });
71
+ }
72
+ (0, commitments_1.renderListPageHint)(response, (line) => this.log(line));
58
73
  }
59
74
  }
60
75
  exports.default = CommitmentsHypotheses;
@@ -34,7 +34,10 @@ class CommitmentsLinksList extends base_command_1.BaseCommand {
34
34
  return;
35
35
  }
36
36
  for (const link of links) {
37
- this.log(`${link.id} ${link.targetType}:${link.target?.title || link.targetId} [${link.roles.join(', ')}] ${link.status}`);
37
+ // `origin: 'goal_lineage'` rows are derived from `goal.commitmentId`, not
38
+ // a work-link row — `links detach` cannot remove them (OSK-10960).
39
+ const provenance = link.origin === 'goal_lineage' ? ' (via goals link — remove with goals unlink)' : '';
40
+ this.log(`${link.id} ${link.targetType}:${link.target?.title || link.targetId} [${link.roles.join(', ')}] ${link.status}${provenance}`);
38
41
  }
39
42
  }
40
43
  }
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr commitments liveness` — is the liveness witness itself alive?
4
+ *
5
+ * Per-commitment health is on `show`; this is the SWEEP's health — the marker
6
+ * the reconciler writes each pass. A stale sweep means every per-commitment
7
+ * verdict is also stale, which no single-commitment surface can tell you
8
+ * (OSK-10958). `healthy: false` or a null `lastSweepAt` means the witness is
9
+ * not running, not that commitments are fine.
10
+ */
11
+ export default class CommitmentsLiveness extends BaseCommand {
12
+ static description: string;
13
+ static examples: string[];
14
+ static flags: {
15
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ };
17
+ run(): Promise<void>;
18
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_command_1 = require("../../base-command");
5
+ const commitments_1 = require("../../lib/commitments");
6
+ /**
7
+ * `skrr commitments liveness` — is the liveness witness itself alive?
8
+ *
9
+ * Per-commitment health is on `show`; this is the SWEEP's health — the marker
10
+ * the reconciler writes each pass. A stale sweep means every per-commitment
11
+ * verdict is also stale, which no single-commitment surface can tell you
12
+ * (OSK-10958). `healthy: false` or a null `lastSweepAt` means the witness is
13
+ * not running, not that commitments are fine.
14
+ */
15
+ class CommitmentsLiveness extends base_command_1.BaseCommand {
16
+ static description = 'Show liveness sweep health — when the witness last ran and what it saw';
17
+ static examples = [
18
+ '<%= config.bin %> commitments liveness',
19
+ '<%= config.bin %> commitments liveness --json',
20
+ ];
21
+ static flags = {
22
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
23
+ };
24
+ async run() {
25
+ this.requireAuth();
26
+ const { flags } = await this.parse(CommitmentsLiveness);
27
+ let health;
28
+ try {
29
+ health = (await commitments_1.commitmentApi.livenessSweep());
30
+ }
31
+ catch (err) {
32
+ this.handleApiError(err);
33
+ }
34
+ if (flags.json) {
35
+ this.log(JSON.stringify(health, null, 2));
36
+ return;
37
+ }
38
+ for (const line of formatSweepHealth(health))
39
+ this.log(line);
40
+ }
41
+ }
42
+ exports.default = CommitmentsLiveness;
43
+ function formatSweepHealth(health) {
44
+ const lines = [];
45
+ if (!health.lastSweepAt) {
46
+ lines.push('Liveness sweep: NO SWEEP RECORDED');
47
+ lines.push(' The reconciler has never completed a sweep on this deployment —');
48
+ lines.push(' every per-commitment health verdict is unverified.');
49
+ return lines;
50
+ }
51
+ const age = health.sweepAgeSeconds ?? 0;
52
+ const status = health.healthy ? 'healthy' : 'STALE';
53
+ lines.push(`Liveness sweep: ${status} (${formatAge(age)} old)`);
54
+ lines.push(` last sweep: ${health.lastSweepAt}`);
55
+ const tick = health.lastTick;
56
+ if (tick) {
57
+ lines.push(` last tick: scanned ${tick.scanned ?? 0}` +
58
+ ` | on_track ${tick.onTrack ?? 0}` +
59
+ ` | stalled ${tick.stalled ?? 0}` +
60
+ ` | unknown ${tick.unknown ?? 0}` +
61
+ ` | unjudged ${tick.unjudged ?? 0}` +
62
+ ` | alerted ${tick.alerted ?? 0}` +
63
+ ` | errors ${tick.errors ?? 0}`);
64
+ }
65
+ if (health.cursor?.id) {
66
+ lines.push(` cursor: ${health.cursor.id}${health.cursor.at ? ` @ ${health.cursor.at}` : ''}`);
67
+ }
68
+ return lines;
69
+ }
70
+ function formatAge(seconds) {
71
+ if (seconds < 90)
72
+ return `${seconds}s`;
73
+ const minutes = Math.floor(seconds / 60);
74
+ if (minutes < 90)
75
+ return `${minutes}m`;
76
+ const hours = Math.floor(minutes / 60);
77
+ if (hours < 48)
78
+ return `${hours}h ${minutes % 60}m`;
79
+ return `${Math.floor(hours / 24)}d ${hours % 24}h`;
80
+ }
@@ -15,6 +15,7 @@ export default class CommitmentsMetrics extends BaseCommand {
15
15
  static flags: {
16
16
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
17
  limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ cursor: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
19
  };
19
20
  run(): Promise<void>;
20
21
  }
@@ -22,13 +22,19 @@ class CommitmentsMetrics extends base_command_1.BaseCommand {
22
22
  static flags = {
23
23
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
24
24
  limit: core_1.Flags.integer({ description: 'Days to include', min: 1, max: 200 }),
25
+ cursor: core_1.Flags.string({
26
+ description: 'Continue from the next_cursor emitted by a previous page',
27
+ }),
25
28
  };
26
29
  async run() {
27
30
  this.requireAuth();
28
31
  const { args, flags } = await this.parse(CommitmentsMetrics);
29
32
  let response;
30
33
  try {
31
- response = await commitments_1.commitmentApi.dailyMetrics(args.commitmentId, flags.limit);
34
+ response = await commitments_1.commitmentApi.dailyMetrics(args.commitmentId, {
35
+ limit: flags.limit,
36
+ cursor: flags.cursor,
37
+ });
32
38
  }
33
39
  catch (err) {
34
40
  this.handleApiError(err);
@@ -38,6 +44,7 @@ class CommitmentsMetrics extends base_command_1.BaseCommand {
38
44
  return;
39
45
  }
40
46
  (0, commitments_1.renderCommitmentMetrics)(response, (line) => this.log(line));
47
+ (0, commitments_1.renderListPageHint)(response, (line) => this.log(line));
41
48
  }
42
49
  }
43
50
  exports.default = CommitmentsMetrics;
@@ -0,0 +1,39 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ import { type CommitmentNextTickProjection } from '../../lib/commitments';
3
+ /**
4
+ * `skrr commitments next-tick <id>` — what the NEXT check would decide.
5
+ *
6
+ * Every other read on a commitment is retrospective: `checks` says what it
7
+ * decided, `receipt` says what one wake produced, `trigger-status` says when it
8
+ * will fire again. None of them answers the question an operator actually has
9
+ * when a commitment is about to nudge somebody — "what is it about to do, and
10
+ * on what grounds" — and the only way to find out used to be to run a real
11
+ * check, which changes the thing you were trying to observe.
12
+ *
13
+ * The server's projection stops at the DecisionEnvelope → Arbiter boundary: no
14
+ * Check row, no budget debit, no delivery gate, no contract write. That is what
15
+ * makes this safe to ask from a terminal, and it is why the envelope is only
16
+ * printed under `--json` — the decision and its policy trail are the answer;
17
+ * the envelope is the evidence behind it.
18
+ */
19
+ export default class CommitmentsNextTick extends BaseCommand {
20
+ static description: string;
21
+ static examples: string[];
22
+ static args: {
23
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
24
+ };
25
+ static flags: {
26
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
+ };
28
+ run(): Promise<void>;
29
+ }
30
+ /**
31
+ * Pure renderer for the next-tick projection.
32
+ *
33
+ * Kept separate from the command for the same reason `formatTriggerStatus` is:
34
+ * it can be unit-tested without a live API, and the command body stays a thin
35
+ * fetch + print. Defensive about every field — this is a projection of a
36
+ * versioned envelope, so a missing key is a shape change, not a reason to throw
37
+ * in front of somebody debugging a live commitment.
38
+ */
39
+ export declare function formatNextTick(projection: CommitmentNextTickProjection): string[];
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatNextTick = formatNextTick;
4
+ const core_1 = require("@oclif/core");
5
+ const base_command_1 = require("../../base-command");
6
+ const commitments_1 = require("../../lib/commitments");
7
+ /**
8
+ * `skrr commitments next-tick <id>` — what the NEXT check would decide.
9
+ *
10
+ * Every other read on a commitment is retrospective: `checks` says what it
11
+ * decided, `receipt` says what one wake produced, `trigger-status` says when it
12
+ * will fire again. None of them answers the question an operator actually has
13
+ * when a commitment is about to nudge somebody — "what is it about to do, and
14
+ * on what grounds" — and the only way to find out used to be to run a real
15
+ * check, which changes the thing you were trying to observe.
16
+ *
17
+ * The server's projection stops at the DecisionEnvelope → Arbiter boundary: no
18
+ * Check row, no budget debit, no delivery gate, no contract write. That is what
19
+ * makes this safe to ask from a terminal, and it is why the envelope is only
20
+ * printed under `--json` — the decision and its policy trail are the answer;
21
+ * the envelope is the evidence behind it.
22
+ */
23
+ class CommitmentsNextTick extends base_command_1.BaseCommand {
24
+ static description = 'Preview what the next check would decide, without running one (no budget, no side effects)';
25
+ static examples = [
26
+ '<%= config.bin %> commitments next-tick obj_abc123',
27
+ '<%= config.bin %> commitments next-tick obj_abc123 --json',
28
+ ];
29
+ static args = {
30
+ id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
31
+ };
32
+ static flags = {
33
+ json: core_1.Flags.boolean({
34
+ description: 'Output the full projection, including the DecisionEnvelope',
35
+ }),
36
+ };
37
+ async run() {
38
+ this.requireAuth();
39
+ const { args, flags } = await this.parse(CommitmentsNextTick);
40
+ let projection;
41
+ try {
42
+ projection = await commitments_1.commitmentApi.nextTick(args.id);
43
+ }
44
+ catch (err) {
45
+ this.handleApiError(err);
46
+ }
47
+ if (flags.json) {
48
+ this.log(JSON.stringify(projection, null, 2));
49
+ return;
50
+ }
51
+ for (const line of formatNextTick(projection))
52
+ this.log(line);
53
+ }
54
+ }
55
+ exports.default = CommitmentsNextTick;
56
+ /**
57
+ * Pure renderer for the next-tick projection.
58
+ *
59
+ * Kept separate from the command for the same reason `formatTriggerStatus` is:
60
+ * it can be unit-tested without a live API, and the command body stays a thin
61
+ * fetch + print. Defensive about every field — this is a projection of a
62
+ * versioned envelope, so a missing key is a shape change, not a reason to throw
63
+ * in front of somebody debugging a live commitment.
64
+ */
65
+ function formatNextTick(projection) {
66
+ const decision = projection.decision ?? {};
67
+ const lines = [
68
+ `Next tick for ${projection.commitmentId ?? '-'} (projected ${projection.projectedAt ?? '-'})`,
69
+ '',
70
+ // The header states what this did NOT do, because the value of the command
71
+ // is entirely in that: a reader who thinks a check just ran will misread
72
+ // every number on the commitment afterwards.
73
+ 'Projection only — no check was recorded, no budget spent, no action routed.',
74
+ '',
75
+ `Posture: ${decision.posture ?? '-'}`,
76
+ `Health: ${decision.health ?? '-'}`,
77
+ `Risk: ${decision.riskLevel ?? '-'}`,
78
+ `Confidence: ${decision.confidence ?? '-'}`,
79
+ ];
80
+ if (decision.whyNow)
81
+ lines.push(`Why now: ${decision.whyNow}`);
82
+ // OSK-11433 — the projected envelope health is a delta read; the stored
83
+ // liveness verdict is the independent witness. Print the witness too so a
84
+ // dispatch-refusal loop can't hide behind an on_track projection.
85
+ if (projection.health || projection.liveness) {
86
+ const census = projection.liveness?.terminalDispositionCensus;
87
+ const detail = [
88
+ projection.liveness?.diagnosisKind,
89
+ census?.workFailures
90
+ ? `${census.workFailures} recent run failure${census.workFailures === 1 ? '' : 's'}`
91
+ : null,
92
+ ]
93
+ .filter(Boolean)
94
+ .join(', ');
95
+ lines.push(`Liveness: ${projection.health ?? '-'}` + (detail ? ` (${detail})` : ''));
96
+ }
97
+ const actions = decision.actionPlan ?? [];
98
+ lines.push('');
99
+ if (actions.length === 0) {
100
+ lines.push('Action plan: none');
101
+ }
102
+ else {
103
+ lines.push(`Action plan (${actions.length}):`);
104
+ for (const action of actions) {
105
+ const label = action.summary || action.title || '';
106
+ lines.push(` - ${action.kind || action.type || 'action'}${label ? `: ${label}` : ''}`);
107
+ }
108
+ }
109
+ const trace = decision.policyTrace ?? [];
110
+ lines.push('');
111
+ if (trace.length === 0) {
112
+ lines.push('Policy trace: none');
113
+ }
114
+ else {
115
+ lines.push(`Policy trace (${trace.length}):`);
116
+ for (const entry of trace) {
117
+ lines.push(` ${entry.rule ?? '-'} → ${entry.decision ?? '-'}` +
118
+ (entry.reason ? ` — ${entry.reason}` : ''));
119
+ }
120
+ }
121
+ return lines;
122
+ }
@@ -26,6 +26,7 @@ export default class CommitmentsObservations extends BaseCommand {
26
26
  'declared-only': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
27
  'changed-only': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
28
28
  since: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
29
+ cursor: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
29
30
  };
30
31
  run(): Promise<void>;
31
32
  }