@a5c-ai/babysitter-sdk 0.0.169 → 0.0.170-staging.00aac85c

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 (76) hide show
  1. package/dist/cli/commands/configure.d.ts +124 -0
  2. package/dist/cli/commands/configure.d.ts.map +1 -0
  3. package/dist/cli/commands/configure.js +514 -0
  4. package/dist/cli/commands/health.d.ts +89 -0
  5. package/dist/cli/commands/health.d.ts.map +1 -0
  6. package/dist/cli/commands/health.js +579 -0
  7. package/dist/cli/commands/hookLog.d.ts +15 -0
  8. package/dist/cli/commands/hookLog.d.ts.map +1 -0
  9. package/dist/cli/commands/hookLog.js +286 -0
  10. package/dist/cli/commands/hookRun.d.ts +20 -0
  11. package/dist/cli/commands/hookRun.d.ts.map +1 -0
  12. package/dist/cli/commands/hookRun.js +544 -0
  13. package/dist/cli/commands/runExecuteTasks.d.ts +42 -0
  14. package/dist/cli/commands/runExecuteTasks.d.ts.map +1 -0
  15. package/dist/cli/commands/runExecuteTasks.js +377 -0
  16. package/dist/cli/commands/runIterate.d.ts +5 -1
  17. package/dist/cli/commands/runIterate.d.ts.map +1 -1
  18. package/dist/cli/commands/runIterate.js +75 -6
  19. package/dist/cli/commands/session.d.ts +97 -0
  20. package/dist/cli/commands/session.d.ts.map +1 -0
  21. package/dist/cli/commands/session.js +922 -0
  22. package/dist/cli/commands/skill.d.ts +87 -0
  23. package/dist/cli/commands/skill.d.ts.map +1 -0
  24. package/dist/cli/commands/skill.js +869 -0
  25. package/dist/cli/completionProof.d.ts +4 -0
  26. package/dist/cli/completionProof.d.ts.map +1 -0
  27. package/dist/cli/{completionSecret.js → completionProof.js} +7 -7
  28. package/dist/cli/main.d.ts +14 -0
  29. package/dist/cli/main.d.ts.map +1 -1
  30. package/dist/cli/main.js +649 -16
  31. package/dist/config/defaults.d.ts +165 -0
  32. package/dist/config/defaults.d.ts.map +1 -0
  33. package/dist/config/defaults.js +281 -0
  34. package/dist/config/index.d.ts +25 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/config/index.js +35 -0
  37. package/dist/hooks/dispatcher.d.ts.map +1 -1
  38. package/dist/hooks/dispatcher.js +2 -1
  39. package/dist/index.d.ts +1 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +1 -0
  42. package/dist/runtime/constants.d.ts +1 -1
  43. package/dist/runtime/constants.d.ts.map +1 -1
  44. package/dist/runtime/createRun.d.ts.map +1 -1
  45. package/dist/runtime/createRun.js +7 -3
  46. package/dist/runtime/exceptions.d.ts +186 -3
  47. package/dist/runtime/exceptions.d.ts.map +1 -1
  48. package/dist/runtime/exceptions.js +416 -15
  49. package/dist/runtime/types.d.ts +1 -0
  50. package/dist/runtime/types.d.ts.map +1 -1
  51. package/dist/session/index.d.ts +9 -0
  52. package/dist/session/index.d.ts.map +1 -0
  53. package/dist/session/index.js +30 -0
  54. package/dist/session/parse.d.ts +45 -0
  55. package/dist/session/parse.d.ts.map +1 -0
  56. package/dist/session/parse.js +159 -0
  57. package/dist/session/types.d.ts +194 -0
  58. package/dist/session/types.d.ts.map +1 -0
  59. package/dist/session/types.js +45 -0
  60. package/dist/session/write.d.ts +50 -0
  61. package/dist/session/write.d.ts.map +1 -0
  62. package/dist/session/write.js +196 -0
  63. package/dist/storage/createRunDir.d.ts.map +1 -1
  64. package/dist/storage/createRunDir.js +1 -0
  65. package/dist/storage/paths.d.ts +5 -1
  66. package/dist/storage/paths.d.ts.map +1 -1
  67. package/dist/storage/paths.js +6 -1
  68. package/dist/storage/types.d.ts +3 -1
  69. package/dist/storage/types.d.ts.map +1 -1
  70. package/dist/tasks/kinds/index.d.ts.map +1 -1
  71. package/dist/tasks/kinds/index.js +6 -1
  72. package/dist/testing/runHarness.d.ts.map +1 -1
  73. package/dist/testing/runHarness.js +5 -1
  74. package/package.json +1 -2
  75. package/dist/cli/completionSecret.d.ts +0 -4
  76. package/dist/cli/completionSecret.d.ts.map +0 -1
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ /**
3
+ * run:execute-tasks command - Execute pending node tasks in a run
4
+ *
5
+ * This command replaces the shell-based task execution logic in native-orchestrator.sh.
6
+ * It:
7
+ * 1. Loads the journal and builds the effect index
8
+ * 2. Filters pending effects by kind (default "node")
9
+ * 3. Slices to maxTasks (default 3)
10
+ * 4. For each task: reads task.json, spawns `node`, captures stdout/stderr, commits result
11
+ * 5. Returns a summary of executed tasks
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.runExecuteTasks = runExecuteTasks;
48
+ const node_child_process_1 = require("node:child_process");
49
+ const node_fs_1 = require("node:fs");
50
+ const path = __importStar(require("node:path"));
51
+ const effectIndex_1 = require("../../runtime/replay/effectIndex");
52
+ const commitEffectResult_1 = require("../../runtime/commitEffectResult");
53
+ const tasks_1 = require("../../storage/tasks");
54
+ const defaults_1 = require("../../config/defaults");
55
+ function log(verbose, ...args) {
56
+ if (verbose) {
57
+ console.error(`[run:execute-tasks]`, ...args);
58
+ }
59
+ }
60
+ /**
61
+ * Resolve a path relative to runDir unless it is already absolute.
62
+ */
63
+ function resolveRelative(runDir, ref) {
64
+ if (path.isAbsolute(ref) || /^[A-Za-z]:[\\/]/.test(ref)) {
65
+ return ref;
66
+ }
67
+ return path.join(runDir, ref);
68
+ }
69
+ /**
70
+ * Make a path relative to runDir, using forward slashes.
71
+ */
72
+ function toRunRelative(runDir, absolute) {
73
+ return path.relative(runDir, absolute).replace(/\\/g, "/");
74
+ }
75
+ /**
76
+ * Spawn a node process for the given task and capture its output.
77
+ */
78
+ function spawnNodeTask(options) {
79
+ return new Promise((resolve) => {
80
+ const child = (0, node_child_process_1.spawn)("node", [options.entry, ...options.args], {
81
+ cwd: options.cwd,
82
+ env: { ...process.env, ...options.env },
83
+ stdio: ["ignore", "pipe", "pipe"],
84
+ timeout: options.timeout,
85
+ });
86
+ const stdoutChunks = [];
87
+ const stderrChunks = [];
88
+ child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
89
+ child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
90
+ child.on("close", (code) => {
91
+ resolve({
92
+ exitCode: code ?? 1,
93
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
94
+ stderr: Buffer.concat(stderrChunks).toString("utf8"),
95
+ });
96
+ });
97
+ child.on("error", (err) => {
98
+ resolve({
99
+ exitCode: 1,
100
+ stdout: Buffer.concat(stdoutChunks).toString("utf8"),
101
+ stderr: `${Buffer.concat(stderrChunks).toString("utf8")}\n${err.message}`,
102
+ });
103
+ });
104
+ });
105
+ }
106
+ /**
107
+ * Execute a single task: read its definition, spawn node, commit the result.
108
+ */
109
+ async function executeOneTask(runDir, record, timeout, verbose) {
110
+ const effectId = record.effectId;
111
+ const label = record.label ?? null;
112
+ log(verbose, `Executing: ${effectId}${label ? ` (${label})` : ""}`);
113
+ // Read task.json
114
+ const taskDef = await (0, tasks_1.readTaskDefinition)(runDir, effectId);
115
+ if (!taskDef) {
116
+ log(verbose, `Missing task definition for ${effectId}`);
117
+ const errorPayload = {
118
+ name: "Error",
119
+ message: `Missing task definition for effect ${effectId}`,
120
+ };
121
+ await (0, commitEffectResult_1.commitEffectResult)({
122
+ runDir,
123
+ effectId,
124
+ invocationKey: record.invocationKey,
125
+ result: {
126
+ status: "error",
127
+ error: errorPayload,
128
+ startedAt: new Date().toISOString(),
129
+ finishedAt: new Date().toISOString(),
130
+ },
131
+ });
132
+ return {
133
+ effectId,
134
+ label,
135
+ status: "error",
136
+ exitCode: 1,
137
+ durationMs: 0,
138
+ stdoutRef: null,
139
+ stderrRef: null,
140
+ resultRef: null,
141
+ error: errorPayload,
142
+ };
143
+ }
144
+ // Extract node config
145
+ const nodeConfig = (taskDef.node ?? {});
146
+ const entry = nodeConfig.entry;
147
+ if (!entry) {
148
+ log(verbose, `Missing node.entry in task.json for ${effectId}`);
149
+ const errorPayload = {
150
+ name: "Error",
151
+ message: `Missing node.entry in task definition for effect ${effectId}`,
152
+ };
153
+ await (0, commitEffectResult_1.commitEffectResult)({
154
+ runDir,
155
+ effectId,
156
+ invocationKey: record.invocationKey,
157
+ result: {
158
+ status: "error",
159
+ error: errorPayload,
160
+ startedAt: new Date().toISOString(),
161
+ finishedAt: new Date().toISOString(),
162
+ },
163
+ });
164
+ return {
165
+ effectId,
166
+ label,
167
+ status: "error",
168
+ exitCode: 1,
169
+ durationMs: 0,
170
+ stdoutRef: null,
171
+ stderrRef: null,
172
+ resultRef: null,
173
+ error: errorPayload,
174
+ };
175
+ }
176
+ const nodeArgs = nodeConfig.args ?? [];
177
+ const taskTimeout = nodeConfig.timeoutMs ?? timeout;
178
+ // Extract IO config
179
+ const ioConfig = (taskDef.io ?? {});
180
+ const inputRef = ioConfig.inputJsonPath ?? `tasks/${effectId}/inputs.json`;
181
+ const outputRef = ioConfig.outputJsonPath ?? `tasks/${effectId}/result.json`;
182
+ const stdoutRef = ioConfig.stdoutPath ?? `tasks/${effectId}/stdout.log`;
183
+ const stderrRef = ioConfig.stderrPath ?? `tasks/${effectId}/stderr.log`;
184
+ // Resolve paths relative to runDir
185
+ const inputAbs = resolveRelative(runDir, inputRef);
186
+ const outputAbs = resolveRelative(runDir, outputRef);
187
+ const stdoutAbs = resolveRelative(runDir, stdoutRef);
188
+ const stderrAbs = resolveRelative(runDir, stderrRef);
189
+ const entryAbs = resolveRelative(runDir, entry);
190
+ const cwdAbs = nodeConfig.cwd ? resolveRelative(runDir, nodeConfig.cwd) : runDir;
191
+ // Ensure directories exist
192
+ await Promise.all([
193
+ node_fs_1.promises.mkdir(path.dirname(inputAbs), { recursive: true }),
194
+ node_fs_1.promises.mkdir(path.dirname(outputAbs), { recursive: true }),
195
+ node_fs_1.promises.mkdir(path.dirname(stdoutAbs), { recursive: true }),
196
+ node_fs_1.promises.mkdir(path.dirname(stderrAbs), { recursive: true }),
197
+ ]);
198
+ // Stage inputs.json
199
+ const inputsRefField = taskDef.inputsRef;
200
+ if (inputsRefField) {
201
+ const sourceAbs = resolveRelative(runDir, inputsRefField);
202
+ try {
203
+ await node_fs_1.promises.copyFile(sourceAbs, inputAbs);
204
+ }
205
+ catch {
206
+ // If the source doesn't exist, write an empty object
207
+ await node_fs_1.promises.writeFile(inputAbs, "{}\n", "utf8");
208
+ }
209
+ }
210
+ else {
211
+ // Extract inline inputs or default to {}
212
+ const inputs = taskDef.inputs ?? {};
213
+ await node_fs_1.promises.writeFile(inputAbs, JSON.stringify(inputs) + "\n", "utf8");
214
+ }
215
+ // Build environment for the child process
216
+ const taskEnv = {
217
+ ...(nodeConfig.env ?? {}),
218
+ BABYSITTER_INPUT_JSON: inputAbs,
219
+ BABYSITTER_OUTPUT_JSON: outputAbs,
220
+ BABYSITTER_STDOUT_PATH: stdoutAbs,
221
+ BABYSITTER_STDERR_PATH: stderrAbs,
222
+ BABYSITTER_EFFECT_ID: effectId,
223
+ };
224
+ // Spawn the node process
225
+ const startedAt = new Date().toISOString();
226
+ const startMs = Date.now();
227
+ const spawnResult = await spawnNodeTask({
228
+ entry: entryAbs,
229
+ args: nodeArgs,
230
+ cwd: cwdAbs,
231
+ env: taskEnv,
232
+ stdoutPath: stdoutAbs,
233
+ stderrPath: stderrAbs,
234
+ timeout: taskTimeout,
235
+ });
236
+ const finishedAt = new Date().toISOString();
237
+ const durationMs = Date.now() - startMs;
238
+ // Write stdout and stderr to disk
239
+ await node_fs_1.promises.writeFile(stdoutAbs, spawnResult.stdout, "utf8");
240
+ await node_fs_1.promises.writeFile(stderrAbs, spawnResult.stderr, "utf8");
241
+ const stdoutRelRef = toRunRelative(runDir, stdoutAbs);
242
+ const stderrRelRef = toRunRelative(runDir, stderrAbs);
243
+ // Commit the result
244
+ if (spawnResult.exitCode === 0) {
245
+ // Read the output file produced by the task (if any)
246
+ let value = undefined;
247
+ try {
248
+ const outputContents = await node_fs_1.promises.readFile(outputAbs, "utf8");
249
+ const trimmed = outputContents.trim();
250
+ if (trimmed.length > 0) {
251
+ value = JSON.parse(trimmed);
252
+ }
253
+ }
254
+ catch {
255
+ // Output file may not exist; that is acceptable
256
+ }
257
+ const committed = await (0, commitEffectResult_1.commitEffectResult)({
258
+ runDir,
259
+ effectId,
260
+ invocationKey: record.invocationKey,
261
+ result: {
262
+ status: "ok",
263
+ value,
264
+ stdoutRef: stdoutRelRef,
265
+ stderrRef: stderrRelRef,
266
+ startedAt,
267
+ finishedAt,
268
+ },
269
+ });
270
+ log(verbose, `Posted result: ${effectId} (ok, ${durationMs}ms)`);
271
+ return {
272
+ effectId,
273
+ label,
274
+ status: "ok",
275
+ exitCode: spawnResult.exitCode,
276
+ durationMs,
277
+ stdoutRef: stdoutRelRef,
278
+ stderrRef: stderrRelRef,
279
+ resultRef: committed.resultRef ?? null,
280
+ };
281
+ }
282
+ else {
283
+ const errorPayload = {
284
+ name: "Error",
285
+ message: `Node task exited non-zero (exitCode=${spawnResult.exitCode})`,
286
+ };
287
+ const committed = await (0, commitEffectResult_1.commitEffectResult)({
288
+ runDir,
289
+ effectId,
290
+ invocationKey: record.invocationKey,
291
+ result: {
292
+ status: "error",
293
+ error: errorPayload,
294
+ stdoutRef: stdoutRelRef,
295
+ stderrRef: stderrRelRef,
296
+ startedAt,
297
+ finishedAt,
298
+ },
299
+ });
300
+ log(verbose, `Posted error: ${effectId} (exitCode=${spawnResult.exitCode}, ${durationMs}ms)`);
301
+ return {
302
+ effectId,
303
+ label,
304
+ status: "error",
305
+ exitCode: spawnResult.exitCode,
306
+ durationMs,
307
+ stdoutRef: stdoutRelRef,
308
+ stderrRef: stderrRelRef,
309
+ resultRef: committed.resultRef ?? null,
310
+ error: errorPayload,
311
+ };
312
+ }
313
+ }
314
+ async function runExecuteTasks(options) {
315
+ const { runDir, verbose, dryRun, } = options;
316
+ const maxTasks = options.maxTasks ?? 3;
317
+ const kind = options.kind ?? "node";
318
+ const config = (0, defaults_1.getConfig)();
319
+ const timeout = options.timeout ?? config.nodeTaskTimeout;
320
+ log(verbose, `Scanning for pending ${kind} tasks in ${runDir} (maxTasks=${maxTasks})`);
321
+ // Build the effect index from journal
322
+ const effectIndex = await (0, effectIndex_1.buildEffectIndex)({ runDir });
323
+ const pendingEffects = effectIndex.listPendingEffects();
324
+ if (pendingEffects.length === 0) {
325
+ log(verbose, "No pending effects found");
326
+ return {
327
+ action: "none",
328
+ count: 0,
329
+ reason: "no-pending-effects",
330
+ tasks: [],
331
+ };
332
+ }
333
+ // Filter by kind
334
+ const matchingEffects = pendingEffects.filter((record) => record.kind?.toLowerCase() === kind.toLowerCase());
335
+ if (matchingEffects.length === 0) {
336
+ log(verbose, `No pending effects matching kind="${kind}"`);
337
+ return {
338
+ action: "none",
339
+ count: 0,
340
+ reason: "no-matching-tasks",
341
+ tasks: [],
342
+ };
343
+ }
344
+ // Slice to maxTasks
345
+ const tasksToExecute = matchingEffects.slice(0, maxTasks);
346
+ log(verbose, `Found ${matchingEffects.length} matching tasks, executing ${tasksToExecute.length}`);
347
+ if (dryRun) {
348
+ const dryRunTasks = tasksToExecute.map((record) => ({
349
+ effectId: record.effectId,
350
+ label: record.label ?? null,
351
+ status: "ok",
352
+ exitCode: 0,
353
+ durationMs: 0,
354
+ stdoutRef: null,
355
+ stderrRef: null,
356
+ resultRef: null,
357
+ }));
358
+ return {
359
+ action: "none",
360
+ count: tasksToExecute.length,
361
+ reason: "dry-run",
362
+ tasks: dryRunTasks,
363
+ };
364
+ }
365
+ // Execute tasks sequentially
366
+ const taskSummaries = [];
367
+ for (const record of tasksToExecute) {
368
+ const summary = await executeOneTask(runDir, record, timeout, verbose);
369
+ taskSummaries.push(summary);
370
+ }
371
+ return {
372
+ action: "executed-tasks",
373
+ count: taskSummaries.length,
374
+ reason: "auto-runnable-tasks",
375
+ tasks: taskSummaries,
376
+ };
377
+ }
@@ -15,20 +15,24 @@ export interface RunIterateOptions {
15
15
  iteration?: number;
16
16
  verbose?: boolean;
17
17
  json?: boolean;
18
+ pluginRoot?: string;
18
19
  }
