@schilderlabs/pitown-core 0.2.1 → 0.2.6
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/agent-runner.d.mts +1 -0
- package/dist/agent-runner.mjs +122 -0
- package/dist/agent-runner.mjs.map +1 -0
- package/dist/index.d.mts +76 -23
- package/dist/index.mjs +327 -277
- package/dist/index.mjs.map +1 -1
- package/dist/tasks-BfQm-7-O.mjs +195 -0
- package/dist/tasks-BfQm-7-O.mjs.map +1 -0
- package/package.json +14 -19
package/dist/index.mjs
CHANGED
|
@@ -1,145 +1,17 @@
|
|
|
1
|
+
import { C as appendJsonl, S as writeAgentState, _ as getLatestAgentSession, a as readTaskRecord, b as readAgentMessages, c as appendAgentMessage, d as getAgentDir, f as getAgentMailboxPath, g as getAgentsDir, h as getAgentStatePath, i as listTaskRecords, l as createAgentSessionRecord, m as getAgentSessionsDir, n as getTaskPath, o as updateTaskRecordStatus, p as getAgentSessionPath, r as getTasksDir, s as writeTaskRecord, t as createTaskRecord, u as createAgentState, v as getSessionIdFromPath, w as readJsonl, x as readAgentState, y as listAgentStates } from "./tasks-BfQm-7-O.mjs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
1
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { basename,
|
|
4
|
+
import { basename, join, resolve } from "node:path";
|
|
3
5
|
import { homedir, hostname } from "node:os";
|
|
4
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
5
|
-
import { spawnSync } from "node:child_process";
|
|
7
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
6
9
|
|
|
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
10
|
//#region src/lease.ts
|
|
139
11
|
function sanitize$1(value) {
|
|
140
12
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
141
13
|
}
|
|
142
|
-
function processAlive(pid) {
|
|
14
|
+
function processAlive$1(pid) {
|
|
143
15
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
144
16
|
try {
|
|
145
17
|
process.kill(pid, 0);
|
|
@@ -162,7 +34,7 @@ function acquireRepoLease(runId, repoId, branch) {
|
|
|
162
34
|
};
|
|
163
35
|
try {
|
|
164
36
|
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}.`);
|
|
37
|
+
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
38
|
rmSync(leasePath, { force: true });
|
|
167
39
|
} catch (error) {
|
|
168
40
|
if (error.code !== "ENOENT") {
|
|
@@ -346,7 +218,7 @@ function createPiInvocationArgs$1(input) {
|
|
|
346
218
|
args.push("-p", input.prompt);
|
|
347
219
|
return args;
|
|
348
220
|
}
|
|
349
|
-
function writeJson$
|
|
221
|
+
function writeJson$1(path, value) {
|
|
350
222
|
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
351
223
|
}
|
|
352
224
|
function writeText(path, value) {
|
|
@@ -355,7 +227,7 @@ function writeText(path, value) {
|
|
|
355
227
|
function createPiPrompt(input) {
|
|
356
228
|
const goal = input.goal ?? "continue from current scaffold state";
|
|
357
229
|
if (input.planPath) return [
|
|
358
|
-
"You are the Pi Town
|
|
230
|
+
"You are the Pi Town mayor agent for this repository.",
|
|
359
231
|
"Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.",
|
|
360
232
|
"",
|
|
361
233
|
"Read the private plans in:",
|
|
@@ -369,7 +241,7 @@ function createPiPrompt(input) {
|
|
|
369
241
|
"Keep any persisted run artifacts high-signal and avoid copying private plan contents into them."
|
|
370
242
|
].join("\n");
|
|
371
243
|
return [
|
|
372
|
-
"You are the Pi Town
|
|
244
|
+
"You are the Pi Town mayor agent for this repository.",
|
|
373
245
|
"Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.",
|
|
374
246
|
"",
|
|
375
247
|
`Work in the repository at: ${input.repoRoot}`,
|
|
@@ -455,21 +327,21 @@ function runController(options) {
|
|
|
455
327
|
goal,
|
|
456
328
|
recommendedPlanDir
|
|
457
329
|
});
|
|
458
|
-
const
|
|
459
|
-
const
|
|
460
|
-
const
|
|
461
|
-
const
|
|
462
|
-
agentId: "
|
|
463
|
-
role: "
|
|
330
|
+
const existingMayorState = readAgentState(artifactsDir, "mayor");
|
|
331
|
+
const existingMayorSession = existingMayorState?.session.sessionPath || existingMayorState?.session.sessionDir ? existingMayorState.session : getLatestAgentSession(artifactsDir, "mayor");
|
|
332
|
+
const mayorSessionDir = existingMayorSession.sessionDir ?? getAgentSessionsDir(artifactsDir, "mayor");
|
|
333
|
+
const mayorState = createAgentState({
|
|
334
|
+
agentId: "mayor",
|
|
335
|
+
role: "mayor",
|
|
464
336
|
status: "starting",
|
|
465
337
|
task: goal,
|
|
466
338
|
branch,
|
|
467
|
-
lastMessage: goal ? `Starting
|
|
339
|
+
lastMessage: goal ? `Starting mayor run for goal: ${goal}` : "Starting mayor run",
|
|
468
340
|
runId,
|
|
469
341
|
session: createAgentSessionRecord({
|
|
470
|
-
sessionDir:
|
|
471
|
-
sessionId:
|
|
472
|
-
sessionPath:
|
|
342
|
+
sessionDir: mayorSessionDir,
|
|
343
|
+
sessionId: existingMayorSession.sessionId,
|
|
344
|
+
sessionPath: existingMayorSession.sessionPath
|
|
473
345
|
})
|
|
474
346
|
});
|
|
475
347
|
assertPiRuntimeAvailable(piCommand);
|
|
@@ -477,11 +349,11 @@ function runController(options) {
|
|
|
477
349
|
mkdirSync(latestDir, { recursive: true });
|
|
478
350
|
writeText(join(runDir, "questions.jsonl"), "");
|
|
479
351
|
writeText(join(runDir, "interventions.jsonl"), "");
|
|
480
|
-
writeJson$
|
|
352
|
+
writeJson$1(join(runDir, "agent-state.json"), {
|
|
481
353
|
status: "starting",
|
|
482
354
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
483
355
|
});
|
|
484
|
-
writeAgentState(artifactsDir,
|
|
356
|
+
writeAgentState(artifactsDir, mayorState);
|
|
485
357
|
const lease = acquireRepoLease(runId, repoId, branch);
|
|
486
358
|
try {
|
|
487
359
|
const manifest = createManifest({
|
|
@@ -512,13 +384,13 @@ function runController(options) {
|
|
|
512
384
|
createdAt: piStartedAt
|
|
513
385
|
});
|
|
514
386
|
writeAgentState(artifactsDir, createAgentState({
|
|
515
|
-
...
|
|
387
|
+
...mayorState,
|
|
516
388
|
status: "running",
|
|
517
|
-
lastMessage: goal ? `
|
|
389
|
+
lastMessage: goal ? `Mayor working on: ${goal}` : "Mayor working"
|
|
518
390
|
}));
|
|
519
391
|
const piResult = runCommandSync(piCommand, createPiInvocationArgs$1({
|
|
520
|
-
sessionDir:
|
|
521
|
-
sessionPath:
|
|
392
|
+
sessionDir: mayorState.session.sessionPath === null ? mayorSessionDir : null,
|
|
393
|
+
sessionPath: mayorState.session.sessionPath,
|
|
522
394
|
prompt,
|
|
523
395
|
appendedSystemPrompt: options.appendedSystemPrompt,
|
|
524
396
|
extensionPath: options.extensionPath
|
|
@@ -527,7 +399,7 @@ function runController(options) {
|
|
|
527
399
|
env: process.env
|
|
528
400
|
});
|
|
529
401
|
const piEndedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
530
|
-
const
|
|
402
|
+
const latestMayorSession = getLatestAgentSession(artifactsDir, "mayor");
|
|
531
403
|
writeText(stdoutPath, piResult.stdout);
|
|
532
404
|
writeText(stderrPath, piResult.stderr);
|
|
533
405
|
const piInvocation = {
|
|
@@ -536,9 +408,9 @@ function runController(options) {
|
|
|
536
408
|
repoRoot,
|
|
537
409
|
planPath,
|
|
538
410
|
goal,
|
|
539
|
-
sessionDir:
|
|
540
|
-
sessionId:
|
|
541
|
-
sessionPath:
|
|
411
|
+
sessionDir: latestMayorSession.sessionDir,
|
|
412
|
+
sessionId: latestMayorSession.sessionId,
|
|
413
|
+
sessionPath: latestMayorSession.sessionPath,
|
|
542
414
|
startedAt: piStartedAt,
|
|
543
415
|
endedAt: piEndedAt,
|
|
544
416
|
exitCode: piResult.exitCode,
|
|
@@ -546,7 +418,7 @@ function runController(options) {
|
|
|
546
418
|
stderrPath,
|
|
547
419
|
promptSummary: planPath ? "Read private plan path and continue from current scaffold state." : "Continue from current scaffold state without a configured private plan path."
|
|
548
420
|
};
|
|
549
|
-
writeJson$
|
|
421
|
+
writeJson$1(join(runDir, "pi-invocation.json"), piInvocation);
|
|
550
422
|
appendJsonl(join(runDir, "events.jsonl"), {
|
|
551
423
|
type: "pi_invocation_finished",
|
|
552
424
|
runId,
|
|
@@ -572,27 +444,27 @@ function runController(options) {
|
|
|
572
444
|
stopReason: piInvocation.exitCode === 0 ? "pi invocation completed" : `pi invocation exited with code ${piInvocation.exitCode}`,
|
|
573
445
|
piExitCode: piInvocation.exitCode
|
|
574
446
|
};
|
|
575
|
-
writeJson$
|
|
576
|
-
writeJson$
|
|
577
|
-
writeJson$
|
|
578
|
-
writeJson$
|
|
447
|
+
writeJson$1(join(runDir, "manifest.json"), finalManifest);
|
|
448
|
+
writeJson$1(join(runDir, "metrics.json"), metrics);
|
|
449
|
+
writeJson$1(join(runDir, "run-summary.json"), summary);
|
|
450
|
+
writeJson$1(join(runDir, "agent-state.json"), {
|
|
579
451
|
status: summary.success ? "completed" : "failed",
|
|
580
452
|
updatedAt: piEndedAt,
|
|
581
453
|
exitCode: piInvocation.exitCode
|
|
582
454
|
});
|
|
583
|
-
writeJson$
|
|
584
|
-
writeJson$
|
|
585
|
-
writeJson$
|
|
455
|
+
writeJson$1(join(latestDir, "manifest.json"), finalManifest);
|
|
456
|
+
writeJson$1(join(latestDir, "metrics.json"), metrics);
|
|
457
|
+
writeJson$1(join(latestDir, "run-summary.json"), summary);
|
|
586
458
|
writeAgentState(artifactsDir, createAgentState({
|
|
587
|
-
...
|
|
459
|
+
...mayorState,
|
|
588
460
|
status: piInvocation.exitCode === 0 ? "idle" : "blocked",
|
|
589
|
-
lastMessage: piInvocation.exitCode === 0 ? "
|
|
461
|
+
lastMessage: piInvocation.exitCode === 0 ? "Mayor run completed and is ready for the next instruction" : `Mayor run stopped with exit code ${piInvocation.exitCode}`,
|
|
590
462
|
blocked: piInvocation.exitCode !== 0,
|
|
591
463
|
waitingOn: piInvocation.exitCode === 0 ? null : "human-or-follow-up-run",
|
|
592
464
|
session: createAgentSessionRecord({
|
|
593
|
-
sessionDir:
|
|
594
|
-
sessionId:
|
|
595
|
-
sessionPath:
|
|
465
|
+
sessionDir: latestMayorSession.sessionDir,
|
|
466
|
+
sessionId: latestMayorSession.sessionId,
|
|
467
|
+
sessionPath: latestMayorSession.sessionPath
|
|
596
468
|
})
|
|
597
469
|
}));
|
|
598
470
|
appendJsonl(join(runDir, "events.jsonl"), {
|
|
@@ -638,74 +510,39 @@ function resolveInterrupt(interrupt, options) {
|
|
|
638
510
|
};
|
|
639
511
|
}
|
|
640
512
|
|
|
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
513
|
//#endregion
|
|
700
514
|
//#region src/loop.ts
|
|
701
515
|
const DEFAULT_MAX_ITERATIONS = 10;
|
|
702
516
|
const DEFAULT_MAX_WALL_TIME_MS = 36e5;
|
|
517
|
+
const DEFAULT_BACKGROUND_POLL_MS = 250;
|
|
703
518
|
function createLoopId() {
|
|
704
519
|
return `loop-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
705
520
|
}
|
|
706
521
|
function writeJson(path, value) {
|
|
707
522
|
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
708
523
|
}
|
|
524
|
+
function sleepMs$1(ms) {
|
|
525
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
526
|
+
}
|
|
527
|
+
function hasBackgroundWork(board) {
|
|
528
|
+
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");
|
|
529
|
+
}
|
|
530
|
+
function waitForBackgroundWorkToSettle(input) {
|
|
531
|
+
const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_BACKGROUND_POLL_MS;
|
|
532
|
+
let board = snapshotBoard(input.artifactsDir);
|
|
533
|
+
while (hasBackgroundWork(board)) {
|
|
534
|
+
if (Date.now() - input.loopStartedAt >= input.maxWallTimeMs) return {
|
|
535
|
+
timedOut: true,
|
|
536
|
+
board
|
|
537
|
+
};
|
|
538
|
+
sleepMs$1(pollIntervalMs);
|
|
539
|
+
board = snapshotBoard(input.artifactsDir);
|
|
540
|
+
}
|
|
541
|
+
return {
|
|
542
|
+
timedOut: false,
|
|
543
|
+
board
|
|
544
|
+
};
|
|
545
|
+
}
|
|
709
546
|
function snapshotBoard(artifactsDir) {
|
|
710
547
|
const tasks = listTaskRecords(artifactsDir);
|
|
711
548
|
const agents = listAgentStates(artifactsDir);
|
|
@@ -720,8 +557,8 @@ function snapshotBoard(artifactsDir) {
|
|
|
720
557
|
blocked: agent.blocked
|
|
721
558
|
})),
|
|
722
559
|
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
|
-
|
|
560
|
+
allRemainingTasksBlocked: tasks.length > 0 && tasks.every((task) => task.status === "completed" || task.status === "blocked" || task.status === "aborted"),
|
|
561
|
+
mayorBlocked: agents.find((agent) => agent.agentId === "mayor")?.blocked === true,
|
|
725
562
|
hasQueuedOrRunningWork: agents.some((agent) => agent.status === "queued" || agent.status === "running" || agent.status === "starting") || tasks.some((task) => task.status === "queued" || task.status === "running")
|
|
726
563
|
};
|
|
727
564
|
}
|
|
@@ -742,8 +579,13 @@ function evaluateStopCondition(input) {
|
|
|
742
579
|
stopReason: "all-tasks-completed",
|
|
743
580
|
continueReason: null
|
|
744
581
|
};
|
|
745
|
-
if (input.board.
|
|
746
|
-
stopReason: "
|
|
582
|
+
if (input.board.mayorBlocked) return {
|
|
583
|
+
stopReason: "mayor-blocked",
|
|
584
|
+
continueReason: null
|
|
585
|
+
};
|
|
586
|
+
const mayor = input.board.agents.find((agent) => agent.agentId === "mayor");
|
|
587
|
+
if (input.stopOnMayorIdleNoWork && mayor && !input.board.hasQueuedOrRunningWork && input.board.tasks.length === 0 && mayor.status === "idle") return {
|
|
588
|
+
stopReason: "mayor-idle-no-work",
|
|
747
589
|
continueReason: null
|
|
748
590
|
};
|
|
749
591
|
if (input.board.allRemainingTasksBlocked) return {
|
|
@@ -757,7 +599,7 @@ function evaluateStopCondition(input) {
|
|
|
757
599
|
const reasons = [];
|
|
758
600
|
if (input.board.hasQueuedOrRunningWork) reasons.push("queued or running work remains");
|
|
759
601
|
if (input.board.tasks.length === 0) reasons.push("no tasks tracked yet");
|
|
760
|
-
if (reasons.length === 0) reasons.push("
|
|
602
|
+
if (reasons.length === 0) reasons.push("mayor idle, no stop condition met");
|
|
761
603
|
return {
|
|
762
604
|
stopReason: null,
|
|
763
605
|
continueReason: reasons.join("; ")
|
|
@@ -813,6 +655,7 @@ function runLoop(options) {
|
|
|
813
655
|
const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
814
656
|
const maxWallTimeMs = options.maxWallTimeMs ?? DEFAULT_MAX_WALL_TIME_MS;
|
|
815
657
|
const stopOnPiFailure = options.stopOnPiFailure ?? true;
|
|
658
|
+
const stopOnMayorIdleNoWork = options.stopOnMayorIdleNoWork ?? false;
|
|
816
659
|
const interruptRateThreshold = options.interruptRateThreshold ?? null;
|
|
817
660
|
const loopId = createLoopId();
|
|
818
661
|
const artifactsDir = options.runOptions.artifactsDir;
|
|
@@ -821,6 +664,7 @@ function runLoop(options) {
|
|
|
821
664
|
const loopStartedAt = Date.now();
|
|
822
665
|
const iterations = [];
|
|
823
666
|
let finalStopReason = "max-iterations-reached";
|
|
667
|
+
let needsMayorFollowUp = false;
|
|
824
668
|
appendJsonl(join(loopDir, "events.jsonl"), {
|
|
825
669
|
type: "loop_started",
|
|
826
670
|
loopId,
|
|
@@ -830,6 +674,26 @@ function runLoop(options) {
|
|
|
830
674
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
831
675
|
});
|
|
832
676
|
for (let iteration = 1; iteration <= maxIterations; iteration++) {
|
|
677
|
+
if (needsMayorFollowUp) {
|
|
678
|
+
const settled = waitForBackgroundWorkToSettle({
|
|
679
|
+
artifactsDir,
|
|
680
|
+
maxWallTimeMs,
|
|
681
|
+
loopStartedAt
|
|
682
|
+
});
|
|
683
|
+
appendJsonl(join(loopDir, "events.jsonl"), {
|
|
684
|
+
type: "loop_background_work_settled",
|
|
685
|
+
loopId,
|
|
686
|
+
iteration,
|
|
687
|
+
timedOut: settled.timedOut,
|
|
688
|
+
boardSnapshot: settled.board,
|
|
689
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
690
|
+
});
|
|
691
|
+
if (settled.timedOut) {
|
|
692
|
+
finalStopReason = "max-wall-time-reached";
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
needsMayorFollowUp = false;
|
|
696
|
+
}
|
|
833
697
|
const iterationStart = Date.now();
|
|
834
698
|
let controllerResult;
|
|
835
699
|
try {
|
|
@@ -856,6 +720,7 @@ function runLoop(options) {
|
|
|
856
720
|
maxWallTimeMs,
|
|
857
721
|
piExitCode: controllerResult.piInvocation.exitCode,
|
|
858
722
|
stopOnPiFailure,
|
|
723
|
+
stopOnMayorIdleNoWork,
|
|
859
724
|
board,
|
|
860
725
|
metrics,
|
|
861
726
|
interruptRateThreshold
|
|
@@ -894,9 +759,11 @@ function runLoop(options) {
|
|
|
894
759
|
finalStopReason = stopReason;
|
|
895
760
|
break;
|
|
896
761
|
}
|
|
762
|
+
needsMayorFollowUp = hasBackgroundWork(board);
|
|
897
763
|
}
|
|
898
764
|
const totalElapsedMs = Date.now() - loopStartedAt;
|
|
899
|
-
const
|
|
765
|
+
const lastIteration = iterations.at(-1);
|
|
766
|
+
const finalBoard = lastIteration ? lastIteration.boardSnapshot : snapshotBoard(artifactsDir);
|
|
900
767
|
const aggregate = aggregateMetrics(iterations);
|
|
901
768
|
const loopResult = {
|
|
902
769
|
loopId,
|
|
@@ -938,11 +805,29 @@ function createPiInvocationArgs(input) {
|
|
|
938
805
|
if (input.prompt) args.push("-p", input.prompt);
|
|
939
806
|
return args;
|
|
940
807
|
}
|
|
808
|
+
function createDetachedRunnerInvocation(encodedPayload) {
|
|
809
|
+
if (fileURLToPath(import.meta.url).endsWith(".ts")) {
|
|
810
|
+
const require = createRequire(import.meta.url);
|
|
811
|
+
return {
|
|
812
|
+
command: process.execPath,
|
|
813
|
+
args: [
|
|
814
|
+
"--import",
|
|
815
|
+
require.resolve("tsx"),
|
|
816
|
+
fileURLToPath(new URL("./agent-runner.ts", import.meta.url)),
|
|
817
|
+
encodedPayload
|
|
818
|
+
]
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
return {
|
|
822
|
+
command: process.execPath,
|
|
823
|
+
args: [fileURLToPath(new URL("./agent-runner.mjs", import.meta.url)), encodedPayload]
|
|
824
|
+
};
|
|
825
|
+
}
|
|
941
826
|
function createRolePrompt(input) {
|
|
942
827
|
const task = input.task ?? "pick the next bounded task from the current repo context";
|
|
943
828
|
switch (input.role) {
|
|
944
|
-
case "
|
|
945
|
-
"You are the Pi Town
|
|
829
|
+
case "mayor": return [
|
|
830
|
+
"You are the Pi Town mayor.",
|
|
946
831
|
"You coordinate work for this repository and act as the primary human-facing agent.",
|
|
947
832
|
"",
|
|
948
833
|
`Repository: ${input.repoRoot}`,
|
|
@@ -989,6 +874,7 @@ function resolveAgentSession(agentId, artifactsDir) {
|
|
|
989
874
|
sessionDir,
|
|
990
875
|
sessionId,
|
|
991
876
|
sessionPath,
|
|
877
|
+
processId: state.session.processId,
|
|
992
878
|
lastAttachedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
993
879
|
})
|
|
994
880
|
};
|
|
@@ -1013,6 +899,7 @@ function queueAgentMessage(input) {
|
|
|
1013
899
|
sessionDir: state.session.sessionDir ?? getAgentSessionsDir(input.artifactsDir, input.agentId),
|
|
1014
900
|
sessionId: state.session.sessionId,
|
|
1015
901
|
sessionPath: state.session.sessionPath,
|
|
902
|
+
processId: state.session.processId,
|
|
1016
903
|
lastAttachedAt: state.session.lastAttachedAt
|
|
1017
904
|
})
|
|
1018
905
|
}));
|
|
@@ -1021,7 +908,7 @@ function updateAgentStatus(input) {
|
|
|
1021
908
|
const state = readAgentState(input.artifactsDir, input.agentId);
|
|
1022
909
|
if (state === null) throw new Error(`Unknown agent: ${input.agentId}`);
|
|
1023
910
|
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;
|
|
911
|
+
const taskStatus = input.status === "completed" ? "completed" : input.status === "blocked" || input.status === "failed" ? "blocked" : input.status === "stopped" ? "aborted" : input.status === "running" || input.status === "queued" ? "running" : null;
|
|
1025
912
|
if (taskStatus) updateTaskRecordStatus(input.artifactsDir, state.taskId, taskStatus);
|
|
1026
913
|
}
|
|
1027
914
|
writeAgentState(input.artifactsDir, createAgentState({
|
|
@@ -1069,46 +956,41 @@ function spawnAgentRun(options) {
|
|
|
1069
956
|
appendedSystemPrompt: options.appendedSystemPrompt,
|
|
1070
957
|
extensionPath: options.extensionPath
|
|
1071
958
|
});
|
|
1072
|
-
const
|
|
959
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
960
|
+
const runner = createDetachedRunnerInvocation(Buffer.from(JSON.stringify({
|
|
961
|
+
repoRoot: options.repoRoot,
|
|
962
|
+
artifactsDir: options.artifactsDir,
|
|
963
|
+
agentId: options.agentId,
|
|
964
|
+
role: options.role,
|
|
965
|
+
task: options.task,
|
|
966
|
+
taskId: options.taskId ?? null,
|
|
967
|
+
sessionDir,
|
|
968
|
+
piArgs
|
|
969
|
+
}), "utf-8").toString("base64url"));
|
|
970
|
+
const child = spawn(runner.command, runner.args, {
|
|
1073
971
|
cwd: options.repoRoot,
|
|
1074
|
-
|
|
972
|
+
detached: true,
|
|
973
|
+
env: process.env,
|
|
974
|
+
stdio: "ignore"
|
|
1075
975
|
});
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
writeFileSync(`${
|
|
1079
|
-
writeFileSync(`${agentArtifactsDir}/latest-stderr.txt`, piResult.stderr, "utf-8");
|
|
1080
|
-
writeFileSync(`${agentArtifactsDir}/latest-invocation.json`, `${JSON.stringify({
|
|
976
|
+
child.unref();
|
|
977
|
+
if (!child.pid) throw new Error(`Failed to launch detached ${options.role} run for ${options.agentId}`);
|
|
978
|
+
writeFileSync(`${getAgentDir(options.artifactsDir, options.agentId)}/latest-invocation.json`, `${JSON.stringify({
|
|
1081
979
|
command: "pi",
|
|
1082
980
|
args: piArgs,
|
|
1083
|
-
exitCode:
|
|
981
|
+
exitCode: null,
|
|
1084
982
|
sessionDir,
|
|
1085
|
-
sessionPath:
|
|
1086
|
-
sessionId:
|
|
983
|
+
sessionPath: null,
|
|
984
|
+
sessionId: null,
|
|
985
|
+
processId: child.pid,
|
|
986
|
+
startedAt
|
|
1087
987
|
}, 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
|
-
}));
|
|
1108
988
|
return {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
989
|
+
launch: {
|
|
990
|
+
processId: child.pid,
|
|
991
|
+
startedAt
|
|
992
|
+
},
|
|
993
|
+
latestSession: createAgentSessionRecord({ sessionDir })
|
|
1112
994
|
};
|
|
1113
995
|
}
|
|
1114
996
|
function runAgentTurn(options) {
|
|
@@ -1160,7 +1042,8 @@ function runAgentTurn(options) {
|
|
|
1160
1042
|
session: createAgentSessionRecord({
|
|
1161
1043
|
sessionDir: latestSession.sessionDir,
|
|
1162
1044
|
sessionId: latestSession.sessionId,
|
|
1163
|
-
sessionPath: latestSession.sessionPath
|
|
1045
|
+
sessionPath: latestSession.sessionPath,
|
|
1046
|
+
processId: null
|
|
1164
1047
|
})
|
|
1165
1048
|
}));
|
|
1166
1049
|
return {
|
|
@@ -1188,7 +1071,7 @@ function delegateTask(options) {
|
|
|
1188
1071
|
from: options.fromAgentId,
|
|
1189
1072
|
body: `Delegated ${task.taskId} to ${agentId}: ${options.task}`
|
|
1190
1073
|
});
|
|
1191
|
-
const {
|
|
1074
|
+
const { launch, latestSession } = spawnAgentRun({
|
|
1192
1075
|
repoRoot: options.repoRoot,
|
|
1193
1076
|
artifactsDir: options.artifactsDir,
|
|
1194
1077
|
role: options.role,
|
|
@@ -1207,21 +1090,188 @@ function delegateTask(options) {
|
|
|
1207
1090
|
});
|
|
1208
1091
|
writeTaskRecord(options.artifactsDir, {
|
|
1209
1092
|
...task,
|
|
1210
|
-
status:
|
|
1093
|
+
status: "running",
|
|
1211
1094
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1212
1095
|
});
|
|
1213
1096
|
return {
|
|
1214
1097
|
task: {
|
|
1215
1098
|
...task,
|
|
1216
|
-
status:
|
|
1099
|
+
status: "running",
|
|
1217
1100
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1218
1101
|
},
|
|
1219
1102
|
agentId,
|
|
1220
|
-
|
|
1103
|
+
launch,
|
|
1221
1104
|
latestSession
|
|
1222
1105
|
};
|
|
1223
1106
|
}
|
|
1224
1107
|
|
|
1225
1108
|
//#endregion
|
|
1226
|
-
|
|
1109
|
+
//#region src/stop.ts
|
|
1110
|
+
const DEFAULT_GRACE_MS = 750;
|
|
1111
|
+
function sleepMs(ms) {
|
|
1112
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
1113
|
+
}
|
|
1114
|
+
function getLocksDir() {
|
|
1115
|
+
return join(homedir(), ".pi-town", "locks");
|
|
1116
|
+
}
|
|
1117
|
+
function processAlive(pid) {
|
|
1118
|
+
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
1119
|
+
try {
|
|
1120
|
+
process.kill(pid, 0);
|
|
1121
|
+
return true;
|
|
1122
|
+
} catch {
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
function terminateProcess(pid, options) {
|
|
1127
|
+
if (!processAlive(pid)) return {
|
|
1128
|
+
signal: null,
|
|
1129
|
+
exited: true
|
|
1130
|
+
};
|
|
1131
|
+
try {
|
|
1132
|
+
process.kill(pid, "SIGTERM");
|
|
1133
|
+
} catch {
|
|
1134
|
+
return {
|
|
1135
|
+
signal: null,
|
|
1136
|
+
exited: !processAlive(pid)
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
const graceMs = options.graceMs ?? DEFAULT_GRACE_MS;
|
|
1140
|
+
const deadline = Date.now() + graceMs;
|
|
1141
|
+
while (Date.now() < deadline) {
|
|
1142
|
+
if (!processAlive(pid)) return {
|
|
1143
|
+
signal: "SIGTERM",
|
|
1144
|
+
exited: true
|
|
1145
|
+
};
|
|
1146
|
+
sleepMs(25);
|
|
1147
|
+
}
|
|
1148
|
+
if (!options.force) return {
|
|
1149
|
+
signal: "SIGTERM",
|
|
1150
|
+
exited: !processAlive(pid)
|
|
1151
|
+
};
|
|
1152
|
+
try {
|
|
1153
|
+
process.kill(pid, "SIGKILL");
|
|
1154
|
+
} catch {
|
|
1155
|
+
return {
|
|
1156
|
+
signal: "SIGTERM",
|
|
1157
|
+
exited: !processAlive(pid)
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
return {
|
|
1161
|
+
signal: "SIGKILL",
|
|
1162
|
+
exited: !processAlive(pid)
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
function readLease(path) {
|
|
1166
|
+
try {
|
|
1167
|
+
return {
|
|
1168
|
+
...JSON.parse(readFileSync(path, "utf-8")),
|
|
1169
|
+
path
|
|
1170
|
+
};
|
|
1171
|
+
} catch {
|
|
1172
|
+
return null;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
function createStopMessage(options) {
|
|
1176
|
+
if (options.reason) return options.reason;
|
|
1177
|
+
if (options.actorId) return `Stopped by ${options.actorId}`;
|
|
1178
|
+
return "Stopped by operator";
|
|
1179
|
+
}
|
|
1180
|
+
function createStopMessageInput(options) {
|
|
1181
|
+
return {
|
|
1182
|
+
...options.actorId === void 0 ? {} : { actorId: options.actorId },
|
|
1183
|
+
...options.reason === void 0 ? {} : { reason: options.reason }
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
function createTerminateOptions(options) {
|
|
1187
|
+
return {
|
|
1188
|
+
...options.force === void 0 ? {} : { force: options.force },
|
|
1189
|
+
...options.graceMs === void 0 ? {} : { graceMs: options.graceMs }
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
function listRepoLeases(repoId) {
|
|
1193
|
+
let entries;
|
|
1194
|
+
try {
|
|
1195
|
+
entries = readdirSync(getLocksDir());
|
|
1196
|
+
} catch {
|
|
1197
|
+
return [];
|
|
1198
|
+
}
|
|
1199
|
+
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);
|
|
1200
|
+
}
|
|
1201
|
+
function stopRepoLeases(options) {
|
|
1202
|
+
const results = listRepoLeases(options.repoId).map((lease) => {
|
|
1203
|
+
const termination = terminateProcess(lease.pid, options);
|
|
1204
|
+
if (termination.exited) rmSync(lease.path, { force: true });
|
|
1205
|
+
return {
|
|
1206
|
+
path: lease.path,
|
|
1207
|
+
runId: lease.runId,
|
|
1208
|
+
repoId: lease.repoId,
|
|
1209
|
+
branch: lease.branch,
|
|
1210
|
+
processId: lease.pid,
|
|
1211
|
+
signal: termination.signal,
|
|
1212
|
+
exited: termination.exited
|
|
1213
|
+
};
|
|
1214
|
+
});
|
|
1215
|
+
return {
|
|
1216
|
+
results,
|
|
1217
|
+
signaledProcesses: results.filter((result) => result.signal !== null).length
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
function stopManagedAgents(options) {
|
|
1221
|
+
const reason = createStopMessage(createStopMessageInput(options));
|
|
1222
|
+
const excluded = new Set(options.excludeAgentIds ?? []);
|
|
1223
|
+
const results = listAgentStates(options.artifactsDir).filter((agent) => {
|
|
1224
|
+
if (excluded.has(agent.agentId)) return false;
|
|
1225
|
+
if (options.agentId && agent.agentId !== options.agentId) return false;
|
|
1226
|
+
return ![
|
|
1227
|
+
"completed",
|
|
1228
|
+
"failed",
|
|
1229
|
+
"stopped"
|
|
1230
|
+
].includes(agent.status);
|
|
1231
|
+
}).map((state) => {
|
|
1232
|
+
const processId = state.session.processId;
|
|
1233
|
+
const termination = processId === null ? {
|
|
1234
|
+
signal: null,
|
|
1235
|
+
exited: true
|
|
1236
|
+
} : terminateProcess(processId, createTerminateOptions(options));
|
|
1237
|
+
if (state.taskId) updateTaskRecordStatus(options.artifactsDir, state.taskId, "aborted");
|
|
1238
|
+
appendAgentMessage({
|
|
1239
|
+
artifactsDir: options.artifactsDir,
|
|
1240
|
+
agentId: state.agentId,
|
|
1241
|
+
box: "outbox",
|
|
1242
|
+
from: options.actorId ?? "system",
|
|
1243
|
+
body: reason
|
|
1244
|
+
});
|
|
1245
|
+
writeAgentState(options.artifactsDir, createAgentState({
|
|
1246
|
+
...state,
|
|
1247
|
+
status: "stopped",
|
|
1248
|
+
lastMessage: reason,
|
|
1249
|
+
waitingOn: "stopped",
|
|
1250
|
+
blocked: true,
|
|
1251
|
+
session: createAgentSessionRecord({
|
|
1252
|
+
sessionDir: state.session.sessionDir,
|
|
1253
|
+
sessionId: state.session.sessionId,
|
|
1254
|
+
sessionPath: state.session.sessionPath,
|
|
1255
|
+
processId: null,
|
|
1256
|
+
lastAttachedAt: state.session.lastAttachedAt
|
|
1257
|
+
})
|
|
1258
|
+
}));
|
|
1259
|
+
return {
|
|
1260
|
+
agentId: state.agentId,
|
|
1261
|
+
previousStatus: state.status,
|
|
1262
|
+
nextStatus: "stopped",
|
|
1263
|
+
processId,
|
|
1264
|
+
signal: termination.signal,
|
|
1265
|
+
exited: termination.exited
|
|
1266
|
+
};
|
|
1267
|
+
});
|
|
1268
|
+
return {
|
|
1269
|
+
results,
|
|
1270
|
+
stoppedAgents: results.length,
|
|
1271
|
+
signaledProcesses: results.filter((result) => result.signal !== null).length
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
//#endregion
|
|
1276
|
+
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, queueAgentMessage, readAgentMessages, readAgentState, readJsonl, readTaskRecord, resolveAgentSession, resolveInterrupt, runAgentTurn, runCommandInteractive, runCommandSync, runController, runLoop, snapshotBoard, spawnAgentRun, stopManagedAgents, stopRepoLeases, updateAgentStatus, updateTaskRecordStatus, writeAgentState, writeTaskRecord };
|
|
1227
1277
|
//# sourceMappingURL=index.mjs.map
|