@wjarka/cezarion 0.14.8 → 0.14.9-dev.1004

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 (274) hide show
  1. package/README.md +129 -2
  2. package/dist/application-update/bin-recovery.d.ts +5 -0
  3. package/dist/application-update/bin-recovery.js +96 -0
  4. package/dist/application-update/bin-recovery.js.map +1 -0
  5. package/dist/application-update/discovery.d.ts +22 -0
  6. package/dist/application-update/discovery.js +91 -0
  7. package/dist/application-update/discovery.js.map +1 -0
  8. package/dist/application-update/helper.d.ts +57 -0
  9. package/dist/application-update/helper.js +374 -0
  10. package/dist/application-update/helper.js.map +1 -0
  11. package/dist/application-update/launcher.d.ts +8 -0
  12. package/dist/application-update/launcher.js +53 -0
  13. package/dist/application-update/launcher.js.map +1 -0
  14. package/dist/application-update/lock.d.ts +4 -0
  15. package/dist/application-update/lock.js +70 -0
  16. package/dist/application-update/lock.js.map +1 -0
  17. package/dist/application-update/npm-process.d.ts +17 -0
  18. package/dist/application-update/npm-process.js +133 -0
  19. package/dist/application-update/npm-process.js.map +1 -0
  20. package/dist/application-update/service.d.ts +69 -0
  21. package/dist/application-update/service.js +456 -0
  22. package/dist/application-update/service.js.map +1 -0
  23. package/dist/artifacts/cli.d.ts +1 -0
  24. package/dist/artifacts/cli.js +32 -0
  25. package/dist/artifacts/cli.js.map +1 -0
  26. package/dist/artifacts/lifecycle.d.ts +4 -0
  27. package/dist/artifacts/lifecycle.js +42 -0
  28. package/dist/artifacts/lifecycle.js.map +1 -0
  29. package/dist/artifacts/resolve.d.ts +18 -0
  30. package/dist/artifacts/resolve.js +102 -0
  31. package/dist/artifacts/resolve.js.map +1 -0
  32. package/dist/artifacts/store.d.ts +8 -0
  33. package/dist/artifacts/store.js +323 -0
  34. package/dist/artifacts/store.js.map +1 -0
  35. package/dist/automations/scheduler.d.ts +6 -0
  36. package/dist/automations/scheduler.js +45 -17
  37. package/dist/automations/scheduler.js.map +1 -1
  38. package/dist/automations/store.d.ts +12 -4
  39. package/dist/automations/store.js +199 -22
  40. package/dist/automations/store.js.map +1 -1
  41. package/dist/automations/types.d.ts +2 -0
  42. package/dist/automations/types.js +1 -0
  43. package/dist/automations/types.js.map +1 -1
  44. package/dist/ci-wait/mcp.d.ts +3 -0
  45. package/dist/ci-wait/mcp.js +14 -3
  46. package/dist/ci-wait/mcp.js.map +1 -1
  47. package/dist/contract/application-update.d.ts +32 -0
  48. package/dist/contract/artifacts.d.ts +83 -0
  49. package/dist/contract/ask-schema.d.ts +32 -0
  50. package/dist/contract/ask.d.ts +2 -32
  51. package/dist/contract/automations.d.ts +6 -0
  52. package/dist/contract/conversations.d.ts +165 -0
  53. package/dist/contract/delegation.d.ts +68 -0
  54. package/dist/contract/discovery.d.ts +134 -0
  55. package/dist/contract/events.d.ts +49 -0
  56. package/dist/contract/health.d.ts +12 -0
  57. package/dist/contract/index.d.ts +3 -0
  58. package/dist/contract/index.js +1654 -1454
  59. package/dist/contract/projects.d.ts +40 -0
  60. package/dist/contract/runs.d.ts +186 -0
  61. package/dist/contract/skills.d.ts +33 -0
  62. package/dist/core/agent-runner.d.ts +33 -4
  63. package/dist/core/agent-runner.js +5 -0
  64. package/dist/core/agent-runner.js.map +1 -1
  65. package/dist/core/claude-cli-runner.d.ts +6 -12
  66. package/dist/core/claude-cli-runner.js +90 -20
  67. package/dist/core/claude-cli-runner.js.map +1 -1
  68. package/dist/core/codex-app-server-runner.d.ts +2 -1
  69. package/dist/core/codex-app-server-runner.js +327 -92
  70. package/dist/core/codex-app-server-runner.js.map +1 -1
  71. package/dist/core/codex-app-server-transport.d.ts +13 -1
  72. package/dist/core/codex-app-server-transport.js +58 -17
  73. package/dist/core/codex-app-server-transport.js.map +1 -1
  74. package/dist/core/cursor-acp-runner.d.ts +6 -1
  75. package/dist/core/cursor-acp-runner.js +162 -26
  76. package/dist/core/cursor-acp-runner.js.map +1 -1
  77. package/dist/core/cursor-provider-error.d.ts +3 -0
  78. package/dist/core/cursor-provider-error.js +16 -1
  79. package/dist/core/cursor-provider-error.js.map +1 -1
  80. package/dist/core/input-submissions.d.ts +14 -0
  81. package/dist/core/input-submissions.js +26 -0
  82. package/dist/core/input-submissions.js.map +1 -0
  83. package/dist/core/opencode-server-runner.d.ts +4 -1
  84. package/dist/core/opencode-server-runner.js +156 -26
  85. package/dist/core/opencode-server-runner.js.map +1 -1
  86. package/dist/core/pi-runner.d.ts +2 -1
  87. package/dist/core/pi-runner.js +88 -10
  88. package/dist/core/pi-runner.js.map +1 -1
  89. package/dist/core/provider-auth.d.ts +99 -1
  90. package/dist/core/provider-auth.js +203 -2
  91. package/dist/core/provider-auth.js.map +1 -1
  92. package/dist/delegation/cli.d.ts +1 -0
  93. package/dist/delegation/cli.js +103 -7
  94. package/dist/delegation/cli.js.map +1 -1
  95. package/dist/delegation/conversations.js +13 -5
  96. package/dist/delegation/conversations.js.map +1 -1
  97. package/dist/delegation/input.d.ts +2 -1
  98. package/dist/delegation/input.js +6 -1
  99. package/dist/delegation/input.js.map +1 -1
  100. package/dist/delegation/policy.d.ts +3 -2
  101. package/dist/delegation/policy.js +3 -1
  102. package/dist/delegation/policy.js.map +1 -1
  103. package/dist/delegation/process-liveness.d.ts +66 -0
  104. package/dist/delegation/process-liveness.js +215 -0
  105. package/dist/delegation/process-liveness.js.map +1 -0
  106. package/dist/delegation/provision.d.ts +1 -1
  107. package/dist/delegation/provision.js +10 -5
  108. package/dist/delegation/provision.js.map +1 -1
  109. package/dist/delegation/questions.d.ts +19 -0
  110. package/dist/delegation/questions.js +45 -0
  111. package/dist/delegation/questions.js.map +1 -0
  112. package/dist/delegation/results.d.ts +1 -1
  113. package/dist/delegation/results.js +33 -19
  114. package/dist/delegation/results.js.map +1 -1
  115. package/dist/delegation/routes.d.ts +185 -11
  116. package/dist/delegation/routes.js +6 -2
  117. package/dist/delegation/routes.js.map +1 -1
  118. package/dist/delegation/service.d.ts +16 -5
  119. package/dist/delegation/service.js +161 -13
  120. package/dist/delegation/service.js.map +1 -1
  121. package/dist/delegation/transport.d.ts +228 -65
  122. package/dist/discovery/catalog.d.ts +14 -0
  123. package/dist/discovery/catalog.js +31 -0
  124. package/dist/discovery/catalog.js.map +1 -0
  125. package/dist/discovery/cli.d.ts +8 -0
  126. package/dist/discovery/cli.js +104 -0
  127. package/dist/discovery/cli.js.map +1 -0
  128. package/dist/git-worktree.d.ts +3 -1
  129. package/dist/git-worktree.js +26 -4
  130. package/dist/git-worktree.js.map +1 -1
  131. package/dist/index.js +92 -26
  132. package/dist/index.js.map +1 -1
  133. package/dist/open-url.d.ts +2 -0
  134. package/dist/open-url.js +20 -0
  135. package/dist/open-url.js.map +1 -0
  136. package/dist/release/snapshot.d.ts +3 -3
  137. package/dist/release/snapshot.js +6 -6
  138. package/dist/release/snapshot.js.map +1 -1
  139. package/dist/runs/agent-tmpdir.d.ts +2 -0
  140. package/dist/runs/agent-tmpdir.js +5 -2
  141. package/dist/runs/agent-tmpdir.js.map +1 -1
  142. package/dist/runs/client-request.d.ts +11 -0
  143. package/dist/runs/client-request.js +26 -0
  144. package/dist/runs/client-request.js.map +1 -0
  145. package/dist/runs/delegation-state.d.ts +17 -0
  146. package/dist/runs/event-history.js +6 -0
  147. package/dist/runs/event-history.js.map +1 -1
  148. package/dist/runs/retention.d.ts +7 -2
  149. package/dist/runs/retention.js +39 -7
  150. package/dist/runs/retention.js.map +1 -1
  151. package/dist/runs/store.d.ts +100 -6
  152. package/dist/runs/store.js +245 -2
  153. package/dist/runs/store.js.map +1 -1
  154. package/dist/runs/webhook.d.ts +125 -0
  155. package/dist/runs/webhook.js +256 -0
  156. package/dist/runs/webhook.js.map +1 -0
  157. package/dist/server/provider-auth-runtime.d.ts +30 -4
  158. package/dist/server/provider-auth-runtime.js +71 -6
  159. package/dist/server/provider-auth-runtime.js.map +1 -1
  160. package/dist/server/server.d.ts +8226 -4860
  161. package/dist/server/server.js +309 -15
  162. package/dist/server/server.js.map +1 -1
  163. package/dist/server-install/platforms/ubuntu-vps.d.ts +5 -1
  164. package/dist/server-install/platforms/ubuntu-vps.js +160 -18
  165. package/dist/server-install/platforms/ubuntu-vps.js.map +1 -1
  166. package/dist/server-install/steps.d.ts +4 -2
  167. package/dist/server-install/steps.js +5 -4
  168. package/dist/server-install/steps.js.map +1 -1
  169. package/dist/skills-remote.d.ts +30 -5
  170. package/dist/skills-remote.js +122 -32
  171. package/dist/skills-remote.js.map +1 -1
  172. package/dist/skills.js +15 -6
  173. package/dist/skills.js.map +1 -1
  174. package/dist/task-cli/cli.d.ts +38 -0
  175. package/dist/task-cli/cli.js +580 -0
  176. package/dist/task-cli/cli.js.map +1 -0
  177. package/dist/task-cli/discovery.d.ts +22 -0
  178. package/dist/task-cli/discovery.js +96 -0
  179. package/dist/task-cli/discovery.js.map +1 -0
  180. package/dist/task-cli/http.d.ts +46 -0
  181. package/dist/task-cli/http.js +101 -0
  182. package/dist/task-cli/http.js.map +1 -0
  183. package/dist/task-cli/projections.d.ts +40 -0
  184. package/dist/task-cli/projections.js +45 -0
  185. package/dist/task-cli/projections.js.map +1 -0
  186. package/dist/task-cli/watch.d.ts +78 -0
  187. package/dist/task-cli/watch.js +336 -0
  188. package/dist/task-cli/watch.js.map +1 -0
  189. package/dist/workflows/run.d.ts +160 -2
  190. package/dist/workflows/run.js +1141 -108
  191. package/dist/workflows/run.js.map +1 -1
  192. package/dist/workspace/agent-profiles.d.ts +22 -0
  193. package/dist/workspace/agent-profiles.js +15 -0
  194. package/dist/workspace/agent-profiles.js.map +1 -1
  195. package/dist/workspace/config.d.ts +9 -0
  196. package/dist/workspace/config.js +13 -1
  197. package/dist/workspace/config.js.map +1 -1
  198. package/dist/workspace/projects-cli.js +1 -1
  199. package/dist/workspace/projects.d.ts +24 -1
  200. package/dist/workspace/projects.js +14 -1
  201. package/dist/workspace/projects.js.map +1 -1
  202. package/package.json +5 -5
  203. package/scripts/mock-claude.mjs +64 -2
  204. package/scripts/mock-codex-app-server.mjs +124 -1
  205. package/scripts/mock-cursor-acp.mjs +54 -3
  206. package/scripts/mock-cursor-hang-stdin-late.mjs +35 -0
  207. package/scripts/mock-cursor-hang-stdin.mjs +30 -0
  208. package/scripts/mock-opencode-serve.mjs +102 -2
  209. package/scripts/mock-pi-rpc.mjs +82 -3
  210. package/web/dist/assets/agent-accounts-CerclGiO.js +1 -0
  211. package/web/dist/assets/centered-state-DH8qtCz-.js +43 -0
  212. package/web/dist/assets/collapsible-De2G0xqQ.js +1 -0
  213. package/web/dist/assets/commit-list-CQubP1iS.js +1 -0
  214. package/web/dist/assets/compare-variants-C_NijJvg.js +1 -0
  215. package/web/dist/assets/{diff-tRE59UNb2.js → diff-8M5HlDxq2.js} +2 -2
  216. package/web/dist/assets/diff-controls-B6ok0TtQ.js +1 -0
  217. package/web/dist/assets/{diff-stat-Cgnl_hYF.js → diff-stat-D1AODN2a.js} +1 -1
  218. package/web/dist/assets/{diff-view-DN1ort7Q.js → diff-view-Bs5Gh7UF.js} +2 -2
  219. package/web/dist/assets/dropdown-menu-7KGQMoFj.js +1 -0
  220. package/web/dist/assets/git-toolbar-DqbapMXr.js +1 -0
  221. package/web/dist/assets/github-lMHiuYSx.js +1 -0
  222. package/web/dist/assets/{image-preview-C2JGcBlC.js → image-preview-jzHoEyLM.js} +1 -1
  223. package/web/dist/assets/index-D4OJTArJ.js +7 -0
  224. package/web/dist/assets/index-D5NkwqY7.css +1 -0
  225. package/web/dist/assets/markdown-DvbymqXz.js +2 -0
  226. package/web/dist/assets/pill-BL6ugwXo.js +1 -0
  227. package/web/dist/assets/project-router-ChC5Rb-Y.js +1 -0
  228. package/web/dist/assets/prompt-templates-j8qlK7c-.js +15 -0
  229. package/web/dist/assets/repo-git-BbPAgkqb.js +1 -0
  230. package/web/dist/assets/{run-diff-CyG0Nciv.js → run-diff-BuATgZpx.js} +2 -2
  231. package/web/dist/assets/run-header-DuAWswYM.js +1 -0
  232. package/web/dist/assets/skills-DiC2XrU1.js +1 -0
  233. package/web/dist/assets/{tab-link-BWNp3mLY.js → tab-link-BmGKj9Rt.js} +1 -1
  234. package/web/dist/assets/task-changes-CP9kPnsy.js +1 -0
  235. package/web/dist/assets/task-commits-D6NfTw5r.js +1 -0
  236. package/web/dist/assets/task-files-W-b_gtcb.js +2 -0
  237. package/web/dist/assets/task-thread-Bw_nQuTx.css +1 -0
  238. package/web/dist/assets/task-thread-Q7Nj33DH.js +9 -0
  239. package/web/dist/assets/textarea-ByZ-txS7.js +1 -0
  240. package/web/dist/assets/thread-loading-DHT9p5o5.js +1 -0
  241. package/web/dist/assets/token-metrics-k4XoovDS.js +1 -0
  242. package/web/dist/assets/utils-BTFBhZ55.js +64 -0
  243. package/web/dist/assets/workflows-DqQszPHJ.js +11 -0
  244. package/web/dist/assets/{zoomable-image-Z3JDnm0b.js → zoomable-image-Ba6y6Wyl.js} +1 -1
  245. package/web/dist/index.html +14 -14
  246. package/web/dist/assets/agent-accounts-BZm_2WAv.js +0 -1
  247. package/web/dist/assets/alert-dialog-B422RI-k.js +0 -43
  248. package/web/dist/assets/collapsible-Cy_Fmkrd.js +0 -1
  249. package/web/dist/assets/commit-list-Dcnk7TnI.js +0 -1
  250. package/web/dist/assets/compare-variants-Ciqwvd_f.js +0 -1
  251. package/web/dist/assets/diff-controls-BGrXGi7O.js +0 -1
  252. package/web/dist/assets/dropdown-menu-dwDGT8MM.js +0 -1
  253. package/web/dist/assets/git-toolbar-UiHnGvE0.js +0 -1
  254. package/web/dist/assets/github-D-MrkbJ7.js +0 -1
  255. package/web/dist/assets/ibm-plex-mono-regular-BF3vfe7_.ttf +0 -0
  256. package/web/dist/assets/index-BszfYvBq.js +0 -7
  257. package/web/dist/assets/index-CWh4pKP3.css +0 -1
  258. package/web/dist/assets/markdown-C_IcKVQd.js +0 -2
  259. package/web/dist/assets/pill-BsbO6G7y.js +0 -1
  260. package/web/dist/assets/project-router-DbLkll25.js +0 -1
  261. package/web/dist/assets/prompt-templates-BlTGJB5W.js +0 -15
  262. package/web/dist/assets/repo-git-Bm3s6Why.js +0 -1
  263. package/web/dist/assets/run-header-IFyIGCey.js +0 -1
  264. package/web/dist/assets/skills-C-C4DVFY.js +0 -1
  265. package/web/dist/assets/task-changes-D2PHtWUW.js +0 -1
  266. package/web/dist/assets/task-commits-N5u9U0_R.js +0 -1
  267. package/web/dist/assets/task-files-BS7c7CFm.js +0 -2
  268. package/web/dist/assets/task-thread-BQFdz1dJ.css +0 -1
  269. package/web/dist/assets/task-thread-DGM2dZV-.js +0 -9
  270. package/web/dist/assets/textarea-FjaU370i.js +0 -1
  271. package/web/dist/assets/thread-loading-77sJ8Yu_.js +0 -1
  272. package/web/dist/assets/token-metrics-Clxh03bE.js +0 -1
  273. package/web/dist/assets/utils-PYYcpCFZ.js +0 -64
  274. package/web/dist/assets/workflows-Czl0ZfXH.js +0 -11
