@schilderlabs/pitown-core 0.2.1 → 0.2.7

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.
package/dist/index.mjs CHANGED
@@ -1,145 +1,14 @@
1
+ import { A as getLatestAgentSession, C as createAgentState, D as getAgentSessionsDir, E as getAgentSessionPath, F as writeAgentState, I as appendJsonl, L as readJsonl, M as listAgentStates, N as readAgentMessages, O as getAgentStatePath, P as readAgentState, S as createAgentSessionRecord, T as getAgentMailboxPath, _ as assertCommandAvailable, a as resolveAgentSession, b as runCommandSync, c as spawnAgentRun, d as getTaskPath, f as getTasksDir, g as writeTaskRecord, h as updateTaskRecordStatus, i as queueAgentMessage, j as getSessionIdFromPath, k as getAgentsDir, l as updateAgentStatus, m as readTaskRecord, n as delegateTask, o as resumeAgentTurnDetached, p as listTaskRecords, r as notifyTaskDelegator, s as runAgentTurn, t as createRolePrompt, u as createTaskRecord, v as assertSuccess, w as getAgentDir, x as appendAgentMessage, y as runCommandInteractive } from "./orchestration-D6XeSl8s.mjs";
1
2
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
2
- import { basename, dirname, join, resolve } from "node:path";
3
+ import { basename, join, resolve } from "node:path";
3
4
  import { homedir, hostname } from "node:os";
4
5
  import { createHash, randomUUID } from "node:crypto";
5
- import { spawnSync } from "node:child_process";
6
6
 
