@a5c-ai/babysitter-sdk 0.0.16

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 (169) hide show
  1. package/dist/cli/main.d.ts +5 -0
  2. package/dist/cli/main.d.ts.map +1 -0
  3. package/dist/cli/main.js +1343 -0
  4. package/dist/cli/nodeTaskRunner.d.ts +16 -0
  5. package/dist/cli/nodeTaskRunner.d.ts.map +1 -0
  6. package/dist/cli/nodeTaskRunner.js +46 -0
  7. package/dist/index.d.ts +10 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +25 -0
  10. package/dist/runner/env.d.ts +58 -0
  11. package/dist/runner/env.d.ts.map +1 -0
  12. package/dist/runner/env.js +113 -0
  13. package/dist/runner/index.d.ts +3 -0
  14. package/dist/runner/index.d.ts.map +1 -0
  15. package/dist/runner/index.js +18 -0
  16. package/dist/runner/nodeRunner.d.ts +60 -0
  17. package/dist/runner/nodeRunner.d.ts.map +1 -0
  18. package/dist/runner/nodeRunner.js +354 -0
  19. package/dist/runtime/commitEffectResult.d.ts +3 -0
  20. package/dist/runtime/commitEffectResult.d.ts.map +1 -0
  21. package/dist/runtime/commitEffectResult.js +172 -0
  22. package/dist/runtime/constants.d.ts +2 -0
  23. package/dist/runtime/constants.d.ts.map +1 -0
  24. package/dist/runtime/constants.js +5 -0
  25. package/dist/runtime/createRun.d.ts +3 -0
  26. package/dist/runtime/createRun.d.ts.map +1 -0
  27. package/dist/runtime/createRun.js +81 -0
  28. package/dist/runtime/errorUtils.d.ts +10 -0
  29. package/dist/runtime/errorUtils.d.ts.map +1 -0
  30. package/dist/runtime/errorUtils.js +42 -0
  31. package/dist/runtime/exceptions.d.ts +45 -0
  32. package/dist/runtime/exceptions.d.ts.map +1 -0
  33. package/dist/runtime/exceptions.js +99 -0
  34. package/dist/runtime/index.d.ts +12 -0
  35. package/dist/runtime/index.d.ts.map +1 -0
  36. package/dist/runtime/index.js +34 -0
  37. package/dist/runtime/instrumentation.d.ts +6 -0
  38. package/dist/runtime/instrumentation.d.ts.map +1 -0
  39. package/dist/runtime/instrumentation.js +14 -0
  40. package/dist/runtime/intrinsics/breakpoint.d.ts +4 -0
  41. package/dist/runtime/intrinsics/breakpoint.d.ts.map +1 -0
  42. package/dist/runtime/intrinsics/breakpoint.js +42 -0
  43. package/dist/runtime/intrinsics/index.d.ts +7 -0
  44. package/dist/runtime/intrinsics/index.d.ts.map +1 -0
  45. package/dist/runtime/intrinsics/index.js +15 -0
  46. package/dist/runtime/intrinsics/orchestratorTask.d.ts +4 -0
  47. package/dist/runtime/intrinsics/orchestratorTask.d.ts.map +1 -0
  48. package/dist/runtime/intrinsics/orchestratorTask.js +28 -0
  49. package/dist/runtime/intrinsics/parallel.d.ts +5 -0
  50. package/dist/runtime/intrinsics/parallel.d.ts.map +1 -0
  51. package/dist/runtime/intrinsics/parallel.js +45 -0
  52. package/dist/runtime/intrinsics/sleep.d.ts +4 -0
  53. package/dist/runtime/intrinsics/sleep.d.ts.map +1 -0
  54. package/dist/runtime/intrinsics/sleep.js +70 -0
  55. package/dist/runtime/intrinsics/task.d.ts +20 -0
  56. package/dist/runtime/intrinsics/task.d.ts.map +1 -0
  57. package/dist/runtime/intrinsics/task.js +237 -0
  58. package/dist/runtime/invocation/hashInvocationKey.d.ts +12 -0
  59. package/dist/runtime/invocation/hashInvocationKey.d.ts.map +1 -0
  60. package/dist/runtime/invocation/hashInvocationKey.js +12 -0
  61. package/dist/runtime/invocation/index.d.ts +3 -0
  62. package/dist/runtime/invocation/index.d.ts.map +1 -0
  63. package/dist/runtime/invocation/index.js +5 -0
  64. package/dist/runtime/orchestrateIteration.d.ts +3 -0
  65. package/dist/runtime/orchestrateIteration.d.ts.map +1 -0
  66. package/dist/runtime/orchestrateIteration.js +195 -0
  67. package/dist/runtime/processContext.d.ts +19 -0
  68. package/dist/runtime/processContext.d.ts.map +1 -0
  69. package/dist/runtime/processContext.js +55 -0
  70. package/dist/runtime/replay/createReplayEngine.d.ts +31 -0
  71. package/dist/runtime/replay/createReplayEngine.d.ts.map +1 -0
  72. package/dist/runtime/replay/createReplayEngine.js +82 -0
  73. package/dist/runtime/replay/effectIndex.d.ts +34 -0
  74. package/dist/runtime/replay/effectIndex.d.ts.map +1 -0
  75. package/dist/runtime/replay/effectIndex.js +241 -0
  76. package/dist/runtime/replay/index.d.ts +7 -0
  77. package/dist/runtime/replay/index.d.ts.map +1 -0
  78. package/dist/runtime/replay/index.js +19 -0
  79. package/dist/runtime/replay/replayCursor.d.ts +7 -0
  80. package/dist/runtime/replay/replayCursor.d.ts.map +1 -0
  81. package/dist/runtime/replay/replayCursor.js +22 -0
  82. package/dist/runtime/replay/stateCache.d.ts +48 -0
  83. package/dist/runtime/replay/stateCache.d.ts.map +1 -0
  84. package/dist/runtime/replay/stateCache.js +211 -0
  85. package/dist/runtime/types.d.ts +147 -0
  86. package/dist/runtime/types.d.ts.map +1 -0
  87. package/dist/runtime/types.js +2 -0
  88. package/dist/storage/atomic.d.ts +2 -0
  89. package/dist/storage/atomic.d.ts.map +1 -0
  90. package/dist/storage/atomic.js +54 -0
  91. package/dist/storage/cleanup.d.ts +4 -0
  92. package/dist/storage/cleanup.d.ts.map +1 -0
  93. package/dist/storage/cleanup.js +96 -0
  94. package/dist/storage/clock.d.ts +6 -0
  95. package/dist/storage/clock.d.ts.map +1 -0
  96. package/dist/storage/clock.js +29 -0
  97. package/dist/storage/createRunDir.d.ts +6 -0
  98. package/dist/storage/createRunDir.d.ts.map +1 -0
  99. package/dist/storage/createRunDir.js +59 -0
  100. package/dist/storage/index.d.ts +9 -0
  101. package/dist/storage/index.d.ts.map +1 -0
  102. package/dist/storage/index.js +28 -0
  103. package/dist/storage/journal.d.ts +4 -0
  104. package/dist/storage/journal.d.ts.map +1 -0
  105. package/dist/storage/journal.js +103 -0
  106. package/dist/storage/lock.d.ts +5 -0
  107. package/dist/storage/lock.d.ts.map +1 -0
  108. package/dist/storage/lock.js +41 -0
  109. package/dist/storage/paths.d.ts +19 -0
  110. package/dist/storage/paths.d.ts.map +1 -0
  111. package/dist/storage/paths.js +46 -0
  112. package/dist/storage/runFiles.d.ts +5 -0
  113. package/dist/storage/runFiles.d.ts.map +1 -0
  114. package/dist/storage/runFiles.js +39 -0
  115. package/dist/storage/snapshotState.d.ts +10 -0
  116. package/dist/storage/snapshotState.d.ts.map +1 -0
  117. package/dist/storage/snapshotState.js +15 -0
  118. package/dist/storage/storeTaskArtifacts.d.ts +6 -0
  119. package/dist/storage/storeTaskArtifacts.d.ts.map +1 -0
  120. package/dist/storage/storeTaskArtifacts.js +58 -0
  121. package/dist/storage/tasks.d.ts +17 -0
  122. package/dist/storage/tasks.d.ts.map +1 -0
  123. package/dist/storage/tasks.js +82 -0
  124. package/dist/storage/types.d.ts +112 -0
  125. package/dist/storage/types.d.ts.map +1 -0
  126. package/dist/storage/types.js +2 -0
  127. package/dist/storage/ulids.d.ts +11 -0
  128. package/dist/storage/ulids.d.ts.map +1 -0
  129. package/dist/storage/ulids.js +25 -0
  130. package/dist/tasks/batching.d.ts +29 -0
  131. package/dist/tasks/batching.d.ts.map +1 -0
  132. package/dist/tasks/batching.js +66 -0
  133. package/dist/tasks/context.d.ts +11 -0
  134. package/dist/tasks/context.d.ts.map +1 -0
  135. package/dist/tasks/context.js +181 -0
  136. package/dist/tasks/defineTask.d.ts +9 -0
  137. package/dist/tasks/defineTask.d.ts.map +1 -0
  138. package/dist/tasks/defineTask.js +58 -0
  139. package/dist/tasks/index.d.ts +8 -0
  140. package/dist/tasks/index.d.ts.map +1 -0
  141. package/dist/tasks/index.js +23 -0
  142. package/dist/tasks/kinds/index.d.ts +7 -0
  143. package/dist/tasks/kinds/index.d.ts.map +1 -0
  144. package/dist/tasks/kinds/index.js +333 -0
  145. package/dist/tasks/registry.d.ts +53 -0
  146. package/dist/tasks/registry.d.ts.map +1 -0
  147. package/dist/tasks/registry.js +145 -0
  148. package/dist/tasks/serializer.d.ts +60 -0
  149. package/dist/tasks/serializer.d.ts.map +1 -0
  150. package/dist/tasks/serializer.js +193 -0
  151. package/dist/tasks/types.d.ts +148 -0
  152. package/dist/tasks/types.d.ts.map +1 -0
  153. package/dist/tasks/types.js +2 -0
  154. package/dist/test-fixtures/kinds/index.d.ts +56 -0
  155. package/dist/test-fixtures/kinds/index.d.ts.map +1 -0
  156. package/dist/test-fixtures/kinds/index.js +44 -0
  157. package/dist/testing/deterministic.d.ts +90 -0
  158. package/dist/testing/deterministic.d.ts.map +1 -0
  159. package/dist/testing/deterministic.js +449 -0
  160. package/dist/testing/index.d.ts +4 -0
  161. package/dist/testing/index.d.ts.map +1 -0
  162. package/dist/testing/index.js +23 -0
  163. package/dist/testing/runHarness.d.ts +64 -0
  164. package/dist/testing/runHarness.d.ts.map +1 -0
  165. package/dist/testing/runHarness.js +161 -0
  166. package/dist/testing/snapshots.d.ts +17 -0
  167. package/dist/testing/snapshots.d.ts.map +1 -0
  168. package/dist/testing/snapshots.js +24 -0
  169. package/package.json +35 -0