19
20
  export interface RunIterateResult {
20
21
  iteration: number;
22
+ iterationCount: number;
21
23
  status: "executed" | "waiting" | "completed" | "failed" | "none";
22
24
  action?: string;
23
25
  reason?: string;
24
26
  count?: number;
25
27
  until?: number;
26
28
  nextActions?: EffectAction[];
27
- completionSecret?: string;
29
+ completionProof?: string;
28
30
  metadata?: {
29
31
  runId: string;
30
32
  processId: string;
31
33
  hookStatus?: string;
34
+ discoveredSkills?: string[];
35
+ discoveredAgents?: string[];
32
36
  };
33
37
  }
34
38
  export declare function runIterate(options: RunIterateOptions): Promise<RunIterateResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"runIterate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/runIterate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgJtF"}
1
+ {"version":3,"file":"runIterate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/runIterate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKxD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;CACH;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+JtF"}
@@ -47,17 +47,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
47
47
  exports.runIterate = runIterate;
48
48
  const path = __importStar(require("path"));
49
49
  const runFiles_1 = require("../../storage/runFiles");
50
+ const journal_1 = require("../../storage/journal");
51
+ const stateCache_1 = require("../../runtime/replay/stateCache");
50
52
  const runtime_1 = require("../../runtime/hooks/runtime");