7
- //#region src/events.ts
8
- function appendJsonl(filePath, value) {
9
- mkdirSync(dirname(filePath), { recursive: true });
10
- writeFileSync(filePath, `${JSON.stringify(value)}\n`, {
11
- encoding: "utf-8",
12
- flag: "a"
13
- });
14
- }
15
- function readJsonl(filePath) {
16
- try {
17
- return readFileSync(filePath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
18
- } catch {
19
- return [];
20
- }
21
- }
22
-
23
- //#endregion
24
- //#region src/agents.ts
25
- function writeJson$3(path, value) {
26
- mkdirSync(dirname(path), { recursive: true });
27
- writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
28
- }
29
- function ensureMailbox(path) {
30
- mkdirSync(dirname(path), { recursive: true });
31
- if (!existsSync(path)) writeFileSync(path, "", "utf-8");
32
- }
33
- function getAgentsDir(artifactsDir) {
34
- return join(artifactsDir, "agents");
35
- }
36
- function getAgentDir(artifactsDir, agentId) {
37
- return join(getAgentsDir(artifactsDir), agentId);
38
- }
39
- function getAgentStatePath(artifactsDir, agentId) {
40
- return join(getAgentDir(artifactsDir, agentId), "state.json");
41
- }
42
- function getAgentSessionPath(artifactsDir, agentId) {
43
- return join(getAgentDir(artifactsDir, agentId), "session.json");
44
- }
45
- function getAgentMailboxPath(artifactsDir, agentId, box) {
46
- return join(getAgentDir(artifactsDir, agentId), `${box}.jsonl`);
47
- }
48
- function getAgentSessionsDir(artifactsDir, agentId) {
49
- return join(getAgentDir(artifactsDir, agentId), "sessions");
50
- }
51
- function getSessionIdFromPath(sessionPath) {
52
- if (!sessionPath) return null;
53
- return /_([0-9a-f-]+)\.jsonl$/i.exec(sessionPath)?.[1] ?? null;
54
- }
55
- function createAgentSessionRecord(input) {
56
- return {
57
- runtime: "pi",
58
- persisted: true,
59
- sessionDir: input?.sessionDir ?? null,
60
- sessionId: input?.sessionId ?? null,
61
- sessionPath: input?.sessionPath ?? null,
62
- lastAttachedAt: input?.lastAttachedAt ?? null
63
- };
64
- }
65
- function createAgentState(input) {
66
- return {
67
- agentId: input.agentId,
68
- role: input.role,
69
- status: input.status,
70
- taskId: input.taskId ?? null,
71
- task: input.task ?? null,
72
- branch: input.branch ?? null,
73
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
74
- lastMessage: input.lastMessage ?? null,
75
- waitingOn: input.waitingOn ?? null,
76
- blocked: input.blocked ?? false,
77
- runId: input.runId ?? null,
78
- session: input.session ?? createAgentSessionRecord()
79
- };
80
- }
81
- function writeAgentState(artifactsDir, state) {
82
- mkdirSync(getAgentDir(artifactsDir, state.agentId), { recursive: true });
83
- ensureMailbox(getAgentMailboxPath(artifactsDir, state.agentId, "inbox"));
84
- ensureMailbox(getAgentMailboxPath(artifactsDir, state.agentId, "outbox"));
85
- writeJson$3(getAgentStatePath(artifactsDir, state.agentId), state);
86
- writeJson$3(getAgentSessionPath(artifactsDir, state.agentId), state.session);
87
- }
88
- function readAgentState(artifactsDir, agentId) {
89
- const statePath = getAgentStatePath(artifactsDir, agentId);
90
- try {
91
- return JSON.parse(readFileSync(statePath, "utf-8"));
92
- } catch {
93
- return null;
94
- }
95
- }
96
- function listAgentStates(artifactsDir) {
97
- const agentsDir = getAgentsDir(artifactsDir);
98
- let entries;
99
- try {
100
- entries = readdirSync(agentsDir);
101
- } catch {
102
- return [];
103
- }
104
- return entries.map((entry) => readAgentState(artifactsDir, entry)).filter((state) => state !== null).sort((left, right) => left.agentId.localeCompare(right.agentId));
105
- }
106
- function appendAgentMessage(input) {
107
- const record = {
108
- box: input.box,
109
- from: input.from,
110
- body: input.body,
111
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
112
- };
113
- appendJsonl(getAgentMailboxPath(input.artifactsDir, input.agentId, input.box), record);
114
- return record;
115
- }
116
- function readAgentMessages(artifactsDir, agentId, box) {
117
- return readJsonl(getAgentMailboxPath(artifactsDir, agentId, box));
118
- }
119
- function getLatestAgentSession(artifactsDir, agentId) {
120
- const sessionDir = getAgentSessionsDir(artifactsDir, agentId);
121
- let entries;
122
- try {
123
- entries = readdirSync(sessionDir);
124
- } catch {
125
- return createAgentSessionRecord({ sessionDir });
126
- }
127
- const latestSessionPath = entries.filter((entry) => entry.endsWith(".jsonl")).sort().at(-1) ?? null;
128
- if (latestSessionPath === null) return createAgentSessionRecord({ sessionDir });
129
- const sessionPath = join(sessionDir, latestSessionPath);
130
- return createAgentSessionRecord({
131
- sessionDir,
132
- sessionPath,
133
- sessionId: getSessionIdFromPath(sessionPath)
134
- });
135
- }
136
-
137
- //#endregion
138
7
  //#region src/lease.ts
139
8
  function sanitize$1(value) {
140
9
  return value.replace(/[^a-zA-Z0-9._-]+/g, "_");
141
10
  }
142
- function processAlive(pid) {
11
+ function processAlive$1(pid) {
143
12
  if (!Number.isFinite(pid) || pid <= 0) return false;
144
13
  try {
145
14
  process.kill(pid, 0);
@@ -162,7 +31,7 @@ function acquireRepoLease(runId, repoId, branch) {
162
31
  };
163
32
  try {
164
33
  const current = JSON.parse(readFileSync(leasePath, "utf-8"));
165
- if (processAlive(current.pid)) throw new Error(`Pi Town lease already held by pid ${current.pid} on ${current.hostname} for run ${current.runId}.`);
34
+ if (processAlive$1(current.pid)) throw new Error(`Pi Town lease already held by pid ${current.pid} on ${current.hostname} for run ${current.runId}.`);
166
35
  rmSync(leasePath, { force: true });
167
36
  } catch (error) {
168
37
  if (error.code !== "ENOENT") {
@@ -244,44 +113,6 @@ function createPiAuthHelpMessage() {
244
113
  return "Pi appears to be installed but not authenticated or configured. Verify Pi works first: pi -p \"hello\". Either set an API key or run `pi` and use `/login`.";
245
114
  }
246
115
 
247
- //#endregion
248
- //#region src/shell.ts
249
- function runCommandSync(command, args, options) {
250
- const result = spawnSync(command, args, {
251
- cwd: options?.cwd,
252
- env: options?.env,
253
- encoding: "utf-8"
254
- });
255
- const errorText = result.error instanceof Error ? `${result.error.message}
256
- ` : "";
257
- return {
258
- stdout: result.stdout ?? "",
259
- stderr: `${errorText}${result.stderr ?? ""}`,
260
- exitCode: result.status ?? 1
261
- };
262
- }
263
- function assertCommandAvailable(command) {
264
- const result = spawnSync(command, ["--help"], {
265
- encoding: "utf-8",
266
- stdio: "ignore"
267
- });
268
- if (result.error instanceof Error) throw new Error(result.error.message);
269
- }
270
- function runCommandInteractive(command, args, options) {
271
- const result = spawnSync(command, args, {
272
- cwd: options?.cwd,
273
- env: options?.env,
274
- stdio: "inherit"
275
- });
276
- if (result.error instanceof Error) throw new Error(result.error.message);
277
- return result.status ?? 1;
278
- }
279
- function assertSuccess(result, context) {
280
- if (result.exitCode === 0) return;
281
- const details = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
282
- throw new Error(`${context} failed${details ? `\n${details}` : ""}`);
283
- }
284
-
285
116
  //#endregion
286
117
  //#region src/repo.ts
287
118
  function gitResult(cwd, args) {
@@ -336,7 +167,7 @@ function createRepoSlug(repoId, repoRoot) {
336
167
  function createRunId() {
337
168
  return `run-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
338
169
  }
339
- function createPiInvocationArgs$1(input) {
170
+ function createPiInvocationArgs(input) {
340
171
  const args = [];
341
172
  if (input.extensionPath) args.push("--extension", input.extensionPath);
342
173
  if (input.appendedSystemPrompt) args.push("--append-system-prompt", input.appendedSystemPrompt);
@@ -346,7 +177,7 @@ function createPiInvocationArgs$1(input) {
346
177
  args.push("-p", input.prompt);
347
178
  return args;
348
179
  }
349
- function writeJson$2(path, value) {
180
+ function writeJson$1(path, value) {
350
181
  writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
351
182
  }
352
183
  function writeText(path, value) {
@@ -355,7 +186,7 @@ function writeText(path, value) {
355
186
  function createPiPrompt(input) {
356
187
  const goal = input.goal ?? "continue from current scaffold state";
357
188
  if (input.planPath) return [
358
- "You are the Pi Town leader agent for this repository.",
189
+ "You are the Pi Town mayor agent for this repository.",
359
190
  "Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.",
360
191
  "",
361
192
  "Read the private plans in:",
@@ -369,7 +200,7 @@ function createPiPrompt(input) {
369
200
  "Keep any persisted run artifacts high-signal and avoid copying private plan contents into them."
370
201
  ].join("\n");
371
202
  return [
372
- "You are the Pi Town leader agent for this repository.",
203
+ "You are the Pi Town mayor agent for this repository.",
373
204
  "Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.",
374
205
  "",
375
206
  `Work in the repository at: ${input.repoRoot}`,
@@ -455,21 +286,21 @@ function runController(options) {
455
286
  goal,
456
287
  recommendedPlanDir
457
288
  });
458
- const existingLeaderState = readAgentState(artifactsDir, "leader");
459
- const existingLeaderSession = existingLeaderState?.session.sessionPath || existingLeaderState?.session.sessionDir ? existingLeaderState.session : getLatestAgentSession(artifactsDir, "leader");
460
- const leaderSessionDir = existingLeaderSession.sessionDir ?? getAgentSessionsDir(artifactsDir, "leader");
461
- const leaderState = createAgentState({
462
- agentId: "leader",
463
- role: "leader",
289
+ const existingMayorState = readAgentState(artifactsDir, "mayor");
290
+ const existingMayorSession = existingMayorState?.session.sessionPath || existingMayorState?.session.sessionDir ? existingMayorState.session : getLatestAgentSession(artifactsDir, "mayor");
291
+ const mayorSessionDir = existingMayorSession.sessionDir ?? getAgentSessionsDir(artifactsDir, "mayor");
292
+ const mayorState = createAgentState({
293
+ agentId: "mayor",
294
+ role: "mayor",
464
295
  status: "starting",
465
296
  task: goal,
466
297
  branch,
467
- lastMessage: goal ? `Starting leader run for goal: ${goal}` : "Starting leader run",
298
+ lastMessage: goal ? `Starting mayor run for goal: ${goal}` : "Starting mayor run",
468
299
  runId,
469
300
  session: createAgentSessionRecord({
470
- sessionDir: leaderSessionDir,
471
- sessionId: existingLeaderSession.sessionId,
472
- sessionPath: existingLeaderSession.sessionPath
301
+ sessionDir: mayorSessionDir,
302
+ sessionId: existingMayorSession.sessionId,
303
+ sessionPath: existingMayorSession.sessionPath
473
304
  })
474
305
  });
475
306
  assertPiRuntimeAvailable(piCommand);
@@ -477,11 +308,11 @@ function runController(options) {
477
308
  mkdirSync(latestDir, { recursive: true });
478
309
  writeText(join(runDir, "questions.jsonl"), "");
479
310
  writeText(join(runDir, "interventions.jsonl"), "");
480
- writeJson$2(join(runDir, "agent-state.json"), {
311
+ writeJson$1(join(runDir, "agent-state.json"), {
481
312
  status: "starting",
482
313
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
483
314
  });
484
- writeAgentState(artifactsDir, leaderState);
315
+ writeAgentState(artifactsDir, mayorState);
485
316
  const lease = acquireRepoLease(runId, repoId, branch);
486
317
  try {
487
318
  const manifest = createManifest({
@@ -512,13 +343,13 @@ function runController(options) {
512
343
  createdAt: piStartedAt
513
344
  });
514
345
  writeAgentState(artifactsDir, createAgentState({
515
- ...leaderState,
346
+ ...mayorState,
516
347
  status: "running",
517
- lastMessage: goal ? `Leader working on: ${goal}` : "Leader working"
348
+ lastMessage: goal ? `Mayor working on: ${goal}` : "Mayor working"
518
349
  }));
519
- const piResult = runCommandSync(piCommand, createPiInvocationArgs$1({
520
- sessionDir: leaderState.session.sessionPath === null ? leaderSessionDir : null,
521
- sessionPath: leaderState.session.sessionPath,
350
+ const piResult = runCommandSync(piCommand, createPiInvocationArgs({
351
+ sessionDir: mayorState.session.sessionPath === null ? mayorSessionDir : null,
352
+ sessionPath: mayorState.session.sessionPath,
522
353
  prompt,
523
354
  appendedSystemPrompt: options.appendedSystemPrompt,
524
355
  extensionPath: options.extensionPath
@@ -527,7 +358,7 @@ function runController(options) {
527
358
  env: process.env
528
359
  });
529
360
  const piEndedAt = (/* @__PURE__ */ new Date()).toISOString();
530
- const latestLeaderSession = getLatestAgentSession(artifactsDir, "leader");
361
+ const latestMayorSession = getLatestAgentSession(artifactsDir, "mayor");
531
362
  writeText(stdoutPath, piResult.stdout);
532
363
  writeText(stderrPath, piResult.stderr);
533
364
  const piInvocation = {
@@ -536,9 +367,9 @@ function runController(options) {
536
367
  repoRoot,
537
368
  planPath,
538
369
  goal,
539
- sessionDir: latestLeaderSession.sessionDir,
540
- sessionId: latestLeaderSession.sessionId,
541
- sessionPath: latestLeaderSession.sessionPath,
370
+ sessionDir: latestMayorSession.sessionDir,
371
+ sessionId: latestMayorSession.sessionId,
372
+ sessionPath: latestMayorSession.sessionPath,
542
373
  startedAt: piStartedAt,
543
374
  endedAt: piEndedAt,
544
375
  exitCode: piResult.exitCode,
@@ -546,7 +377,7 @@ function runController(options) {
546
377
  stderrPath,
547
378
  promptSummary: planPath ? "Read private plan path and continue from current scaffold state." : "Continue from current scaffold state without a configured private plan path."
548
379
  };
549
- writeJson$2(join(runDir, "pi-invocation.json"), piInvocation);
380
+ writeJson$1(join(runDir, "pi-invocation.json"), piInvocation);
550
381
  appendJsonl(join(runDir, "events.jsonl"), {
551
382
  type: "pi_invocation_finished",
552
383
  runId,
@@ -572,27 +403,27 @@ function runController(options) {
572
403
  stopReason: piInvocation.exitCode === 0 ? "pi invocation completed" : `pi invocation exited with code ${piInvocation.exitCode}`,
573
404
  piExitCode: piInvocation.exitCode
574
405
  };
575
- writeJson$2(join(runDir, "manifest.json"), finalManifest);
576
- writeJson$2(join(runDir, "metrics.json"), metrics);
577
- writeJson$2(join(runDir, "run-summary.json"), summary);
578
- writeJson$2(join(runDir, "agent-state.json"), {
406
+ writeJson$1(join(runDir, "manifest.json"), finalManifest);
407
+ writeJson$1(join(runDir, "metrics.json"), metrics);
408
+ writeJson$1(join(runDir, "run-summary.json"), summary);
409
+ writeJson$1(join(runDir, "agent-state.json"), {
579
410
  status: summary.success ? "completed" : "failed",
580
411
  updatedAt: piEndedAt,
581
412
  exitCode: piInvocation.exitCode
582
413
  });
583
- writeJson$2(join(latestDir, "manifest.json"), finalManifest);
584
- writeJson$2(join(latestDir, "metrics.json"), metrics);
585
- writeJson$2(join(latestDir, "run-summary.json"), summary);
414
+ writeJson$1(join(latestDir, "manifest.json"), finalManifest);
415
+ writeJson$1(join(latestDir, "metrics.json"), metrics);
416
+ writeJson$1(join(latestDir, "run-summary.json"), summary);
586
417
  writeAgentState(artifactsDir, createAgentState({
587
- ...leaderState,
418
+ ...mayorState,
588
419
  status: piInvocation.exitCode === 0 ? "idle" : "blocked",
589
- lastMessage: piInvocation.exitCode === 0 ? "Leader run completed and is ready for the next instruction" : `Leader run stopped with exit code ${piInvocation.exitCode}`,
420
+ lastMessage: piInvocation.exitCode === 0 ? "Mayor run completed and is ready for the next instruction" : `Mayor run stopped with exit code ${piInvocation.exitCode}`,
590
421
  blocked: piInvocation.exitCode !== 0,
591
422
  waitingOn: piInvocation.exitCode === 0 ? null : "human-or-follow-up-run",
592
423
  session: createAgentSessionRecord({
593
- sessionDir: latestLeaderSession.sessionDir,
594
- sessionId: latestLeaderSession.sessionId,
595
- sessionPath: latestLeaderSession.sessionPath
424
+ sessionDir: latestMayorSession.sessionDir,
425
+ sessionId: latestMayorSession.sessionId,
426
+ sessionPath: latestMayorSession.sessionPath
596
427
  })
597
428
  }));
598
429
  appendJsonl(join(runDir, "events.jsonl"), {
@@ -638,74 +469,39 @@ function resolveInterrupt(interrupt, options) {
638
469
  };
639
470
  }
640
471
 
641
- //#endregion
642
- //#region src/tasks.ts
643
- function writeJson$1(path, value) {
644
- mkdirSync(dirname(path), { recursive: true });
645
- writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
646
- }
647
- function getTasksDir(artifactsDir) {
648
- return join(artifactsDir, "tasks");
649
- }
650
- function getTaskPath(artifactsDir, taskId) {
651
- return join(getTasksDir(artifactsDir), `${taskId}.json`);
652
- }
653
- function createTaskRecord(input) {
654
- const now = (/* @__PURE__ */ new Date()).toISOString();
655
- return {
656
- taskId: input.taskId,
657
- title: input.title,
658
- status: input.status,
659
- role: input.role,
660
- assignedAgentId: input.assignedAgentId,
661
- createdBy: input.createdBy,
662
- createdAt: now,
663
- updatedAt: now
664
- };
665
- }
666
- function writeTaskRecord(artifactsDir, task) {
667
- writeJson$1(getTaskPath(artifactsDir, task.taskId), task);
668
- }
669
- function updateTaskRecordStatus(artifactsDir, taskId, status) {
670
- const task = readTaskRecord(artifactsDir, taskId);
671
- if (task === null) return null;
672
- const updatedTask = {
673
- ...task,
674
- status,
675
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
676
- };
677
- writeTaskRecord(artifactsDir, updatedTask);
678
- return updatedTask;
679
- }
680
- function readTaskRecord(artifactsDir, taskId) {
681
- const path = getTaskPath(artifactsDir, taskId);
682
- try {
683
- return JSON.parse(readFileSync(path, "utf-8"));
684
- } catch {
685
- return null;
686
- }
687
- }
688
- function listTaskRecords(artifactsDir) {
689
- const tasksDir = getTasksDir(artifactsDir);
690
- let entries;
691
- try {
692
- entries = readdirSync(tasksDir);
693
- } catch {
694
- return [];
695
- }
696
- return entries.filter((entry) => entry.endsWith(".json")).map((entry) => readTaskRecord(artifactsDir, entry.replace(/\.json$/, ""))).filter((task) => task !== null).sort((left, right) => left.taskId.localeCompare(right.taskId));
697
- }
698
-
699
472
  //#endregion
700
473
  //#region src/loop.ts
701
474
  const DEFAULT_MAX_ITERATIONS = 10;
702
475
  const DEFAULT_MAX_WALL_TIME_MS = 36e5;
476
+ const DEFAULT_BACKGROUND_POLL_MS = 250;
703
477
  function createLoopId() {
704
478
  return `loop-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
705
479
  }
706
480
  function writeJson(path, value) {
707
481
  writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
708
482
  }
483
+ function sleepMs$1(ms) {
484
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
485
+ }
486
+ function hasBackgroundWork(board) {
487
+ return board.agents.some((agent) => agent.agentId !== "mayor" && (agent.status === "queued" || agent.status === "running" || agent.status === "starting")) || board.tasks.some((task) => task.status === "queued" || task.status === "running");
488
+ }
489
+ function waitForBackgroundWorkToSettle(input) {
490
+ const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_BACKGROUND_POLL_MS;
491
+ let board = snapshotBoard(input.artifactsDir);
492
+ while (hasBackgroundWork(board)) {
493
+ if (Date.now() - input.loopStartedAt >= input.maxWallTimeMs) return {
494
+ timedOut: true,
495
+ board
496
+ };
497
+ sleepMs$1(pollIntervalMs);
498
+ board = snapshotBoard(input.artifactsDir);
499
+ }
500
+ return {
501
+ timedOut: false,
502
+ board
503
+ };
504
+ }
709
505
  function snapshotBoard(artifactsDir) {
710
506
  const tasks = listTaskRecords(artifactsDir);
711
507
  const agents = listAgentStates(artifactsDir);
@@ -720,8 +516,8 @@ function snapshotBoard(artifactsDir) {
720
516
  blocked: agent.blocked
721
517
  })),
722
518
  allTasksCompleted: tasks.length > 0 && tasks.every((task) => task.status === "completed"),
723
- allRemainingTasksBlocked: tasks.length > 0 && tasks.every((task) => task.status === "completed" || task.status === "blocked"),
724
- leaderBlocked: agents.find((agent) => agent.agentId === "leader")?.blocked === true,
519
+ allRemainingTasksBlocked: tasks.length > 0 && tasks.every((task) => task.status === "completed" || task.status === "blocked" || task.status === "aborted"),
520
+ mayorBlocked: agents.find((agent) => agent.agentId === "mayor")?.blocked === true,
725
521
  hasQueuedOrRunningWork: agents.some((agent) => agent.status === "queued" || agent.status === "running" || agent.status === "starting") || tasks.some((task) => task.status === "queued" || task.status === "running")
726
522
  };
727
523
  }
@@ -742,8 +538,13 @@ function evaluateStopCondition(input) {
742
538
  stopReason: "all-tasks-completed",
743
539
  continueReason: null
744
540
  };
745
- if (input.board.leaderBlocked) return {
746
- stopReason: "leader-blocked",
541
+ if (input.board.mayorBlocked) return {
542
+ stopReason: "mayor-blocked",
543
+ continueReason: null
544
+ };
545
+ const mayor = input.board.agents.find((agent) => agent.agentId === "mayor");
546
+ if (input.stopOnMayorIdleNoWork && mayor && !input.board.hasQueuedOrRunningWork && input.board.tasks.length === 0 && mayor.status === "idle") return {
547
+ stopReason: "mayor-idle-no-work",
747
548
  continueReason: null
748
549
  };
749
550
  if (input.board.allRemainingTasksBlocked) return {
@@ -757,7 +558,7 @@ function evaluateStopCondition(input) {
757
558
  const reasons = [];
758
559
  if (input.board.hasQueuedOrRunningWork) reasons.push("queued or running work remains");
759
560
  if (input.board.tasks.length === 0) reasons.push("no tasks tracked yet");
760
- if (reasons.length === 0) reasons.push("leader idle, no stop condition met");
561
+ if (reasons.length === 0) reasons.push("mayor idle, no stop condition met");
761
562
  return {
762
563
  stopReason: null,
763
564
  continueReason: reasons.join("; ")
@@ -813,6 +614,7 @@ function runLoop(options) {
813
614
  const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
814
615
  const maxWallTimeMs = options.maxWallTimeMs ?? DEFAULT_MAX_WALL_TIME_MS;
815
616
  const stopOnPiFailure = options.stopOnPiFailure ?? true;
617
+ const stopOnMayorIdleNoWork = options.stopOnMayorIdleNoWork ?? false;
816
618
  const interruptRateThreshold = options.interruptRateThreshold ?? null;
817
619
  const loopId = createLoopId();
818
620
  const artifactsDir = options.runOptions.artifactsDir;
@@ -821,6 +623,7 @@ function runLoop(options) {
821
623
  const loopStartedAt = Date.now();
822
624
  const iterations = [];
823
625
  let finalStopReason = "max-iterations-reached";
626
+ let needsMayorFollowUp = false;
824
627
  appendJsonl(join(loopDir, "events.jsonl"), {
825
628
  type: "loop_started",
826
629
  loopId,
@@ -830,6 +633,26 @@ function runLoop(options) {
830
633
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
831
634
  });
832
635
  for (let iteration = 1; iteration <= maxIterations; iteration++) {
636
+ if (needsMayorFollowUp) {
637
+ const settled = waitForBackgroundWorkToSettle({
638
+ artifactsDir,
639
+ maxWallTimeMs,
640
+ loopStartedAt
641
+ });
642
+ appendJsonl(join(loopDir, "events.jsonl"), {
643
+ type: "loop_background_work_settled",
644
+ loopId,
645
+ iteration,
646
+ timedOut: settled.timedOut,
647
+ boardSnapshot: settled.board,
648
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
649
+ });
650
+ if (settled.timedOut) {
651
+ finalStopReason = "max-wall-time-reached";
652
+ break;
653
+ }
654
+ needsMayorFollowUp = false;
655
+ }
833
656
  const iterationStart = Date.now();
834
657
  let controllerResult;
835
658
  try {
@@ -856,6 +679,7 @@ function runLoop(options) {
856
679
  maxWallTimeMs,
857
680
  piExitCode: controllerResult.piInvocation.exitCode,
858
681
  stopOnPiFailure,
682
+ stopOnMayorIdleNoWork,
859
683
  board,
860
684
  metrics,
861
685
  interruptRateThreshold
@@ -894,9 +718,11 @@ function runLoop(options) {
894
718
  finalStopReason = stopReason;
895
719
  break;
896
720
  }
721
+ needsMayorFollowUp = hasBackgroundWork(board);
897
722
  }
898
723
  const totalElapsedMs = Date.now() - loopStartedAt;
899
- const finalBoard = iterations.length > 0 ? iterations[iterations.length - 1].boardSnapshot : snapshotBoard(artifactsDir);
724
+ const lastIteration = iterations.at(-1);
725
+ const finalBoard = lastIteration ? lastIteration.boardSnapshot : snapshotBoard(artifactsDir);
900
726
  const aggregate = aggregateMetrics(iterations);
901
727
  const loopResult = {
902
728
  loopId,
@@ -927,301 +753,172 @@ function runLoop(options) {
927
753
  }
928
754
 
929
755
  //#endregion
930
- //#region src/orchestration.ts
931
- function createPiInvocationArgs(input) {
932
- const args = [];
933
- if (input.extensionPath) args.push("--extension", input.extensionPath);
934
- if (input.appendedSystemPrompt) args.push("--append-system-prompt", input.appendedSystemPrompt);
935
- if (input.sessionPath) args.push("--session", input.sessionPath);
936
- else if (input.sessionDir) args.push("--session-dir", input.sessionDir);
937
- else throw new Error("Pi invocation requires a session path or session directory");
938
- if (input.prompt) args.push("-p", input.prompt);
939
- return args;
756
+ //#region src/stop.ts
757
+ const DEFAULT_GRACE_MS = 750;
758
+ function sleepMs(ms) {
759
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
760
+ }
761
+ function getLocksDir() {
762
+ return join(homedir(), ".pi-town", "locks");
940
763
  }
941
- function createRolePrompt(input) {
942
- const task = input.task ?? "pick the next bounded task from the current repo context";
943
- switch (input.role) {
944
- case "leader": return [
945
- "You are the Pi Town leader.",
946
- "You coordinate work for this repository and act as the primary human-facing agent.",
947
- "",
948
- `Repository: ${input.repoRoot}`,
949
- `Task: ${task}`,
950
- "Keep updates concise, choose bounded next steps, and leave a durable artifact trail."
951
- ].join("\n");
952
- case "reviewer": return [
953
- "You are the Pi Town reviewer.",
954
- "You review work for correctness, safety, and completeness.",
955
- "",
956
- `Repository: ${input.repoRoot}`,
957
- `Task: ${task}`,
958
- "Focus on validation confidence, regressions, and whether the output is ready for a human handoff."
959
- ].join("\n");
960
- case "docs-keeper": return [
961
- "You are the Pi Town docs keeper.",
962
- "You summarize outcomes, blockers, and continuity in compact factual language.",
963
- "",
964
- `Repository: ${input.repoRoot}`,
965
- `Task: ${task}`,
966
- "Keep the output concise and useful for the next run or human review."
967
- ].join("\n");
968
- default: return [
969
- "You are the Pi Town worker.",
970
- "You implement one bounded task at a time.",
971
- "",
972
- `Repository: ${input.repoRoot}`,
973
- `Task: ${task}`,
974
- "Keep scope tight, prefer explicit validations, and summarize what changed and what still needs follow-up."
975
- ].join("\n");
764
+ function processAlive(pid) {
765
+ if (!Number.isFinite(pid) || pid <= 0) return false;
766
+ try {
767
+ process.kill(pid, 0);
768
+ return true;
769
+ } catch {
770
+ return false;
976
771
  }
977
772
  }
978
- function resolveAgentSession(agentId, artifactsDir) {
979
- const state = readAgentState(artifactsDir, agentId);
980
- if (state === null) throw new Error(`Unknown agent: ${agentId}`);
981
- const latestSession = getLatestAgentSession(artifactsDir, agentId);
982
- const sessionPath = state.session.sessionPath ?? latestSession.sessionPath;
983
- const sessionId = state.session.sessionId ?? latestSession.sessionId;
984
- const sessionDir = state.session.sessionDir ?? latestSession.sessionDir ?? getAgentSessionsDir(artifactsDir, agentId);
985
- if (sessionPath === null) throw new Error(`Agent ${agentId} does not have a persisted Pi session yet.`);
773
+ function terminateProcess(pid, options) {
774
+ if (!processAlive(pid)) return {
775
+ signal: null,
776
+ exited: true
777
+ };
778
+ try {
779
+ process.kill(pid, "SIGTERM");
780
+ } catch {
781
+ return {
782
+ signal: null,
783
+ exited: !processAlive(pid)
784
+ };
785
+ }
786
+ const graceMs = options.graceMs ?? DEFAULT_GRACE_MS;
787
+ const deadline = Date.now() + graceMs;
788
+ while (Date.now() < deadline) {
789
+ if (!processAlive(pid)) return {
790
+ signal: "SIGTERM",
791
+ exited: true
792
+ };
793
+ sleepMs(25);
794
+ }
795
+ if (!options.force) return {
796
+ signal: "SIGTERM",
797
+ exited: !processAlive(pid)
798
+ };
799
+ try {
800
+ process.kill(pid, "SIGKILL");
801
+ } catch {
802
+ return {
803
+ signal: "SIGTERM",
804
+ exited: !processAlive(pid)
805
+ };
806
+ }
986
807
  return {
987
- state,
988
- session: createAgentSessionRecord({
989
- sessionDir,
990
- sessionId,
991
- sessionPath,
992
- lastAttachedAt: (/* @__PURE__ */ new Date()).toISOString()
993
- })
808
+ signal: "SIGKILL",
809
+ exited: !processAlive(pid)
994
810
  };
995
811
  }
996
- function queueAgentMessage(input) {
997
- const state = readAgentState(input.artifactsDir, input.agentId);
998
- if (state === null) throw new Error(`Unknown agent: ${input.agentId}`);
999
- appendAgentMessage({
1000
- artifactsDir: input.artifactsDir,
1001
- agentId: input.agentId,
1002
- box: "inbox",
1003
- from: input.from,
1004
- body: input.body
1005
- });
1006
- writeAgentState(input.artifactsDir, createAgentState({
1007
- ...state,
1008
- status: state.status === "idle" ? "queued" : state.status,
1009
- lastMessage: input.body,
1010
- waitingOn: null,
1011
- blocked: false,
1012
- session: createAgentSessionRecord({
1013
- sessionDir: state.session.sessionDir ?? getAgentSessionsDir(input.artifactsDir, input.agentId),
1014
- sessionId: state.session.sessionId,
1015
- sessionPath: state.session.sessionPath,
1016
- lastAttachedAt: state.session.lastAttachedAt
1017
- })
1018
- }));
1019
- }
1020
- function updateAgentStatus(input) {
1021
- const state = readAgentState(input.artifactsDir, input.agentId);
1022
- if (state === null) throw new Error(`Unknown agent: ${input.agentId}`);
1023
- if (state.taskId) {
1024
- const taskStatus = input.status === "completed" ? "completed" : input.status === "blocked" || input.status === "failed" ? "blocked" : input.status === "running" || input.status === "queued" ? "running" : null;
1025
- if (taskStatus) updateTaskRecordStatus(input.artifactsDir, state.taskId, taskStatus);
812
+ function readLease(path) {
813
+ try {
814
+ return {
815
+ ...JSON.parse(readFileSync(path, "utf-8")),
816
+ path
817
+ };
818
+ } catch {
819
+ return null;
1026
820
  }
1027
- writeAgentState(input.artifactsDir, createAgentState({
1028
- ...state,
1029
- status: input.status,
1030
- lastMessage: input.lastMessage ?? state.lastMessage,
1031
- waitingOn: input.waitingOn ?? state.waitingOn,
1032
- blocked: input.blocked ?? state.blocked,
1033
- session: state.session
1034
- }));
1035
821
  }
1036
- function spawnAgentRun(options) {
1037
- const sessionDir = getAgentSessionsDir(options.artifactsDir, options.agentId);
1038
- if (readAgentState(options.artifactsDir, options.agentId) !== null) throw new Error(`Agent already exists: ${options.agentId}`);
1039
- assertCommandAvailable("pi");
1040
- const state = createAgentState({
1041
- agentId: options.agentId,
1042
- role: options.role,
1043
- status: "queued",
1044
- taskId: options.taskId ?? null,
1045
- task: options.task,
1046
- lastMessage: options.task ? `Spawned with task: ${options.task}` : `Spawned ${options.role} agent`,
1047
- session: createAgentSessionRecord({ sessionDir })
1048
- });
1049
- writeAgentState(options.artifactsDir, state);
1050
- if (options.task) appendAgentMessage({
1051
- artifactsDir: options.artifactsDir,
1052
- agentId: options.agentId,
1053
- box: "inbox",
1054
- from: "system",
1055
- body: options.task
1056
- });
1057
- writeAgentState(options.artifactsDir, createAgentState({
1058
- ...state,
1059
- status: "running",
1060
- lastMessage: options.task ? `Running ${options.role} task: ${options.task}` : `Running ${options.role} agent`
1061
- }));
1062
- const piArgs = createPiInvocationArgs({
1063
- sessionDir,
1064
- prompt: createRolePrompt({
1065
- role: options.role,
1066
- task: options.task,
1067
- repoRoot: options.repoRoot
1068
- }),
1069
- appendedSystemPrompt: options.appendedSystemPrompt,
1070
- extensionPath: options.extensionPath
1071
- });
1072
- const piResult = runCommandSync("pi", piArgs, {
1073
- cwd: options.repoRoot,
1074
- env: process.env
1075
- });
1076
- const latestSession = getLatestAgentSession(options.artifactsDir, options.agentId);
1077
- const agentArtifactsDir = getAgentDir(options.artifactsDir, options.agentId);
1078
- writeFileSync(`${agentArtifactsDir}/latest-stdout.txt`, piResult.stdout, "utf-8");
1079
- writeFileSync(`${agentArtifactsDir}/latest-stderr.txt`, piResult.stderr, "utf-8");
1080
- writeFileSync(`${agentArtifactsDir}/latest-invocation.json`, `${JSON.stringify({
1081
- command: "pi",
1082
- args: piArgs,
1083
- exitCode: piResult.exitCode,
1084
- sessionDir,
1085
- sessionPath: latestSession.sessionPath,
1086
- sessionId: latestSession.sessionId
1087
- }, null, 2)}\n`, "utf-8");
1088
- const completionMessage = piResult.stdout.trim() || (piResult.exitCode === 0 ? `${options.role} run completed` : `${options.role} run exited with code ${piResult.exitCode}`);
1089
- appendAgentMessage({
1090
- artifactsDir: options.artifactsDir,
1091
- agentId: options.agentId,
1092
- box: "outbox",
1093
- from: options.agentId,
1094
- body: completionMessage
1095
- });
1096
- writeAgentState(options.artifactsDir, createAgentState({
1097
- ...state,
1098
- status: piResult.exitCode === 0 ? "idle" : "blocked",
1099
- lastMessage: completionMessage,
1100
- blocked: piResult.exitCode !== 0,
1101
- waitingOn: piResult.exitCode === 0 ? null : "human-or-follow-up-run",
1102
- session: createAgentSessionRecord({
1103
- sessionDir: latestSession.sessionDir,
1104
- sessionId: latestSession.sessionId,
1105
- sessionPath: latestSession.sessionPath
1106
- })
1107
- }));
822
+ function createStopMessage(options) {
823
+ if (options.reason) return options.reason;
824
+ if (options.actorId) return `Stopped by ${options.actorId}`;
825
+ return "Stopped by operator";
826
+ }
827
+ function createStopMessageInput(options) {
1108
828
  return {
1109
- piResult,
1110
- latestSession,
1111
- completionMessage
829
+ ...options.actorId === void 0 ? {} : { actorId: options.actorId },
830
+ ...options.reason === void 0 ? {} : { reason: options.reason }
1112
831
  };
1113
832
  }
1114
- function runAgentTurn(options) {
1115
- assertCommandAvailable("pi");
1116
- const resolved = resolveAgentSession(options.agentId, options.artifactsDir);
1117
- const messageSource = options.from ?? "human";
1118
- writeAgentState(options.artifactsDir, createAgentState({
1119
- ...resolved.state,
1120
- status: "running",
1121
- lastMessage: `Responding to ${messageSource}: ${options.message}`,
1122
- waitingOn: null,
1123
- blocked: false,
1124
- session: resolved.session
1125
- }));
1126
- const piArgs = options.runtimeArgs && options.runtimeArgs.length > 0 ? options.runtimeArgs : createPiInvocationArgs({
1127
- sessionPath: resolved.session.sessionPath,
1128
- prompt: options.message
1129
- });
1130
- const piResult = runCommandSync("pi", piArgs, {
1131
- cwd: options.repoRoot,
1132
- env: process.env
1133
- });
1134
- const latestSession = getLatestAgentSession(options.artifactsDir, options.agentId);
1135
- const agentArtifactsDir = getAgentDir(options.artifactsDir, options.agentId);
1136
- writeFileSync(`${agentArtifactsDir}/latest-stdout.txt`, piResult.stdout, "utf-8");
1137
- writeFileSync(`${agentArtifactsDir}/latest-stderr.txt`, piResult.stderr, "utf-8");
1138
- writeFileSync(`${agentArtifactsDir}/latest-invocation.json`, `${JSON.stringify({
1139
- command: "pi",
1140
- args: piArgs,
1141
- exitCode: piResult.exitCode,
1142
- sessionDir: latestSession.sessionDir,
1143
- sessionPath: latestSession.sessionPath,
1144
- sessionId: latestSession.sessionId
1145
- }, null, 2)}\n`, "utf-8");
1146
- const completionMessage = piResult.stdout.trim() || (piResult.exitCode === 0 ? `${resolved.state.role} turn completed` : `${resolved.state.role} turn exited with code ${piResult.exitCode}`);
1147
- appendAgentMessage({
1148
- artifactsDir: options.artifactsDir,
1149
- agentId: options.agentId,
1150
- box: "outbox",
1151
- from: options.agentId,
1152
- body: completionMessage
1153
- });
1154
- writeAgentState(options.artifactsDir, createAgentState({
1155
- ...resolved.state,
1156
- status: piResult.exitCode === 0 ? "idle" : "blocked",
1157
- lastMessage: completionMessage,
1158
- waitingOn: piResult.exitCode === 0 ? null : "human-or-follow-up-run",
1159
- blocked: piResult.exitCode !== 0,
1160
- session: createAgentSessionRecord({
1161
- sessionDir: latestSession.sessionDir,
1162
- sessionId: latestSession.sessionId,
1163
- sessionPath: latestSession.sessionPath
1164
- })
1165
- }));
833
+ function createTerminateOptions(options) {
1166
834
  return {
1167
- piResult,
1168
- latestSession,
1169
- completionMessage
835
+ ...options.force === void 0 ? {} : { force: options.force },
836
+ ...options.graceMs === void 0 ? {} : { graceMs: options.graceMs }
1170
837
  };
1171
838
  }
1172
- function delegateTask(options) {
1173
- if (readAgentState(options.artifactsDir, options.fromAgentId) === null) throw new Error(`Unknown delegating agent: ${options.fromAgentId}`);
1174
- const agentId = options.agentId ?? `${options.role}-${Date.now()}`;
1175
- const task = createTaskRecord({
1176
- taskId: `task-${Date.now()}`,
1177
- title: options.task,
1178
- status: "queued",
1179
- role: options.role,
1180
- assignedAgentId: agentId,
1181
- createdBy: options.fromAgentId
1182
- });
1183
- writeTaskRecord(options.artifactsDir, task);
1184
- appendAgentMessage({
1185
- artifactsDir: options.artifactsDir,
1186
- agentId: options.fromAgentId,
1187
- box: "outbox",
1188
- from: options.fromAgentId,
1189
- body: `Delegated ${task.taskId} to ${agentId}: ${options.task}`
1190
- });
1191
- const { piResult, latestSession } = spawnAgentRun({
1192
- repoRoot: options.repoRoot,
1193
- artifactsDir: options.artifactsDir,
1194
- role: options.role,
1195
- agentId,
1196
- appendedSystemPrompt: options.appendedSystemPrompt,
1197
- extensionPath: options.extensionPath,
1198
- task: options.task,
1199
- taskId: task.taskId
1200
- });
1201
- appendAgentMessage({
1202
- artifactsDir: options.artifactsDir,
1203
- agentId,
1204
- box: "inbox",
1205
- from: options.fromAgentId,
1206
- body: `Delegated by ${options.fromAgentId} as ${task.taskId}: ${options.task}`
839
+ function listRepoLeases(repoId) {
840
+ let entries;
841
+ try {
842
+ entries = readdirSync(getLocksDir());
843
+ } catch {
844
+ return [];
845
+ }
846
+ return entries.filter((entry) => entry.endsWith(".json")).map((entry) => readLease(join(getLocksDir(), entry))).filter((record) => record !== null).filter((record) => repoId === void 0 || repoId === null || record.repoId === repoId);
847
+ }
848
+ function stopRepoLeases(options) {
849
+ const results = listRepoLeases(options.repoId).map((lease) => {
850
+ const termination = terminateProcess(lease.pid, options);
851
+ if (termination.exited) rmSync(lease.path, { force: true });
852
+ return {
853
+ path: lease.path,
854
+ runId: lease.runId,
855
+ repoId: lease.repoId,
856
+ branch: lease.branch,
857
+ processId: lease.pid,
858
+ signal: termination.signal,
859
+ exited: termination.exited
860
+ };
1207
861
  });
1208
- writeTaskRecord(options.artifactsDir, {
1209
- ...task,
1210
- status: piResult.exitCode === 0 ? "completed" : "blocked",
1211
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
862
+ return {
863
+ results,
864
+ signaledProcesses: results.filter((result) => result.signal !== null).length
865
+ };
866
+ }
867
+ function stopManagedAgents(options) {
868
+ const reason = createStopMessage(createStopMessageInput(options));
869
+ const excluded = new Set(options.excludeAgentIds ?? []);
870
+ const results = listAgentStates(options.artifactsDir).filter((agent) => {
871
+ if (excluded.has(agent.agentId)) return false;
872
+ if (options.agentId && agent.agentId !== options.agentId) return false;
873
+ return ![
874
+ "completed",
875
+ "failed",
876
+ "stopped"
877
+ ].includes(agent.status);
878
+ }).map((state) => {
879
+ const processId = state.session.processId;
880
+ const termination = processId === null ? {
881
+ signal: null,
882
+ exited: true
883
+ } : terminateProcess(processId, createTerminateOptions(options));
884
+ if (state.taskId) updateTaskRecordStatus(options.artifactsDir, state.taskId, "aborted");
885
+ appendAgentMessage({
886
+ artifactsDir: options.artifactsDir,
887
+ agentId: state.agentId,
888
+ box: "outbox",
889
+ from: options.actorId ?? "system",
890
+ body: reason
891
+ });
892
+ writeAgentState(options.artifactsDir, createAgentState({
893
+ ...state,
894
+ status: "stopped",
895
+ lastMessage: reason,
896
+ waitingOn: "stopped",
897
+ blocked: true,
898
+ session: createAgentSessionRecord({
899
+ sessionDir: state.session.sessionDir,
900
+ sessionId: state.session.sessionId,
901
+ sessionPath: state.session.sessionPath,
902
+ processId: null,
903
+ lastAttachedAt: state.session.lastAttachedAt
904
+ })
905
+ }));
906
+ return {
907
+ agentId: state.agentId,
908
+ previousStatus: state.status,
909
+ nextStatus: "stopped",
910
+ processId,
911
+ signal: termination.signal,
912
+ exited: termination.exited
913
+ };
1212
914
  });
1213
915
  return {
1214
- task: {
1215
- ...task,
1216
- status: piResult.exitCode === 0 ? "completed" : "blocked",
1217
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1218
- },
1219
- agentId,
1220
- piResult,
1221
- latestSession
916
+ results,
917
+ stoppedAgents: results.length,
918
+ signaledProcesses: results.filter((result) => result.signal !== null).length
1222
919
  };
1223
920
  }
1224
921
 
1225
922
  //#endregion
1226
- export { acquireRepoLease, appendAgentMessage, appendJsonl, assertCommandAvailable, assertSuccess, computeAutonomousCompletionRate, computeContextCoverageScore, computeFeedbackToDemoCycleTime, computeInterruptRate, computeMeanTimeToCorrect, computeMetrics, createAgentSessionRecord, createAgentState, createInterruptRecord, createPiAuthHelpMessage, createRepoSlug, createRolePrompt, createTaskRecord, delegateTask, detectPiAuthFailure, evaluateStopCondition, getAgentDir, getAgentMailboxPath, getAgentSessionPath, getAgentSessionsDir, getAgentStatePath, getAgentsDir, getCurrentBranch, getLatestAgentSession, getRepoIdentity, getRepoRoot, getSessionIdFromPath, getTaskPath, getTasksDir, isGitRepo, listAgentStates, listTaskRecords, queueAgentMessage, readAgentMessages, readAgentState, readJsonl, readTaskRecord, resolveAgentSession, resolveInterrupt, runAgentTurn, runCommandInteractive, runCommandSync, runController, runLoop, snapshotBoard, spawnAgentRun, updateAgentStatus, updateTaskRecordStatus, writeAgentState, writeTaskRecord };
923
+ export { acquireRepoLease, appendAgentMessage, appendJsonl, assertCommandAvailable, assertSuccess, computeAutonomousCompletionRate, computeContextCoverageScore, computeFeedbackToDemoCycleTime, computeInterruptRate, computeMeanTimeToCorrect, computeMetrics, createAgentSessionRecord, createAgentState, createInterruptRecord, createPiAuthHelpMessage, createRepoSlug, createRolePrompt, createTaskRecord, delegateTask, detectPiAuthFailure, evaluateStopCondition, getAgentDir, getAgentMailboxPath, getAgentSessionPath, getAgentSessionsDir, getAgentStatePath, getAgentsDir, getCurrentBranch, getLatestAgentSession, getRepoIdentity, getRepoRoot, getSessionIdFromPath, getTaskPath, getTasksDir, isGitRepo, listAgentStates, listRepoLeases, listTaskRecords, notifyTaskDelegator, queueAgentMessage, readAgentMessages, readAgentState, readJsonl, readTaskRecord, resolveAgentSession, resolveInterrupt, resumeAgentTurnDetached, runAgentTurn, runCommandInteractive, runCommandSync, runController, runLoop, snapshotBoard, spawnAgentRun, stopManagedAgents, stopRepoLeases, updateAgentStatus, updateTaskRecordStatus, writeAgentState, writeTaskRecord };
1227
924
  //# sourceMappingURL=index.mjs.map