botmux 2.93.1 → 2.95.0

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 (290) hide show
  1. package/dist/adapters/backend/tmux-backend.d.ts +18 -2
  2. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  3. package/dist/adapters/backend/tmux-backend.js +45 -3
  4. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  5. package/dist/adapters/backend/tmux-pipe-backend.js +1 -1
  6. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  7. package/dist/adapters/backend/types.d.ts +8 -0
  8. package/dist/adapters/backend/types.d.ts.map +1 -1
  9. package/dist/adapters/backend/types.js.map +1 -1
  10. package/dist/adapters/backend/zellij-backend.js +1 -1
  11. package/dist/adapters/backend/zellij-backend.js.map +1 -1
  12. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  13. package/dist/adapters/cli/claude-code.js +6 -1
  14. package/dist/adapters/cli/claude-code.js.map +1 -1
  15. package/dist/bot-registry.d.ts +50 -1
  16. package/dist/bot-registry.d.ts.map +1 -1
  17. package/dist/bot-registry.js +30 -0
  18. package/dist/bot-registry.js.map +1 -1
  19. package/dist/cli/workflow.d.ts.map +1 -1
  20. package/dist/cli/workflow.js +11 -4
  21. package/dist/cli/workflow.js.map +1 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +146 -1
  24. package/dist/cli.js.map +1 -1
  25. package/dist/core/command-handler.d.ts.map +1 -1
  26. package/dist/core/command-handler.js +28 -3
  27. package/dist/core/command-handler.js.map +1 -1
  28. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  29. package/dist/core/dashboard-ipc-server.js +92 -0
  30. package/dist/core/dashboard-ipc-server.js.map +1 -1
  31. package/dist/core/inherit-peer.d.ts +5 -0
  32. package/dist/core/inherit-peer.d.ts.map +1 -1
  33. package/dist/core/inherit-peer.js +3 -0
  34. package/dist/core/inherit-peer.js.map +1 -1
  35. package/dist/core/session-discovery.d.ts +9 -0
  36. package/dist/core/session-discovery.d.ts.map +1 -1
  37. package/dist/core/session-discovery.js +24 -0
  38. package/dist/core/session-discovery.js.map +1 -1
  39. package/dist/core/session-manager.d.ts.map +1 -1
  40. package/dist/core/session-manager.js +7 -6
  41. package/dist/core/session-manager.js.map +1 -1
  42. package/dist/core/terminal-url.d.ts.map +1 -1
  43. package/dist/core/terminal-url.js +15 -0
  44. package/dist/core/terminal-url.js.map +1 -1
  45. package/dist/core/trigger-session.js +2 -2
  46. package/dist/core/trigger-session.js.map +1 -1
  47. package/dist/core/worker-pool.d.ts.map +1 -1
  48. package/dist/core/worker-pool.js +30 -0
  49. package/dist/core/worker-pool.js.map +1 -1
  50. package/dist/daemon.d.ts.map +1 -1
  51. package/dist/daemon.js +296 -23
  52. package/dist/daemon.js.map +1 -1
  53. package/dist/dashboard/aggregator.d.ts +5 -0
  54. package/dist/dashboard/aggregator.d.ts.map +1 -1
  55. package/dist/dashboard/aggregator.js +7 -0
  56. package/dist/dashboard/aggregator.js.map +1 -1
  57. package/dist/dashboard/auth.d.ts.map +1 -1
  58. package/dist/dashboard/auth.js +7 -1
  59. package/dist/dashboard/auth.js.map +1 -1
  60. package/dist/dashboard/bot-payload.d.ts +2 -0
  61. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  62. package/dist/dashboard/bot-payload.js +2 -0
  63. package/dist/dashboard/bot-payload.js.map +1 -1
  64. package/dist/dashboard/connector-api.d.ts.map +1 -1
  65. package/dist/dashboard/connector-api.js +14 -3
  66. package/dist/dashboard/connector-api.js.map +1 -1
  67. package/dist/dashboard/settings-write-applier.d.ts +2 -1
  68. package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
  69. package/dist/dashboard/settings-write-applier.js +7 -0
  70. package/dist/dashboard/settings-write-applier.js.map +1 -1
  71. package/dist/dashboard/v3-runs-api.d.ts +26 -0
  72. package/dist/dashboard/v3-runs-api.d.ts.map +1 -0
  73. package/dist/dashboard/v3-runs-api.js +67 -0
  74. package/dist/dashboard/v3-runs-api.js.map +1 -0
  75. package/dist/dashboard/web/app.js +21 -9
  76. package/dist/dashboard/web/app.js.map +1 -1
  77. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  78. package/dist/dashboard/web/bot-defaults.js +128 -33
  79. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  80. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  81. package/dist/dashboard/web/i18n.js +42 -6
  82. package/dist/dashboard/web/i18n.js.map +1 -1
  83. package/dist/dashboard/web/legacy-workflow-link.d.ts +2 -0
  84. package/dist/dashboard/web/legacy-workflow-link.d.ts.map +1 -0
  85. package/dist/dashboard/web/legacy-workflow-link.js +12 -0
  86. package/dist/dashboard/web/legacy-workflow-link.js.map +1 -0
  87. package/dist/dashboard/web/settings.d.ts.map +1 -1
  88. package/dist/dashboard/web/settings.js +11 -0
  89. package/dist/dashboard/web/settings.js.map +1 -1
  90. package/dist/dashboard/web/v3-terminal.d.ts +11 -0
  91. package/dist/dashboard/web/v3-terminal.d.ts.map +1 -0
  92. package/dist/dashboard/web/v3-terminal.js +143 -0
  93. package/dist/dashboard/web/v3-terminal.js.map +1 -0
  94. package/dist/dashboard/web/v3.d.ts +2 -0
  95. package/dist/dashboard/web/v3.d.ts.map +1 -0
  96. package/dist/dashboard/web/v3.js +564 -0
  97. package/dist/dashboard/web/v3.js.map +1 -0
  98. package/dist/dashboard/web/whiteboards.d.ts.map +1 -1
  99. package/dist/dashboard/web/whiteboards.js +14 -5
  100. package/dist/dashboard/web/whiteboards.js.map +1 -1
  101. package/dist/dashboard/web/workflows.d.ts.map +1 -1
  102. package/dist/dashboard/web/workflows.js +12 -8
  103. package/dist/dashboard/web/workflows.js.map +1 -1
  104. package/dist/dashboard-web/app.js +834 -724
  105. package/dist/dashboard-web/apple-touch-icon.png +0 -0
  106. package/dist/dashboard-web/favicon.png +0 -0
  107. package/dist/dashboard-web/index.html +3 -1
  108. package/dist/dashboard-web/style.css +223 -0
  109. package/dist/dashboard.js +170 -10
  110. package/dist/dashboard.js.map +1 -1
  111. package/dist/global-config.d.ts +10 -0
  112. package/dist/global-config.d.ts.map +1 -1
  113. package/dist/global-config.js +8 -0
  114. package/dist/global-config.js.map +1 -1
  115. package/dist/i18n/en.d.ts.map +1 -1
  116. package/dist/i18n/en.js +23 -3
  117. package/dist/i18n/en.js.map +1 -1
  118. package/dist/i18n/zh.d.ts.map +1 -1
  119. package/dist/i18n/zh.js +23 -3
  120. package/dist/i18n/zh.js.map +1 -1
  121. package/dist/im/lark/card-handler.d.ts +12 -0
  122. package/dist/im/lark/card-handler.d.ts.map +1 -1
  123. package/dist/im/lark/card-handler.js +28 -0
  124. package/dist/im/lark/card-handler.js.map +1 -1
  125. package/dist/im/lark/client.d.ts.map +1 -1
  126. package/dist/im/lark/client.js +3 -12
  127. package/dist/im/lark/client.js.map +1 -1
  128. package/dist/im/lark/event-dispatcher.d.ts +2 -1
  129. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  130. package/dist/im/lark/event-dispatcher.js +20 -6
  131. package/dist/im/lark/event-dispatcher.js.map +1 -1
  132. package/dist/im/lark/grant-command.js +4 -4
  133. package/dist/im/lark/grant-command.js.map +1 -1
  134. package/dist/im/lark/message-parser.d.ts +29 -1
  135. package/dist/im/lark/message-parser.d.ts.map +1 -1
  136. package/dist/im/lark/message-parser.js +35 -1
  137. package/dist/im/lark/message-parser.js.map +1 -1
  138. package/dist/im/lark/v3-blocked-card-handler.d.ts +28 -0
  139. package/dist/im/lark/v3-blocked-card-handler.d.ts.map +1 -0
  140. package/dist/im/lark/v3-blocked-card-handler.js +134 -0
  141. package/dist/im/lark/v3-blocked-card-handler.js.map +1 -0
  142. package/dist/im/lark/v3-blocked-card.d.ts +75 -0
  143. package/dist/im/lark/v3-blocked-card.d.ts.map +1 -0
  144. package/dist/im/lark/v3-blocked-card.js +206 -0
  145. package/dist/im/lark/v3-blocked-card.js.map +1 -0
  146. package/dist/im/lark/v3-gate-card-handler.d.ts +31 -0
  147. package/dist/im/lark/v3-gate-card-handler.d.ts.map +1 -0
  148. package/dist/im/lark/v3-gate-card-handler.js +110 -0
  149. package/dist/im/lark/v3-gate-card-handler.js.map +1 -0
  150. package/dist/im/lark/v3-gate-card.d.ts +47 -0
  151. package/dist/im/lark/v3-gate-card.d.ts.map +1 -0
  152. package/dist/im/lark/v3-gate-card.js +119 -0
  153. package/dist/im/lark/v3-gate-card.js.map +1 -0
  154. package/dist/im/lark/v3-loop-grant-card-handler.d.ts +28 -0
  155. package/dist/im/lark/v3-loop-grant-card-handler.d.ts.map +1 -0
  156. package/dist/im/lark/v3-loop-grant-card-handler.js +90 -0
  157. package/dist/im/lark/v3-loop-grant-card-handler.js.map +1 -0
  158. package/dist/im/lark/v3-loop-grant-card.d.ts +46 -0
  159. package/dist/im/lark/v3-loop-grant-card.d.ts.map +1 -0
  160. package/dist/im/lark/v3-loop-grant-card.js +119 -0
  161. package/dist/im/lark/v3-loop-grant-card.js.map +1 -0
  162. package/dist/im/lark/v3-revisit-grant-card-handler.d.ts +29 -0
  163. package/dist/im/lark/v3-revisit-grant-card-handler.d.ts.map +1 -0
  164. package/dist/im/lark/v3-revisit-grant-card-handler.js +96 -0
  165. package/dist/im/lark/v3-revisit-grant-card-handler.js.map +1 -0
  166. package/dist/im/lark/v3-revisit-grant-card.d.ts +52 -0
  167. package/dist/im/lark/v3-revisit-grant-card.d.ts.map +1 -0
  168. package/dist/im/lark/v3-revisit-grant-card.js +123 -0
  169. package/dist/im/lark/v3-revisit-grant-card.js.map +1 -0
  170. package/dist/im/lark/workflow-cards.d.ts.map +1 -1
  171. package/dist/im/lark/workflow-cards.js +5 -1
  172. package/dist/im/lark/workflow-cards.js.map +1 -1
  173. package/dist/im/lark/workflow-progress-card.d.ts +1 -1
  174. package/dist/im/lark/workflow-progress-card.js +1 -1
  175. package/dist/im/lark/workflow-slash-command.d.ts +28 -0
  176. package/dist/im/lark/workflow-slash-command.d.ts.map +1 -1
  177. package/dist/im/lark/workflow-slash-command.js +61 -5
  178. package/dist/im/lark/workflow-slash-command.js.map +1 -1
  179. package/dist/platform/binding.d.ts +6 -0
  180. package/dist/platform/binding.d.ts.map +1 -1
  181. package/dist/platform/binding.js +17 -0
  182. package/dist/platform/binding.js.map +1 -1
  183. package/dist/platform/tunnel-client.d.ts +2 -0
  184. package/dist/platform/tunnel-client.d.ts.map +1 -1
  185. package/dist/platform/tunnel-client.js.map +1 -1
  186. package/dist/services/bot-config-store.d.ts.map +1 -1
  187. package/dist/services/bot-config-store.js +1 -0
  188. package/dist/services/bot-config-store.js.map +1 -1
  189. package/dist/services/card-prefs-store.d.ts +4 -0
  190. package/dist/services/card-prefs-store.d.ts.map +1 -1
  191. package/dist/services/card-prefs-store.js +19 -0
  192. package/dist/services/card-prefs-store.js.map +1 -1
  193. package/dist/services/oncall-store.d.ts +25 -0
  194. package/dist/services/oncall-store.d.ts.map +1 -1
  195. package/dist/services/oncall-store.js +56 -0
  196. package/dist/services/oncall-store.js.map +1 -1
  197. package/dist/services/transcript-resolver.d.ts.map +1 -1
  198. package/dist/services/transcript-resolver.js +21 -4
  199. package/dist/services/transcript-resolver.js.map +1 -1
  200. package/dist/setup/bot-config-editor.d.ts +7 -0
  201. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  202. package/dist/setup/bot-config-editor.js +33 -0
  203. package/dist/setup/bot-config-editor.js.map +1 -1
  204. package/dist/skills/definitions.d.ts.map +1 -1
  205. package/dist/skills/definitions.js +208 -4
  206. package/dist/skills/definitions.js.map +1 -1
  207. package/dist/types.d.ts +1 -0
  208. package/dist/types.d.ts.map +1 -1
  209. package/dist/utils/terminal-favicon.d.ts +2 -0
  210. package/dist/utils/terminal-favicon.d.ts.map +1 -0
  211. package/dist/utils/terminal-favicon.js +5 -0
  212. package/dist/utils/terminal-favicon.js.map +1 -0
  213. package/dist/worker.js +152 -8
  214. package/dist/worker.js.map +1 -1
  215. package/dist/workflows/definition.d.ts +80 -80
  216. package/dist/workflows/events/payloads.d.ts +4 -4
  217. package/dist/workflows/events/schema.d.ts +16 -16
  218. package/dist/workflows/v3/architect.d.ts +37 -0
  219. package/dist/workflows/v3/architect.d.ts.map +1 -0
  220. package/dist/workflows/v3/architect.js +226 -0
  221. package/dist/workflows/v3/architect.js.map +1 -0
  222. package/dist/workflows/v3/bot-resolve.d.ts +21 -0
  223. package/dist/workflows/v3/bot-resolve.d.ts.map +1 -0
  224. package/dist/workflows/v3/bot-resolve.js +48 -0
  225. package/dist/workflows/v3/bot-resolve.js.map +1 -0
  226. package/dist/workflows/v3/cli-run.d.ts +24 -0
  227. package/dist/workflows/v3/cli-run.d.ts.map +1 -0
  228. package/dist/workflows/v3/cli-run.js +265 -0
  229. package/dist/workflows/v3/cli-run.js.map +1 -0
  230. package/dist/workflows/v3/contract.d.ts +302 -0
  231. package/dist/workflows/v3/contract.d.ts.map +1 -0
  232. package/dist/workflows/v3/contract.js +91 -0
  233. package/dist/workflows/v3/contract.js.map +1 -0
  234. package/dist/workflows/v3/daemon-run.d.ts +311 -0
  235. package/dist/workflows/v3/daemon-run.d.ts.map +1 -0
  236. package/dist/workflows/v3/daemon-run.js +775 -0
  237. package/dist/workflows/v3/daemon-run.js.map +1 -0
  238. package/dist/workflows/v3/dag.d.ts +332 -0
  239. package/dist/workflows/v3/dag.d.ts.map +1 -0
  240. package/dist/workflows/v3/dag.js +1040 -0
  241. package/dist/workflows/v3/dag.js.map +1 -0
  242. package/dist/workflows/v3/ephemeral-pool.d.ts +29 -0
  243. package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -0
  244. package/dist/workflows/v3/ephemeral-pool.js +331 -0
  245. package/dist/workflows/v3/ephemeral-pool.js.map +1 -0
  246. package/dist/workflows/v3/grill-state.d.ts +92 -0
  247. package/dist/workflows/v3/grill-state.d.ts.map +1 -0
  248. package/dist/workflows/v3/grill-state.js +151 -0
  249. package/dist/workflows/v3/grill-state.js.map +1 -0
  250. package/dist/workflows/v3/host.d.ts +88 -0
  251. package/dist/workflows/v3/host.d.ts.map +1 -0
  252. package/dist/workflows/v3/host.js +349 -0
  253. package/dist/workflows/v3/host.js.map +1 -0
  254. package/dist/workflows/v3/human-gate.d.ts +85 -0
  255. package/dist/workflows/v3/human-gate.d.ts.map +1 -0
  256. package/dist/workflows/v3/human-gate.js +153 -0
  257. package/dist/workflows/v3/human-gate.js.map +1 -0
  258. package/dist/workflows/v3/journal.d.ts +207 -0
  259. package/dist/workflows/v3/journal.d.ts.map +1 -0
  260. package/dist/workflows/v3/journal.js +74 -0
  261. package/dist/workflows/v3/journal.js.map +1 -0
  262. package/dist/workflows/v3/manifest.d.ts +17 -0
  263. package/dist/workflows/v3/manifest.d.ts.map +1 -0
  264. package/dist/workflows/v3/manifest.js +266 -0
  265. package/dist/workflows/v3/manifest.js.map +1 -0
  266. package/dist/workflows/v3/ops-projection.d.ts +110 -0
  267. package/dist/workflows/v3/ops-projection.d.ts.map +1 -0
  268. package/dist/workflows/v3/ops-projection.js +0 -0
  269. package/dist/workflows/v3/ops-projection.js.map +1 -0
  270. package/dist/workflows/v3/orchestrator.d.ts +168 -0
  271. package/dist/workflows/v3/orchestrator.d.ts.map +1 -0
  272. package/dist/workflows/v3/orchestrator.js +417 -0
  273. package/dist/workflows/v3/orchestrator.js.map +1 -0
  274. package/dist/workflows/v3/runtime.d.ts +193 -0
  275. package/dist/workflows/v3/runtime.d.ts.map +1 -0
  276. package/dist/workflows/v3/runtime.js +1284 -0
  277. package/dist/workflows/v3/runtime.js.map +1 -0
  278. package/dist/workflows/v3/spec.d.ts +32 -0
  279. package/dist/workflows/v3/spec.d.ts.map +1 -0
  280. package/dist/workflows/v3/spec.js +173 -0
  281. package/dist/workflows/v3/spec.js.map +1 -0
  282. package/dist/workflows/v3/state.d.ts +74 -0
  283. package/dist/workflows/v3/state.d.ts.map +1 -0
  284. package/dist/workflows/v3/state.js +353 -0
  285. package/dist/workflows/v3/state.js.map +1 -0
  286. package/package.json +2 -2
  287. package/dist/dashboard/web/workflow-catalog.d.ts +0 -2
  288. package/dist/dashboard/web/workflow-catalog.d.ts.map +0 -1
  289. package/dist/dashboard/web/workflow-catalog.js +0 -323
  290. package/dist/dashboard/web/workflow-catalog.js.map +0 -1