51
53
  const orchestrateIteration_1 = require("../../runtime/orchestrateIteration");
52
- const completionSecret_1 = require("../completionSecret");
54
+ const completionProof_1 = require("../completionProof");
55
+ const skill_1 = require("./skill");
53
56
  async function runIterate(options) {
54
57
  const { runDir, verbose } = options;
55
58
  // Read run metadata
56
59
  const metadata = await (0, runFiles_1.readRunMetadata)(runDir);
57
60
  const runId = metadata.runId;
58
- // Determine iteration number
59
- // TODO: Read from state.json or journal
60
- const iteration = options.iteration ?? 1;
61
+ // Determine iteration number from state cache or journal
62
+ const iterationCount = await detectIterationCount(runDir);
63
+ const iteration = options.iteration ?? (iterationCount + 1);
61
64
  const projectRoot = path.dirname(path.dirname(path.dirname(runDir)));
62
65
  if (verbose) {
63
66
  console.error(`[run:iterate] Starting iteration ${iteration} for run ${runId}`);
@@ -66,7 +69,7 @@ async function runIterate(options) {
66
69
  // This is what creates EFFECT_REQUESTED entries that hooks can observe via task:list.
67
70
  const iterationResult = await (0, orchestrateIteration_1.orchestrateIteration)({ runDir });
68
71
  if (iterationResult.status === "completed") {
69
- const completionSecret = (0, completionSecret_1.resolveCompletionSecret)(metadata);
72
+ const completionProof = (0, completionProof_1.resolveCompletionProof)(metadata);
70
73
  await (0, runtime_1.callRuntimeHook)("on-iteration-end", {
71
74
  runId,
72
75
  iteration,
@@ -77,10 +80,11 @@ async function runIterate(options) {
77
80
  }, { cwd: projectRoot, logger: verbose ? ((msg) => console.error(msg)) : undefined });
78
81
  return {
79
82
  iteration,
83
+ iterationCount,
80
84
  status: "completed",
81
85
  action: "none",
82
86
  reason: "completed",
83
- completionSecret,
87
+ completionProof,
84
88
  metadata: { runId, processId: metadata.processId, hookStatus: "executed" },
85
89
  };
86
90
  }
@@ -95,6 +99,7 @@ async function runIterate(options) {
95
99
  }, { cwd: projectRoot, logger: verbose ? ((msg) => console.error(msg)) : undefined });
96
100
  return {
97
101
  iteration,
102
+ iterationCount,
98
103
  status: "failed",
99
104
  action: "none",
100
105
  reason: "failed",
@@ -155,6 +160,7 @@ async function runIterate(options) {
155
160
  // Return result
156
161
  const result = {
157
162
  iteration,
163
+ iterationCount,
158
164
  status,
159
165
  action,
160
166
  reason,
@@ -167,8 +173,71 @@ async function runIterate(options) {
167
173
  hookStatus: hookResult.executedHooks?.length > 0 ? "executed" : "none",
168
174
  },
169
175
  };
176
+ // Discover available skills and agents
177
+ const pluginRoot = options.pluginRoot;
178
+ if (pluginRoot && result.metadata) {
179
+ try {
180
+ const discoverResult = await (0, skill_1.discoverSkillsInternal)({ pluginRoot, runId });
181
+ result.metadata.discoveredSkills = discoverResult.skills.map(s => s.name);
182
+ result.metadata.discoveredAgents = discoverResult.agents.map(a => a.name);
183
+ }
184
+ catch {
185
+ // Non-fatal
186
+ }
187
+ }
170
188
  return result;
171
189
  }
190
+ /**
191
+ * Detect the current iteration count from state cache or journal.
192
+ *
193
+ * The iteration count represents how many iterations have been completed so far.
194
+ * This is used to determine the next iteration number when --iteration is not specified.
195
+ *
196
+ * Strategy:
197
+ * 1. Read from state.json (stateCache snapshot) if available - uses stateVersion
198
+ * which tracks the journal sequence number
199
+ * 2. Fall back to counting RUN_ITERATION events in the journal
200
+ * 3. Return 0 if neither is available (fresh run)
201
+ */
202
+ async function detectIterationCount(runDir) {
203
+ // Strategy 1: Read from state cache
204
+ try {
205
+ const stateCache = await (0, stateCache_1.readStateCache)(runDir);
206
+ if (stateCache && typeof stateCache.stateVersion === "number" && stateCache.stateVersion > 0) {
207
+ // stateVersion tracks journal sequence, which correlates to iteration progress
208
+ // We derive iteration count from the number of completed iteration cycles
209
+ // Each iteration typically produces multiple journal events, so we use
210
+ // RUN_ITERATION event count as the more accurate measure
211
+ const iterationCountFromJournal = await countIterationsFromJournal(runDir);
212
+ if (iterationCountFromJournal > 0) {
213
+ return iterationCountFromJournal;
214
+ }
215
+ // If no RUN_ITERATION events but we have state, estimate from stateVersion
216
+ // This provides backward compatibility for runs that don't log RUN_ITERATION
217
+ return Math.max(0, Math.floor(stateCache.stateVersion / 2));
218
+ }
219
+ }
220
+ catch {
221
+ // State cache not available, fall through to journal
222
+ }
223
+ // Strategy 2: Count RUN_ITERATION events in journal
224
+ try {
225
+ return await countIterationsFromJournal(runDir);
226
+ }
227
+ catch {
228
+ // Journal not available
229
+ }
230
+ // Strategy 3: Default to 0 for fresh runs
231
+ return 0;
232
+ }
233
+ /**
234
+ * Count the number of RUN_ITERATION events in the journal.
235
+ * Each RUN_ITERATION event represents one completed iteration.
236
+ */
237
+ async function countIterationsFromJournal(runDir) {
238
+ const events = await (0, journal_1.loadJournal)(runDir);
239
+ return events.filter((event) => event.type === "RUN_ITERATION").length;
240
+ }
172
241
  function parseHookDecision(output) {
173
242
  const record = parseMaybeJsonRecord(output);
174
243
  if (!record)
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Session management CLI commands.
3
+ * Replaces bash logic from babysitter plugin shell scripts.
4
+ */
5
+ /**
6
+ * Parsed arguments for session commands.
7
+ */
8
+ export interface SessionCommandArgs {
9
+ sessionId?: string;
10
+ stateDir?: string;
11
+ maxIterations?: number;
12
+ runId?: string;
13
+ prompt?: string;
14
+ iteration?: number;
15
+ lastIterationAt?: string;
16
+ iterationTimes?: string;
17
+ delete?: boolean;
18
+ json: boolean;
19
+ runsDir?: string;
20
+ }
21
+ /**
22
+ * Handle session:init command.
23
+ * Initializes a new session state file.
24
+ */
25
+ export declare function handleSessionInit(args: SessionCommandArgs): Promise<number>;
26
+ /**
27
+ * Handle session:associate command.
28
+ * Associates a session with a run ID.
29
+ */
30
+ export declare function handleSessionAssociate(args: SessionCommandArgs): Promise<number>;
31
+ /**
32
+ * Handle session:resume command.
33
+ * Resumes an existing run in a new session.
34
+ */
35
+ export declare function handleSessionResume(args: SessionCommandArgs): Promise<number>;
36
+ /**
37
+ * Handle session:state command.
38
+ * Reads and returns session state.
39
+ */
40
+ export declare function handleSessionState(args: SessionCommandArgs): Promise<number>;
41
+ /**
42
+ * Handle session:update command.
43
+ * Updates session state fields.
44
+ */
45
+ export declare function handleSessionUpdate(args: SessionCommandArgs): Promise<number>;
46
+ /**
47
+ * Handle session:check-iteration command.
48
+ * Checks if iteration should continue based on timing and limits.
49
+ */
50
+ export declare function handleSessionCheckIteration(args: SessionCommandArgs): Promise<number>;
51
+ export interface SessionLastMessageArgs {
52
+ transcriptPath: string;
53
+ json: boolean;
54
+ }
55
+ export interface SessionLastMessageResult {
56
+ found: boolean;
57
+ text: string | null;
58
+ hasPromise: boolean;
59
+ promiseValue: string | null;
60
+ error?: string;
61
+ }
62
+ /**
63
+ * Parse a JSONL transcript file and extract the last assistant text message.
64
+ * Also detects <promise>...</promise> tags in the text.
65
+ */
66
+ export declare function parseTranscriptLastAssistantMessage(content: string): {
67
+ found: boolean;
68
+ text: string | null;
69
+ };
70
+ /**
71
+ * Extract content from first <promise>...</promise> tag.
72
+ * Trims whitespace and collapses internal whitespace to single spaces.
73
+ */
74
+ export declare function extractPromiseTag(text: string): string | null;
75
+ export declare function handleSessionLastMessage(args: SessionLastMessageArgs): number;
76
+ export interface SessionIterationMessageArgs {
77
+ runId?: string;
78
+ iteration?: number;
79
+ runsDir: string;
80
+ pluginRoot?: string;
81
+ json: boolean;
82
+ }
83
+ export interface SessionIterationMessageResult {
84
+ systemMessage: string;
85
+ runState: string | null;
86
+ completionProof: string | null;
87
+ pendingKinds: string | null;
88
+ skillContext: string | null;
89
+ iteration: number;
90
+ }
91
+ /**
92
+ * Handle session:iteration-message command.
93
+ * Generates the formatted system message for the next babysitter iteration.
94
+ * Replaces ~22 lines of bash branching + skill-context-resolver call in babysitter-stop-hook.sh.
95
+ */
96
+ export declare function handleSessionIterationMessage(args: SessionIterationMessageArgs): Promise<number>;
97
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0GjF;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoGtF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0InF;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmElF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwGnF;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyG3F;AAID,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,MAAM,GAAG;IACpE,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAoDA;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,sBAAsB,GAC3B,MAAM,CA+CR;AAID,MAAM,WAAW,2BAA2B;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,6BAA6B;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,MAAM,CAAC,CA4GjB"}