@@ -0,0 +1,1343 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createBabysitterCli = createBabysitterCli;
37
+ const node_fs_1 = require("node:fs");
38
+ const path = __importStar(require("node:path"));
39
+ const nodeTaskRunner_1 = require("./nodeTaskRunner");
40
+ const orchestrateIteration_1 = require("../runtime/orchestrateIteration");
41
+ const createRun_1 = require("../runtime/createRun");
42
+ const effectIndex_1 = require("../runtime/replay/effectIndex");
43
+ const stateCache_1 = require("../runtime/replay/stateCache");
44
+ const tasks_1 = require("../storage/tasks");
45
+ const journal_1 = require("../storage/journal");
46
+ const runFiles_1 = require("../storage/runFiles");
47
+ const USAGE = `Usage:
48
+ babysitter run:create --process-id <id> --entry <path#export> [--runs-dir <dir>] [--inputs <file>] [--run-id <id>] [--process-revision <rev>] [--request <id>] [--json] [--dry-run]
49
+ babysitter run:status <runDir> [--runs-dir <dir>] [--json]
50
+ babysitter run:events <runDir> [--runs-dir <dir>] [--json] [--limit <n>] [--reverse] [--filter-type <type>]
51
+ babysitter run:rebuild-state <runDir> [--runs-dir <dir>] [--json] [--dry-run]
52
+ babysitter task:run <runDir> <effectId> [--runs-dir <dir>] [--json] [--dry-run]
53
+ babysitter run:step <runDir> [--runs-dir <dir>] [--json] [--now <iso8601>]
54
+ babysitter run:continue <runDir> [--runs-dir <dir>] [--json] [--dry-run] [--auto-node-tasks] [--auto-node-max <n>] [--auto-node-label <text>]
55
+ babysitter task:list <runDir> [--runs-dir <dir>] [--pending] [--kind <kind>] [--json]
56
+ babysitter task:show <runDir> <effectId> [--runs-dir <dir>] [--json]
57
+
58
+ Global flags:
59
+ --runs-dir <dir> Override the runs directory (defaults to current working directory).
60
+ --json Emit JSON output when supported by the command.
61
+ --dry-run Describe planned mutations without changing on-disk state.
62
+ --verbose Log resolved paths and options to stderr for debugging.
63
+ --help, -h Show this help text.`;
64
+ const LARGE_RESULT_PREVIEW_LIMIT = 1024 * 1024; // 1 MiB
65
+ function parseArgs(argv) {
66
+ const [initialCommand, ...rest] = argv;
67
+ const parsed = {
68
+ command: initialCommand,
69
+ runsDir: ".",
70
+ json: false,
71
+ dryRun: false,
72
+ verbose: false,
73
+ helpRequested: false,
74
+ autoNodeTasks: false,
75
+ pendingOnly: false,
76
+ reverseOrder: false,
77
+ };
78
+ if (parsed.command === "--help" || parsed.command === "-h") {
79
+ parsed.command = undefined;
80
+ parsed.helpRequested = true;
81
+ }
82
+ const positionals = [];
83
+ for (let i = 0; i < rest.length; i += 1) {
84
+ const arg = rest[i];
85
+ if (arg === "--help" || arg === "-h") {
86
+ parsed.helpRequested = true;
87
+ continue;
88
+ }
89
+ if (arg === "--runs-dir") {
90
+ parsed.runsDir = expectFlagValue(rest, ++i, "--runs-dir");
91
+ continue;
92
+ }
93
+ if (arg === "--json") {
94
+ parsed.json = true;
95
+ continue;
96
+ }
97
+ if (arg === "--dry-run") {
98
+ parsed.dryRun = true;
99
+ continue;
100
+ }
101
+ if (arg === "--verbose") {
102
+ parsed.verbose = true;
103
+ continue;
104
+ }
105
+ if (arg === "--auto-node-tasks") {
106
+ parsed.autoNodeTasks = true;
107
+ continue;
108
+ }
109
+ if (arg === "--pending") {
110
+ parsed.pendingOnly = true;
111
+ continue;
112
+ }
113
+ if (arg === "--kind") {
114
+ parsed.kindFilter = expectFlagValue(rest, ++i, "--kind");
115
+ continue;
116
+ }
117
+ if (arg === "--limit") {
118
+ const raw = expectFlagValue(rest, ++i, "--limit");
119
+ parsed.limit = parsePositiveInteger(raw, "--limit");
120
+ continue;
121
+ }
122
+ if (arg === "--reverse") {
123
+ parsed.reverseOrder = true;
124
+ continue;
125
+ }
126
+ if (arg === "--filter-type") {
127
+ parsed.filterType = expectFlagValue(rest, ++i, "--filter-type");
128
+ continue;
129
+ }
130
+ if (arg === "--process-id") {
131
+ parsed.processId = expectFlagValue(rest, ++i, "--process-id");
132
+ continue;
133
+ }
134
+ if (arg === "--entry") {
135
+ parsed.entrySpecifier = expectFlagValue(rest, ++i, "--entry");
136
+ continue;
137
+ }
138
+ if (arg === "--inputs") {
139
+ parsed.inputsPath = expectFlagValue(rest, ++i, "--inputs");
140
+ continue;
141
+ }
142
+ if (arg === "--run-id") {
143
+ parsed.runIdOverride = expectFlagValue(rest, ++i, "--run-id");
144
+ continue;
145
+ }
146
+ if (arg === "--process-revision") {
147
+ parsed.processRevision = expectFlagValue(rest, ++i, "--process-revision");
148
+ continue;
149
+ }
150
+ if (arg === "--request") {
151
+ parsed.requestId = expectFlagValue(rest, ++i, "--request");
152
+ continue;
153
+ }
154
+ if (arg === "--now") {
155
+ parsed.nowOverride = expectFlagValue(rest, ++i, "--now");
156
+ continue;
157
+ }
158
+ if (arg === "--auto-node-max") {
159
+ const raw = expectFlagValue(rest, ++i, "--auto-node-max");
160
+ parsed.autoNodeMax = parsePositiveInteger(raw, "--auto-node-max");
161
+ continue;
162
+ }
163
+ if (arg === "--auto-node-label") {
164
+ parsed.autoNodeLabel = expectFlagValue(rest, ++i, "--auto-node-label");
165
+ continue;
166
+ }
167
+ positionals.push(arg);
168
+ }
169
+ if (parsed.command === "task:run") {
170
+ [parsed.runDirArg, parsed.effectId] = positionals;
171
+ }
172
+ else if (parsed.command === "run:continue") {
173
+ [parsed.runDirArg] = positionals;
174
+ }
175
+ else if (parsed.command === "task:list") {
176
+ [parsed.runDirArg] = positionals;
177
+ }
178
+ else if (parsed.command === "task:show") {
179
+ [parsed.runDirArg, parsed.effectId] = positionals;
180
+ }
181
+ else if (parsed.command === "run:status") {
182
+ [parsed.runDirArg] = positionals;
183
+ }
184
+ else if (parsed.command === "run:events") {
185
+ [parsed.runDirArg] = positionals;
186
+ }
187
+ else if (parsed.command === "run:rebuild-state") {
188
+ [parsed.runDirArg] = positionals;
189
+ }
190
+ else if (parsed.command === "run:step") {
191
+ [parsed.runDirArg] = positionals;
192
+ }
193
+ return parsed;
194
+ }
195
+ function resolveRunDir(baseDir, runDirArg) {
196
+ if (!runDirArg)
197
+ throw new Error("Run directory argument is required.");
198
+ return path.resolve(baseDir, runDirArg);
199
+ }
200
+ function expectFlagValue(args, index, flag) {
201
+ const value = args[index];
202
+ if (!value) {
203
+ throw new Error(`${flag} requires a value`);
204
+ }
205
+ return value;
206
+ }
207
+ function parsePositiveInteger(raw, flag) {
208
+ const parsed = Number(raw);
209
+ if (!Number.isFinite(parsed) || parsed <= 0) {
210
+ throw new Error(`${flag} must be a positive integer`);
211
+ }
212
+ return Math.floor(parsed);
213
+ }
214
+ function summarizeActions(actions) {
215
+ return actions.map((action) => ({
216
+ effectId: action.effectId,
217
+ kind: action.kind,
218
+ label: action.label,
219
+ }));
220
+ }
221
+ function matchesAutoNodeLabel(action, filter) {
222
+ if (!filter)
223
+ return true;
224
+ const needle = filter.toLowerCase();
225
+ const haystacks = [action.label, ...(action.labels ?? []), action.effectId];
226
+ return haystacks.some((value) => (value ? value.toLowerCase().includes(needle) : false));
227
+ }
228
+ function logPendingActions(actions, options = {}) {
229
+ const summaries = summarizeActions(actions);
230
+ if (options.command && options.includeHeader !== false) {
231
+ const headerParts = [
232
+ `[${options.command}] status=waiting`,
233
+ `pending=${summaries.length}`,
234
+ ...(options.metadataParts ?? []),
235
+ ];
236
+ console.error(headerParts.join(" "));
237
+ }
238
+ for (const summary of summaries) {
239
+ const label = summary.label ? ` ${summary.label}` : "";
240
+ console.error(`- ${summary.effectId} [${summary.kind}]${label}`);
241
+ }
242
+ return summaries;
243
+ }
244
+ function countActionsByKind(actions) {
245
+ const counts = new Map();
246
+ for (const action of actions) {
247
+ counts.set(action.kind, (counts.get(action.kind) ?? 0) + 1);
248
+ }
249
+ return Object.fromEntries(Array.from(counts.entries()).sort(([a], [b]) => a.localeCompare(b)));
250
+ }
251
+ function enrichIterationMetadata(metadata, pendingActions) {
252
+ if (!pendingActions?.length) {
253
+ return metadata;
254
+ }
255
+ if (metadata?.pendingEffectsByKind) {
256
+ return metadata;
257
+ }
258
+ return {
259
+ ...(metadata ?? {}),
260
+ pendingEffectsByKind: countActionsByKind(pendingActions),
261
+ };
262
+ }
263
+ function logSleepHints(command, actions) {
264
+ for (const action of actions) {
265
+ const sleepMs = action.schedulerHints?.sleepUntilEpochMs;
266
+ if (typeof sleepMs !== "number")
267
+ continue;
268
+ const iso = new Date(sleepMs).toISOString();
269
+ const label = action.label ? ` ${action.label}` : "";
270
+ const pendingInfo = typeof action.schedulerHints?.pendingCount === "number"
271
+ ? ` pendingCount=${action.schedulerHints.pendingCount}`
272
+ : "";
273
+ console.error(`[${command}] sleep-until=${iso} effect=${action.effectId}${label}${pendingInfo}`);
274
+ }
275
+ }
276
+ function logRunContinueStatus(iterationStatus, executedCount, metadataParts, options) {
277
+ const parts = [`[run:continue] status=${iterationStatus}`];
278
+ if (options.dryRun) {
279
+ parts.push("dryRun=true");
280
+ }
281
+ if (executedCount > 0) {
282
+ parts.push(`autoNode=${executedCount}`);
283
+ }
284
+ parts.push(...metadataParts);
285
+ console.error(parts.join(" "));
286
+ }
287
+ function logAutoRunPlan(nodeSummaries) {
288
+ console.error(`[run:continue] dry-run auto-node tasks count=${nodeSummaries.length}`);
289
+ if (!nodeSummaries.length) {
290
+ return;
291
+ }
292
+ for (const summary of nodeSummaries) {
293
+ const label = summary.label ? ` ${summary.label}` : "";
294
+ console.error(` - ${summary.effectId} [${summary.kind}]${label}`);
295
+ }
296
+ }
297
+ function formatResolvedEntrypoint(importPath, exportName) {
298
+ return `${importPath}${exportName ? `#${exportName}` : ""}`;
299
+ }
300
+ function formatVerboseValue(value) {
301
+ if (value === null)
302
+ return "null";
303
+ if (value === undefined)
304
+ return "undefined";
305
+ if (typeof value === "string")
306
+ return value;
307
+ if (typeof value === "number" || typeof value === "boolean")
308
+ return String(value);
309
+ return JSON.stringify(value);
310
+ }
311
+ function allowSecretLogs(parsed) {
312
+ if (!parsed.json || !parsed.verbose) {
313
+ return false;
314
+ }
315
+ const raw = process.env.BABYSITTER_ALLOW_SECRET_LOGS;
316
+ if (!raw) {
317
+ return false;
318
+ }
319
+ const normalized = raw.trim().toLowerCase();
320
+ return normalized === "1" || normalized === "true";
321
+ }
322
+ function logVerbose(command, parsed, details) {
323
+ if (!parsed.verbose)
324
+ return;
325
+ const formatted = Object.entries(details)
326
+ .filter(([, value]) => value !== undefined)
327
+ .map(([key, value]) => `${key}=${formatVerboseValue(value)}`)
328
+ .join(" ");
329
+ console.error(`[${command}] verbose ${formatted}`);
330
+ }
331
+ function determineTaskStatus(result) {
332
+ if (result.timedOut)
333
+ return "timeout";
334
+ if (result.exitCode == null)
335
+ return "skipped";
336
+ return result.exitCode === 0 ? "ok" : "error";
337
+ }
338
+ function toRunRelativePosix(runDir, absolutePath) {
339
+ if (!absolutePath)
340
+ return undefined;
341
+ return path.relative(runDir, absolutePath).replace(/\\/g, "/");
342
+ }
343
+ function normalizeArtifactRef(runDir, ref) {
344
+ const absolute = resolveArtifactAbsolutePath(runDir, ref);
345
+ if (!absolute)
346
+ return null;
347
+ const relative = toRunRelativePosix(runDir, absolute);
348
+ return relative ?? null;
349
+ }
350
+ function resolveArtifactAbsolutePath(runDir, ref) {
351
+ if (!ref)
352
+ return null;
353
+ const normalized = ref.trim();
354
+ if (!normalized)
355
+ return null;
356
+ const absoluteRunDir = path.resolve(runDir);
357
+ if (path.isAbsolute(normalized) || /^[A-Za-z]:[\\/]/.test(normalized)) {
358
+ return path.normalize(normalized);
359
+ }
360
+ const candidates = collectArtifactCandidates(absoluteRunDir, normalized);
361
+ if (candidates.length > 0) {
362
+ candidates.sort((a, b) => {
363
+ if (a.outsideRun !== b.outsideRun)
364
+ return a.outsideRun ? 1 : -1;
365
+ return a.relative.length - b.relative.length;
366
+ });
367
+ return candidates[0].absolute;
368
+ }
369
+ return path.join(absoluteRunDir, normalized);
370
+ }
371
+ function collectArtifactCandidates(runDir, ref) {
372
+ const seen = new Map();
373
+ const pushCandidate = (absolute) => {
374
+ const normalizedAbs = path.normalize(absolute);
375
+ const relative = path.relative(runDir, normalizedAbs).replace(/\\/g, "/");
376
+ const outsideRun = relative.startsWith("..");
377
+ seen.set(normalizedAbs, { absolute: normalizedAbs, relative, outsideRun });
378
+ };
379
+ pushCandidate(path.join(runDir, ref));
380
+ pushCandidate(path.resolve(ref));
381
+ return Array.from(seen.values());
382
+ }
383
+ function defaultResultRef(effectId) {
384
+ return `tasks/${effectId}/result.json`;
385
+ }
386
+ function formatEntrypointSpecifier(entrypoint) {
387
+ return `${entrypoint.importPath}#${entrypoint.exportName}`;
388
+ }
389
+ function parseEntrypointSpecifier(specifier) {
390
+ if (!specifier) {
391
+ throw new Error("Entrypoint must be provided as <path>#<export>");
392
+ }
393
+ const hashIndex = specifier.lastIndexOf("#");
394
+ if (hashIndex === 0) {
395
+ throw new Error("Entrypoint must include a module path before '#'");
396
+ }
397
+ if (hashIndex === -1) {
398
+ return { importPath: specifier };
399
+ }
400
+ const importPath = specifier.slice(0, hashIndex);
401
+ if (!importPath) {
402
+ throw new Error("Entrypoint must include a module path before '#'");
403
+ }
404
+ const exportName = specifier.slice(hashIndex + 1) || undefined;
405
+ return { importPath, exportName };
406
+ }
407
+ async function readInputsFile(filePath) {
408
+ const absolute = path.resolve(filePath);
409
+ let contents;
410
+ try {
411
+ contents = await node_fs_1.promises.readFile(absolute, "utf8");
412
+ }
413
+ catch (error) {
414
+ throw new Error(`Failed to read inputs file ${absolute}: ${error instanceof Error ? error.message : String(error)}`);
415
+ }
416
+ try {
417
+ return JSON.parse(contents);
418
+ }
419
+ catch (error) {
420
+ throw new Error(`Failed to parse inputs file ${absolute} as JSON: ${error instanceof Error ? error.message : String(error)}`);
421
+ }
422
+ }
423
+ async function handleRunCreate(parsed) {
424
+ if (!parsed.processId) {
425
+ console.error("--process-id is required for run:create");
426
+ console.error(USAGE);
427
+ return 1;
428
+ }
429
+ if (!parsed.entrySpecifier) {
430
+ console.error("--entry is required for run:create");
431
+ console.error(USAGE);
432
+ return 1;
433
+ }
434
+ let entrypoint;
435
+ try {
436
+ entrypoint = parseEntrypointSpecifier(parsed.entrySpecifier);
437
+ }
438
+ catch (error) {
439
+ console.error(error instanceof Error ? error.message : String(error));
440
+ return 1;
441
+ }
442
+ const runsDir = path.resolve(parsed.runsDir);
443
+ const absoluteImportPath = path.resolve(entrypoint.importPath);
444
+ const resolvedEntry = formatResolvedEntrypoint(absoluteImportPath, entrypoint.exportName);
445
+ logVerbose("run:create", parsed, {
446
+ runsDir,
447
+ processId: parsed.processId,
448
+ entry: resolvedEntry,
449
+ dryRun: parsed.dryRun,
450
+ json: parsed.json,
451
+ request: parsed.requestId,
452
+ processRevision: parsed.processRevision,
453
+ runId: parsed.runIdOverride,
454
+ inputsPath: parsed.inputsPath ? path.resolve(parsed.inputsPath) : undefined,
455
+ });
456
+ let inputs;
457
+ if (parsed.inputsPath) {
458
+ try {
459
+ inputs = await readInputsFile(parsed.inputsPath);
460
+ }
461
+ catch (error) {
462
+ console.error(error instanceof Error ? error.message : String(error));
463
+ return 1;
464
+ }
465
+ }
466
+ if (parsed.dryRun) {
467
+ const summary = {
468
+ dryRun: true,
469
+ runsDir,
470
+ processId: parsed.processId,
471
+ entry: resolvedEntry,
472
+ runId: parsed.runIdOverride ?? null,
473
+ request: parsed.requestId ?? null,
474
+ processRevision: parsed.processRevision ?? null,
475
+ inputsPath: parsed.inputsPath ? path.resolve(parsed.inputsPath) : null,
476
+ };
477
+ if (parsed.json) {
478
+ console.log(JSON.stringify(summary));
479
+ }
480
+ else {
481
+ const parts = [
482
+ "[run:create] dry-run",
483
+ `runsDir=${runsDir}`,
484
+ `processId=${parsed.processId}`,
485
+ `entry=${resolvedEntry}`,
486
+ `runId=${summary.runId ?? "auto"}`,
487
+ ];
488
+ if (parsed.requestId)
489
+ parts.push(`request=${parsed.requestId}`);
490
+ if (parsed.processRevision)
491
+ parts.push(`processRevision=${parsed.processRevision}`);
492
+ if (summary.inputsPath)
493
+ parts.push(`inputs=${summary.inputsPath}`);
494
+ console.log(parts.join(" "));
495
+ }
496
+ return 0;
497
+ }
498
+ const result = await (0, createRun_1.createRun)({
499
+ runsDir,
500
+ runId: parsed.runIdOverride,
501
+ request: parsed.requestId,
502
+ processRevision: parsed.processRevision,
503
+ process: {
504
+ processId: parsed.processId,
505
+ importPath: absoluteImportPath,
506
+ exportName: entrypoint.exportName,
507
+ },
508
+ inputs,
509
+ });
510
+ const entrySpec = formatEntrypointSpecifier(result.metadata.entrypoint);
511
+ if (parsed.json) {
512
+ console.log(JSON.stringify({ runId: result.runId, runDir: result.runDir, entry: entrySpec }));
513
+ }
514
+ else {
515
+ console.log(`[run:create] runId=${result.runId} runDir=${result.runDir} entry=${entrySpec}`);
516
+ }
517
+ return 0;
518
+ }
519
+ async function handleRunStatus(parsed) {
520
+ if (!parsed.runDirArg) {
521
+ console.error(USAGE);
522
+ return 1;
523
+ }
524
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
525
+ logVerbose("run:status", parsed, {
526
+ runDir,
527
+ json: parsed.json,
528
+ });
529
+ const metadata = await readRunMetadataSafe(runDir, "run:status");
530
+ if (!metadata)
531
+ return 1;
532
+ const journal = await loadJournalSafe(runDir, "run:status");
533
+ if (!journal)
534
+ return 1;
535
+ const index = await buildEffectIndexSafe(runDir, "run:status", journal);
536
+ if (!index)
537
+ return 1;
538
+ const pendingRecords = index.listPendingEffects();
539
+ const pendingByKind = countPendingByKind(pendingRecords);
540
+ const pendingTotal = pendingRecords.length;
541
+ const stateSnapshot = await readStateCacheSafe(runDir, "run:status");
542
+ const mergedMetadata = mergeMetadataSources({
543
+ pendingEffectsByKind: pendingByKind,
544
+ }, { snapshot: stateSnapshot, pendingByKind });
545
+ const formattedMetadata = formatIterationMetadata(mergedMetadata);
546
+ const lastEvent = journal.at(-1);
547
+ const lastLifecycleEvent = findLastLifecycleEvent(journal);
548
+ const state = deriveRunState(lastLifecycleEvent?.type, pendingTotal);
549
+ const lastSummary = formatLastEventSummary(lastEvent);
550
+ if (parsed.json) {
551
+ console.log(JSON.stringify({
552
+ state,
553
+ lastEvent: lastEvent ? serializeJournalEvent(lastEvent, runDir) : null,
554
+ pendingByKind,
555
+ metadata: formattedMetadata.jsonMetadata ?? null,
556
+ }));
557
+ return 0;
558
+ }
559
+ const suffix = formattedMetadata.textParts.length ? ` ${formattedMetadata.textParts.join(" ")}` : "";
560
+ console.log(`[run:status] state=${state} last=${lastSummary}${suffix}`);
561
+ return 0;
562
+ }
563
+ async function handleRunEvents(parsed) {
564
+ if (!parsed.runDirArg) {
565
+ console.error(USAGE);
566
+ return 1;
567
+ }
568
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
569
+ logVerbose("run:events", parsed, {
570
+ runDir,
571
+ json: parsed.json,
572
+ limit: parsed.limit,
573
+ reverse: parsed.reverseOrder,
574
+ filterType: parsed.filterType,
575
+ });
576
+ if (!(await readRunMetadataSafe(runDir, "run:events")))
577
+ return 1;
578
+ const stateSnapshot = await readStateCacheSafe(runDir, "run:events");
579
+ const journal = await loadJournalSafe(runDir, "run:events");
580
+ if (!journal)
581
+ return 1;
582
+ const filterType = parsed.filterType ? parsed.filterType.toUpperCase() : undefined;
583
+ const filtered = filterType ? journal.filter((event) => event.type.toUpperCase() === filterType) : journal;
584
+ const orderedBase = filtered.slice();
585
+ const ordered = parsed.reverseOrder ? orderedBase.reverse() : orderedBase;
586
+ const limited = parsed.limit !== undefined ? ordered.slice(0, parsed.limit) : ordered;
587
+ const metadata = mergeMetadataSources(undefined, { snapshot: stateSnapshot });
588
+ const formattedMetadata = formatIterationMetadata(metadata);
589
+ if (parsed.json) {
590
+ console.log(JSON.stringify({
591
+ events: limited.map((event) => serializeJournalEvent(event, runDir)),
592
+ metadata: formattedMetadata.jsonMetadata ?? null,
593
+ }));
594
+ return 0;
595
+ }
596
+ const headerParts = [
597
+ `total=${journal.length}`,
598
+ `matching=${filtered.length}`,
599
+ `showing=${limited.length}`,
600
+ ];
601
+ if (filterType)
602
+ headerParts.push(`filter=${filterType}`);
603
+ if (parsed.limit)
604
+ headerParts.push(`limit=${parsed.limit}`);
605
+ if (parsed.reverseOrder)
606
+ headerParts.push("order=desc");
607
+ const metadataSuffix = formattedMetadata.textParts.length ? ` ${formattedMetadata.textParts.join(" ")}` : "";
608
+ console.log(`[run:events] ${headerParts.join(" ")}${metadataSuffix}`);
609
+ for (const event of limited) {
610
+ console.log(`- ${formatEventLine(event)}`);
611
+ }
612
+ return 0;
613
+ }
614
+ async function handleRunRebuildState(parsed) {
615
+ if (!parsed.runDirArg) {
616
+ console.error(USAGE);
617
+ return 1;
618
+ }
619
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
620
+ logVerbose("run:rebuild-state", parsed, {
621
+ runDir,
622
+ dryRun: parsed.dryRun,
623
+ json: parsed.json,
624
+ });
625
+ if (!(await readRunMetadataSafe(runDir, "run:rebuild-state")))
626
+ return 1;
627
+ if (parsed.dryRun) {
628
+ const plan = { dryRun: true, runDir, plan: "rebuild_state_cache", reason: "cli_manual" };
629
+ if (parsed.json) {
630
+ console.log(JSON.stringify(plan));
631
+ }
632
+ else {
633
+ console.log(`[run:rebuild-state] dry-run runDir=${runDir} plan=${plan.plan} reason=${plan.reason}`);
634
+ }
635
+ return 0;
636
+ }
637
+ const snapshot = await (0, stateCache_1.rebuildStateCache)(runDir, { reason: "cli_manual" });
638
+ const metadata = {
639
+ pendingEffectsByKind: snapshot.pendingEffectsByKind,
640
+ stateVersion: snapshot.stateVersion,
641
+ journalHead: snapshot.journalHead ?? null,
642
+ stateRebuilt: true,
643
+ stateRebuildReason: snapshot.rebuildReason ?? undefined,
644
+ };
645
+ const formatted = formatIterationMetadata(metadata);
646
+ if (parsed.json) {
647
+ console.log(JSON.stringify({ runDir, metadata: formatted.jsonMetadata ?? null }));
648
+ return 0;
649
+ }
650
+ const suffix = formatted.textParts.length ? ` ${formatted.textParts.join(" ")}` : "";
651
+ console.log(`[run:rebuild-state] runDir=${runDir}${suffix}`);
652
+ return 0;
653
+ }
654
+ async function handleTaskRun(parsed) {
655
+ if (!parsed.runDirArg || !parsed.effectId) {
656
+ console.error(USAGE);
657
+ return 1;
658
+ }
659
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
660
+ const secretLogsAllowed = allowSecretLogs(parsed);
661
+ const streamers = buildTaskRunStreamers(parsed);
662
+ logVerbose("task:run", parsed, {
663
+ runDir,
664
+ effectId: parsed.effectId,
665
+ dryRun: parsed.dryRun,
666
+ json: parsed.json,
667
+ secretLogsAllowed,
668
+ });
669
+ const index = await buildEffectIndexSafe(runDir, "task:run");
670
+ if (!index)
671
+ return 1;
672
+ const record = index.getByEffectId(parsed.effectId);
673
+ if (!record) {
674
+ console.error(`[task:run] effect ${parsed.effectId} not found at ${runDir}`);
675
+ return 1;
676
+ }
677
+ const kind = (record.kind ?? "").toLowerCase();
678
+ if (kind !== "node") {
679
+ console.error(`[task:run] effect ${parsed.effectId} has kind=${record.kind ?? "unknown"}; task:run only supports kind="node"`);
680
+ return 1;
681
+ }
682
+ const result = await (0, nodeTaskRunner_1.runNodeTaskFromCli)({
683
+ runDir,
684
+ effectId: parsed.effectId,
685
+ invocationKey: record.invocationKey,
686
+ dryRun: parsed.dryRun,
687
+ onStdoutChunk: streamers.onStdoutChunk,
688
+ onStderrChunk: streamers.onStderrChunk,
689
+ });
690
+ const status = determineTaskStatus(result);
691
+ const stdoutRef = resolveTaskRunArtifactRef(runDir, result.committed?.stdoutRef, result.io.stdoutPath);
692
+ const stderrRef = resolveTaskRunArtifactRef(runDir, result.committed?.stderrRef, result.io.stderrPath);
693
+ const outputRef = resolveTaskRunArtifactRef(runDir, result.committed?.resultRef, result.io.outputJsonPath);
694
+ const planPayload = parsed.dryRun ? buildTaskRunPlanPayload(runDir, result) : null;
695
+ if (parsed.dryRun && planPayload) {
696
+ logTaskRunPlan(planPayload);
697
+ }
698
+ if (parsed.json) {
699
+ const payload = {
700
+ status,
701
+ committed: result.committed ?? null,
702
+ stdoutRef: stdoutRef ?? null,
703
+ stderrRef: stderrRef ?? null,
704
+ resultRef: outputRef ?? null,
705
+ };
706
+ console.log(JSON.stringify(payload));
707
+ }
708
+ else {
709
+ const parts = [`[task:run] status=${status}`];
710
+ if (stdoutRef)
711
+ parts.push(`stdoutRef=${stdoutRef}`);
712
+ if (stderrRef)
713
+ parts.push(`stderrRef=${stderrRef}`);
714
+ if (outputRef)
715
+ parts.push(`resultRef=${outputRef}`);
716
+ console.log(parts.join(" "));
717
+ }
718
+ return status === "ok" || status === "skipped" ? 0 : 1;
719
+ }
720
+ async function autoRunNodeTasks(runDir, actions, executed) {
721
+ for (const action of actions) {
722
+ const summary = {
723
+ effectId: action.effectId,
724
+ kind: action.kind,
725
+ label: action.label,
726
+ };
727
+ executed.push(summary);
728
+ const label = summary.label ? ` ${summary.label}` : "";
729
+ console.error(`[auto-run] ${summary.effectId} [${summary.kind}]${label}`);
730
+ await (0, nodeTaskRunner_1.runNodeTaskFromCli)({
731
+ runDir,
732
+ effectId: action.effectId,
733
+ task: action.taskDef,
734
+ invocationKey: action.invocationKey,
735
+ dryRun: false,
736
+ });
737
+ }
738
+ }
739
+ function emitJsonResult(iteration, context) {
740
+ const payload = {
741
+ status: iteration.status,
742
+ autoRun: { executed: context.executed, pending: context.autoPending },
743
+ metadata: context.metadata ?? null,
744
+ };
745
+ if (iteration.status === "completed") {
746
+ payload.output = context.output;
747
+ }
748
+ else if (iteration.status === "failed") {
749
+ payload.error = context.error ?? null;
750
+ }
751
+ else {
752
+ payload.pending = context.pending;
753
+ }
754
+ console.log(JSON.stringify(payload));
755
+ }
756
+ async function handleRunContinue(parsed) {
757
+ if (!parsed.runDirArg) {
758
+ console.error(USAGE);
759
+ return 1;
760
+ }
761
+ if (parsed.nowOverride) {
762
+ console.error("[run:continue] --now is not supported; use run:step for single iterations");
763
+ return 1;
764
+ }
765
+ if ((parsed.autoNodeMax !== undefined || parsed.autoNodeLabel) && !parsed.autoNodeTasks) {
766
+ console.error("[run:continue] --auto-node-max/--auto-node-label require --auto-node-tasks");
767
+ return 1;
768
+ }
769
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
770
+ logVerbose("run:continue", parsed, {
771
+ runDir,
772
+ dryRun: parsed.dryRun,
773
+ json: parsed.json,
774
+ autoNodeTasks: parsed.autoNodeTasks,
775
+ autoNodeMax: parsed.autoNodeMax ?? null,
776
+ autoNodeLabel: parsed.autoNodeLabel ?? null,
777
+ });
778
+ if (!(await readRunMetadataSafe(runDir, "run:continue")))
779
+ return 1;
780
+ const stateSnapshot = await readStateCacheSafe(runDir, "run:continue");
781
+ const executed = [];
782
+ const autoNodeLimit = parsed.autoNodeMax ?? Number.POSITIVE_INFINITY;
783
+ let autoNodeRemaining = autoNodeLimit;
784
+ let autoNodeLimitLogged = false;
785
+ while (true) {
786
+ const iteration = await (0, orchestrateIteration_1.orchestrateIteration)({ runDir });
787
+ const pendingActions = iteration.status === "waiting" ? iteration.nextActions : undefined;
788
+ const pendingCounts = pendingActions ? countActionsByKind(pendingActions) : undefined;
789
+ const enrichedMetadata = enrichIterationMetadata(iteration.metadata, pendingActions);
790
+ const metadata = mergeMetadataSources(enrichedMetadata, {
791
+ snapshot: stateSnapshot,
792
+ pendingByKind: pendingCounts,
793
+ });
794
+ const formattedMetadata = formatIterationMetadata(metadata);
795
+ logRunContinueStatus(iteration.status, executed.length, formattedMetadata.textParts, {
796
+ dryRun: parsed.dryRun,
797
+ });
798
+ if (iteration.status === "waiting") {
799
+ const pending = logPendingActions(iteration.nextActions, {
800
+ command: "run:continue",
801
+ includeHeader: false,
802
+ });
803
+ logSleepHints("run:continue", iteration.nextActions);
804
+ const nodeActions = iteration.nextActions.filter((action) => action.kind === "node");
805
+ const eligibleAutoActions = parsed.autoNodeTasks
806
+ ? nodeActions.filter((action) => matchesAutoNodeLabel(action, parsed.autoNodeLabel))
807
+ : nodeActions;
808
+ const planCap = parsed.autoNodeTasks
809
+ ? Math.min(eligibleAutoActions.length, Number.isFinite(autoNodeRemaining) ? Math.max(0, Math.floor(autoNodeRemaining)) : eligibleAutoActions.length)
810
+ : eligibleAutoActions.length;
811
+ const plannedAutoActions = eligibleAutoActions.slice(0, planCap);
812
+ const nodeSummaries = summarizeActions(nodeActions);
813
+ const autoPendingSummaries = parsed.autoNodeTasks ? summarizeActions(plannedAutoActions) : nodeSummaries;
814
+ if (parsed.autoNodeTasks && eligibleAutoActions.length > 0 && autoNodeRemaining <= 0 && Number.isFinite(autoNodeLimit)) {
815
+ if (!autoNodeLimitLogged) {
816
+ console.error(`[auto-run] reached --auto-node-max=${parsed.autoNodeMax}`);
817
+ autoNodeLimitLogged = true;
818
+ }
819
+ }
820
+ if (parsed.autoNodeTasks && parsed.autoNodeLabel && eligibleAutoActions.length === 0 && nodeActions.length > 0) {
821
+ console.error(`[auto-run] no node tasks matched --auto-node-label=${parsed.autoNodeLabel}; ${nodeActions.length} pending`);
822
+ }
823
+ if (parsed.autoNodeTasks && plannedAutoActions.length > 0) {
824
+ if (parsed.dryRun) {
825
+ logAutoRunPlan(autoPendingSummaries);
826
+ if (parsed.json) {
827
+ emitJsonResult({ status: "waiting" }, {
828
+ executed,
829
+ pending,
830
+ autoPending: autoPendingSummaries,
831
+ metadata: formattedMetadata.jsonMetadata ?? null,
832
+ });
833
+ }
834
+ return 0;
835
+ }
836
+ await autoRunNodeTasks(runDir, plannedAutoActions, executed);
837
+ if (Number.isFinite(autoNodeRemaining)) {
838
+ autoNodeRemaining = Math.max(0, autoNodeRemaining - plannedAutoActions.length);
839
+ if (autoNodeRemaining <= 0 && !autoNodeLimitLogged && parsed.autoNodeMax !== undefined) {
840
+ console.error(`[auto-run] reached --auto-node-max=${parsed.autoNodeMax}`);
841
+ autoNodeLimitLogged = true;
842
+ }
843
+ }
844
+ continue;
845
+ }
846
+ if (parsed.json) {
847
+ emitJsonResult({ status: "waiting" }, {
848
+ executed,
849
+ pending,
850
+ autoPending: autoPendingSummaries,
851
+ metadata: formattedMetadata.jsonMetadata ?? null,
852
+ });
853
+ }
854
+ return 0;
855
+ }
856
+ if (iteration.status === "completed") {
857
+ if (parsed.json) {
858
+ emitJsonResult({ status: "completed", output: iteration.output }, {
859
+ executed,
860
+ pending: [],
861
+ autoPending: [],
862
+ metadata: formattedMetadata.jsonMetadata ?? null,
863
+ output: iteration.output,
864
+ });
865
+ }
866
+ return 0;
867
+ }
868
+ if (parsed.json) {
869
+ emitJsonResult({ status: "failed", error: iteration.error ?? null }, {
870
+ executed,
871
+ pending: [],
872
+ autoPending: [],
873
+ metadata: formattedMetadata.jsonMetadata ?? null,
874
+ error: iteration.error ?? null,
875
+ });
876
+ }
877
+ else if (iteration.error !== undefined) {
878
+ console.error(iteration.error);
879
+ }
880
+ return 1;
881
+ }
882
+ }
883
+ function parseNowOverride(nowOverride) {
884
+ if (!nowOverride)
885
+ return null;
886
+ const parsed = new Date(nowOverride);
887
+ if (Number.isNaN(parsed.getTime())) {
888
+ throw new Error(`--now must be a valid ISO 8601 timestamp (received: ${nowOverride})`);
889
+ }
890
+ return parsed;
891
+ }
892
+ async function handleRunStep(parsed) {
893
+ if (!parsed.runDirArg) {
894
+ console.error(USAGE);
895
+ return 1;
896
+ }
897
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
898
+ logVerbose("run:step", parsed, {
899
+ runDir,
900
+ now: parsed.nowOverride ?? "auto",
901
+ json: parsed.json,
902
+ });
903
+ if (!(await readRunMetadataSafe(runDir, "run:step")))
904
+ return 1;
905
+ let now;
906
+ try {
907
+ now = parseNowOverride(parsed.nowOverride) ?? new Date();
908
+ }
909
+ catch (error) {
910
+ console.error(error instanceof Error ? error.message : String(error));
911
+ return 1;
912
+ }
913
+ const iteration = await (0, orchestrateIteration_1.orchestrateIteration)({ runDir, now });
914
+ const pendingActions = iteration.status === "waiting" ? iteration.nextActions : undefined;
915
+ const metadata = enrichIterationMetadata(iteration.metadata, pendingActions);
916
+ const formattedMetadata = formatIterationMetadata(metadata);
917
+ if (parsed.json) {
918
+ console.log(JSON.stringify({ ...iteration, metadata: formattedMetadata.jsonMetadata ?? null }));
919
+ return iteration.status === "failed" ? 1 : 0;
920
+ }
921
+ if (iteration.status === "completed") {
922
+ const output = JSON.stringify(iteration.output ?? null);
923
+ const suffix = formattedMetadata.textParts.length ? ` ${formattedMetadata.textParts.join(" ")}` : "";
924
+ console.error(`[run:step] status=completed output=${output}${suffix}`);
925
+ return 0;
926
+ }
927
+ if (iteration.status === "waiting") {
928
+ logPendingActions(iteration.nextActions, {
929
+ command: "run:step",
930
+ metadataParts: formattedMetadata.textParts,
931
+ });
932
+ logSleepHints("run:step", iteration.nextActions);
933
+ return 0;
934
+ }
935
+ const suffix = formattedMetadata.textParts.length ? ` ${formattedMetadata.textParts.join(" ")}` : "";
936
+ console.error(`[run:step] status=failed${suffix}`);
937
+ if (iteration.error !== undefined) {
938
+ console.error(iteration.error);
939
+ }
940
+ return 1;
941
+ }
942
+ async function handleTaskList(parsed) {
943
+ if (!parsed.runDirArg) {
944
+ console.error(USAGE);
945
+ return 1;
946
+ }
947
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
948
+ logVerbose("task:list", parsed, {
949
+ runDir,
950
+ json: parsed.json,
951
+ pending: parsed.pendingOnly,
952
+ kind: parsed.kindFilter,
953
+ });
954
+ const index = await buildEffectIndexSafe(runDir, "task:list");
955
+ if (!index)
956
+ return 1;
957
+ const rawRecords = parsed.pendingOnly ? index.listPendingEffects() : index.listEffects();
958
+ const records = rawRecords
959
+ .filter((record) => parsed.kindFilter ? record.kind?.toLowerCase() === parsed.kindFilter.toLowerCase() : true)
960
+ .sort((a, b) => a.effectId.localeCompare(b.effectId));
961
+ const entries = records.map((record) => toTaskListEntry(record, runDir));
962
+ if (parsed.json) {
963
+ console.log(JSON.stringify({ tasks: entries }));
964
+ return 0;
965
+ }
966
+ const scope = parsed.pendingOnly ? "pending" : "total";
967
+ console.log(`[task:list] ${scope}=${entries.length}`);
968
+ for (const entry of entries) {
969
+ const label = entry.label ? ` ${entry.label}` : "";
970
+ console.log(`- ${entry.effectId} [${entry.kind ?? "unknown"} ${entry.status}]${label} (taskId=${entry.taskId ?? "n/a"})`);
971
+ }
972
+ return 0;
973
+ }
974
+ async function handleTaskShow(parsed) {
975
+ if (!parsed.runDirArg || !parsed.effectId) {
976
+ console.error(USAGE);
977
+ return 1;
978
+ }
979
+ const runDir = resolveRunDir(parsed.runsDir, parsed.runDirArg);
980
+ const secretLogsAllowed = allowSecretLogs(parsed);
981
+ logVerbose("task:show", parsed, {
982
+ runDir,
983
+ effectId: parsed.effectId,
984
+ json: parsed.json,
985
+ secretLogsAllowed,
986
+ });
987
+ const index = await buildEffectIndexSafe(runDir, "task:show");
988
+ if (!index)
989
+ return 1;
990
+ const record = index.getByEffectId(parsed.effectId);
991
+ if (!record) {
992
+ console.error(`[task:show] effect ${parsed.effectId} not found in ${runDir}`);
993
+ return 1;
994
+ }
995
+ const taskDef = await (0, tasks_1.readTaskDefinition)(runDir, parsed.effectId);
996
+ if (!taskDef) {
997
+ console.error(`[task:show] task definition missing for effect ${parsed.effectId}`);
998
+ return 1;
999
+ }
1000
+ const preview = await loadTaskResultPreview(runDir, parsed.effectId, record);
1001
+ const entry = toTaskListEntry(record, runDir);
1002
+ const inlineResult = preview.large ? null : preview.result ?? null;
1003
+ const largeResultRef = preview.large ? entry.resultRef ?? defaultResultRef(record.effectId) : null;
1004
+ if (parsed.json) {
1005
+ console.log(JSON.stringify({
1006
+ effect: entry,
1007
+ task: secretLogsAllowed ? taskDef : null,
1008
+ result: secretLogsAllowed ? inlineResult : null,
1009
+ largeResult: largeResultRef,
1010
+ }));
1011
+ return 0;
1012
+ }
1013
+ console.log(`[task:show] ${entry.effectId} [${entry.kind ?? "unknown"} ${entry.status}] ${entry.label ?? "(no label)"} (taskId=${entry.taskId})`);
1014
+ console.log(` stepId=${entry.stepId} requestedAt=${entry.requestedAt ?? "n/a"} resolvedAt=${entry.resolvedAt ?? "n/a"}`);
1015
+ console.log(` taskDefRef=${entry.taskDefRef ?? "n/a"}`);
1016
+ console.log(` inputsRef=${entry.inputsRef ?? "n/a"}`);
1017
+ console.log(` resultRef=${entry.resultRef ?? "n/a"}`);
1018
+ console.log(` stdoutRef=${entry.stdoutRef ?? "n/a"}`);
1019
+ console.log(` stderrRef=${entry.stderrRef ?? "n/a"}`);
1020
+ if (!secretLogsAllowed) {
1021
+ console.log(" payloads: redacted (set BABYSITTER_ALLOW_SECRET_LOGS=true and rerun with --json --verbose to view task/result blobs)");
1022
+ if (!inlineResult && !preview.large) {
1023
+ console.log(" result: (not yet written)");
1024
+ }
1025
+ return 0;
1026
+ }
1027
+ console.log(" taskDef:", JSON.stringify(taskDef, null, 2));
1028
+ if (preview.large) {
1029
+ console.log(` result: see ${largeResultRef ?? entry.resultRef ?? defaultResultRef(record.effectId)}`);
1030
+ }
1031
+ else if (inlineResult) {
1032
+ console.log(" result:", JSON.stringify(inlineResult, null, 2));
1033
+ }
1034
+ else {
1035
+ console.log(" result: (not yet written)");
1036
+ }
1037
+ return 0;
1038
+ }
1039
+ function toTaskListEntry(record, runDir) {
1040
+ return {
1041
+ effectId: record.effectId,
1042
+ taskId: record.taskId ?? "unknown",
1043
+ stepId: record.stepId ?? "unknown",
1044
+ status: record.status ?? "unknown",
1045
+ kind: record.kind,
1046
+ label: record.label,
1047
+ labels: record.labels,
1048
+ taskDefRef: normalizeArtifactRef(runDir, record.taskDefRef ?? `tasks/${record.effectId}/task.json`),
1049
+ inputsRef: normalizeArtifactRef(runDir, record.inputsRef),
1050
+ resultRef: normalizeArtifactRef(runDir, record.resultRef),
1051
+ stdoutRef: normalizeArtifactRef(runDir, record.stdoutRef),
1052
+ stderrRef: normalizeArtifactRef(runDir, record.stderrRef),
1053
+ requestedAt: record.requestedAt,
1054
+ resolvedAt: record.resolvedAt,
1055
+ };
1056
+ }
1057
+ async function buildEffectIndexSafe(runDir, command, events) {
1058
+ try {
1059
+ return await (0, effectIndex_1.buildEffectIndex)({ runDir, events });
1060
+ }
1061
+ catch (error) {
1062
+ console.error(`[${command}] unable to read run at ${runDir}: ${error instanceof Error ? error.message : String(error)}`);
1063
+ return null;
1064
+ }
1065
+ }
1066
+ async function readRunMetadataSafe(runDir, command) {
1067
+ try {
1068
+ return await (0, runFiles_1.readRunMetadata)(runDir);
1069
+ }
1070
+ catch (error) {
1071
+ console.error(`[${command}] unable to read run metadata at ${runDir}: ${error instanceof Error ? error.message : String(error)}`);
1072
+ return null;
1073
+ }
1074
+ }
1075
+ async function loadJournalSafe(runDir, command) {
1076
+ try {
1077
+ return await (0, journal_1.loadJournal)(runDir);
1078
+ }
1079
+ catch (error) {
1080
+ console.error(`[${command}] unable to read journal at ${runDir}: ${error instanceof Error ? error.message : String(error)}`);
1081
+ return null;
1082
+ }
1083
+ }
1084
+ async function readStateCacheSafe(runDir, command) {
1085
+ try {
1086
+ const snapshot = await (0, stateCache_1.readStateCache)(runDir);
1087
+ if (!snapshot) {
1088
+ console.warn(`[${command}] state cache snapshot missing at ${runDir} (continuing without metadata)`);
1089
+ return null;
1090
+ }
1091
+ return snapshot;
1092
+ }
1093
+ catch (error) {
1094
+ console.warn(`[${command}] unable to read state cache at ${runDir}: ${error instanceof Error ? error.message : String(error)} (continuing without metadata)`);
1095
+ return null;
1096
+ }
1097
+ }
1098
+ const RUN_LIFECYCLE_TYPES = new Set([
1099
+ "RUN_CREATED",
1100
+ "RUN_COMPLETED",
1101
+ "RUN_FAILED",
1102
+ ]);
1103
+ function findLastLifecycleEvent(events) {
1104
+ for (let i = events.length - 1; i >= 0; i -= 1) {
1105
+ const event = events[i];
1106
+ if (RUN_LIFECYCLE_TYPES.has(event.type)) {
1107
+ return event;
1108
+ }
1109
+ }
1110
+ return undefined;
1111
+ }
1112
+ function countPendingByKind(records) {
1113
+ const counts = new Map();
1114
+ for (const record of records) {
1115
+ const key = record.kind ?? "unknown";
1116
+ counts.set(key, (counts.get(key) ?? 0) + 1);
1117
+ }
1118
+ return Object.fromEntries(Array.from(counts.entries()).sort(([a], [b]) => a.localeCompare(b)));
1119
+ }
1120
+ async function loadTaskResultPreview(runDir, effectId, record) {
1121
+ const absolutePath = resolveArtifactAbsolutePath(runDir, record.resultRef ?? defaultResultRef(effectId));
1122
+ if (!absolutePath)
1123
+ return { result: undefined, large: false };
1124
+ try {
1125
+ const stats = await node_fs_1.promises.stat(absolutePath);
1126
+ if (stats.size > LARGE_RESULT_PREVIEW_LIMIT) {
1127
+ return { result: undefined, large: true };
1128
+ }
1129
+ }
1130
+ catch (error) {
1131
+ const err = error;
1132
+ if (err.code === "ENOENT") {
1133
+ return { result: undefined, large: false };
1134
+ }
1135
+ throw error;
1136
+ }
1137
+ const data = await (0, tasks_1.readTaskResult)(runDir, effectId, record.resultRef);
1138
+ return { result: data ?? undefined, large: false };
1139
+ }
1140
+ function buildTaskRunPlanPayload(runDir, result) {
1141
+ if (!result.command) {
1142
+ throw new Error("task runner did not supply command metadata for dry-run planning");
1143
+ }
1144
+ const normalize = (absolute) => toRunRelativePosix(runDir, absolute) ?? absolute;
1145
+ return {
1146
+ command: {
1147
+ binary: normalize(result.command.binary),
1148
+ args: result.command.args.map((arg, index) => (index === 0 ? normalize(arg) : arg)),
1149
+ cwd: normalize(result.command.cwd),
1150
+ },
1151
+ io: {
1152
+ input: normalize(result.io.inputJsonPath),
1153
+ output: normalize(result.io.outputJsonPath),
1154
+ stdout: normalize(result.io.stdoutPath),
1155
+ stderr: normalize(result.io.stderrPath),
1156
+ },
1157
+ };
1158
+ }
1159
+ function logTaskRunPlan(plan) {
1160
+ console.error(`[task:run] dry-run plan ${JSON.stringify(plan)}`);
1161
+ }
1162
+ function resolveTaskRunArtifactRef(runDir, committedRef, fallbackPath) {
1163
+ return normalizeArtifactRef(runDir, committedRef) ?? toRunRelativePosix(runDir, fallbackPath);
1164
+ }
1165
+ function buildTaskRunStreamers(parsed) {
1166
+ const stdoutTarget = parsed.json ? process.stderr : process.stdout;
1167
+ const stderrTarget = process.stderr;
1168
+ return {
1169
+ onStdoutChunk: (chunk) => {
1170
+ stdoutTarget.write(chunk);
1171
+ },
1172
+ onStderrChunk: (chunk) => {
1173
+ stderrTarget.write(chunk);
1174
+ },
1175
+ };
1176
+ }
1177
+ function deriveRunState(lastLifecycleEventType, pendingTotal) {
1178
+ if (lastLifecycleEventType === "RUN_COMPLETED")
1179
+ return "completed";
1180
+ if (lastLifecycleEventType === "RUN_FAILED")
1181
+ return "failed";
1182
+ if (pendingTotal > 0)
1183
+ return "waiting";
1184
+ return "created";
1185
+ }
1186
+ function formatLastEventSummary(event) {
1187
+ if (!event)
1188
+ return "none";
1189
+ return `${event.type}#${formatSeq(event.seq)} ${event.recordedAt}`;
1190
+ }
1191
+ function mergeMetadataSources(metadata, options) {
1192
+ const snapshot = options.snapshot ?? null;
1193
+ const hasPendingOverride = options.pendingByKind !== undefined;
1194
+ const snapshotHasInfo = Boolean(snapshot);
1195
+ if (!metadata && !hasPendingOverride && !snapshotHasInfo) {
1196
+ return undefined;
1197
+ }
1198
+ const next = { ...(metadata ?? {}) };
1199
+ if (hasPendingOverride) {
1200
+ next.pendingEffectsByKind = { ...(options.pendingByKind ?? {}) };
1201
+ }
1202
+ else if (!next.pendingEffectsByKind && snapshot) {
1203
+ next.pendingEffectsByKind = { ...snapshot.pendingEffectsByKind };
1204
+ }
1205
+ if (snapshot) {
1206
+ if (next.stateVersion === undefined) {
1207
+ next.stateVersion = snapshot.stateVersion;
1208
+ }
1209
+ if (next.journalHead === undefined) {
1210
+ next.journalHead = snapshot.journalHead ?? null;
1211
+ }
1212
+ if (snapshot.rebuildReason) {
1213
+ next.stateRebuilt = true;
1214
+ if (!next.stateRebuildReason) {
1215
+ next.stateRebuildReason = snapshot.rebuildReason;
1216
+ }
1217
+ }
1218
+ }
1219
+ if (next.stateVersion === undefined &&
1220
+ next.stateRebuilt === undefined &&
1221
+ next.pendingEffectsByKind === undefined &&
1222
+ next.journalHead === undefined) {
1223
+ return undefined;
1224
+ }
1225
+ return next;
1226
+ }
1227
+ function formatIterationMetadata(metadata) {
1228
+ const textParts = [];
1229
+ if (!metadata) {
1230
+ return { textParts, jsonMetadata: undefined };
1231
+ }
1232
+ if (metadata.stateVersion !== undefined) {
1233
+ textParts.push(`stateVersion=${metadata.stateVersion}`);
1234
+ }
1235
+ if (metadata.journalHead && typeof metadata.journalHead.seq === "number") {
1236
+ const seq = formatSeq(metadata.journalHead.seq);
1237
+ textParts.push(`journalHead=#${seq}`);
1238
+ if (metadata.journalHead.ulid) {
1239
+ textParts.push(`journalHead.ulid=${metadata.journalHead.ulid}`);
1240
+ }
1241
+ if (metadata.journalHead.checksum) {
1242
+ textParts.push(`journalHead.checksum=${metadata.journalHead.checksum}`);
1243
+ }
1244
+ }
1245
+ if (metadata.stateRebuilt) {
1246
+ const reasonSuffix = metadata.stateRebuildReason ? `(${metadata.stateRebuildReason})` : "";
1247
+ textParts.push(`stateRebuilt=true${reasonSuffix}`);
1248
+ }
1249
+ if (metadata.pendingEffectsByKind) {
1250
+ const pendingEntries = Object.entries(metadata.pendingEffectsByKind).sort(([a], [b]) => a.localeCompare(b));
1251
+ const pendingTotal = pendingEntries.reduce((sum, [, count]) => sum + count, 0);
1252
+ textParts.push(`pending[total]=${pendingTotal}`);
1253
+ for (const [kind, count] of pendingEntries) {
1254
+ textParts.push(`pending[${kind}]=${count}`);
1255
+ }
1256
+ }
1257
+ return { textParts, jsonMetadata: metadata };
1258
+ }
1259
+ function serializeJournalEvent(event, runDir) {
1260
+ const data = ensureIterationMetadata(event.data);
1261
+ return {
1262
+ seq: event.seq,
1263
+ ulid: event.ulid,
1264
+ type: event.type,
1265
+ recordedAt: event.recordedAt,
1266
+ filename: event.filename,
1267
+ path: toRunRelativePosix(runDir, event.path),
1268
+ data,
1269
+ };
1270
+ }
1271
+ function ensureIterationMetadata(data) {
1272
+ const iteration = data.iteration;
1273
+ if (!iteration || typeof iteration !== "object" || Array.isArray(iteration)) {
1274
+ return data;
1275
+ }
1276
+ const iterationRecord = iteration;
1277
+ const metadata = iterationRecord.metadata;
1278
+ return {
1279
+ ...data,
1280
+ iteration: {
1281
+ ...iterationRecord,
1282
+ metadata: metadata === undefined ? null : metadata,
1283
+ },
1284
+ };
1285
+ }
1286
+ function formatEventLine(event) {
1287
+ return `#${formatSeq(event.seq)} ${event.type} ${event.recordedAt}`;
1288
+ }
1289
+ function formatSeq(seq) {
1290
+ return seq.toString().padStart(6, "0");
1291
+ }
1292
+ function createBabysitterCli() {
1293
+ return {
1294
+ async run(argv = process.argv.slice(2)) {
1295
+ try {
1296
+ const parsed = parseArgs(argv);
1297
+ if (!parsed.command || parsed.helpRequested) {
1298
+ console.log(USAGE);
1299
+ return 0;
1300
+ }
1301
+ if (parsed.command === "run:create") {
1302
+ return await handleRunCreate(parsed);
1303
+ }
1304
+ if (parsed.command === "run:rebuild-state") {
1305
+ return await handleRunRebuildState(parsed);
1306
+ }
1307
+ if (parsed.command === "run:status") {
1308
+ return await handleRunStatus(parsed);
1309
+ }
1310
+ if (parsed.command === "run:events") {
1311
+ return await handleRunEvents(parsed);
1312
+ }
1313
+ if (parsed.command === "task:run") {
1314
+ return await handleTaskRun(parsed);
1315
+ }
1316
+ if (parsed.command === "run:step") {
1317
+ return await handleRunStep(parsed);
1318
+ }
1319
+ if (parsed.command === "run:continue") {
1320
+ return await handleRunContinue(parsed);
1321
+ }
1322
+ if (parsed.command === "task:list") {
1323
+ return await handleTaskList(parsed);
1324
+ }
1325
+ if (parsed.command === "task:show") {
1326
+ return await handleTaskShow(parsed);
1327
+ }
1328
+ console.error(USAGE);
1329
+ return 1;
1330
+ }
1331
+ catch (error) {
1332
+ console.error(error instanceof Error ? error.message : String(error));
1333
+ return 1;
1334
+ }
1335
+ },
1336
+ formatHelp() {
1337
+ return USAGE;
1338
+ },
1339
+ };
1340
+ }
1341
+ if (require.main === module) {
1342
+ void createBabysitterCli().run();
1343
+ }