@@ -0,0 +1,85 @@
1
+ /**
2
+ * v3 humanGate — file-backed approval waits.
3
+ *
4
+ * Codex's v1-review blocker #4: a workflow gate is RUNTIME state, not an
5
+ * in-memory chat ask. Its pending/resolved status MUST persist to the runDir
6
+ * so a daemon restart doesn't lose a pending approval. The journal already
7
+ * records `gateDispatched` / `gateResolved` (audit truth); this module owns the
8
+ * materialized, mutable wait files under `runDir/waits/<waitId>.json` — the
9
+ * active state the Lark card layer keys off and the restart-recovery scan reads.
10
+ *
11
+ * Split of concerns:
12
+ * - THIS file: the file-wait store + a gate resolver that persists
13
+ * pending → resolved around an injected decision source. Pure file IO,
14
+ * bot-agnostic, testable without the daemon.
15
+ * - daemon (later): supplies `awaitDecision` — posts the Lark approval card
16
+ * (reusing v0.2's card-builder / card-handler UX) and resolves when the
17
+ * button is clicked; on restart it re-arms pending waits via
18
+ * `listPendingWaits`.
19
+ *
20
+ * The wait shape mirrors v0.2's `waitKind: 'human-gate'` lineage but is
21
+ * deliberately scoped to v3's gate needs: no deadline, but options /
22
+ * approveOptions / approvers are persisted for crash-safe card recovery.
23
+ */
24
+ import { type V3HumanGate } from './dag.js';
25
+ import type { V3RuntimeDeps } from './runtime.js';
26
+ export type GateWaitStatus = 'pending' | 'approved' | 'rejected';
27
+ export interface GateWait {
28
+ waitId: string;
29
+ nodeId: string;
30
+ /** The runtime instance this gate belongs to (`A#001`). A revisit makes a
31
+ * fresh instance + fresh gate; resolve-time validation rejects a stale card
32
+ * whose instance is no longer the node's effective one (code review). */
33
+ instanceId?: string;
34
+ prompt: string;
35
+ options: string[];
36
+ approveOptions: string[];
37
+ approvers: string[];
38
+ status: GateWaitStatus;
39
+ createdAt: number;
40
+ resolvedAt?: number;
41
+ /** open_id (or 'system') of the resolver, once resolved. */
42
+ by?: string;
43
+ /** The concrete option selected by the reviewer. */
44
+ selected?: string;
45
+ }
46
+ /** The concrete (non-optional) shape the runtime injects as `resolveGate`. */
47
+ export type GateResolver = NonNullable<V3RuntimeDeps['resolveGate']>;
48
+ export declare function waitsDir(runDir: string): string;
49
+ export declare function waitPath(runDir: string, waitId: string): string;
50
+ /** Write the initial `pending` wait file for a gate. Overwrites any stale
51
+ * file at the same waitId (a re-dispatched gate). */
52
+ export declare function writePendingWait(runDir: string, input: {
53
+ waitId: string;
54
+ nodeId: string;
55
+ prompt: string;
56
+ } & Partial<Pick<GateWait, 'options' | 'approveOptions' | 'approvers' | 'instanceId'>>): GateWait;
57
+ /** Read a single wait file, or `undefined` if it doesn't exist. */
58
+ export declare function readWait(runDir: string, waitId: string): GateWait | undefined;
59
+ /** Transition a wait to approved / rejected. Throws if the wait is missing
60
+ * (a resolution for an unknown gate is a programming error, not a no-op). */
61
+ export declare function resolveWait(runDir: string, waitId: string, resolution: 'approved' | 'rejected', by: string, selected?: string): GateWait;
62
+ export declare function normalizeGateWaitInput(gate: V3HumanGate): Pick<GateWait, 'prompt' | 'options' | 'approveOptions' | 'approvers'>;
63
+ export declare function selectedResolution(wait: Pick<GateWait, 'options' | 'approveOptions'>, selected: string): 'approved' | 'rejected' | undefined;
64
+ export declare function canResolveGateWait(wait: Pick<GateWait, 'approvers'>, by: string | undefined): boolean;
65
+ /** All still-pending waits in the runDir — the daemon's restart-recovery scan
66
+ * uses this to re-post / re-arm approval cards after a crash. */
67
+ export declare function listPendingWaits(runDir: string): GateWait[];
68
+ /**
69
+ * Build the `resolveGate` the runtime injects. Persists the wait as `pending`,
70
+ * delegates to the daemon-supplied `awaitDecision` (post card + await the
71
+ * click), then persists the resolution — so the file store is authoritative
72
+ * for pending/resolved regardless of whether the in-memory decision promise
73
+ * survives a restart (the daemon re-arms via `listPendingWaits`).
74
+ *
75
+ * `awaitDecision` is the only daemon-coupled seam; everything else here is file
76
+ * IO, which is why this factory is unit-testable with a fake decision source.
77
+ */
78
+ export declare function createFileGate(deps: {
79
+ awaitDecision: (wait: GateWait) => Promise<{
80
+ resolution: 'approved' | 'rejected';
81
+ by: string;
82
+ selected?: string;
83
+ }>;
84
+ }): GateResolver;
85
+ //# sourceMappingURL=human-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human-gate.d.ts","sourceRoot":"","sources":["../../../src/workflows/v3/human-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAEjE,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;8EAE0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;AAIrE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/D;AAWD;sDACsD;AACtD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvD,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,GAAG,gBAAgB,GAAG,WAAW,GAAG,YAAY,CAAC,CAAC,GACnF,QAAQ,CAgBV;AAED,mEAAmE;AACnE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAI7E;AAED;8EAC8E;AAC9E,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GAAG,UAAU,EACnC,EAAE,EAAE,MAAM,EACV,QAAQ,CAAC,EAAE,MAAM,GAChB,QAAQ,CAMV;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,gBAAgB,GAAG,WAAW,CAAC,CAQ/H;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,GAAG,gBAAgB,CAAC,EAClD,QAAQ,EAAE,MAAM,GACf,UAAU,GAAG,UAAU,GAAG,SAAS,CAGrC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAErG;AAED;kEACkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAc3D;AAsBD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,aAAa,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC;QAAE,UAAU,EAAE,UAAU,GAAG,UAAU,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpH,GAAG,YAAY,CAOf"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * v3 humanGate — file-backed approval waits.
3
+ *
4
+ * Codex's v1-review blocker #4: a workflow gate is RUNTIME state, not an
5
+ * in-memory chat ask. Its pending/resolved status MUST persist to the runDir
6
+ * so a daemon restart doesn't lose a pending approval. The journal already
7
+ * records `gateDispatched` / `gateResolved` (audit truth); this module owns the
8
+ * materialized, mutable wait files under `runDir/waits/<waitId>.json` — the
9
+ * active state the Lark card layer keys off and the restart-recovery scan reads.
10
+ *
11
+ * Split of concerns:
12
+ * - THIS file: the file-wait store + a gate resolver that persists
13
+ * pending → resolved around an injected decision source. Pure file IO,
14
+ * bot-agnostic, testable without the daemon.
15
+ * - daemon (later): supplies `awaitDecision` — posts the Lark approval card
16
+ * (reusing v0.2's card-builder / card-handler UX) and resolves when the
17
+ * button is clicked; on restart it re-arms pending waits via
18
+ * `listPendingWaits`.
19
+ *
20
+ * The wait shape mirrors v0.2's `waitKind: 'human-gate'` lineage but is
21
+ * deliberately scoped to v3's gate needs: no deadline, but options /
22
+ * approveOptions / approvers are persisted for crash-safe card recovery.
23
+ */
24
+ import { writeFileSync, readFileSync, existsSync, mkdirSync, renameSync, readdirSync } from 'node:fs';
25
+ import { join } from 'node:path';
26
+ import { DEFAULT_HUMAN_GATE_OPTIONS } from './dag.js';
27
+ // ─── File-wait store ────────────────────────────────────────────────────────
28
+ export function waitsDir(runDir) {
29
+ return join(runDir, 'waits');
30
+ }
31
+ export function waitPath(runDir, waitId) {
32
+ return join(waitsDir(runDir), `${waitId}.json`);
33
+ }
34
+ /** Atomic JSON write (tmp + rename) so a crash never leaves a torn wait file. */
35
+ function atomicWriteJson(path, value) {
36
+ const dir = join(path, '..');
37
+ if (!existsSync(dir))
38
+ mkdirSync(dir, { recursive: true });
39
+ const tmp = `${path}.tmp`;
40
+ writeFileSync(tmp, JSON.stringify(value, null, 2));
41
+ renameSync(tmp, path);
42
+ }
43
+ /** Write the initial `pending` wait file for a gate. Overwrites any stale
44
+ * file at the same waitId (a re-dispatched gate). */
45
+ export function writePendingWait(runDir, input) {
46
+ const options = input.options ?? [...DEFAULT_HUMAN_GATE_OPTIONS];
47
+ const approveOptions = input.approveOptions ?? (options.includes('approve') ? ['approve'] : [options[0]]);
48
+ const wait = {
49
+ waitId: input.waitId,
50
+ nodeId: input.nodeId,
51
+ ...(input.instanceId ? { instanceId: input.instanceId } : {}),
52
+ prompt: input.prompt,
53
+ options,
54
+ approveOptions,
55
+ approvers: input.approvers ?? [],
56
+ status: 'pending',
57
+ createdAt: Date.now(),
58
+ };
59
+ atomicWriteJson(waitPath(runDir, input.waitId), wait);
60
+ return wait;
61
+ }
62
+ /** Read a single wait file, or `undefined` if it doesn't exist. */
63
+ export function readWait(runDir, waitId) {
64
+ const path = waitPath(runDir, waitId);
65
+ if (!existsSync(path))
66
+ return undefined;
67
+ return normalizeWaitFile(JSON.parse(readFileSync(path, 'utf-8')));
68
+ }
69
+ /** Transition a wait to approved / rejected. Throws if the wait is missing
70
+ * (a resolution for an unknown gate is a programming error, not a no-op). */
71
+ export function resolveWait(runDir, waitId, resolution, by, selected) {
72
+ const existing = readWait(runDir, waitId);
73
+ if (!existing)
74
+ throw new Error(`v3 human-gate: no pending wait "${waitId}" in ${runDir}`);
75
+ const resolved = { ...existing, status: resolution, resolvedAt: Date.now(), by, selected };
76
+ atomicWriteJson(waitPath(runDir, waitId), resolved);
77
+ return resolved;
78
+ }
79
+ export function normalizeGateWaitInput(gate) {
80
+ const options = gate.options ?? [...DEFAULT_HUMAN_GATE_OPTIONS];
81
+ return {
82
+ prompt: gate.prompt,
83
+ options,
84
+ approveOptions: gate.approveOptions ?? (options.includes('approve') ? ['approve'] : [options[0]]),
85
+ approvers: gate.approvers ?? [],
86
+ };
87
+ }
88
+ export function selectedResolution(wait, selected) {
89
+ if (!wait.options.includes(selected))
90
+ return undefined;
91
+ return wait.approveOptions.includes(selected) ? 'approved' : 'rejected';
92
+ }
93
+ export function canResolveGateWait(wait, by) {
94
+ return wait.approvers.length === 0 || (!!by && wait.approvers.includes(by));
95
+ }
96
+ /** All still-pending waits in the runDir — the daemon's restart-recovery scan
97
+ * uses this to re-post / re-arm approval cards after a crash. */
98
+ export function listPendingWaits(runDir) {
99
+ const dir = waitsDir(runDir);
100
+ if (!existsSync(dir))
101
+ return [];
102
+ const out = [];
103
+ for (const name of readdirSync(dir)) {
104
+ if (!name.endsWith('.json') || name.endsWith('.tmp'))
105
+ continue;
106
+ try {
107
+ const wait = normalizeWaitFile(JSON.parse(readFileSync(join(dir, name), 'utf-8')));
108
+ if (wait.status === 'pending')
109
+ out.push(wait);
110
+ }
111
+ catch {
112
+ // skip a torn / unparseable wait file (mid-write crash)
113
+ }
114
+ }
115
+ return out;
116
+ }
117
+ function normalizeWaitFile(raw) {
118
+ const options = raw.options ?? [...DEFAULT_HUMAN_GATE_OPTIONS];
119
+ return {
120
+ waitId: raw.waitId ?? '',
121
+ nodeId: raw.nodeId ?? '',
122
+ ...(raw.instanceId ? { instanceId: raw.instanceId } : {}),
123
+ prompt: raw.prompt ?? '',
124
+ options,
125
+ approveOptions: raw.approveOptions ?? (options.includes('approve') ? ['approve'] : [options[0]]),
126
+ approvers: raw.approvers ?? [],
127
+ status: raw.status ?? 'pending',
128
+ createdAt: raw.createdAt ?? 0,
129
+ resolvedAt: raw.resolvedAt,
130
+ by: raw.by,
131
+ selected: raw.selected,
132
+ };
133
+ }
134
+ // ─── Gate resolver (injected into the runtime) ──────────────────────────────
135
+ /**
136
+ * Build the `resolveGate` the runtime injects. Persists the wait as `pending`,
137
+ * delegates to the daemon-supplied `awaitDecision` (post card + await the
138
+ * click), then persists the resolution — so the file store is authoritative
139
+ * for pending/resolved regardless of whether the in-memory decision promise
140
+ * survives a restart (the daemon re-arms via `listPendingWaits`).
141
+ *
142
+ * `awaitDecision` is the only daemon-coupled seam; everything else here is file
143
+ * IO, which is why this factory is unit-testable with a fake decision source.
144
+ */
145
+ export function createFileGate(deps) {
146
+ return async ({ nodeId, prompt, waitId, runDir }) => {
147
+ const wait = writePendingWait(runDir, { waitId, nodeId, prompt });
148
+ const { resolution, by, selected } = await deps.awaitDecision(wait);
149
+ resolveWait(runDir, waitId, resolution, by, selected);
150
+ return { resolution, by, selected };
151
+ };
152
+ }
153
+ //# sourceMappingURL=human-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"human-gate.js","sourceRoot":"","sources":["../../../src/workflows/v3/human-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * v3 journal — append-only event stream (the run's audit truth).
3
+ *
4
+ * Codex's v1-review blocker #1: v3 is NOT a "only-mutable-STATE" recoverable
5
+ * system. `journal.ndjson` is the append-only source of audit truth (one JSON
6
+ * object per line, `ts`-stamped) from which `state.ts` materializes the STATE
7
+ * checkpoint. Concurrency / retry / gate / cancel / failure-root-cause all
8
+ * leave an ordered trail here.
9
+ *
10
+ * Append-only + line-oriented = crash-tolerant by construction: a torn final
11
+ * line (process died mid-write) is skipped on read; everything before it is
12
+ * intact. No locking needed for the journal itself — appends are serialized
13
+ * by the single runtime loop (the per-node LOCK guards worker dispatch, not
14
+ * the journal).
15
+ */
16
+ import type { GoalAsk } from './contract.js';
17
+ /** Why a node failed — drives fail-fast root-cause reporting + retry policy
18
+ * (`classifyTerminal` maps each class to `blocked` or `failed`).
19
+ * `gateRejected` / `cancelled` are user-driven; the rest are faults. */
20
+ export type V3ErrorClass = 'workerError' | 'manifestInvalid' | 'resultInvalid' | 'timeout' | 'gateRejected' | 'cancelled';
21
+ export type V3RunFailureReason = 'allSinksSkipped';
22
+ /**
23
+ * The MVP event union. Static DAG + fail-fast, so the lifecycle is small:
24
+ * run boundaries, per-node dispatch/settle, and gate dispatch/resolve. Retry
25
+ * (`attempts/NNN`) is modeled by `attemptId` on dispatch/settle events — a new
26
+ * attempt is just another `nodeDispatched` with a fresh `attemptId`.
27
+ */
28
+ /**
29
+ * Structured loop reference carried on body-instance dispatches. The expanded
30
+ * nodeId (`repairLoop.i001.code`) is an OPAQUE key — projections/dashboards
31
+ * group by THIS field and never parse the id string (body ids may themselves
32
+ * contain dots).
33
+ */
34
+ export interface V3LoopRef {
35
+ loopId: string;
36
+ iteration: number;
37
+ bodyNodeId: string;
38
+ }
39
+ export type V3Event = {
40
+ type: 'runStarted';
41
+ runId: string;
42
+ } | {
43
+ type: 'nodeDispatched';
44
+ nodeId: string;
45
+ instanceId?: string;
46
+ attemptId: string;
47
+ loop?: V3LoopRef;
48
+ } | {
49
+ type: 'nodeSessionReady';
50
+ nodeId: string;
51
+ instanceId?: string;
52
+ attemptId: string;
53
+ sessionInfo: {
54
+ sessionId: string;
55
+ webPort?: number;
56
+ };
57
+ ptyLogPath?: string;
58
+ } | {
59
+ type: 'nodeSucceeded';
60
+ nodeId: string;
61
+ instanceId?: string;
62
+ attemptId: string;
63
+ manifestPath: string;
64
+ } | {
65
+ type: 'nodeFailed';
66
+ nodeId: string;
67
+ instanceId?: string;
68
+ attemptId: string;
69
+ errorClass: V3ErrorClass;
70
+ errorCode?: string;
71
+ message?: string;
72
+ } | {
73
+ type: 'nodeBlocked';
74
+ nodeId: string;
75
+ instanceId?: string;
76
+ attemptId: string;
77
+ errorClass: V3ErrorClass;
78
+ errorCode?: string;
79
+ message?: string;
80
+ ask?: GoalAsk;
81
+ revisitTo?: string;
82
+ } | {
83
+ type: 'nodeRetryRequested';
84
+ nodeId: string;
85
+ instanceId?: string;
86
+ previousAttemptId: string;
87
+ nextAttemptId: string;
88
+ reason: 'blockedRetry';
89
+ previousErrorClass?: V3ErrorClass;
90
+ previousErrorCode?: string;
91
+ answer?: {
92
+ path: string;
93
+ preview: string;
94
+ by: string;
95
+ };
96
+ } | {
97
+ type: 'gateDispatched';
98
+ nodeId: string;
99
+ instanceId?: string;
100
+ waitId: string;
101
+ } | {
102
+ type: 'gateResolved';
103
+ nodeId: string;
104
+ instanceId?: string;
105
+ waitId: string;
106
+ resolution: 'approved' | 'rejected';
107
+ by: string;
108
+ selected?: string;
109
+ } | {
110
+ type: 'edgeResolved';
111
+ from: string;
112
+ to: string;
113
+ fromInstanceId?: string;
114
+ toInstanceId?: string;
115
+ sourceAttemptId: string;
116
+ active: boolean;
117
+ detail?: string;
118
+ } | {
119
+ type: 'nodeSkipped';
120
+ nodeId: string;
121
+ reason: 'triggerRuleUnsatisfied';
122
+ detail?: string;
123
+ } | {
124
+ type: 'nodeCancelled';
125
+ nodeId: string;
126
+ instanceId?: string;
127
+ attemptId?: string;
128
+ reason: 'earlyReleaseLoser';
129
+ byNodeId: string;
130
+ detail?: string;
131
+ } | {
132
+ type: 'nodeRevisitRequested';
133
+ nodeId: string;
134
+ instanceId: string;
135
+ attemptId: string;
136
+ toNodeId: string;
137
+ reason?: string;
138
+ reasonPath?: string;
139
+ sourceManifestPath?: string;
140
+ targetPreviousManifestPath?: string;
141
+ } | {
142
+ type: 'nodeInstanceSuperseded';
143
+ nodeId: string;
144
+ instanceId: string;
145
+ byNodeId: string;
146
+ reason: 'refresh';
147
+ } | {
148
+ type: 'revisitBudgetGranted';
149
+ sourceNodeId?: string;
150
+ toNodeId?: string;
151
+ by: string;
152
+ reason?: string;
153
+ } | {
154
+ type: 'loopStarted';
155
+ loopId: string;
156
+ } | {
157
+ type: 'loopIterationStarted';
158
+ loopId: string;
159
+ iteration: number;
160
+ } | {
161
+ type: 'loopIterationDecision';
162
+ loopId: string;
163
+ iteration: number;
164
+ decision: 'exit' | 'continue' | 'exhausted';
165
+ /** Human-readable why (e.g. `result.passed=false (2/3 iterations used)`). */
166
+ detail?: string;
167
+ } | {
168
+ type: 'loopIterationGranted';
169
+ loopId: string;
170
+ fromIteration: number;
171
+ by?: string;
172
+ } | {
173
+ type: 'runSucceeded';
174
+ } | {
175
+ type: 'runFailed';
176
+ failedNodeId?: string;
177
+ reason?: V3RunFailureReason;
178
+ detail?: string;
179
+ } | {
180
+ type: 'runBlocked';
181
+ blockedNodeId: string;
182
+ };
183
+ /** A journal line: the event flattened with its append timestamp (flattened —
184
+ * not `{ts, event}` — so `grep nodeFailed journal.ndjson` just works). */
185
+ export type StoredEvent = V3Event & {
186
+ ts: number;
187
+ };
188
+ /**
189
+ * Append one event as a single NDJSON line. Stamps `ts` (epoch ms) at write
190
+ * time. Creates the parent directory if missing so the very first
191
+ * `runStarted` doesn't require the caller to pre-create the runDir.
192
+ *
193
+ * Synchronous on purpose: the runtime loop must observe its own writes in
194
+ * order, and the journal is the linearization point — an async append would
195
+ * open a window where `decideNext` runs against stale state.
196
+ */
197
+ export declare function appendEvent(journalPath: string, event: V3Event): StoredEvent;
198
+ /**
199
+ * Read every event in append order. Tolerates a torn FINAL line (crash
200
+ * mid-append) but throws on any earlier unparseable line — a mid-file parse
201
+ * failure is real corruption, and silently dropping a middle event would
202
+ * desync the replayed state (e.g. a lost `nodeSucceeded` leaves the node
203
+ * looking pending forever), so fail loud instead (codex hardening #11).
204
+ * Returns `[]` if the file does not exist yet (a run that never started).
205
+ */
206
+ export declare function readJournal(journalPath: string): StoredEvent[];
207
+ //# sourceMappingURL=journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../../src/workflows/v3/journal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * v3 journal — append-only event stream (the run's audit truth).
3
+ *
4
+ * Codex's v1-review blocker #1: v3 is NOT a "only-mutable-STATE" recoverable
5
+ * system. `journal.ndjson` is the append-only source of audit truth (one JSON
6
+ * object per line, `ts`-stamped) from which `state.ts` materializes the STATE
7
+ * checkpoint. Concurrency / retry / gate / cancel / failure-root-cause all
8
+ * leave an ordered trail here.
9
+ *
10
+ * Append-only + line-oriented = crash-tolerant by construction: a torn final
11
+ * line (process died mid-write) is skipped on read; everything before it is
12
+ * intact. No locking needed for the journal itself — appends are serialized
13
+ * by the single runtime loop (the per-node LOCK guards worker dispatch, not
14
+ * the journal).
15
+ */
16
+ import { appendFileSync, readFileSync, existsSync, mkdirSync } from 'node:fs';
17
+ import { dirname } from 'node:path';
18
+ // ─── Append ─────────────────────────────────────────────────────────────────
19
+ /**
20
+ * Append one event as a single NDJSON line. Stamps `ts` (epoch ms) at write
21
+ * time. Creates the parent directory if missing so the very first
22
+ * `runStarted` doesn't require the caller to pre-create the runDir.
23
+ *
24
+ * Synchronous on purpose: the runtime loop must observe its own writes in
25
+ * order, and the journal is the linearization point — an async append would
26
+ * open a window where `decideNext` runs against stale state.
27
+ */
28
+ export function appendEvent(journalPath, event) {
29
+ const stored = { ts: Date.now(), ...event };
30
+ const dir = dirname(journalPath);
31
+ if (!existsSync(dir))
32
+ mkdirSync(dir, { recursive: true });
33
+ appendFileSync(journalPath, JSON.stringify(stored) + '\n');
34
+ return stored;
35
+ }
36
+ // ─── Read / replay ────────────────────────────────────────────────────────
37
+ /**
38
+ * Read every event in append order. Tolerates a torn FINAL line (crash
39
+ * mid-append) but throws on any earlier unparseable line — a mid-file parse
40
+ * failure is real corruption, and silently dropping a middle event would
41
+ * desync the replayed state (e.g. a lost `nodeSucceeded` leaves the node
42
+ * looking pending forever), so fail loud instead (codex hardening #11).
43
+ * Returns `[]` if the file does not exist yet (a run that never started).
44
+ */
45
+ export function readJournal(journalPath) {
46
+ if (!existsSync(journalPath))
47
+ return [];
48
+ const raw = readFileSync(journalPath, 'utf-8');
49
+ const lines = raw.split('\n');
50
+ // Only the last non-empty line can legitimately be a half-written append.
51
+ let lastNonEmpty = -1;
52
+ for (let i = lines.length - 1; i >= 0; i--) {
53
+ if (lines[i].trim()) {
54
+ lastNonEmpty = i;
55
+ break;
56
+ }
57
+ }
58
+ const out = [];
59
+ for (let i = 0; i < lines.length; i++) {
60
+ const trimmed = lines[i].trim();
61
+ if (!trimmed)
62
+ continue;
63
+ try {
64
+ out.push(JSON.parse(trimmed));
65
+ }
66
+ catch (err) {
67
+ if (i === lastNonEmpty)
68
+ break; // torn final line from an interrupted append — tolerate
69
+ throw new Error(`v3 journal corrupted at line ${i + 1} of ${journalPath}: ${err instanceof Error ? err.message : String(err)}`);
70
+ }
71
+ }
72
+ return out;
73
+ }
74
+ //# sourceMappingURL=journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.js","sourceRoot":"","sources":["../../../src/workflows/v3/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0NpC,+EAA+E;AAE/E;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,KAAc;IAC7D,MAAM,MAAM,GAAgB,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC;IACzD,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,6EAA6E;AAE7E;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,0EAA0E;IAC1E,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YAAC,YAAY,GAAG,CAAC,CAAC;YAAC,MAAM;QAAC,CAAC;IACpD,CAAC;IACD,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,YAAY;gBAAE,MAAM,CAAC,wDAAwD;YACvF,MAAM,IAAI,KAAK,CACb,gCAAgC,CAAC,GAAG,CAAC,OAAO,WAAW,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC/G,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * v3 node manifest validator.
3
+ *
4
+ * Goal-mode workers write `manifest.json` at BOTMUX_GOAL_MANIFEST_PATH.
5
+ * The runtime treats that file as untrusted agent output: this module checks
6
+ * the shape, status invariants, path containment, file metadata, and hashes
7
+ * before downstream nodes receive any file paths.
8
+ */
9
+ import { type Manifest } from './contract.js';
10
+ export declare class ManifestValidationError extends Error {
11
+ readonly problems: string[];
12
+ constructor(problems: string[]);
13
+ }
14
+ export declare function readAndValidateManifest(manifestPath: string, outputDir: string): Promise<Manifest>;
15
+ export declare function validateManifest(value: unknown, outputDir: string): Promise<Manifest>;
16
+ export declare function resolveManifestFilePath(outputDir: string, relativePath: string): string;
17
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/workflows/v3/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAML,KAAK,QAAQ,EAId,MAAM,eAAe,CAAC;AAEvB,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,QAAQ,EAAE,MAAM,EAAE;gBAAlB,QAAQ,EAAE,MAAM,EAAE;CAI/C;AAED,wBAAsB,uBAAuB,CAC3C,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,CAAC,CAoBnB;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkD3F;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEvF"}