@@ -0,0 +1,336 @@
1
+ import { apiRunSchema, runHistoryPageSchema, runRecordSchema, } from '../contract/index.js';
2
+ import { invalidResponse, refuse, request, TaskCliError } from './http.js';
3
+ import { SUCCESS_STATUSES, TERMINAL_STATUSES } from './projections.js';
4
+ /**
5
+ * Watching a task from a terminal (#504, spec 2026-09-24-cez-task-cli). Every loop here ends —
6
+ * on a terminal status or at the caller's deadline — because a bot's tool call that never
7
+ * returns is the failure this command family exists to prevent.
8
+ */
9
+ export const DEFAULT_POLL_MS = 1_500;
10
+ const MAX_FIELD_CHARS = 2_000;
11
+ function entryFor(id, run) {
12
+ if (!run)
13
+ return { id, status: 'missing' };
14
+ return {
15
+ id,
16
+ status: run.status,
17
+ ...(run.activity === undefined ? {} : { activity: run.activity }),
18
+ hasPendingHumanAsk: run.hasPendingHumanAsk ?? false,
19
+ };
20
+ }
21
+ /** Settled = nothing more will happen without a human; `missing` counts, it will never change. */
22
+ function isSettled(entry, until) {
23
+ if (entry.status === 'unknown')
24
+ return false;
25
+ if (entry.status === 'missing' || TERMINAL_STATUSES.includes(entry.status))
26
+ return true;
27
+ return until === 'attention' && (entry.status === 'waiting' || entry.hasPendingHumanAsk === true);
28
+ }
29
+ /** A failure is only a terminal non-success; stopping for attention is not one. */
30
+ function isFailure(entry) {
31
+ return entry.status === 'missing' || entry.status === 'failed' || entry.status === 'cancelled';
32
+ }
33
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
34
+ /**
35
+ * Grace for the millisecond race between a budget-bounded poll's abort and the
36
+ * deadline check (#538): `AbortSignal.timeout(budget)` can fire while
37
+ * `Date.now()` still reads just under the deadline, turning a timeout into an
38
+ * `unavailable` error (exit 2 instead of 3). A poll whose own abort consumed
39
+ * (almost) all of its budget failed *at* the deadline, so it answers "timed
40
+ * out". The grace never applies to other errors: a genuine failure stays
41
+ * `unavailable` even when it lands inside the grace window.
42
+ */
43
+ export const TIMEOUT_GRACE_MS = 250;
44
+ export function pollHitDeadline(startedAt, budgetMs, now = Date.now()) {
45
+ return now - startedAt >= budgetMs - TIMEOUT_GRACE_MS;
46
+ }
47
+ /**
48
+ * True when the wrapped cockpit error came from the poll's own abort (its
49
+ * budget running out) rather than a fast failure such as a refused
50
+ * connection. `fetchJson` folds every fetch failure into `unavailable`, so the
51
+ * abort surfaces only through the original message it preserves (`TimeoutError:
52
+ * The operation was aborted due to timeout`).
53
+ */
54
+ export function abortedPoll(error) {
55
+ if (!(error instanceof TaskCliError))
56
+ return false;
57
+ const body = error.body;
58
+ return /abort|timeout/i.test(String(body.error ?? ''));
59
+ }
60
+ /**
61
+ * Polls `GET /runs`: one call covers any number of runs and holds no socket open. Each poll is
62
+ * bounded by what is left of the deadline, so a slow cockpit answers "timed out" on time rather
63
+ * than holding the caller for a full request timeout.
64
+ */
65
+ export async function waitForRuns(cockpit, ids, options) {
66
+ const deadline = Date.now() + options.timeoutMs;
67
+ let entries = ids.map((id) => ({ id, status: 'unknown' }));
68
+ for (;;) {
69
+ const budget = deadline - Date.now();
70
+ if (budget <= 0)
71
+ return { exitCode: 3, runs: entries, timedOut: true };
72
+ const pollStart = Date.now();
73
+ let result;
74
+ try {
75
+ result = await request(cockpit, '/runs', { timeoutMs: budget });
76
+ }
77
+ catch (error) {
78
+ if (Date.now() >= deadline)
79
+ return { exitCode: 3, runs: entries, timedOut: true };
80
+ if (abortedPoll(error) && pollHitDeadline(pollStart, budget))
81
+ return { exitCode: 3, runs: entries, timedOut: true };
82
+ throw error;
83
+ }
84
+ if (result.status !== 200)
85
+ refuse(result);
86
+ const runs = apiRunSchema.array().safeParse(result.data);
87
+ if (!runs.success)
88
+ invalidResponse('run list');
89
+ const byId = new Map(runs.data.map((run) => [run.id, run]));
90
+ entries = ids.map((id) => entryFor(id, byId.get(id)));
91
+ const settled = entries.filter((entry) => isSettled(entry, options.until));
92
+ const done = options.mode === 'any' ? settled.length > 0 : settled.length === entries.length;
93
+ if (done) {
94
+ const judged = options.mode === 'any' ? settled : entries;
95
+ return { exitCode: judged.some(isFailure) && (options.mode === 'all' || judged.every(isFailure)) ? 1 : 0, runs: entries, timedOut: false };
96
+ }
97
+ const remaining = deadline - Date.now();
98
+ if (remaining <= 0)
99
+ return { exitCode: 3, runs: entries, timedOut: true };
100
+ await sleep(Math.min(options.pollMs ?? DEFAULT_POLL_MS, remaining));
101
+ }
102
+ }
103
+ const LOG_TYPES = new Set(['text', 'tool-call', 'tool-result', 'step-start', 'error', 'user-message']);
104
+ function clip(value) {
105
+ if (value === undefined)
106
+ return undefined;
107
+ const text = typeof value === 'string' ? value : JSON.stringify(value);
108
+ return text.length > MAX_FIELD_CHARS ? `${text.slice(0, MAX_FIELD_CHARS - 1)}…` : text;
109
+ }
110
+ /** One printable line per event the log keeps, or undefined for the rest. */
111
+ export function logLine(event) {
112
+ if (!LOG_TYPES.has(event.type))
113
+ return undefined;
114
+ const fields = {
115
+ seq: event.seq,
116
+ ts: event.ts,
117
+ type: event.type,
118
+ ...(event.stepId === undefined ? {} : { stepId: event.stepId }),
119
+ };
120
+ switch (event.type) {
121
+ case 'text':
122
+ case 'user-message':
123
+ fields.text = clip(event.text);
124
+ break;
125
+ case 'tool-call':
126
+ fields.tool = event.tool;
127
+ fields.input = clip(event.input);
128
+ break;
129
+ case 'tool-result':
130
+ fields.result = clip(event.result);
131
+ break;
132
+ case 'step-start':
133
+ fields.name = event.name;
134
+ if (event.iteration !== undefined)
135
+ fields.iteration = event.iteration;
136
+ break;
137
+ case 'error':
138
+ fields.message = clip(event.message);
139
+ break;
140
+ }
141
+ return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));
142
+ }
143
+ /** Keeps the newest lines within `maxChars` (counting the newline between lines). */
144
+ class LineTail {
145
+ maxChars;
146
+ lines = [];
147
+ size = 0;
148
+ constructor(maxChars) {
149
+ this.maxChars = maxChars;
150
+ }
151
+ push(line) {
152
+ this.lines.push(line);
153
+ this.size += line.length + (this.lines.length > 1 ? 1 : 0);
154
+ while (this.size > this.maxChars && this.lines.length) {
155
+ const dropped = this.lines.shift();
156
+ this.size -= dropped.length + (this.lines.length ? 1 : 0);
157
+ }
158
+ }
159
+ drain() {
160
+ const lines = this.lines;
161
+ this.lines = [];
162
+ this.size = 0;
163
+ return lines;
164
+ }
165
+ }
166
+ /** Minimal SSE framing: `event:` / `data:` fields, blank-line separated. */
167
+ async function* sseFrames(body) {
168
+ const decoder = new TextDecoder();
169
+ let buffer = '';
170
+ for await (const chunk of body) {
171
+ buffer += decoder.decode(chunk, { stream: true }).replace(/\r\n/g, '\n');
172
+ let boundary;
173
+ while ((boundary = buffer.indexOf('\n\n')) >= 0) {
174
+ const block = buffer.slice(0, boundary);
175
+ buffer = buffer.slice(boundary + 2);
176
+ let event = 'message';
177
+ const data = [];
178
+ for (const line of block.split('\n')) {
179
+ if (line.startsWith('event:'))
180
+ event = line.slice(6).trim();
181
+ else if (line.startsWith('data:'))
182
+ data.push(line.slice(5).replace(/^ /, ''));
183
+ }
184
+ yield { event, data: data.join('\n') };
185
+ }
186
+ }
187
+ }
188
+ /**
189
+ * `log`, read from the run's SSE stream, which replays every event after `afterSeq` and then
190
+ * streams live. The route subscribes to live `run` updates BEFORE it replays, so a `run` frame
191
+ * says nothing about where the replay is; the only reliable boundary is a `seq`. So:
192
+ *
193
+ * - the replay ends at `asOfSeq`, the event file's high-water mark read from `GET /history` just
194
+ * before connecting — everything up to it is the tail, bounded to `maxChars`, and without
195
+ * `follow` the command ends there;
196
+ * - with `follow`, a terminal status ends the command only once the stream has caught up with a
197
+ * SECOND high-water read taken after that status arrived, so events the engine wrote just
198
+ * before finishing are not dropped when the status frame overtakes them (exit 0/1, final line
199
+ * is the status).
200
+ *
201
+ * One `deadline` bounds every request, the history reads included (exit 3). Deduped by `seq`.
202
+ * The stream rather than `GET /history` pages: a history page starts at its first transcript
203
+ * item, so it drops lifecycle events such as the opening `step-start`.
204
+ */
205
+ export async function readLog(cockpit, id, options) {
206
+ const tail = new LineTail(options.maxChars);
207
+ const remaining = () => options.deadline - Date.now();
208
+ let lastSeq = options.afterSeq;
209
+ let seenSeq = options.afterSeq;
210
+ let status;
211
+ let drainSeq;
212
+ /** The event file's high-water mark, or undefined once the deadline has passed. */
213
+ const highWater = async () => {
214
+ const budget = remaining();
215
+ if (budget <= 0)
216
+ return undefined;
217
+ const startedAt = Date.now();
218
+ let history;
219
+ try {
220
+ history = await request(cockpit, `/runs/${encodeURIComponent(id)}/history`, { timeoutMs: budget });
221
+ }
222
+ catch (error) {
223
+ if (remaining() <= 0)
224
+ return undefined;
225
+ if (abortedPoll(error) && pollHitDeadline(startedAt, budget))
226
+ return undefined;
227
+ throw error;
228
+ }
229
+ if (history.status !== 200)
230
+ refuse(history);
231
+ const page = runHistoryPageSchema.safeParse(history.data);
232
+ return page.success ? page.data.asOfSeq : invalidResponse('history');
233
+ };
234
+ const boundarySeq = await highWater();
235
+ if (boundarySeq === undefined)
236
+ return timedOut();
237
+ let replaying = boundarySeq > options.afterSeq;
238
+ if (!replaying && !options.follow)
239
+ return 0;
240
+ const controller = new AbortController();
241
+ const timer = setTimeout(() => controller.abort(), Math.max(remaining(), 0));
242
+ try {
243
+ let response;
244
+ try {
245
+ response = await fetch(`${cockpit.api}/runs/${encodeURIComponent(id)}/events?afterSeq=${lastSeq}`, {
246
+ redirect: 'error', signal: controller.signal, headers: { accept: 'text/event-stream' },
247
+ });
248
+ }
249
+ catch (error) {
250
+ if (controller.signal.aborted)
251
+ return timedOut();
252
+ throw new TaskCliError(2, { code: 'unavailable', error: `cockpit request failed: ${error instanceof Error ? error.message : String(error)}` });
253
+ }
254
+ if (!response.ok || !response.body) {
255
+ const text = await response.text().catch(() => '');
256
+ let data = text;
257
+ try {
258
+ data = JSON.parse(text);
259
+ }
260
+ catch { /* not JSON */ }
261
+ refuse({ status: response.status, data });
262
+ }
263
+ try {
264
+ for await (const frame of sseFrames(response.body)) {
265
+ if (frame.event === 'run-event' || frame.event === 'ui-event') {
266
+ const event = JSON.parse(frame.data);
267
+ if (typeof event.seq !== 'number')
268
+ continue;
269
+ // Both streams share the file's seq space, so either one can reach a boundary;
270
+ // only v1 lines are printed, deduped by seq.
271
+ seenSeq = Math.max(seenSeq, event.seq);
272
+ if (frame.event === 'run-event' && event.seq > lastSeq) {
273
+ lastSeq = event.seq;
274
+ const line = logLine(event);
275
+ if (line) {
276
+ if (replaying)
277
+ tail.push(JSON.stringify(line));
278
+ else
279
+ options.print(JSON.stringify(line));
280
+ }
281
+ }
282
+ }
283
+ else if (frame.event === 'run') {
284
+ const run = runRecordSchema.safeParse(JSON.parse(frame.data));
285
+ if (run.success)
286
+ status = run.data.status;
287
+ }
288
+ let exit = step();
289
+ if (exit === 'drain') {
290
+ drainSeq = await highWater();
291
+ if (drainSeq === undefined)
292
+ return timedOut();
293
+ exit = step();
294
+ }
295
+ if (typeof exit === 'number')
296
+ return exit;
297
+ }
298
+ }
299
+ catch (error) {
300
+ if (!controller.signal.aborted)
301
+ throw error;
302
+ }
303
+ if (controller.signal.aborted)
304
+ return timedOut();
305
+ throw new TaskCliError(2, { code: 'unavailable', error: 'the cockpit closed the event stream' });
306
+ }
307
+ finally {
308
+ clearTimeout(timer);
309
+ controller.abort();
310
+ }
311
+ /** Ends the replay at its boundary; then a terminal status ends the command once drained. */
312
+ function step() {
313
+ if (replaying && seenSeq >= boundarySeq) {
314
+ replaying = false;
315
+ for (const line of tail.drain())
316
+ options.print(line);
317
+ if (!options.follow)
318
+ return 0;
319
+ }
320
+ if (replaying || status === undefined || !TERMINAL_STATUSES.includes(status))
321
+ return undefined;
322
+ if (drainSeq === undefined)
323
+ return 'drain';
324
+ if (seenSeq < drainSeq)
325
+ return undefined;
326
+ options.print(JSON.stringify({ id, status, timedOut: false }));
327
+ return SUCCESS_STATUSES.includes(status) ? 0 : 1;
328
+ }
329
+ function timedOut() {
330
+ for (const line of tail.drain())
331
+ options.print(line);
332
+ options.print(JSON.stringify({ id, ...(status === undefined ? {} : { status }), timedOut: true }));
333
+ return 3;
334
+ }
335
+ }
336
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/task-cli/watch.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,7 @@ export type DelegationExecutionSettings = {
37
37
  cwd: string;
38
38
  runner: RunnerId;
39
39
  model?: string;
40
+ modelIdentity?: string;
40
41
  effort?: string;
41
42
  agentProfile: string;
42
43
  accountBinding?: WorkerAccountBinding;
@@ -44,6 +45,10 @@ export type DelegationExecutionSettings = {
44
45
  allowedTools?: string[];
45
46
  bashAllowlist?: string[];
46
47
  };
48
+ /** Safety cap on autonomous auto-continues per run — stops a stuck agent from nudging forever. */
49
+ /** #505: a real steer is read at the harness's next model step; a quiet boundary this long
50
+ * with input still unread means the harness will not read it without help. */
51
+ export declare const UNREAD_INPUT_GRACE_MS = 30000;
47
52
  /**
48
53
  * Auto-resume after a provider usage limit (spec 2026-08-03-auto-resume-after-usage-limit).
49
54
  *
@@ -114,6 +119,8 @@ export interface StartRunInput {
114
119
  * user — turn-ends auto-continue until the agent signals done or the safety
115
120
  * cap is hit. No "needs you" is ever raised. */
116
121
  autonomous?: boolean;
122
+ /** Task webhook opt-in (#589). Persisted on the record at creation; read from there after. */
123
+ notify?: boolean;
117
124
  /** Follow-up inbox generation (spec 007, #444). Omitted means enabled for
118
125
  * compatibility; the handoff journal runs either way. */
119
126
  generateFollowups?: boolean;
@@ -213,6 +220,16 @@ export declare function pastedAttachmentsNote(attachments: PersistedAttachment[]
213
220
  export declare const VARIANT_LETTERS: readonly ['A', 'B', 'C'];
214
221
  /** Only an original workflow that has never executed may return to its queue. */
215
222
  export declare function isUntouchedCancelledRun(run: RunRecord): boolean;
223
+ /** #469: why destroy could not prove a crashed generation's termination. */
224
+ export type WorkerTerminationBlocker = {
225
+ kind: 'unreadable';
226
+ } | {
227
+ kind: 'controller';
228
+ pid: number;
229
+ } | {
230
+ kind: 'processes';
231
+ pids: number[];
232
+ };
216
233
  /**
217
234
  * The mini workflow engine: executes a `WorkflowDef` against a repo, one step
218
235
  * at a time, persisting every event to the RunStore (which the SSE endpoints
@@ -242,9 +259,53 @@ export declare class RunManager {
242
259
  * exception or an interrupt request cannot stand in for session termination. */
243
260
  private trackWorkerSessionResult;
244
261
  private persistWorkerCompletion;
262
+ /** #469: the generation a dead controller left `starting`, if this manager may judge it. A
263
+ * generation this process controls is never judged here: the in-memory execution map owns it,
264
+ * and a disposed manager's still-running sessions look like orphans. `busy` is transient (this
265
+ * manager holds the run); `unknown` is a present record that proves nothing. */
266
+ private orphanState;
267
+ private orphanedWorkerGeneration;
268
+ /** Completes a crashed generation's proof once every one of its processes is proven gone (#469).
269
+ * Sync and signal-free; recovery, resume, delivery, collect and destroy then take their normal paths.
270
+ * A non-gone probe is cached briefly: on darwin the scan is a synchronous `lsof` on the event loop. */
271
+ settleOrphanedWorkerExecution(runId: string, opts?: {
272
+ admitting?: boolean;
273
+ fresh?: boolean;
274
+ }): boolean;
275
+ private readonly orphanProbes;
276
+ private readonly orphanReprobes;
277
+ private readonly orphanBlockers;
278
+ private readonly reportedOrphanBlockers;
279
+ private orphanReprobeMs;
280
+ private orphanReprobeLimitMs;
281
+ private orphanReprobeSlowMs;
282
+ private orphanTermGraceMs;
283
+ /** #469: a survivor that dies after recovery has no other wake source (no exit callback for a
284
+ * process another cezar spawned). Unref'd; finalization's `run` event then lets worker waits and
285
+ * outcomes observe it. Fast for the first window, then slow but uncapped, so a long-lived
286
+ * survivor is still noticed when it exits. A tick while this manager holds the run is skipped;
287
+ * only terminal reasons (proof settled, generation changed, run gone, unknown record, dispose)
288
+ * stop it. */
289
+ private armOrphanReprobe;
290
+ private clearOrphanReprobe;
291
+ /** Why the last destroy could not prove termination (#469), and whether that differs from the
292
+ * reason last reported, so a retry loop appends one lifecycle event per distinct blocker set. */
293
+ takeWorkerTerminationBlocker(runId: string): {
294
+ blocker: WorkerTerminationBlocker;
295
+ changed: boolean;
296
+ } | undefined;
297
+ /** Continue over a live orphan names what still runs; other refusals keep the generic text. */
298
+ private orphanAdmissionRefusal;
299
+ /** Destroy only (#469): signal the recorded, token-verified survivors of a generation whose
300
+ * controller is proven dead, then finalize on `gone`. Scan-only processes are never signalled. */
301
+ private reapOrphanedWorker;
302
+ /** Best effort: a failed write leaves the working-directory scan as this process's evidence. */
303
+ private recordWorkerProcess;
245
304
  private trackTurnEnd;
246
305
  requestWorkerStop(runId: string): WorkerStopResult;
247
- awaitRunTermination(runId: string, timeoutMs: number): Promise<boolean>;
306
+ awaitRunTermination(runId: string, timeoutMs: number, opts?: {
307
+ reapOrphans?: boolean;
308
+ }): Promise<boolean>;
248
309
  /** Private cleanup capability, never serialized. Obtain after stop/termination
249
310
  * under the service's destroy lock; each invocation rechecks the same generation. */
250
311
  getWorkerNoMaterializationProof(runId: string): WorkerNoMaterializationProof | undefined;
@@ -267,8 +328,11 @@ export declare class RunManager {
267
328
  private readonly workerWakeAdmitted;
268
329
  private readonly workerWakeQueuedAt;
269
330
  private readonly workerWaitTimers;
331
+ private readonly inboxClaimTimers;
270
332
  private reconcilingWorkers;
271
333
  private recovering;
334
+ /** Quiet window before unread input is resubmitted or left unconfirmed (#505). */
335
+ private readonly unreadInputGraceMs;
272
336
  private disposed;
273
337
  private readonly onDelegationRun;
274
338
  private readonly pendingJobs;
@@ -328,6 +392,7 @@ export declare class RunManager {
328
392
  private readonly offSemaphore;
329
393
  constructor(store: RunStore, repoRoot: string, options?: {
330
394
  semaphore?: WorkspaceSemaphore;
395
+ unreadInputGraceMs?: number;
331
396
  });
332
397
  /**
333
398
  * Release everything this manager owns without touching run records
@@ -432,10 +497,27 @@ export declare class RunManager {
432
497
  model?: string;
433
498
  effort?: string;
434
499
  agentProfile?: string;
435
- }): Promise<DelegationExecutionSettings>;
500
+ }, validateModel?: (settings: DelegationExecutionSettings) => Promise<void>): Promise<DelegationExecutionSettings>;
501
+ /**
502
+ * Idempotent start (#504, spec 2026-09-24-cez-task-cli). Lookup and create share one
503
+ * synchronous path, so the event loop serialises concurrent retries: the first creates, every
504
+ * later one with the same hash gets that run back, and a different hash is a conflict.
505
+ */
506
+ startRunIdempotent(workflow: WorkflowDef, input: StartRunInput, request: {
507
+ id: string;
508
+ hash: string;
509
+ }): {
510
+ run: RunRecord;
511
+ created: boolean;
512
+ } | {
513
+ conflict: true;
514
+ };
436
515
  startRun(workflow: WorkflowDef, input: StartRunInput, group?: {
437
516
  groupId: string;
438
517
  variant: string;
518
+ }, clientRequest?: {
519
+ id: string;
520
+ hash: string;
439
521
  }): RunRecord;
440
522
  /** Accept only the store's already-durable owned creation, never caller-supplied paths/workflows. */
441
523
  enqueueOwnedRun(runId: string): void;
@@ -749,8 +831,43 @@ export declare class RunManager {
749
831
  private hasUnansweredHumanAsk;
750
832
  /** Both roles can select their own requests without acquiring worker-management authority. */
751
833
  registerRequestWait(runId: string, request: RequestWaitRequest): WorkerWait;
834
+ /** A wait wake is only a pointer. Only provider submission/opening prompts own delivery. */
835
+ private providerOwnsInboxInput;
836
+ canClaimInboxInput(runId: string, id: string): boolean;
837
+ /** The service supplies authorized, bounded IDs; claim and flight reservations are synchronous. */
838
+ reserveInboxInputs(runId: string, generation: string, ids: readonly string[]): {
839
+ receiptId: string;
840
+ expiresAt: string;
841
+ inputIds: string[];
842
+ } | undefined;
843
+ acknowledgeInbox(runId: string, generation: string, receiptId: string): 'acknowledged' | 'already-acknowledged';
844
+ releaseInbox(runId: string, generation: string, receiptId: string): 'released';
845
+ /** Expiry is an independent wake source, including after the provider's last turn. */
846
+ private armInboxClaimExpiry;
752
847
  /** Accepted conversation input uses the existing scheduler admission for idle recipients. */
753
848
  deliverConversationInput(runId: string): void;
849
+ /** A worker's pending question goes to its owning parent as a conversation request
850
+ * (#505). The worker still parks on its ask; only the parent's reply, or a human after
851
+ * fallback, answers it. Routing is idempotent: the message ID derives from the ask seq. */
852
+ private routeWorkerQuestion;
853
+ /** A human answering a worker question its parent handed back (#505): the reviewing parent
854
+ * can no longer answer it, so it must not also block the human. */
855
+ private answersFallenBackAsk;
856
+ /** The worker's pending ask when it went to the parent and has not fallen back to a human. */
857
+ private routedAsk;
858
+ /** The parent's reply answers the routed question like a human answer would: through the
859
+ * live session's native answer seam, or by reopening a session that is gone (#505). */
860
+ private answerRoutedQuestion;
861
+ /** A routed question settled without a reply (its worker stopped, a deadline, fallback) can
862
+ * never be answered by the parent any more: hand it to the human on the worker (#505). */
863
+ private retireSettledQuestions;
864
+ /** Routed questions this parent has not answered yet, by asking worker. */
865
+ private unansweredQuestions;
866
+ /** The parent can no longer answer: its workers' routed questions go back to the human
867
+ * (#505). The outcome lands first, so a crash before the worker's event repeats this. */
868
+ private fallbackRoutedQuestions;
869
+ /** The parent can still read and answer a routed question; answering needs its steer grant. */
870
+ private parentCanReceive;
754
871
  /** Cancel only the wait; persist its settlement before ordinary wake admission. */
755
872
  cancelWorkerWait(parentId: string, waitId: string): WorkerWait;
756
873
  private workerWait;
@@ -777,6 +894,37 @@ export declare class RunManager {
777
894
  /** Accepted input may be temporarily refused while a backend HTTP ack is
778
895
  * outstanding. That is not an empty queue and must not trigger automatic DONE. */
779
896
  private hasQueuedAgentInputs;
897
+ /** Only the current session's observation writes consumedAt (#505). An ID reported
898
+ * before its acceptance checkpoint lands is applied when that checkpoint commits. */
899
+ private handleAgentInputConsumed;
900
+ /** #505: input the harness accepted but will never read returns to the queue, so
901
+ * DONE, auto-end and park see queued work. Out of a turn (an OpenCode lost wake)
902
+ * it is submitted right away; at a turn-end the handler's own flush submits it. */
903
+ private retireUnreadInputs;
904
+ /** #505: the harness started the opening turn, so the opening input was accepted.
905
+ * Its replay-prompt retirement still waits for that turn's successful end. */
906
+ private recordOpeningAccepted;
907
+ /** The conversation messages the next submission would carry, if nothing but
908
+ * conversation input leads the queue (lifecycle input stays a barrier). */
909
+ private pendingConversationBatch;
910
+ /** Bundled messages rode the answer's own write: delivered now, read when that turn ends. */
911
+ private commitBundledDelivery;
912
+ /** The turn that carried bundled messages has ended: the model read them. */
913
+ private readBundledInputs;
914
+ /** #505: the session closed without reporting it read (failure, stop, exit): the input
915
+ * goes back to the queue so a later session delivers it; never shown as delivered. */
916
+ private requeueUnreadAtClose;
917
+ /** An idle, open boundary with nothing left to deliver: DONE closes, otherwise the
918
+ * run parks as waiting or monitoring. Shared by acknowledgements that land after a
919
+ * turn ended and by the unread-input grace timer (#505). */
920
+ private settleIdleBoundary;
921
+ /** #505 liveness bound: a harness that accepted input and then neither read it nor ran
922
+ * another turn must not hold the run and its slot forever. After a quiet grace window the
923
+ * input is resubmitted once; after a second it is left delivered but unconfirmed. */
924
+ private armUnreadInputTimer;
925
+ private clearUnreadInputTimer;
926
+ /** #505: the harness accepted input this session has not reported reading yet. */
927
+ private harnessOwesInput;
780
928
  /** A callback from an old/replaced/disposed session carries no authority. */
781
929
  private handleAgentInputReady;
782
930
  /** Reservation is synchronous; only an acknowledged transport may checkpoint delivery. */
@@ -811,6 +959,11 @@ export declare class RunManager {
811
959
  private waitingBeforeFinalWorkflowStep;
812
960
  /** Locate the original workflow step whose closed session a synthetic Continue is resuming. */
813
961
  private waitingWorkflowStepIndex;
962
+ /**
963
+ * Session ids Cursor will accept on `session/load`. A launch UUID written
964
+ * before `session.started` is only for the step rail (#583).
965
+ */
966
+ private resumableSessionId;
814
967
  /**
815
968
  * "Continue" (spec 003): reopen a finished run's claude session in-process
816
969
  * (`claude --resume <sessionId>`) as a new synthetic step. The session then
@@ -829,6 +982,8 @@ export declare class RunManager {
829
982
  /** Agent account for the reopened session (spec 2026-07-29-agent-profiles). Omitted = the
830
983
  * account the run is already on. */
831
984
  agentProfile?: string;
985
+ /** #505: the parent reply this continuation delivers as the answer to a routed question. */
986
+ answerInputId?: string;
832
987
  },
833
988
  /** Restart recovery may discover several interrupted tasks at once. Those
834
989
  * continuations are queued; an explicit user Continue remains immediate. */
@@ -862,6 +1017,9 @@ export declare class RunManager {
862
1017
  /** Persist the invocation checkpoint before launching a runner. A throw or
863
1018
  * process exit before `turn.started` therefore leaves a durable mismatch. */
864
1019
  private beginUsageInvocation;
1020
+ /** Claude's `total_cost_usd` is cumulative for the conversation, including
1021
+ * turns in Continue steps. Other runners emit per-message cost deltas. */
1022
+ private recordReportedCost;
865
1023
  /** Fold backend-neutral completed-turn usage into the current step exactly
866
1024
  * once. Invocation/turn counters are written before the event reaches the
867
1025
  * NDJSON sink so crashes cannot preserve a falsely complete subtotal. */