@wrongstack/core 0.282.0 → 0.282.1
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/README.md +1 -1
- package/dist/{agent-subagent-runner-Dksf0QVU.d.ts → agent-subagent-runner-DCczSoQj.d.ts} +6 -6
- package/dist/{config-BCAEJicb.d.ts → config-DkCbA3Bw.d.ts} +22 -0
- package/dist/coordination/index.d.ts +15 -15
- package/dist/coordination/index.js +802 -139
- package/dist/coordination/index.js.map +1 -1
- package/dist/{default-config-azFprTB3.d.ts → default-config-Buho8yge.d.ts} +1 -0
- package/dist/defaults/index.d.ts +18 -18
- package/dist/defaults/index.js +811 -119
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-CovDylaH.d.ts → events-BOv8h6I1.d.ts} +1 -1
- package/dist/execution/index.d.ts +9 -9
- package/dist/execution/index.js +8 -1
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +4 -4
- package/dist/{global-mailbox-CNfgvRw3.d.ts → global-mailbox-MDDFhLYh.d.ts} +1 -1
- package/dist/{goal-store-CBd749M4.d.ts → goal-store-BEmDmSKF.d.ts} +1 -1
- package/dist/hq/index.d.ts +4 -4
- package/dist/{index-D5HB7WkV.d.ts → index-Dd-PJJ8A.d.ts} +3 -3
- package/dist/index.d.ts +209 -30
- package/dist/index.js +29562 -28136
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +3 -3
- package/dist/infrastructure/index.js +8 -0
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +7 -7
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-DJYwZXyH.d.ts → mcp-servers-BUx9A_AQ.d.ts} +1 -1
- package/dist/models/index.d.ts +4 -4
- package/dist/models/index.js +18 -20
- package/dist/models/index.js.map +1 -1
- package/dist/{multi-agent-coordinator-4DC31QWu.d.ts → multi-agent-coordinator-BRqtpn-a.d.ts} +1 -1
- package/dist/{null-fleet-bus-DuvA8PIR.d.ts → null-fleet-bus-BkptvIVo.d.ts} +7 -6
- package/dist/observability/index.d.ts +1 -1
- package/dist/{parallel-eternal-engine-BwcA0bAt.d.ts → parallel-eternal-engine-BXECuOVG.d.ts} +4 -4
- package/dist/{pipeline-DM-CPTUs.d.ts → pipeline-ixSFe5jg.d.ts} +2 -2
- package/dist/{provider-model-resolve-hNUbewMd.d.ts → provider-model-resolve-DIxKL_T-.d.ts} +1 -1
- package/dist/{provider-runner-Bz4GyUqo.d.ts → provider-runner-CJtCs1Rw.d.ts} +1 -1
- package/dist/sdd/index.d.ts +7 -7
- package/dist/sdd/index.js.map +1 -1
- package/dist/security/index.js +6 -0
- package/dist/security/index.js.map +1 -1
- package/dist/storage/index.d.ts +9 -9
- package/dist/storage/index.js +10 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/{task-format-vGOIftmK.d.ts → task-format-GX0B1mMC.d.ts} +1 -1
- package/dist/{task-graph-u1q9Jkyk.d.ts → task-graph-CH3acNQ7.d.ts} +10 -1
- package/dist/{todos-checkpoint-addCdQ9f.d.ts → todos-checkpoint-Bw83WMh9.d.ts} +2 -2
- package/dist/{tool-executor-B3spV_Q6.d.ts → tool-executor-4mWN2vHW.d.ts} +7 -7
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +8 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +12 -12
- package/dist/types/index.js +22 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +5 -5
- package/dist/utils/index.js.map +1 -1
- package/dist/{worktree-manager-BBXdJq-Y.d.ts → worktree-manager-BrtjUFYk.d.ts} +1 -1
- package/instructions/leader-after-task.md +4 -4
- package/instructions/system.md +11 -0
- package/package.json +1 -1
- package/skills/api-design/SKILL.md +1 -1
- package/skills/audit-log/SKILL.md +3 -3
- package/skills/bug-hunter/SKILL.md +3 -3
- package/skills/chimera/SKILL.md +3 -3
- package/skills/docker-deploy/SKILL.md +1 -1
- package/skills/git-flow/SKILL.md +3 -3
- package/skills/mailbox-bridge/SKILL.md +1 -1
- package/skills/multi-agent/SKILL.md +3 -3
- package/skills/node-modern/SKILL.md +1 -1
- package/skills/observability/SKILL.md +1 -1
- package/skills/output-standards/SKILL.md +31 -30
- package/skills/output-standards/SKILL.save.md +5 -5
- package/skills/plugin-author/SKILL.md +1 -1
- package/skills/prompt-engineering/SKILL.md +1 -1
- package/skills/react-modern/SKILL.md +1 -1
- package/skills/refactor-planner/SKILL.md +3 -3
- package/skills/research-web/SKILL.md +1 -1
- package/skills/sdd/SKILL.md +1 -1
- package/skills/security-scanner/SKILL.md +3 -3
- package/skills/skill-creator/SKILL.md +1 -1
- package/skills/tech-stack/SKILL.md +3 -3
- package/skills/testing/SKILL.md +1 -1
- package/skills/typescript-strict/SKILL.md +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID, createHash, randomBytes } from 'crypto';
|
|
2
2
|
import * as fsp7 from 'fs/promises';
|
|
3
|
-
import * as
|
|
3
|
+
import * as path10 from 'path';
|
|
4
4
|
import { isAbsolute, resolve } from 'path';
|
|
5
5
|
import * as os from 'os';
|
|
6
6
|
import { hostname } from 'os';
|
|
@@ -12,9 +12,9 @@ import { execFileSync } from 'child_process';
|
|
|
12
12
|
|
|
13
13
|
// src/coordination/agent-bridge.ts
|
|
14
14
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
15
|
-
const dir =
|
|
15
|
+
const dir = path10.dirname(targetPath);
|
|
16
16
|
await fsp7.mkdir(dir, { recursive: true });
|
|
17
|
-
const tmp =
|
|
17
|
+
const tmp = path10.join(dir, `.${path10.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
18
18
|
try {
|
|
19
19
|
if (typeof content === "string") {
|
|
20
20
|
await fsp7.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
@@ -32,8 +32,8 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
32
32
|
}
|
|
33
33
|
let mode;
|
|
34
34
|
try {
|
|
35
|
-
const
|
|
36
|
-
mode =
|
|
35
|
+
const stat8 = await fsp7.stat(targetPath);
|
|
36
|
+
mode = stat8.mode & 511;
|
|
37
37
|
} catch {
|
|
38
38
|
mode = opts.mode;
|
|
39
39
|
}
|
|
@@ -59,9 +59,9 @@ async function ensureDir(dir) {
|
|
|
59
59
|
await fsp7.mkdir(dir, { recursive: true });
|
|
60
60
|
}
|
|
61
61
|
async function withFileLock(targetPath, fn, opts = {}) {
|
|
62
|
-
const dir =
|
|
62
|
+
const dir = path10.dirname(targetPath);
|
|
63
63
|
await fsp7.mkdir(dir, { recursive: true });
|
|
64
|
-
const lockPath =
|
|
64
|
+
const lockPath = path10.join(dir, `.${path10.basename(targetPath)}.lock`);
|
|
65
65
|
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
66
66
|
const staleMs = opts.staleMs ?? 3e4;
|
|
67
67
|
const started = Date.now();
|
|
@@ -79,8 +79,8 @@ async function withFileLock(targetPath, fn, opts = {}) {
|
|
|
79
79
|
}
|
|
80
80
|
if (code !== "EEXIST") throw err;
|
|
81
81
|
try {
|
|
82
|
-
const
|
|
83
|
-
if (Date.now() -
|
|
82
|
+
const stat8 = await fsp7.stat(lockPath);
|
|
83
|
+
if (Date.now() - stat8.mtimeMs > staleMs) {
|
|
84
84
|
await fsp7.unlink(lockPath);
|
|
85
85
|
continue;
|
|
86
86
|
}
|
|
@@ -95,7 +95,7 @@ async function withFileLock(targetPath, fn, opts = {}) {
|
|
|
95
95
|
context: { timeoutMs }
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
|
-
await new Promise((
|
|
98
|
+
await new Promise((resolve7) => setTimeout(resolve7, 25));
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
try {
|
|
@@ -129,7 +129,7 @@ async function renameWithRetry(from, to) {
|
|
|
129
129
|
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
130
130
|
throw err;
|
|
131
131
|
}
|
|
132
|
-
await new Promise((
|
|
132
|
+
await new Promise((resolve7) => setTimeout(resolve7, delays[i]));
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
throw lastErr;
|
|
@@ -236,8 +236,8 @@ async function expandGlob(pattern) {
|
|
|
236
236
|
for (const e of entries) {
|
|
237
237
|
const full = `${dir}${SEP}${e}`;
|
|
238
238
|
try {
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
239
|
+
const stat8 = await fsp7.stat(full);
|
|
240
|
+
if (stat8.isDirectory()) await walk(full, rest);
|
|
241
241
|
} catch {
|
|
242
242
|
}
|
|
243
243
|
}
|
|
@@ -254,8 +254,8 @@ async function expandGlob(pattern) {
|
|
|
254
254
|
if (entries.includes(seg)) {
|
|
255
255
|
const full = `${dir}${SEP}${seg}`;
|
|
256
256
|
try {
|
|
257
|
-
const
|
|
258
|
-
if (
|
|
257
|
+
const stat8 = await fsp7.stat(full);
|
|
258
|
+
if (stat8.isDirectory()) await walk(full, rest);
|
|
259
259
|
} catch {
|
|
260
260
|
}
|
|
261
261
|
}
|
|
@@ -396,9 +396,9 @@ function sessionScopedPath(dir, sessionId, suffix) {
|
|
|
396
396
|
if (!sessionId || sessionId.includes("\\") || sessionId.includes("..")) {
|
|
397
397
|
throw invalid(sessionId);
|
|
398
398
|
}
|
|
399
|
-
const resolved =
|
|
400
|
-
const rel =
|
|
401
|
-
if (rel.startsWith("..") ||
|
|
399
|
+
const resolved = path10.resolve(dir, `${sessionId}${suffix}`);
|
|
400
|
+
const rel = path10.relative(path10.resolve(dir), resolved);
|
|
401
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) {
|
|
402
402
|
throw invalid(sessionId);
|
|
403
403
|
}
|
|
404
404
|
return resolved;
|
|
@@ -442,8 +442,8 @@ function truncate(s, max) {
|
|
|
442
442
|
return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
|
|
443
443
|
}
|
|
444
444
|
function projectSlug(absRoot) {
|
|
445
|
-
const base = slugify(
|
|
446
|
-
const hash = createHash("sha256").update(
|
|
445
|
+
const base = slugify(path10.basename(absRoot));
|
|
446
|
+
const hash = createHash("sha256").update(path10.resolve(absRoot)).digest("hex").slice(0, 6);
|
|
447
447
|
return `${base}-${hash}`;
|
|
448
448
|
}
|
|
449
449
|
function slugify(name) {
|
|
@@ -451,8 +451,8 @@ function slugify(name) {
|
|
|
451
451
|
}
|
|
452
452
|
function wstackGlobalRoot() {
|
|
453
453
|
const fromEnv = process.env["WRONGSTACK_HOME"];
|
|
454
|
-
if (fromEnv && fromEnv.trim().length > 0) return
|
|
455
|
-
return
|
|
454
|
+
if (fromEnv && fromEnv.trim().length > 0) return path10.resolve(fromEnv);
|
|
455
|
+
return path10.join(os.homedir(), ".wrongstack");
|
|
456
456
|
}
|
|
457
457
|
|
|
458
458
|
// src/types/errors.ts
|
|
@@ -632,7 +632,7 @@ var InMemoryAgentBridge = class {
|
|
|
632
632
|
});
|
|
633
633
|
}
|
|
634
634
|
this.inflightGuards.add(correlationId);
|
|
635
|
-
return new Promise((
|
|
635
|
+
return new Promise((resolve7, reject) => {
|
|
636
636
|
const timer = setTimeout(() => {
|
|
637
637
|
this.inflightGuards.delete(correlationId);
|
|
638
638
|
this.pendingRequests.delete(correlationId);
|
|
@@ -651,7 +651,7 @@ var InMemoryAgentBridge = class {
|
|
|
651
651
|
return;
|
|
652
652
|
}
|
|
653
653
|
this.pendingRequests.set(correlationId, {
|
|
654
|
-
resolve:
|
|
654
|
+
resolve: resolve7,
|
|
655
655
|
reject,
|
|
656
656
|
timer
|
|
657
657
|
});
|
|
@@ -1000,13 +1000,13 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
1000
1000
|
if (!bus?.hasListenerFor("budget.threshold_reached")) {
|
|
1001
1001
|
return Promise.resolve("stop");
|
|
1002
1002
|
}
|
|
1003
|
-
return new Promise((
|
|
1003
|
+
return new Promise((resolve7) => {
|
|
1004
1004
|
let resolved = false;
|
|
1005
1005
|
const respond = (d) => {
|
|
1006
1006
|
if (resolved) return;
|
|
1007
1007
|
resolved = true;
|
|
1008
1008
|
clearTimeout(fallback);
|
|
1009
|
-
|
|
1009
|
+
resolve7(d);
|
|
1010
1010
|
};
|
|
1011
1011
|
const fallback = setTimeout(() => respond("stop"), _SubagentBudget.DECISION_TIMEOUT_MS);
|
|
1012
1012
|
const sessionId = this.currentSessionId();
|
|
@@ -1417,7 +1417,7 @@ function agentPrompt(id) {
|
|
|
1417
1417
|
let resolved = "";
|
|
1418
1418
|
for (const dir of agentPromptDirCandidates(envDir)) {
|
|
1419
1419
|
try {
|
|
1420
|
-
resolved = readFileSync(
|
|
1420
|
+
resolved = readFileSync(path10.join(dir, fileName), "utf8").trimEnd();
|
|
1421
1421
|
break;
|
|
1422
1422
|
} catch {
|
|
1423
1423
|
}
|
|
@@ -1426,20 +1426,20 @@ function agentPrompt(id) {
|
|
|
1426
1426
|
return resolved;
|
|
1427
1427
|
}
|
|
1428
1428
|
function agentPromptDirCandidates(envDir) {
|
|
1429
|
-
const globalRoot = process.env["WRONGSTACK_HOME"] ||
|
|
1429
|
+
const globalRoot = process.env["WRONGSTACK_HOME"] || path10.join(os.homedir(), ".wrongstack");
|
|
1430
1430
|
const candKey = `${envDir}\0${globalRoot}`;
|
|
1431
1431
|
const cached = candidateCache.get(candKey);
|
|
1432
1432
|
if (cached !== void 0) return cached;
|
|
1433
|
-
const here =
|
|
1433
|
+
const here = path10.dirname(fileURLToPath(import.meta.url));
|
|
1434
1434
|
const explicitDir = envDir || void 0;
|
|
1435
1435
|
const candidates = [
|
|
1436
|
-
...explicitDir ? [
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1436
|
+
...explicitDir ? [path10.resolve(explicitDir)] : [],
|
|
1437
|
+
path10.join(globalRoot, "instructions", "agents"),
|
|
1438
|
+
path10.resolve(here, "../../../../instructions/agents"),
|
|
1439
|
+
path10.resolve(here, "../../../instructions/agents"),
|
|
1440
|
+
path10.resolve(here, "../../instructions/agents"),
|
|
1441
|
+
path10.resolve(here, "../instructions/agents"),
|
|
1442
|
+
path10.resolve(here, "instructions/agents")
|
|
1443
1443
|
];
|
|
1444
1444
|
const ordered = candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));
|
|
1445
1445
|
candidateCache.set(candKey, ordered);
|
|
@@ -3055,12 +3055,12 @@ var BrainDecisionQueue = class {
|
|
|
3055
3055
|
options: request.options,
|
|
3056
3056
|
rationale: "Decision escalated to human authority."
|
|
3057
3057
|
};
|
|
3058
|
-
const pending = new Promise((
|
|
3059
|
-
const entry = { request, resolve:
|
|
3058
|
+
const pending = new Promise((resolve7) => {
|
|
3059
|
+
const entry = { request, resolve: resolve7 };
|
|
3060
3060
|
if (this.opts.timeoutMs && this.opts.timeoutMs > 0) {
|
|
3061
3061
|
entry.timer = setTimeout(() => {
|
|
3062
3062
|
this.pending.delete(request.id);
|
|
3063
|
-
|
|
3063
|
+
resolve7({ type: "deny", reason: "Brain human decision timed out." });
|
|
3064
3064
|
}, this.opts.timeoutMs);
|
|
3065
3065
|
}
|
|
3066
3066
|
this.pending.set(request.id, entry);
|
|
@@ -3379,7 +3379,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
3379
3379
|
}
|
|
3380
3380
|
for (const filePath of allFiles) {
|
|
3381
3381
|
try {
|
|
3382
|
-
const [content,
|
|
3382
|
+
const [content, stat8] = await Promise.all([
|
|
3383
3383
|
fsp7.readFile(filePath, "utf8"),
|
|
3384
3384
|
fsp7.stat(filePath)
|
|
3385
3385
|
]);
|
|
@@ -3389,8 +3389,8 @@ var CollabSession = class extends EventEmitter {
|
|
|
3389
3389
|
path: filePath,
|
|
3390
3390
|
content,
|
|
3391
3391
|
language,
|
|
3392
|
-
snapshotMtimeMs:
|
|
3393
|
-
snapshotSizeBytes:
|
|
3392
|
+
snapshotMtimeMs: stat8.mtimeMs,
|
|
3393
|
+
snapshotSizeBytes: stat8.size
|
|
3394
3394
|
});
|
|
3395
3395
|
} catch {
|
|
3396
3396
|
this.snapshot.files.push({ path: filePath, content: "", language: void 0 });
|
|
@@ -3803,9 +3803,9 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
3803
3803
|
for (const file of this.snapshot.files) {
|
|
3804
3804
|
if (file.snapshotMtimeMs === void 0 && file.snapshotSizeBytes === void 0) continue;
|
|
3805
3805
|
try {
|
|
3806
|
-
const
|
|
3807
|
-
const mtimeChanged = file.snapshotMtimeMs !== void 0 &&
|
|
3808
|
-
const sizeChanged = file.snapshotSizeBytes !== void 0 &&
|
|
3806
|
+
const stat8 = await fsp7.stat(file.path);
|
|
3807
|
+
const mtimeChanged = file.snapshotMtimeMs !== void 0 && stat8.mtimeMs > file.snapshotMtimeMs + 1;
|
|
3808
|
+
const sizeChanged = file.snapshotSizeBytes !== void 0 && stat8.size !== file.snapshotSizeBytes;
|
|
3809
3809
|
if (mtimeChanged || sizeChanged) {
|
|
3810
3810
|
warnings.push(`${file.path} changed after the collab snapshot was captured.`);
|
|
3811
3811
|
}
|
|
@@ -4203,7 +4203,7 @@ function createDelegateTool(opts) {
|
|
|
4203
4203
|
subagentId
|
|
4204
4204
|
});
|
|
4205
4205
|
const dir = director;
|
|
4206
|
-
const result = await new Promise((
|
|
4206
|
+
const result = await new Promise((resolve7) => {
|
|
4207
4207
|
let settled = false;
|
|
4208
4208
|
let timer;
|
|
4209
4209
|
const finish = (value) => {
|
|
@@ -4213,7 +4213,7 @@ function createDelegateTool(opts) {
|
|
|
4213
4213
|
offTool();
|
|
4214
4214
|
offIter();
|
|
4215
4215
|
offProgress();
|
|
4216
|
-
|
|
4216
|
+
resolve7(value);
|
|
4217
4217
|
};
|
|
4218
4218
|
const arm = () => {
|
|
4219
4219
|
if (timer) clearTimeout(timer);
|
|
@@ -4424,13 +4424,13 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
4424
4424
|
if (!opts.sessionsRoot) return void 0;
|
|
4425
4425
|
const candidates = [];
|
|
4426
4426
|
if (opts.directorRunId) {
|
|
4427
|
-
candidates.push(
|
|
4427
|
+
candidates.push(path10.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
|
|
4428
4428
|
} else {
|
|
4429
4429
|
try {
|
|
4430
4430
|
const entries = await fsp7.readdir(opts.sessionsRoot, { withFileTypes: true });
|
|
4431
4431
|
for (const entry of entries) {
|
|
4432
4432
|
if (entry.isDirectory()) {
|
|
4433
|
-
candidates.push(
|
|
4433
|
+
candidates.push(path10.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
|
|
4434
4434
|
}
|
|
4435
4435
|
}
|
|
4436
4436
|
} catch {
|
|
@@ -4786,7 +4786,14 @@ var DirectorStateCheckpoint = class {
|
|
|
4786
4786
|
mode: 384
|
|
4787
4787
|
});
|
|
4788
4788
|
} catch (err) {
|
|
4789
|
-
console.warn(
|
|
4789
|
+
console.warn(
|
|
4790
|
+
JSON.stringify({
|
|
4791
|
+
level: "warn",
|
|
4792
|
+
event: "director_state.checkpoint_write_failed",
|
|
4793
|
+
message: toErrorMessage(err),
|
|
4794
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4795
|
+
})
|
|
4796
|
+
);
|
|
4790
4797
|
} finally {
|
|
4791
4798
|
this.writing = false;
|
|
4792
4799
|
if (this.rewriteRequested) {
|
|
@@ -4847,7 +4854,7 @@ function readBundledInstructionText(relativePath) {
|
|
|
4847
4854
|
let resolved = "";
|
|
4848
4855
|
for (const root of instructionRootCandidates()) {
|
|
4849
4856
|
try {
|
|
4850
|
-
resolved = readFileSync(
|
|
4857
|
+
resolved = readFileSync(path10.join(root, relativePath), "utf8").trimEnd();
|
|
4851
4858
|
break;
|
|
4852
4859
|
} catch {
|
|
4853
4860
|
}
|
|
@@ -4863,11 +4870,11 @@ function renderInstructionTemplate(template, values) {
|
|
|
4863
4870
|
}
|
|
4864
4871
|
function instructionRootCandidates() {
|
|
4865
4872
|
if (rootCandidates !== void 0) return rootCandidates;
|
|
4866
|
-
const here =
|
|
4873
|
+
const here = path10.dirname(fileURLToPath(import.meta.url));
|
|
4867
4874
|
const candidates = [
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4875
|
+
path10.resolve(here, "../../instructions"),
|
|
4876
|
+
path10.resolve(here, "../instructions"),
|
|
4877
|
+
path10.resolve(here, "instructions")
|
|
4871
4878
|
];
|
|
4872
4879
|
rootCandidates = candidates.sort((a, b) => Number(!isDirectory2(a)) - Number(!isDirectory2(b)));
|
|
4873
4880
|
return rootCandidates;
|
|
@@ -4941,6 +4948,361 @@ function rosterSummaryFromConfigs(roster) {
|
|
|
4941
4948
|
return lines.join("\n");
|
|
4942
4949
|
}
|
|
4943
4950
|
|
|
4951
|
+
// src/kanban/types.ts
|
|
4952
|
+
var DEFAULT_COLUMNS = [
|
|
4953
|
+
{ id: "backlog", title: "Backlog", order: 0, wipLimit: 0, color: "#64748b" },
|
|
4954
|
+
{ id: "todo", title: "To Do", order: 1, wipLimit: 0, color: "#2563eb" },
|
|
4955
|
+
{ id: "in-progress", title: "In Progress", order: 2, wipLimit: 5, color: "#d97706" },
|
|
4956
|
+
{ id: "review", title: "Review", order: 3, wipLimit: 0, color: "#7c3aed" },
|
|
4957
|
+
{ id: "done", title: "Done", order: 4, wipLimit: 0, color: "#16a34a" }
|
|
4958
|
+
];
|
|
4959
|
+
var CURRENT_KANBAN_VERSION = 1;
|
|
4960
|
+
|
|
4961
|
+
// src/kanban/storage.ts
|
|
4962
|
+
var KANBANS_DIR = "kanbans";
|
|
4963
|
+
var BOARD_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
4964
|
+
function getKanbanDir(projectRoot) {
|
|
4965
|
+
return path10.join(projectRoot, ".wrongstack", KANBANS_DIR);
|
|
4966
|
+
}
|
|
4967
|
+
function getKanbanPath(projectRoot, boardId) {
|
|
4968
|
+
assertValidBoardId(boardId);
|
|
4969
|
+
const dir = path10.resolve(getKanbanDir(projectRoot));
|
|
4970
|
+
const resolved = path10.resolve(dir, `${boardId}.json`);
|
|
4971
|
+
const rel = path10.relative(dir, resolved);
|
|
4972
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) {
|
|
4973
|
+
throw invalidBoardId(boardId);
|
|
4974
|
+
}
|
|
4975
|
+
return resolved;
|
|
4976
|
+
}
|
|
4977
|
+
function isValidBoardId(boardId) {
|
|
4978
|
+
return BOARD_ID_RE.test(boardId) && !boardId.includes("..");
|
|
4979
|
+
}
|
|
4980
|
+
function assertValidBoardId(boardId) {
|
|
4981
|
+
if (!isValidBoardId(boardId)) throw invalidBoardId(boardId);
|
|
4982
|
+
}
|
|
4983
|
+
function invalidBoardId(boardId) {
|
|
4984
|
+
return new Error(`Invalid kanban board id: ${boardId}`);
|
|
4985
|
+
}
|
|
4986
|
+
function isEnoent(err) {
|
|
4987
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
4988
|
+
}
|
|
4989
|
+
async function pathExists(filePath) {
|
|
4990
|
+
try {
|
|
4991
|
+
await fsp7.stat(filePath);
|
|
4992
|
+
return true;
|
|
4993
|
+
} catch (err) {
|
|
4994
|
+
if (isEnoent(err)) return false;
|
|
4995
|
+
throw err;
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
async function listBoardIds(projectRoot) {
|
|
4999
|
+
const dir = getKanbanDir(projectRoot);
|
|
5000
|
+
try {
|
|
5001
|
+
const entries = await fsp7.readdir(dir, { withFileTypes: true });
|
|
5002
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -5)).filter(isValidBoardId).sort();
|
|
5003
|
+
} catch (err) {
|
|
5004
|
+
if (isEnoent(err)) return [];
|
|
5005
|
+
throw err;
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
async function resolveBoardRef(projectRoot, boardRef) {
|
|
5009
|
+
assertValidBoardId(boardRef);
|
|
5010
|
+
if (await pathExists(getKanbanPath(projectRoot, boardRef))) return boardRef;
|
|
5011
|
+
const matches = (await listBoardIds(projectRoot)).filter((id) => id.startsWith(boardRef));
|
|
5012
|
+
if (matches.length === 0) return null;
|
|
5013
|
+
if (matches.length > 1) {
|
|
5014
|
+
throw new Error(`Ambiguous kanban board id "${boardRef}": ${matches.slice(0, 5).join(", ")}`);
|
|
5015
|
+
}
|
|
5016
|
+
return matches[0] ?? null;
|
|
5017
|
+
}
|
|
5018
|
+
async function readBoard(projectRoot, boardRef) {
|
|
5019
|
+
const boardId = await resolveBoardRef(projectRoot, boardRef);
|
|
5020
|
+
if (!boardId) return null;
|
|
5021
|
+
try {
|
|
5022
|
+
const raw = await fsp7.readFile(getKanbanPath(projectRoot, boardId), "utf8");
|
|
5023
|
+
return normalizeBoard(JSON.parse(raw));
|
|
5024
|
+
} catch (err) {
|
|
5025
|
+
if (isEnoent(err)) return null;
|
|
5026
|
+
throw err;
|
|
5027
|
+
}
|
|
5028
|
+
}
|
|
5029
|
+
async function mutateBoard(projectRoot, boardRef, mutator) {
|
|
5030
|
+
const boardId = await resolveBoardRef(projectRoot, boardRef);
|
|
5031
|
+
if (!boardId) return null;
|
|
5032
|
+
const filePath = getKanbanPath(projectRoot, boardId);
|
|
5033
|
+
return withFileLock(filePath, async () => {
|
|
5034
|
+
let board;
|
|
5035
|
+
try {
|
|
5036
|
+
const raw = await fsp7.readFile(filePath, "utf8");
|
|
5037
|
+
board = normalizeBoard(JSON.parse(raw));
|
|
5038
|
+
} catch (err) {
|
|
5039
|
+
if (isEnoent(err)) return null;
|
|
5040
|
+
throw err;
|
|
5041
|
+
}
|
|
5042
|
+
const result = await mutator(board);
|
|
5043
|
+
await writeBoardUnlocked(filePath, normalizeBoard(board));
|
|
5044
|
+
return { board, result };
|
|
5045
|
+
});
|
|
5046
|
+
}
|
|
5047
|
+
function summarizeBoard(board) {
|
|
5048
|
+
const total = board.tasks.length;
|
|
5049
|
+
const completed = board.tasks.filter((task) => task.status === "completed").length;
|
|
5050
|
+
const lastActivity = latestActivity(board);
|
|
5051
|
+
return {
|
|
5052
|
+
id: board.id,
|
|
5053
|
+
title: board.title,
|
|
5054
|
+
createdAt: board.createdAt,
|
|
5055
|
+
updatedAt: board.updatedAt,
|
|
5056
|
+
columnCount: board.columns.length,
|
|
5057
|
+
taskCount: total,
|
|
5058
|
+
completedTaskCount: completed,
|
|
5059
|
+
...board.description !== void 0 ? { description: board.description } : {},
|
|
5060
|
+
...board.tags !== void 0 ? { tags: board.tags } : {},
|
|
5061
|
+
...lastActivity !== void 0 ? { lastActivity } : {}
|
|
5062
|
+
};
|
|
5063
|
+
}
|
|
5064
|
+
async function listBoardSummaries(projectRoot) {
|
|
5065
|
+
const summaries = [];
|
|
5066
|
+
for (const id of await listBoardIds(projectRoot)) {
|
|
5067
|
+
const board = await readBoard(projectRoot, id);
|
|
5068
|
+
if (board) summaries.push(summarizeBoard(board));
|
|
5069
|
+
}
|
|
5070
|
+
return summaries.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
5071
|
+
}
|
|
5072
|
+
function normalizeBoard(board) {
|
|
5073
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5074
|
+
const columns = [...board.columns?.length ? board.columns : DEFAULT_COLUMNS].map((column, index) => ({
|
|
5075
|
+
...column,
|
|
5076
|
+
order: column.order ?? index
|
|
5077
|
+
})).sort((a, b) => a.order - b.order).map((column, index) => ({ ...column, order: index }));
|
|
5078
|
+
const columnIds = new Set(columns.map((column) => column.id));
|
|
5079
|
+
const fallbackColumnId = columns[0]?.id ?? "backlog";
|
|
5080
|
+
const tasks = normalizeTaskOrders(
|
|
5081
|
+
(board.tasks ?? []).map((task, index) => ({
|
|
5082
|
+
...task,
|
|
5083
|
+
columnId: columnIds.has(task.columnId) ? task.columnId : fallbackColumnId,
|
|
5084
|
+
order: task.order ?? index,
|
|
5085
|
+
priority: task.priority ?? "medium",
|
|
5086
|
+
status: task.status ?? "pending",
|
|
5087
|
+
createdAt: task.createdAt ?? now,
|
|
5088
|
+
updatedAt: task.updatedAt ?? now
|
|
5089
|
+
}))
|
|
5090
|
+
);
|
|
5091
|
+
return {
|
|
5092
|
+
...board,
|
|
5093
|
+
version: board.version ?? CURRENT_KANBAN_VERSION,
|
|
5094
|
+
createdAt: board.createdAt ?? now,
|
|
5095
|
+
updatedAt: board.updatedAt ?? now,
|
|
5096
|
+
columns,
|
|
5097
|
+
tasks
|
|
5098
|
+
};
|
|
5099
|
+
}
|
|
5100
|
+
function latestActivity(board) {
|
|
5101
|
+
return [board.updatedAt, ...board.tasks.map((task) => task.updatedAt)].filter(Boolean).sort().reverse()[0];
|
|
5102
|
+
}
|
|
5103
|
+
async function writeBoardUnlocked(filePath, board) {
|
|
5104
|
+
await atomicWrite(filePath, `${JSON.stringify(board, null, 2)}
|
|
5105
|
+
`, { encoding: "utf8" });
|
|
5106
|
+
}
|
|
5107
|
+
function normalizeTaskOrders(tasks) {
|
|
5108
|
+
const byColumn = /* @__PURE__ */ new Map();
|
|
5109
|
+
for (const task of tasks) {
|
|
5110
|
+
const columnTasks = byColumn.get(task.columnId) ?? [];
|
|
5111
|
+
columnTasks.push(task);
|
|
5112
|
+
byColumn.set(task.columnId, columnTasks);
|
|
5113
|
+
}
|
|
5114
|
+
for (const columnTasks of byColumn.values()) {
|
|
5115
|
+
columnTasks.sort((a, b) => a.order - b.order || a.createdAt.localeCompare(b.createdAt)).forEach((task, index) => {
|
|
5116
|
+
task.order = index;
|
|
5117
|
+
});
|
|
5118
|
+
}
|
|
5119
|
+
return tasks;
|
|
5120
|
+
}
|
|
5121
|
+
|
|
5122
|
+
// src/kanban/manager.ts
|
|
5123
|
+
async function listBoards(projectRoot) {
|
|
5124
|
+
return listBoardSummaries(projectRoot);
|
|
5125
|
+
}
|
|
5126
|
+
async function updateTaskAssignment(projectRoot, boardId, taskId, patch) {
|
|
5127
|
+
const updated = await mutateBoard(projectRoot, boardId, (board) => {
|
|
5128
|
+
const task = findTask(board, taskId);
|
|
5129
|
+
if (!task) return null;
|
|
5130
|
+
const nextAssignment = {
|
|
5131
|
+
...task.assignment ?? { status: "assigned" }
|
|
5132
|
+
};
|
|
5133
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
5134
|
+
if (value !== void 0) {
|
|
5135
|
+
nextAssignment[key] = value;
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
task.assignment = nextAssignment;
|
|
5139
|
+
if (task.assignment.agentId) task.assignedAgent = task.assignment.agentId;
|
|
5140
|
+
if (task.assignment.status === "completed") {
|
|
5141
|
+
task.assignment.completedAt = task.assignment.completedAt ?? nowIso();
|
|
5142
|
+
task.status = "completed";
|
|
5143
|
+
task.completedAt = task.assignment.completedAt;
|
|
5144
|
+
if (patch.error === void 0) delete task.assignment.error;
|
|
5145
|
+
} else if (task.assignment.status === "running") {
|
|
5146
|
+
delete task.assignment.completedAt;
|
|
5147
|
+
if (patch.error === void 0) delete task.assignment.error;
|
|
5148
|
+
task.status = "in_progress";
|
|
5149
|
+
delete task.completedAt;
|
|
5150
|
+
} else if (task.assignment.status === "failed") {
|
|
5151
|
+
delete task.assignment.completedAt;
|
|
5152
|
+
task.status = "failed";
|
|
5153
|
+
delete task.completedAt;
|
|
5154
|
+
} else if (task.assignment.status === "cancelled") {
|
|
5155
|
+
delete task.assignment.completedAt;
|
|
5156
|
+
if (patch.error === void 0) delete task.assignment.error;
|
|
5157
|
+
task.status = "blocked";
|
|
5158
|
+
delete task.completedAt;
|
|
5159
|
+
} else if (task.assignment.status === "queued" || task.assignment.status === "assigned") {
|
|
5160
|
+
delete task.assignment.completedAt;
|
|
5161
|
+
if (patch.error === void 0) delete task.assignment.error;
|
|
5162
|
+
if (task.status === "completed" || task.status === "failed") {
|
|
5163
|
+
task.status = task.assignment.status === "queued" ? "ready" : "pending";
|
|
5164
|
+
}
|
|
5165
|
+
delete task.completedAt;
|
|
5166
|
+
}
|
|
5167
|
+
task.updatedAt = nowIso();
|
|
5168
|
+
board.updatedAt = task.updatedAt;
|
|
5169
|
+
return task;
|
|
5170
|
+
});
|
|
5171
|
+
return updated?.result ? updated.board : null;
|
|
5172
|
+
}
|
|
5173
|
+
async function claimReadyTask(projectRoot, input = {}) {
|
|
5174
|
+
if (input.boardId) return claimReadyTaskOnBoard(projectRoot, input.boardId, input);
|
|
5175
|
+
for (const board of await listBoards(projectRoot)) {
|
|
5176
|
+
const claimed = await claimReadyTaskOnBoard(projectRoot, board.id, input);
|
|
5177
|
+
if (claimed) return claimed;
|
|
5178
|
+
}
|
|
5179
|
+
return null;
|
|
5180
|
+
}
|
|
5181
|
+
async function searchKanban(projectRoot, input = {}) {
|
|
5182
|
+
const boardIds = input.boardId ? [input.boardId] : (await listBoards(projectRoot)).map((b) => b.id);
|
|
5183
|
+
const results = [];
|
|
5184
|
+
for (const boardId of boardIds) {
|
|
5185
|
+
const board = await readBoard(projectRoot, boardId);
|
|
5186
|
+
if (!board) continue;
|
|
5187
|
+
for (const task of board.tasks) {
|
|
5188
|
+
if (!matchesKanbanSearch(board, task, input)) continue;
|
|
5189
|
+
results.push({ board: summarizeBoard(board), task });
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
5192
|
+
return results;
|
|
5193
|
+
}
|
|
5194
|
+
async function listReadyTasks(projectRoot, input = {}) {
|
|
5195
|
+
const results = await searchKanban(projectRoot, { ...input, readyOnly: true });
|
|
5196
|
+
return input.limit && input.limit > 0 ? results.slice(0, input.limit) : results;
|
|
5197
|
+
}
|
|
5198
|
+
function areDependenciesMet(board, taskId) {
|
|
5199
|
+
const task = findTask(board, taskId);
|
|
5200
|
+
if (!task?.dependsOn?.length) return true;
|
|
5201
|
+
return task.dependsOn.every((depId) => {
|
|
5202
|
+
const depTask = board.tasks.find((candidate) => candidate.id === depId);
|
|
5203
|
+
return depTask?.status === "completed";
|
|
5204
|
+
});
|
|
5205
|
+
}
|
|
5206
|
+
function buildAssignment(input) {
|
|
5207
|
+
return {
|
|
5208
|
+
status: input.status ?? "assigned",
|
|
5209
|
+
...input.agentId !== void 0 ? { agentId: input.agentId } : {},
|
|
5210
|
+
...input.name !== void 0 ? { name: input.name } : {},
|
|
5211
|
+
...input.role !== void 0 ? { role: input.role } : {},
|
|
5212
|
+
...input.provider !== void 0 ? { provider: input.provider } : {},
|
|
5213
|
+
...input.model !== void 0 ? { model: input.model } : {},
|
|
5214
|
+
...input.fallbackProfile !== void 0 ? { fallbackProfile: input.fallbackProfile } : {},
|
|
5215
|
+
...input.fallbackModels !== void 0 ? { fallbackModels: input.fallbackModels } : {},
|
|
5216
|
+
...input.tools !== void 0 ? { tools: input.tools } : {},
|
|
5217
|
+
...input.allowedCapabilities !== void 0 ? { allowedCapabilities: input.allowedCapabilities } : {}
|
|
5218
|
+
};
|
|
5219
|
+
}
|
|
5220
|
+
async function claimReadyTaskOnBoard(projectRoot, boardId, input) {
|
|
5221
|
+
const updated = await mutateBoard(projectRoot, boardId, (board) => {
|
|
5222
|
+
const candidates = input.taskId ? [findTask(board, input.taskId)].filter((task2) => Boolean(task2)) : board.tasks.filter((task2) => isTaskReadyForWork(board, task2)).sort(compareTasksForWork);
|
|
5223
|
+
const task = candidates.find((candidate) => isTaskReadyForWork(board, candidate));
|
|
5224
|
+
if (!task) return null;
|
|
5225
|
+
const current = task.assignment;
|
|
5226
|
+
const assignment = buildAssignment({
|
|
5227
|
+
...current?.agentId !== void 0 ? { agentId: current.agentId } : {},
|
|
5228
|
+
...current?.name !== void 0 ? { name: current.name } : {},
|
|
5229
|
+
...current?.role !== void 0 ? { role: current.role } : {},
|
|
5230
|
+
...current?.provider !== void 0 ? { provider: current.provider } : {},
|
|
5231
|
+
...current?.model !== void 0 ? { model: current.model } : {},
|
|
5232
|
+
...current?.fallbackProfile !== void 0 ? { fallbackProfile: current.fallbackProfile } : {},
|
|
5233
|
+
...current?.fallbackModels !== void 0 ? { fallbackModels: current.fallbackModels } : {},
|
|
5234
|
+
...current?.tools !== void 0 ? { tools: current.tools } : {},
|
|
5235
|
+
...current?.allowedCapabilities !== void 0 ? { allowedCapabilities: current.allowedCapabilities } : {},
|
|
5236
|
+
...input.agentId !== void 0 ? { agentId: input.agentId } : {},
|
|
5237
|
+
...input.name !== void 0 ? { name: input.name } : {},
|
|
5238
|
+
...input.role !== void 0 ? { role: input.role } : {},
|
|
5239
|
+
...input.provider !== void 0 ? { provider: input.provider } : {},
|
|
5240
|
+
...input.model !== void 0 ? { model: input.model } : {},
|
|
5241
|
+
...input.fallbackProfile !== void 0 ? { fallbackProfile: input.fallbackProfile } : {},
|
|
5242
|
+
...input.fallbackModels !== void 0 ? { fallbackModels: input.fallbackModels } : {},
|
|
5243
|
+
...input.tools !== void 0 ? { tools: input.tools } : {},
|
|
5244
|
+
...input.allowedCapabilities !== void 0 ? { allowedCapabilities: input.allowedCapabilities } : {},
|
|
5245
|
+
...input.assignee !== void 0 ? { assignee: input.assignee } : {},
|
|
5246
|
+
status: input.status ?? "queued"
|
|
5247
|
+
});
|
|
5248
|
+
assignment.dispatchedAt = assignment.dispatchedAt ?? nowIso();
|
|
5249
|
+
task.assignment = assignment;
|
|
5250
|
+
if (assignment.agentId ?? assignment.role ?? assignment.name) {
|
|
5251
|
+
task.assignedAgent = assignment.agentId ?? assignment.role ?? assignment.name;
|
|
5252
|
+
}
|
|
5253
|
+
if (input.assignee ?? assignment.name ?? assignment.agentId) {
|
|
5254
|
+
task.assignee = input.assignee ?? assignment.name ?? assignment.agentId;
|
|
5255
|
+
}
|
|
5256
|
+
task.status = assignment.status === "running" ? "in_progress" : "ready";
|
|
5257
|
+
delete task.completedAt;
|
|
5258
|
+
task.updatedAt = nowIso();
|
|
5259
|
+
board.updatedAt = task.updatedAt;
|
|
5260
|
+
return task;
|
|
5261
|
+
});
|
|
5262
|
+
return updated?.result ? { board: updated.board, task: updated.result } : null;
|
|
5263
|
+
}
|
|
5264
|
+
function compareTasksForWork(a, b) {
|
|
5265
|
+
const priorityRank = {
|
|
5266
|
+
critical: 0,
|
|
5267
|
+
high: 1,
|
|
5268
|
+
medium: 2,
|
|
5269
|
+
low: 3
|
|
5270
|
+
};
|
|
5271
|
+
return priorityRank[a.priority] - priorityRank[b.priority] || a.columnId.localeCompare(b.columnId) || a.order - b.order || a.createdAt.localeCompare(b.createdAt);
|
|
5272
|
+
}
|
|
5273
|
+
function matchesKanbanSearch(board, task, input) {
|
|
5274
|
+
const query = input.query?.trim().toLowerCase();
|
|
5275
|
+
if (input.assignedAgent && task.assignedAgent !== input.assignedAgent) return false;
|
|
5276
|
+
if (input.status && task.status !== input.status) return false;
|
|
5277
|
+
if (input.priority && task.priority !== input.priority) return false;
|
|
5278
|
+
if (input.label && !task.labels?.includes(input.label)) return false;
|
|
5279
|
+
if (input.chainId && task.chain?.chainId !== input.chainId) return false;
|
|
5280
|
+
if (input.readyOnly && !isTaskReadyForWork(board, task)) return false;
|
|
5281
|
+
if (!query) return true;
|
|
5282
|
+
return [task.title, task.description, task.assignedAgent, task.assignee, ...task.labels ?? []].filter(Boolean).some((value) => String(value).toLowerCase().includes(query));
|
|
5283
|
+
}
|
|
5284
|
+
function findTask(board, taskId) {
|
|
5285
|
+
const exact = board.tasks.find((task) => task.id === taskId);
|
|
5286
|
+
if (exact) return exact;
|
|
5287
|
+
const matches = board.tasks.filter((task) => task.id.startsWith(taskId));
|
|
5288
|
+
if (matches.length > 1) {
|
|
5289
|
+
throw new Error(
|
|
5290
|
+
`Ambiguous kanban task id "${taskId}": ${matches.slice(0, 5).map((task) => task.id).join(", ")}`
|
|
5291
|
+
);
|
|
5292
|
+
}
|
|
5293
|
+
return matches[0];
|
|
5294
|
+
}
|
|
5295
|
+
function isTaskReadyForWork(board, task) {
|
|
5296
|
+
if (!["pending", "ready"].includes(task.status)) return false;
|
|
5297
|
+
if (task.assignment && ["queued", "running"].includes(task.assignment.status)) return false;
|
|
5298
|
+
if (task.mergedIntoTaskId) return false;
|
|
5299
|
+
if (!areDependenciesMet(board, task.id)) return false;
|
|
5300
|
+
return true;
|
|
5301
|
+
}
|
|
5302
|
+
function nowIso() {
|
|
5303
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5304
|
+
}
|
|
5305
|
+
|
|
4944
5306
|
// src/coordination/dispatcher.ts
|
|
4945
5307
|
var DEFAULT_DISPATCH_ROLE = "executor";
|
|
4946
5308
|
var FALLBACK_DEFINITION = {
|
|
@@ -5618,6 +5980,298 @@ function makeAssignTool(director) {
|
|
|
5618
5980
|
}
|
|
5619
5981
|
};
|
|
5620
5982
|
}
|
|
5983
|
+
function makeKanbanQueueTool(director, roster) {
|
|
5984
|
+
return {
|
|
5985
|
+
name: "kanban_queue",
|
|
5986
|
+
description: "Claim dependency-ready Kanban tasks and dispatch them into the Director fleet. Preserves per-task provider/model/role/tool routing metadata, assigns each claimed task to a spawned subagent, and can await results while writing completion back to Kanban.",
|
|
5987
|
+
usageHint: 'Use action:"dispatch_ready" with optional boardId/taskId/maxTasks. Set awaitCompletion:true when you want this call to update Kanban to completed/failed before returning; otherwise use await_tasks and kanban mark_assignment later.',
|
|
5988
|
+
permission: "auto",
|
|
5989
|
+
mutating: true,
|
|
5990
|
+
capabilities: [ToolCapabilities.SUBAGENT_SPAWN, ToolCapabilities.FS_WRITE],
|
|
5991
|
+
inputSchema: {
|
|
5992
|
+
type: "object",
|
|
5993
|
+
properties: {
|
|
5994
|
+
action: { type: "string", enum: ["dispatch_ready"] },
|
|
5995
|
+
boardId: { type: "string", description: "Optional board id/prefix to claim from." },
|
|
5996
|
+
taskId: { type: "string", description: "Optional exact task id/prefix to claim." },
|
|
5997
|
+
query: { type: "string", description: "Optional natural-language filter for ready tasks." },
|
|
5998
|
+
maxTasks: {
|
|
5999
|
+
type: "number",
|
|
6000
|
+
minimum: 1,
|
|
6001
|
+
maximum: 20,
|
|
6002
|
+
description: "Maximum number of ready tasks to claim and dispatch. Default 1."
|
|
6003
|
+
},
|
|
6004
|
+
awaitCompletion: {
|
|
6005
|
+
type: "boolean",
|
|
6006
|
+
description: "When true, waits for assigned fleet task results and writes completed/failed back to Kanban."
|
|
6007
|
+
},
|
|
6008
|
+
timeoutMs: {
|
|
6009
|
+
type: "number",
|
|
6010
|
+
minimum: 1,
|
|
6011
|
+
description: "Optional per-assigned-task timeout in ms."
|
|
6012
|
+
},
|
|
6013
|
+
maxToolCalls: {
|
|
6014
|
+
type: "number",
|
|
6015
|
+
minimum: 1,
|
|
6016
|
+
description: "Optional per-assigned-task tool-call cap."
|
|
6017
|
+
},
|
|
6018
|
+
agentId: { type: "string" },
|
|
6019
|
+
name: { type: "string" },
|
|
6020
|
+
role: { type: "string" },
|
|
6021
|
+
provider: { type: "string" },
|
|
6022
|
+
model: { type: "string" },
|
|
6023
|
+
fallbackModels: { type: "array", items: { type: "string" } },
|
|
6024
|
+
tools: { type: "array", items: { type: "string" } },
|
|
6025
|
+
allowedCapabilities: { type: "array", items: { type: "string" } },
|
|
6026
|
+
worktree: {
|
|
6027
|
+
anyOf: [{ type: "boolean" }, { type: "string", enum: ["auto", "required", "off"] }]
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
},
|
|
6031
|
+
async execute(input, ctx) {
|
|
6032
|
+
const i = normalizeKanbanQueueInput(input);
|
|
6033
|
+
const rawAction = input?.action;
|
|
6034
|
+
if (rawAction !== void 0 && rawAction !== "dispatch_ready") {
|
|
6035
|
+
return { error: `Unknown kanban_queue action: ${String(rawAction)}` };
|
|
6036
|
+
}
|
|
6037
|
+
const projectRoot = ctx.projectRoot;
|
|
6038
|
+
if (!projectRoot) return { error: "kanban_queue requires ctx.projectRoot." };
|
|
6039
|
+
const maxTasks = Math.max(1, Math.min(20, Math.floor(i.maxTasks ?? 1)));
|
|
6040
|
+
const candidateTaskIds = i.taskId !== void 0 ? [i.taskId] : i.query ? (await listReadyTasks(projectRoot, {
|
|
6041
|
+
...i.boardId !== void 0 ? { boardId: i.boardId } : {}
|
|
6042
|
+
})).filter((candidate) => matchesKanbanQueueQuery(candidate.task, i.query ?? "")).slice(0, maxTasks).map((candidate) => candidate.task.id) : void 0;
|
|
6043
|
+
const dispatches = [];
|
|
6044
|
+
const errors = [];
|
|
6045
|
+
const resultFailures = [];
|
|
6046
|
+
for (let index = 0; index < maxTasks; index++) {
|
|
6047
|
+
const candidateTaskId = candidateTaskIds?.[index];
|
|
6048
|
+
if (candidateTaskIds && !candidateTaskId) break;
|
|
6049
|
+
const claim = await claimReadyTask(projectRoot, {
|
|
6050
|
+
...i.boardId !== void 0 ? { boardId: i.boardId } : {},
|
|
6051
|
+
...candidateTaskId !== void 0 ? { taskId: candidateTaskId } : {},
|
|
6052
|
+
...i.agentId !== void 0 ? { agentId: i.agentId } : {},
|
|
6053
|
+
...i.name !== void 0 ? { name: i.name } : {},
|
|
6054
|
+
...i.role !== void 0 ? { role: i.role } : {},
|
|
6055
|
+
...i.provider !== void 0 ? { provider: i.provider } : {},
|
|
6056
|
+
...i.model !== void 0 ? { model: i.model } : {},
|
|
6057
|
+
...i.fallbackModels !== void 0 ? { fallbackModels: i.fallbackModels } : {},
|
|
6058
|
+
...i.tools !== void 0 ? { tools: i.tools } : {},
|
|
6059
|
+
...i.allowedCapabilities !== void 0 ? { allowedCapabilities: i.allowedCapabilities } : {},
|
|
6060
|
+
status: "queued"
|
|
6061
|
+
});
|
|
6062
|
+
if (!claim) {
|
|
6063
|
+
if (candidateTaskIds) continue;
|
|
6064
|
+
break;
|
|
6065
|
+
}
|
|
6066
|
+
let subagentId;
|
|
6067
|
+
let runTaskId;
|
|
6068
|
+
try {
|
|
6069
|
+
const config = buildKanbanSubagentConfig(claim.task, i, roster);
|
|
6070
|
+
subagentId = await director.spawn(config);
|
|
6071
|
+
runTaskId = await director.assign({
|
|
6072
|
+
id: randomUUID(),
|
|
6073
|
+
subagentId,
|
|
6074
|
+
description: buildKanbanFleetTaskPrompt(claim.board, claim.task),
|
|
6075
|
+
...i.maxToolCalls !== void 0 ? { maxToolCalls: i.maxToolCalls } : {},
|
|
6076
|
+
...i.timeoutMs !== void 0 ? { timeoutMs: i.timeoutMs } : {},
|
|
6077
|
+
context: {
|
|
6078
|
+
kanban: {
|
|
6079
|
+
boardId: claim.board.id,
|
|
6080
|
+
taskId: claim.task.id,
|
|
6081
|
+
origin: claim.task.origin
|
|
6082
|
+
}
|
|
6083
|
+
}
|
|
6084
|
+
});
|
|
6085
|
+
await updateTaskAssignment(projectRoot, claim.board.id, claim.task.id, {
|
|
6086
|
+
...claim.task.assignment ?? {},
|
|
6087
|
+
status: "running",
|
|
6088
|
+
subagentId,
|
|
6089
|
+
runTaskId
|
|
6090
|
+
});
|
|
6091
|
+
dispatches.push({
|
|
6092
|
+
boardId: claim.board.id,
|
|
6093
|
+
taskId: claim.task.id,
|
|
6094
|
+
title: claim.task.title,
|
|
6095
|
+
subagentId,
|
|
6096
|
+
runTaskId,
|
|
6097
|
+
...config.provider !== void 0 ? { provider: config.provider } : {},
|
|
6098
|
+
...config.model !== void 0 ? { model: config.model } : {}
|
|
6099
|
+
});
|
|
6100
|
+
} catch (err) {
|
|
6101
|
+
let message = toErrorMessage(err);
|
|
6102
|
+
if (subagentId && !runTaskId) {
|
|
6103
|
+
try {
|
|
6104
|
+
await director.terminate(subagentId);
|
|
6105
|
+
} catch (cleanupErr) {
|
|
6106
|
+
message = `${message}; cleanup failed for spawned subagent ${subagentId}: ${toErrorMessage(cleanupErr)}`;
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
6109
|
+
await updateTaskAssignment(projectRoot, claim.board.id, claim.task.id, {
|
|
6110
|
+
...claim.task.assignment ?? {},
|
|
6111
|
+
status: "failed",
|
|
6112
|
+
...subagentId !== void 0 ? { subagentId } : {},
|
|
6113
|
+
...runTaskId !== void 0 ? { runTaskId } : {},
|
|
6114
|
+
error: message
|
|
6115
|
+
});
|
|
6116
|
+
errors.push({ taskId: claim.task.id, error: message });
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
6119
|
+
let results;
|
|
6120
|
+
if (i.awaitCompletion && dispatches.length > 0) {
|
|
6121
|
+
results = await director.awaitTasks(dispatches.map((dispatch) => dispatch.runTaskId));
|
|
6122
|
+
for (const result of results) {
|
|
6123
|
+
const dispatch = dispatches.find((candidate) => candidate.runTaskId === result.taskId);
|
|
6124
|
+
if (!dispatch) continue;
|
|
6125
|
+
await updateTaskAssignment(projectRoot, dispatch.boardId, dispatch.taskId, {
|
|
6126
|
+
status: result.status === "success" ? "completed" : "failed",
|
|
6127
|
+
subagentId: result.subagentId,
|
|
6128
|
+
runTaskId: result.taskId,
|
|
6129
|
+
...result.status === "success" ? { lastResult: resultToText(result) } : { error: resultErrorText(result) }
|
|
6130
|
+
});
|
|
6131
|
+
if (result.status !== "success") {
|
|
6132
|
+
resultFailures.push({
|
|
6133
|
+
taskId: dispatch.taskId,
|
|
6134
|
+
runTaskId: result.taskId,
|
|
6135
|
+
status: result.status,
|
|
6136
|
+
error: resultErrorText(result)
|
|
6137
|
+
});
|
|
6138
|
+
}
|
|
6139
|
+
}
|
|
6140
|
+
}
|
|
6141
|
+
return {
|
|
6142
|
+
ok: errors.length === 0 && resultFailures.length === 0,
|
|
6143
|
+
dispatched: dispatches,
|
|
6144
|
+
count: dispatches.length,
|
|
6145
|
+
...results !== void 0 ? { results } : {},
|
|
6146
|
+
...errors.length > 0 ? { errors } : {},
|
|
6147
|
+
...resultFailures.length > 0 ? { resultFailures } : {},
|
|
6148
|
+
message: dispatches.length > 0 ? `Dispatched ${dispatches.length} kanban task(s).` : "No ready kanban task matched."
|
|
6149
|
+
};
|
|
6150
|
+
}
|
|
6151
|
+
};
|
|
6152
|
+
}
|
|
6153
|
+
function normalizeKanbanQueueInput(input) {
|
|
6154
|
+
const raw = input ?? {};
|
|
6155
|
+
return {
|
|
6156
|
+
action: raw.action === "dispatch_ready" ? "dispatch_ready" : void 0,
|
|
6157
|
+
boardId: typeof raw.boardId === "string" ? raw.boardId : void 0,
|
|
6158
|
+
taskId: typeof raw.taskId === "string" ? raw.taskId : void 0,
|
|
6159
|
+
query: typeof raw.query === "string" ? raw.query : void 0,
|
|
6160
|
+
maxTasks: typeof raw.maxTasks === "number" ? raw.maxTasks : void 0,
|
|
6161
|
+
awaitCompletion: typeof raw.awaitCompletion === "boolean" ? raw.awaitCompletion : void 0,
|
|
6162
|
+
timeoutMs: typeof raw.timeoutMs === "number" ? raw.timeoutMs : void 0,
|
|
6163
|
+
maxToolCalls: typeof raw.maxToolCalls === "number" ? raw.maxToolCalls : void 0,
|
|
6164
|
+
agentId: typeof raw.agentId === "string" ? raw.agentId : void 0,
|
|
6165
|
+
name: typeof raw.name === "string" ? raw.name : void 0,
|
|
6166
|
+
role: typeof raw.role === "string" ? raw.role : void 0,
|
|
6167
|
+
provider: typeof raw.provider === "string" ? raw.provider : void 0,
|
|
6168
|
+
model: typeof raw.model === "string" ? raw.model : void 0,
|
|
6169
|
+
fallbackModels: stringArray(raw.fallbackModels),
|
|
6170
|
+
tools: stringArray(raw.tools),
|
|
6171
|
+
allowedCapabilities: stringArray(raw.allowedCapabilities),
|
|
6172
|
+
worktree: normalizeWorktreeOverride(raw.worktree)
|
|
6173
|
+
};
|
|
6174
|
+
}
|
|
6175
|
+
function buildKanbanSubagentConfig(task, input, roster) {
|
|
6176
|
+
const assignment = task.assignment;
|
|
6177
|
+
const role = input.role ?? assignment?.role;
|
|
6178
|
+
const base = role && roster?.[role] ? instantiateRosterConfig2(role, roster[role] ?? {}) : void 0;
|
|
6179
|
+
const tools = input.tools ?? assignment?.tools ?? base?.tools;
|
|
6180
|
+
const name = input.name ?? assignment?.name ?? input.agentId ?? assignment?.agentId ?? task.assignedAgent ?? role ?? "kanban-agent";
|
|
6181
|
+
return {
|
|
6182
|
+
...base ?? { name },
|
|
6183
|
+
name: base?.name ?? name,
|
|
6184
|
+
...role !== void 0 ? { role } : {},
|
|
6185
|
+
...input.provider ?? assignment?.provider ? { provider: input.provider ?? assignment?.provider } : {},
|
|
6186
|
+
...input.model ?? assignment?.model ? { model: input.model ?? assignment?.model } : {},
|
|
6187
|
+
...input.fallbackModels ?? assignment?.fallbackModels ? { fallbackModels: input.fallbackModels ?? assignment?.fallbackModels } : {},
|
|
6188
|
+
...tools ? { tools: ensureKanbanTool(tools) } : {},
|
|
6189
|
+
...input.allowedCapabilities ?? assignment?.allowedCapabilities ? { allowedCapabilities: input.allowedCapabilities ?? assignment?.allowedCapabilities } : {},
|
|
6190
|
+
...input.worktree !== void 0 ? { worktree: input.worktree } : {}
|
|
6191
|
+
};
|
|
6192
|
+
}
|
|
6193
|
+
function ensureKanbanTool(tools) {
|
|
6194
|
+
return tools.includes("kanban") ? [...tools] : [...tools, "kanban"];
|
|
6195
|
+
}
|
|
6196
|
+
function matchesKanbanQueueQuery(task, query) {
|
|
6197
|
+
const normalized = query.trim().toLowerCase();
|
|
6198
|
+
if (!normalized) return true;
|
|
6199
|
+
return [
|
|
6200
|
+
task.title,
|
|
6201
|
+
task.description,
|
|
6202
|
+
task.assignedAgent,
|
|
6203
|
+
task.assignee,
|
|
6204
|
+
task.origin?.system,
|
|
6205
|
+
task.origin?.graphId,
|
|
6206
|
+
task.origin?.phaseId,
|
|
6207
|
+
...task.labels ?? []
|
|
6208
|
+
].filter(Boolean).some((value) => String(value).toLowerCase().includes(normalized));
|
|
6209
|
+
}
|
|
6210
|
+
function buildKanbanFleetTaskPrompt(board, task) {
|
|
6211
|
+
const dependencyLines = (task.dependsOn ?? []).map((depId) => board.tasks.find((candidate) => candidate.id === depId)).filter((dep) => Boolean(dep)).map((dep) => `- ${dep.title} [${dep.status}] (${dep.id})`);
|
|
6212
|
+
const checks = task.successCriteria?.map((check) => `- ${check.description}`).join("\n");
|
|
6213
|
+
const metrics = task.goalMetrics?.map(
|
|
6214
|
+
(metric) => `- ${metric.name}: ${metric.current ?? "n/a"}${metric.target !== void 0 ? ` / ${metric.target}` : ""}${metric.unit ? ` ${metric.unit}` : ""} [${metric.status}]`
|
|
6215
|
+
).join("\n");
|
|
6216
|
+
const chain = task.chain ? [
|
|
6217
|
+
`chainId: ${task.chain.chainId}`,
|
|
6218
|
+
`order: ${task.chain.order}`,
|
|
6219
|
+
task.chain.previousTaskId ? `previous: ${task.chain.previousTaskId}` : "",
|
|
6220
|
+
task.chain.nextTaskId ? `next: ${task.chain.nextTaskId}` : ""
|
|
6221
|
+
].filter(Boolean).join("\n") : "";
|
|
6222
|
+
const routing = [
|
|
6223
|
+
task.assignment?.role ? `role: ${task.assignment.role}` : "",
|
|
6224
|
+
task.assignment?.provider ? `provider: ${task.assignment.provider}` : "",
|
|
6225
|
+
task.assignment?.model ? `model: ${task.assignment.model}` : "",
|
|
6226
|
+
task.assignment?.fallbackProfile ? `fallbackProfile: ${task.assignment.fallbackProfile}` : "",
|
|
6227
|
+
task.assignment?.fallbackModels?.length ? `fallbackModels: ${task.assignment.fallbackModels.join(", ")}` : ""
|
|
6228
|
+
].filter(Boolean);
|
|
6229
|
+
const origin = task.origin ? [
|
|
6230
|
+
`system: ${task.origin.system}`,
|
|
6231
|
+
task.origin.graphId ? `graphId: ${task.origin.graphId}` : "",
|
|
6232
|
+
task.origin.phaseId ? `phaseId: ${task.origin.phaseId}` : "",
|
|
6233
|
+
task.origin.taskId ? `sourceTaskId: ${task.origin.taskId}` : ""
|
|
6234
|
+
].filter(Boolean).join("\n") : "";
|
|
6235
|
+
return [
|
|
6236
|
+
"You are processing a claimed WrongStack Kanban task.",
|
|
6237
|
+
"",
|
|
6238
|
+
`Board: ${board.title} (${board.id})`,
|
|
6239
|
+
`Task: ${task.title} (${task.id})`,
|
|
6240
|
+
`Status: ${task.status}`,
|
|
6241
|
+
`Priority: ${task.priority}`,
|
|
6242
|
+
task.description ? `Description:
|
|
6243
|
+
${task.description}` : "",
|
|
6244
|
+
origin ? `Origin:
|
|
6245
|
+
${origin}` : "",
|
|
6246
|
+
routing.length ? `Routing hints:
|
|
6247
|
+
${routing.join("\n")}` : "",
|
|
6248
|
+
chain ? `Task chain:
|
|
6249
|
+
${chain}` : "",
|
|
6250
|
+
dependencyLines.length ? `Dependencies:
|
|
6251
|
+
${dependencyLines.join("\n")}` : "",
|
|
6252
|
+
checks ? `Success criteria:
|
|
6253
|
+
${checks}` : "",
|
|
6254
|
+
metrics ? `Goal metrics:
|
|
6255
|
+
${metrics}` : "",
|
|
6256
|
+
task.labels?.length ? `Labels: ${task.labels.join(", ")}` : "",
|
|
6257
|
+
"",
|
|
6258
|
+
"Work this task end-to-end. If scope is too broad or too small, use the kanban tool to split_task or merge_tasks instead of losing traceability.",
|
|
6259
|
+
`When you start or finish, call kanban with action "mark_assignment", boardId "${board.id}", taskId "${task.id}", and assignmentStatus "running", "completed", or "failed". Include lastResult or error when you finish.`,
|
|
6260
|
+
"When finished, report what changed, what you verified, and any remaining blockers."
|
|
6261
|
+
].filter(Boolean).join("\n");
|
|
6262
|
+
}
|
|
6263
|
+
function resultToText(result) {
|
|
6264
|
+
if (typeof result.result === "string") return result.result;
|
|
6265
|
+
if (result.result === void 0) return "";
|
|
6266
|
+
try {
|
|
6267
|
+
return JSON.stringify(result.result);
|
|
6268
|
+
} catch {
|
|
6269
|
+
return String(result.result);
|
|
6270
|
+
}
|
|
6271
|
+
}
|
|
6272
|
+
function resultErrorText(result) {
|
|
6273
|
+
return result.error ? `${result.error.kind}: ${result.error.message}` : result.status;
|
|
6274
|
+
}
|
|
5621
6275
|
function makeAwaitTasksTool(director) {
|
|
5622
6276
|
return {
|
|
5623
6277
|
name: "await_tasks",
|
|
@@ -6991,7 +7645,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
6991
7645
|
taskIds.map((id) => {
|
|
6992
7646
|
const cached = this.completedResults.find((r) => r.taskId === id);
|
|
6993
7647
|
if (cached) return cached;
|
|
6994
|
-
return new Promise((
|
|
7648
|
+
return new Promise((resolve7, reject) => {
|
|
6995
7649
|
const timeout = setTimeout(() => {
|
|
6996
7650
|
this.off("task.completed", handler);
|
|
6997
7651
|
reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
|
|
@@ -7000,7 +7654,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
7000
7654
|
if (result.taskId === id) {
|
|
7001
7655
|
clearTimeout(timeout);
|
|
7002
7656
|
this.off("task.completed", handler);
|
|
7003
|
-
|
|
7657
|
+
resolve7(result);
|
|
7004
7658
|
}
|
|
7005
7659
|
};
|
|
7006
7660
|
this.on("task.completed", handler);
|
|
@@ -7025,13 +7679,13 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
7025
7679
|
const done = new Set(completed.map((r) => r.taskId));
|
|
7026
7680
|
return { completed, pending: taskIds.filter((id) => !done.has(id)) };
|
|
7027
7681
|
}
|
|
7028
|
-
return new Promise((
|
|
7682
|
+
return new Promise((resolve7) => {
|
|
7029
7683
|
let timer;
|
|
7030
7684
|
const handler = ({ result }) => {
|
|
7031
7685
|
if (!ids.has(result.taskId)) return;
|
|
7032
7686
|
if (timer) clearTimeout(timer);
|
|
7033
7687
|
this.off("task.completed", handler);
|
|
7034
|
-
|
|
7688
|
+
resolve7({
|
|
7035
7689
|
completed: [result],
|
|
7036
7690
|
pending: taskIds.filter((id) => id !== result.taskId)
|
|
7037
7691
|
});
|
|
@@ -7039,7 +7693,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
7039
7693
|
if (opts?.timeoutMs !== void 0) {
|
|
7040
7694
|
timer = setTimeout(() => {
|
|
7041
7695
|
this.off("task.completed", handler);
|
|
7042
|
-
|
|
7696
|
+
resolve7({ completed: [], pending: [...taskIds], timedOut: true });
|
|
7043
7697
|
}, opts.timeoutMs);
|
|
7044
7698
|
}
|
|
7045
7699
|
this.on("task.completed", handler);
|
|
@@ -7309,12 +7963,12 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
7309
7963
|
}
|
|
7310
7964
|
return new Promise((resolveDecision) => {
|
|
7311
7965
|
let settled = false;
|
|
7312
|
-
const
|
|
7966
|
+
const resolve7 = (d) => {
|
|
7313
7967
|
if (settled) return;
|
|
7314
7968
|
settled = true;
|
|
7315
7969
|
resolveDecision(d);
|
|
7316
7970
|
};
|
|
7317
|
-
const fallback = setTimeout(() =>
|
|
7971
|
+
const fallback = setTimeout(() => resolve7("stop"), DECISION_TIMEOUT_MS);
|
|
7318
7972
|
const sessionId = this.currentSessionId();
|
|
7319
7973
|
budget._events?.emit("budget.threshold_reached", {
|
|
7320
7974
|
...sessionId ? { sessionId } : {},
|
|
@@ -7332,11 +7986,11 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
7332
7986
|
// disagreeing, resolves as a stop). Async grants still resolve.
|
|
7333
7987
|
extend: (extra) => {
|
|
7334
7988
|
clearTimeout(fallback);
|
|
7335
|
-
queueMicrotask(() =>
|
|
7989
|
+
queueMicrotask(() => resolve7({ extend: extra }));
|
|
7336
7990
|
},
|
|
7337
7991
|
deny: () => {
|
|
7338
7992
|
clearTimeout(fallback);
|
|
7339
|
-
|
|
7993
|
+
resolve7("stop");
|
|
7340
7994
|
}
|
|
7341
7995
|
});
|
|
7342
7996
|
});
|
|
@@ -8646,7 +9300,7 @@ var Director = class _Director {
|
|
|
8646
9300
|
})),
|
|
8647
9301
|
usage: this.usage.snapshot()
|
|
8648
9302
|
};
|
|
8649
|
-
await fsp7.mkdir(
|
|
9303
|
+
await fsp7.mkdir(path10.dirname(this.manifestPath), { recursive: true });
|
|
8650
9304
|
await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
|
|
8651
9305
|
return this.manifestPath;
|
|
8652
9306
|
}
|
|
@@ -8800,11 +9454,11 @@ var Director = class _Director {
|
|
|
8800
9454
|
if (cached) return cached;
|
|
8801
9455
|
const existing = this.taskWaiters.get(id);
|
|
8802
9456
|
if (existing) return existing.promise;
|
|
8803
|
-
let
|
|
9457
|
+
let resolve7;
|
|
8804
9458
|
const promise = new Promise((res) => {
|
|
8805
|
-
|
|
9459
|
+
resolve7 = res;
|
|
8806
9460
|
});
|
|
8807
|
-
this.taskWaiters.set(id, { promise, resolve:
|
|
9461
|
+
this.taskWaiters.set(id, { promise, resolve: resolve7 });
|
|
8808
9462
|
return promise;
|
|
8809
9463
|
})
|
|
8810
9464
|
);
|
|
@@ -8833,10 +9487,10 @@ var Director = class _Director {
|
|
|
8833
9487
|
pending: taskIds.filter((id) => !done.has(id))
|
|
8834
9488
|
});
|
|
8835
9489
|
}
|
|
8836
|
-
return new Promise((
|
|
9490
|
+
return new Promise((resolve7) => {
|
|
8837
9491
|
const entry = {
|
|
8838
9492
|
ids: new Set(taskIds),
|
|
8839
|
-
resolve: (r) =>
|
|
9493
|
+
resolve: (r) => resolve7({
|
|
8840
9494
|
completed: [r],
|
|
8841
9495
|
pending: taskIds.filter((id) => id !== r.taskId)
|
|
8842
9496
|
})
|
|
@@ -8844,7 +9498,7 @@ var Director = class _Director {
|
|
|
8844
9498
|
if (opts?.timeoutMs !== void 0) {
|
|
8845
9499
|
entry.timer = setTimeout(() => {
|
|
8846
9500
|
this.anyWaiters.delete(entry);
|
|
8847
|
-
|
|
9501
|
+
resolve7({ completed: [], pending: [...taskIds], timedOut: true });
|
|
8848
9502
|
}, opts.timeoutMs);
|
|
8849
9503
|
}
|
|
8850
9504
|
this.anyWaiters.add(entry);
|
|
@@ -8966,7 +9620,7 @@ var Director = class _Director {
|
|
|
8966
9620
|
*/
|
|
8967
9621
|
async readSession(subagentId, tail) {
|
|
8968
9622
|
if (!this.sessionsRoot) return null;
|
|
8969
|
-
const filePath =
|
|
9623
|
+
const filePath = path10.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
|
|
8970
9624
|
let raw;
|
|
8971
9625
|
try {
|
|
8972
9626
|
raw = await fsp7.readFile(filePath, "utf8");
|
|
@@ -9076,6 +9730,7 @@ var Director = class _Director {
|
|
|
9076
9730
|
const t = [
|
|
9077
9731
|
makeSpawnTool(this, effectiveRoster),
|
|
9078
9732
|
makeAssignTool(this),
|
|
9733
|
+
makeKanbanQueueTool(this, effectiveRoster),
|
|
9079
9734
|
makeAwaitTasksTool(this),
|
|
9080
9735
|
makeAskTool(this),
|
|
9081
9736
|
makeAskResultTool(this),
|
|
@@ -9148,7 +9803,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9148
9803
|
this.meta = meta;
|
|
9149
9804
|
this.events = events;
|
|
9150
9805
|
this.resumed = opts.resumed ?? false;
|
|
9151
|
-
this.manifestFile = opts.dir ?
|
|
9806
|
+
this.manifestFile = opts.dir ? path10.join(opts.dir, `${path10.basename(id)}.summary.json`) : "";
|
|
9152
9807
|
this.filePath = opts.filePath ?? "";
|
|
9153
9808
|
this.secretScrubber = opts.secretScrubber;
|
|
9154
9809
|
this.onCloseCb = opts.onClose;
|
|
@@ -9883,17 +10538,17 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
9883
10538
|
}
|
|
9884
10539
|
/** Absolute path to the session index file. */
|
|
9885
10540
|
get indexFile() {
|
|
9886
|
-
return
|
|
10541
|
+
return path10.join(this.dir, "_index.jsonl");
|
|
9887
10542
|
}
|
|
9888
10543
|
/** Join session ID to its absolute path within the store directory. */
|
|
9889
10544
|
sessionPath(id, ext) {
|
|
9890
10545
|
return sessionScopedPath(this.dir, id, ext);
|
|
9891
10546
|
}
|
|
9892
10547
|
shardManifestPath(shardKey) {
|
|
9893
|
-
return shardKey ?
|
|
10548
|
+
return shardKey ? path10.join(this.dir, shardKey, "_manifest.json") : path10.join(this.dir, "_manifest.json");
|
|
9894
10549
|
}
|
|
9895
10550
|
shardKeyForSessionId(id) {
|
|
9896
|
-
const dirName =
|
|
10551
|
+
const dirName = path10.dirname(id);
|
|
9897
10552
|
return dirName === "." ? "" : dirName;
|
|
9898
10553
|
}
|
|
9899
10554
|
invalidateShardManifestBySessionId(id) {
|
|
@@ -9905,7 +10560,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
9905
10560
|
* subdirectory so sessions group naturally by day.
|
|
9906
10561
|
*/
|
|
9907
10562
|
async ensureShardDir(id) {
|
|
9908
|
-
const dirPath =
|
|
10563
|
+
const dirPath = path10.dirname(sessionScopedPath(this.dir, id, ""));
|
|
9909
10564
|
await ensureDir(dirPath);
|
|
9910
10565
|
return dirPath;
|
|
9911
10566
|
}
|
|
@@ -9975,7 +10630,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
9975
10630
|
// Shard directory (sessions/<date>/) — must match create() so the
|
|
9976
10631
|
// .summary.json sidecar lands next to the JSONL instead of the
|
|
9977
10632
|
// sessions root (where summaryFor() would never find it).
|
|
9978
|
-
dir:
|
|
10633
|
+
dir: path10.dirname(file),
|
|
9979
10634
|
filePath: file,
|
|
9980
10635
|
secretScrubber: this.secretScrubber,
|
|
9981
10636
|
onClose: (s) => this.appendToIndex(s)
|
|
@@ -10022,9 +10677,9 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10022
10677
|
let cacheHit = false;
|
|
10023
10678
|
try {
|
|
10024
10679
|
const s = await fsp7.stat(file);
|
|
10025
|
-
const
|
|
10680
|
+
const stat8 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
10026
10681
|
const cached = this._loadCache.get(id);
|
|
10027
|
-
if (cached && cached.mtimeMs ===
|
|
10682
|
+
if (cached && cached.mtimeMs === stat8.mtimeMs && cached.size === stat8.size) {
|
|
10028
10683
|
cacheHit = true;
|
|
10029
10684
|
this._loadCache.delete(id);
|
|
10030
10685
|
this._loadCache.set(id, cached);
|
|
@@ -10147,7 +10802,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10147
10802
|
this._loadCache.delete(oldest);
|
|
10148
10803
|
}
|
|
10149
10804
|
}
|
|
10150
|
-
this._loadCache.set(id, { mtimeMs:
|
|
10805
|
+
this._loadCache.set(id, { mtimeMs: stat8.mtimeMs, size: stat8.size, data });
|
|
10151
10806
|
}
|
|
10152
10807
|
return data;
|
|
10153
10808
|
} catch (err) {
|
|
@@ -10189,14 +10844,14 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10189
10844
|
const limit = opts?.limit;
|
|
10190
10845
|
const signal = opts?.signal;
|
|
10191
10846
|
const out = [];
|
|
10192
|
-
let
|
|
10847
|
+
let stat8;
|
|
10193
10848
|
try {
|
|
10194
|
-
|
|
10849
|
+
stat8 = await fsp7.stat(file);
|
|
10195
10850
|
} catch (err) {
|
|
10196
10851
|
if (err.code === "ENOENT") return [];
|
|
10197
10852
|
throw err;
|
|
10198
10853
|
}
|
|
10199
|
-
if (
|
|
10854
|
+
if (stat8.size === 0) return [];
|
|
10200
10855
|
let fh;
|
|
10201
10856
|
try {
|
|
10202
10857
|
fh = await fsp7.open(file, "r");
|
|
@@ -10379,15 +11034,15 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10379
11034
|
* Returns empty array when the index doesn't exist or is corrupt.
|
|
10380
11035
|
*/
|
|
10381
11036
|
async readIndex() {
|
|
10382
|
-
let
|
|
11037
|
+
let stat8;
|
|
10383
11038
|
try {
|
|
10384
11039
|
const s = await fsp7.stat(this.indexFile);
|
|
10385
|
-
|
|
11040
|
+
stat8 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
10386
11041
|
} catch {
|
|
10387
11042
|
this._indexCache = null;
|
|
10388
11043
|
return [];
|
|
10389
11044
|
}
|
|
10390
|
-
if (this._indexCache !== null && this._indexCache.mtimeMs ===
|
|
11045
|
+
if (this._indexCache !== null && this._indexCache.mtimeMs === stat8.mtimeMs && this._indexCache.size === stat8.size) {
|
|
10391
11046
|
return [...this._indexCache.summaries];
|
|
10392
11047
|
}
|
|
10393
11048
|
let raw;
|
|
@@ -10420,7 +11075,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10420
11075
|
if (a.startedAt > b.startedAt) return -1;
|
|
10421
11076
|
return a.id.localeCompare(b.id);
|
|
10422
11077
|
});
|
|
10423
|
-
this._indexCache = { ...
|
|
11078
|
+
this._indexCache = { ...stat8, summaries };
|
|
10424
11079
|
return [...summaries];
|
|
10425
11080
|
}
|
|
10426
11081
|
/**
|
|
@@ -10511,7 +11166,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10511
11166
|
return entry;
|
|
10512
11167
|
}
|
|
10513
11168
|
async collectSessionFilesInShard(shardKey) {
|
|
10514
|
-
const dir = shardKey ?
|
|
11169
|
+
const dir = shardKey ? path10.join(this.dir, shardKey) : this.dir;
|
|
10515
11170
|
const entries = await this.collectSessionFiles(dir, shardKey);
|
|
10516
11171
|
return shardKey ? entries.filter((entry) => entry.id.startsWith(`${shardKey}/`)) : entries.filter((entry) => !entry.id.includes("/"));
|
|
10517
11172
|
}
|
|
@@ -10534,13 +11189,13 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10534
11189
|
if (entry.name === "_index.jsonl") continue;
|
|
10535
11190
|
const base = entry.name.replace(/\.jsonl$/, "");
|
|
10536
11191
|
const id = prefix ? `${prefix}/${base}` : base;
|
|
10537
|
-
files.push({ id, filePath:
|
|
11192
|
+
files.push({ id, filePath: path10.join(dir, entry.name) });
|
|
10538
11193
|
}
|
|
10539
11194
|
}
|
|
10540
11195
|
const childFileArrays = await Promise.all(
|
|
10541
11196
|
dirEntries.map((entry) => {
|
|
10542
11197
|
const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
|
|
10543
|
-
return this.collectSessionFiles(
|
|
11198
|
+
return this.collectSessionFiles(path10.join(dir, entry.name), childPrefix, depth + 1);
|
|
10544
11199
|
})
|
|
10545
11200
|
);
|
|
10546
11201
|
return [...childFileArrays.flat(), ...files];
|
|
@@ -10573,7 +11228,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10573
11228
|
const childIdArrays = await Promise.all(
|
|
10574
11229
|
dirEntries.map((entry) => {
|
|
10575
11230
|
const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
|
|
10576
|
-
return this.collectSessionIds(
|
|
11231
|
+
return this.collectSessionIds(path10.join(dir, entry.name), childPrefix, depth + 1);
|
|
10577
11232
|
})
|
|
10578
11233
|
);
|
|
10579
11234
|
return [...childIdArrays.flat(), ...fileIds];
|
|
@@ -10587,8 +11242,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10587
11242
|
if (fromManifest) return fromManifest;
|
|
10588
11243
|
try {
|
|
10589
11244
|
const full = this.sessionPath(id, ".jsonl");
|
|
10590
|
-
const
|
|
10591
|
-
const summary = await this.summarize(id,
|
|
11245
|
+
const stat8 = await fsp7.stat(full);
|
|
11246
|
+
const summary = await this.summarize(id, stat8.mtime.toISOString());
|
|
10592
11247
|
await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
|
|
10593
11248
|
const msg = toErrorMessage(err);
|
|
10594
11249
|
this.emitError(id, manifest, "summary_fallback", msg, true);
|
|
@@ -10631,18 +11286,18 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10631
11286
|
async summaryHeaderFor(ref) {
|
|
10632
11287
|
let mtime = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
10633
11288
|
try {
|
|
10634
|
-
const
|
|
10635
|
-
if (!
|
|
11289
|
+
const stat8 = await fsp7.stat(ref.filePath);
|
|
11290
|
+
if (!stat8.isFile()) {
|
|
10636
11291
|
return {
|
|
10637
11292
|
id: ref.id,
|
|
10638
11293
|
title: "(damaged)",
|
|
10639
|
-
startedAt:
|
|
11294
|
+
startedAt: stat8.mtime.toISOString(),
|
|
10640
11295
|
model: "unknown",
|
|
10641
11296
|
provider: "unknown",
|
|
10642
11297
|
tokenTotal: 0
|
|
10643
11298
|
};
|
|
10644
11299
|
}
|
|
10645
|
-
mtime =
|
|
11300
|
+
mtime = stat8.mtime.toISOString();
|
|
10646
11301
|
} catch {
|
|
10647
11302
|
return null;
|
|
10648
11303
|
}
|
|
@@ -10690,9 +11345,9 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10690
11345
|
async deleteSession(id) {
|
|
10691
11346
|
const jsonlPath = this.sessionPath(id, ".jsonl");
|
|
10692
11347
|
const summaryPath = this.sessionPath(id, ".summary.json");
|
|
10693
|
-
const shardDir =
|
|
10694
|
-
const base =
|
|
10695
|
-
const sessDir =
|
|
11348
|
+
const shardDir = path10.dirname(jsonlPath);
|
|
11349
|
+
const base = path10.basename(id);
|
|
11350
|
+
const sessDir = path10.join(shardDir, base);
|
|
10696
11351
|
const deletions = [
|
|
10697
11352
|
fsp7.unlink(jsonlPath),
|
|
10698
11353
|
fsp7.unlink(summaryPath),
|
|
@@ -10733,7 +11388,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10733
11388
|
*/
|
|
10734
11389
|
async readActiveSessionId() {
|
|
10735
11390
|
try {
|
|
10736
|
-
const raw = await fsp7.readFile(
|
|
11391
|
+
const raw = await fsp7.readFile(path10.join(this.dir, "active.json"), "utf8");
|
|
10737
11392
|
const active = JSON.parse(raw);
|
|
10738
11393
|
return active.sessionId ?? null;
|
|
10739
11394
|
} catch {
|
|
@@ -10796,10 +11451,10 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10796
11451
|
const activeSessionId = await this.readActiveSessionId();
|
|
10797
11452
|
const isPrunableJsonl = (name) => name.endsWith(".jsonl") && name !== "_index.jsonl" && name !== "_mailbox.jsonl" && !name.endsWith(".replay.jsonl") && !name.endsWith(".audit.jsonl");
|
|
10798
11453
|
const pruneFile = async (dir, name, prefix) => {
|
|
10799
|
-
const jsonlPath =
|
|
11454
|
+
const jsonlPath = path10.join(dir, name);
|
|
10800
11455
|
try {
|
|
10801
|
-
const
|
|
10802
|
-
if (
|
|
11456
|
+
const stat8 = await fsp7.stat(jsonlPath);
|
|
11457
|
+
if (stat8.mtimeMs >= cutoff) return;
|
|
10803
11458
|
} catch {
|
|
10804
11459
|
return;
|
|
10805
11460
|
}
|
|
@@ -10816,7 +11471,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10816
11471
|
continue;
|
|
10817
11472
|
}
|
|
10818
11473
|
if (!entry.isDirectory()) continue;
|
|
10819
|
-
const dateDir =
|
|
11474
|
+
const dateDir = path10.join(this.dir, entry.name);
|
|
10820
11475
|
const files = await fsp7.readdir(dateDir, { withFileTypes: true }).catch(() => []);
|
|
10821
11476
|
for (const file of files) {
|
|
10822
11477
|
if (!file.isFile() || !isPrunableJsonl(file.name)) continue;
|
|
@@ -10828,7 +11483,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
10828
11483
|
}
|
|
10829
11484
|
for (const entry of entries) {
|
|
10830
11485
|
if (!entry.isDirectory()) continue;
|
|
10831
|
-
const dateDir =
|
|
11486
|
+
const dateDir = path10.join(this.dir, entry.name);
|
|
10832
11487
|
try {
|
|
10833
11488
|
const remaining = await fsp7.readdir(dateDir);
|
|
10834
11489
|
if (remaining.length === 0) {
|
|
@@ -10959,9 +11614,9 @@ function makeDirectorSessionFactory(opts) {
|
|
|
10959
11614
|
let dir;
|
|
10960
11615
|
if (opts.store) {
|
|
10961
11616
|
store = opts.store;
|
|
10962
|
-
dir = opts.sessionsRoot ?
|
|
11617
|
+
dir = opts.sessionsRoot ? path10.join(opts.sessionsRoot, runId) : "(caller-managed)";
|
|
10963
11618
|
} else if (opts.sessionsRoot) {
|
|
10964
|
-
dir =
|
|
11619
|
+
dir = path10.join(opts.sessionsRoot, runId);
|
|
10965
11620
|
store = new DefaultSessionStore({ dir });
|
|
10966
11621
|
} else {
|
|
10967
11622
|
throw new Error("makeDirectorSessionFactory requires either `store` or `sessionsRoot`");
|
|
@@ -11217,7 +11872,7 @@ var FleetManager = class {
|
|
|
11217
11872
|
})),
|
|
11218
11873
|
usage: this.usage.snapshot()
|
|
11219
11874
|
};
|
|
11220
|
-
await fsp7.mkdir(
|
|
11875
|
+
await fsp7.mkdir(path10.dirname(this.manifestPath), { recursive: true });
|
|
11221
11876
|
await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
|
|
11222
11877
|
return this.manifestPath;
|
|
11223
11878
|
}
|
|
@@ -11370,7 +12025,7 @@ var REGISTRY_CACHE_TTL_MS = 2e3;
|
|
|
11370
12025
|
var LINE_SEPARATOR = "\n";
|
|
11371
12026
|
var MESSAGE_CACHE_MAX_ENTRIES = 1e4;
|
|
11372
12027
|
function resolveProjectDir(projectRoot, globalRoot) {
|
|
11373
|
-
return
|
|
12028
|
+
return path10.join(globalRoot, "projects", projectSlug(projectRoot));
|
|
11374
12029
|
}
|
|
11375
12030
|
var GlobalMailbox = class {
|
|
11376
12031
|
/** Path to the JSONL message file. */
|
|
@@ -11423,14 +12078,14 @@ var GlobalMailbox = class {
|
|
|
11423
12078
|
* @param hqPublisher — optional HQ publisher, or getter, for cross-project telemetry
|
|
11424
12079
|
*/
|
|
11425
12080
|
constructor(projectDir, events, hqPublisher) {
|
|
11426
|
-
this.messagePath =
|
|
11427
|
-
this.registryPath =
|
|
11428
|
-
this.clientRegistryPath =
|
|
12081
|
+
this.messagePath = path10.join(projectDir, MAILBOX_FILE);
|
|
12082
|
+
this.registryPath = path10.join(projectDir, "_mailbox.registry.json");
|
|
12083
|
+
this.clientRegistryPath = path10.join(projectDir, CLIENT_REGISTRY_FILE);
|
|
11429
12084
|
this._events = events;
|
|
11430
12085
|
this._hqPublisher = hqPublisher;
|
|
11431
12086
|
}
|
|
11432
12087
|
get hqMailboxId() {
|
|
11433
|
-
return `${
|
|
12088
|
+
return `${path10.basename(path10.dirname(this.messagePath))}:mailbox`;
|
|
11434
12089
|
}
|
|
11435
12090
|
get hqPublisher() {
|
|
11436
12091
|
return typeof this._hqPublisher === "function" ? this._hqPublisher() : this._hqPublisher;
|
|
@@ -11467,7 +12122,7 @@ var GlobalMailbox = class {
|
|
|
11467
12122
|
taskContext: input.taskContext
|
|
11468
12123
|
};
|
|
11469
12124
|
const line = JSON.stringify(msg) + LINE_SEPARATOR;
|
|
11470
|
-
await fsp7.mkdir(
|
|
12125
|
+
await fsp7.mkdir(path10.dirname(this.messagePath), { recursive: true });
|
|
11471
12126
|
await withFileLock(this.messagePath, async () => {
|
|
11472
12127
|
await fsp7.appendFile(this.messagePath, line, "utf8");
|
|
11473
12128
|
this._pushToCache(msg);
|
|
@@ -12065,7 +12720,7 @@ var GlobalMailbox = class {
|
|
|
12065
12720
|
this._messageCache.push(msg);
|
|
12066
12721
|
}
|
|
12067
12722
|
async _ensureRegistry() {
|
|
12068
|
-
await fsp7.mkdir(
|
|
12723
|
+
await fsp7.mkdir(path10.dirname(this.registryPath), { recursive: true });
|
|
12069
12724
|
}
|
|
12070
12725
|
async _readRegistry(opts) {
|
|
12071
12726
|
if (!opts?.fresh && this._registryCache && Date.now() - this._registryCacheAt < REGISTRY_CACHE_TTL_MS) {
|
|
@@ -12120,7 +12775,7 @@ var GlobalMailbox = class {
|
|
|
12120
12775
|
}
|
|
12121
12776
|
// ── Client registry internals ───────────────────────────────────────────
|
|
12122
12777
|
async _ensureClientRegistry() {
|
|
12123
|
-
await fsp7.mkdir(
|
|
12778
|
+
await fsp7.mkdir(path10.dirname(this.clientRegistryPath), { recursive: true });
|
|
12124
12779
|
}
|
|
12125
12780
|
async _readClientRegistry(opts) {
|
|
12126
12781
|
if (!opts?.fresh && this._clientRegistryCache && Date.now() - this._clientRegistryCacheAt < REGISTRY_CACHE_TTL_MS) {
|
|
@@ -13256,7 +13911,7 @@ var DefaultMailbox = class {
|
|
|
13256
13911
|
/** Counts malformed JSONL lines skipped during parsing for observability. */
|
|
13257
13912
|
_corruptionCount = 0;
|
|
13258
13913
|
constructor(sessionDir) {
|
|
13259
|
-
this.filePath =
|
|
13914
|
+
this.filePath = path10.join(sessionDir, MAILBOX_FILE2);
|
|
13260
13915
|
}
|
|
13261
13916
|
get mailboxPath() {
|
|
13262
13917
|
return this.filePath;
|
|
@@ -13285,7 +13940,7 @@ var DefaultMailbox = class {
|
|
|
13285
13940
|
taskContext: input.taskContext
|
|
13286
13941
|
};
|
|
13287
13942
|
const line = JSON.stringify(msg) + LINE_SEPARATOR2;
|
|
13288
|
-
await fsp7.mkdir(
|
|
13943
|
+
await fsp7.mkdir(path10.dirname(this.filePath), { recursive: true });
|
|
13289
13944
|
await withFileLock(this.filePath, async () => {
|
|
13290
13945
|
await fsp7.appendFile(this.filePath, line, "utf8");
|
|
13291
13946
|
this._pushToCache(msg);
|
|
@@ -13937,7 +14592,7 @@ var NULL_FLEET_BUS = new FleetBus();
|
|
|
13937
14592
|
var DEFAULT_MAX_ENTRIES = 1e4;
|
|
13938
14593
|
var LOG_FILENAME = "package-authors.json";
|
|
13939
14594
|
function logPath(storageDir) {
|
|
13940
|
-
return
|
|
14595
|
+
return path10.join(storageDir, LOG_FILENAME);
|
|
13941
14596
|
}
|
|
13942
14597
|
async function loadLog(storageDir, projectRoot) {
|
|
13943
14598
|
try {
|
|
@@ -13961,7 +14616,7 @@ async function saveLog(storageDir, log) {
|
|
|
13961
14616
|
await fsp7.rename(tmp, logPath(storageDir));
|
|
13962
14617
|
}
|
|
13963
14618
|
function detectEcosystem(manifestPath) {
|
|
13964
|
-
const name =
|
|
14619
|
+
const name = path10.basename(manifestPath).toLowerCase();
|
|
13965
14620
|
if (name === "package.json") return "npm";
|
|
13966
14621
|
if (name === "go.mod") return "go";
|
|
13967
14622
|
if (name === "cargo.toml") return "cargo";
|
|
@@ -14209,8 +14864,8 @@ mvn versions:use-latest-versions`;
|
|
|
14209
14864
|
var MAILBOX_BRIDGE_LOCK_FILENAME = ".mailbox-bridge.lock";
|
|
14210
14865
|
var MAILBOX_BRIDGE_TOKEN_FILENAME = ".mailbox.token";
|
|
14211
14866
|
async function acquireOrJoin(opts) {
|
|
14212
|
-
const lockPath =
|
|
14213
|
-
const tokenPath =
|
|
14867
|
+
const lockPath = path10.join(opts.projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
|
|
14868
|
+
const tokenPath = path10.join(opts.projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
|
|
14214
14869
|
const inspected = await readLockForInspection(lockPath);
|
|
14215
14870
|
if (inspected.kind === "live") {
|
|
14216
14871
|
const existing = inspected.lock;
|
|
@@ -14238,8 +14893,8 @@ async function acquireOrJoin(opts) {
|
|
|
14238
14893
|
return { kind: "acquired", lock: tentative, tokenPath };
|
|
14239
14894
|
}
|
|
14240
14895
|
async function finalize(projectDir, tentative, boundPort) {
|
|
14241
|
-
const lockPath =
|
|
14242
|
-
const tokenPath =
|
|
14896
|
+
const lockPath = path10.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
|
|
14897
|
+
const tokenPath = path10.join(projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
|
|
14243
14898
|
const finalized = {
|
|
14244
14899
|
...tentative,
|
|
14245
14900
|
port: boundPort,
|
|
@@ -14250,8 +14905,8 @@ async function finalize(projectDir, tentative, boundPort) {
|
|
|
14250
14905
|
return finalized;
|
|
14251
14906
|
}
|
|
14252
14907
|
async function release(projectDir, generation) {
|
|
14253
|
-
const lockPath =
|
|
14254
|
-
const tokenPath =
|
|
14908
|
+
const lockPath = path10.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
|
|
14909
|
+
const tokenPath = path10.join(projectDir, MAILBOX_BRIDGE_TOKEN_FILENAME);
|
|
14255
14910
|
try {
|
|
14256
14911
|
const raw = await fsp7.readFile(lockPath, "utf-8");
|
|
14257
14912
|
const parsed = JSON.parse(raw);
|
|
@@ -14285,7 +14940,7 @@ async function readLockForInspection(lockPath) {
|
|
|
14285
14940
|
return { kind: "live", lock: parsed };
|
|
14286
14941
|
}
|
|
14287
14942
|
async function readLiveLock(projectDir) {
|
|
14288
|
-
const lockPath =
|
|
14943
|
+
const lockPath = path10.join(projectDir, MAILBOX_BRIDGE_LOCK_FILENAME);
|
|
14289
14944
|
const result = await readLockForInspection(lockPath);
|
|
14290
14945
|
if (result.kind === "live") {
|
|
14291
14946
|
return { kind: "live", lock: result.lock };
|
|
@@ -14296,7 +14951,7 @@ async function readLiveLock(projectDir) {
|
|
|
14296
14951
|
return { kind: "absent" };
|
|
14297
14952
|
}
|
|
14298
14953
|
async function atomicWriteJson(targetPath, value) {
|
|
14299
|
-
const dir =
|
|
14954
|
+
const dir = path10.dirname(targetPath);
|
|
14300
14955
|
await fsp7.mkdir(dir, { recursive: true });
|
|
14301
14956
|
const tmp = `${targetPath}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
|
|
14302
14957
|
const body = JSON.stringify(value, null, 2) + "\n";
|
|
@@ -14768,9 +15423,9 @@ var AgentMonitorService = class {
|
|
|
14768
15423
|
this._onEntry?.(entry);
|
|
14769
15424
|
}
|
|
14770
15425
|
async _appendToFile(subagentId, entry) {
|
|
14771
|
-
const dir =
|
|
15426
|
+
const dir = path10.join(this._transcriptsDir, subagentId);
|
|
14772
15427
|
await fsp7.mkdir(dir, { recursive: true });
|
|
14773
|
-
const filePath =
|
|
15428
|
+
const filePath = path10.join(dir, "transcript.jsonl");
|
|
14774
15429
|
const line = JSON.stringify(entry) + "\n";
|
|
14775
15430
|
await fsp7.appendFile(filePath, line, { encoding: "utf8" });
|
|
14776
15431
|
}
|
|
@@ -15176,8 +15831,8 @@ var KnowledgeGraph = class {
|
|
|
15176
15831
|
return this.index;
|
|
15177
15832
|
}
|
|
15178
15833
|
constructor(sessionDir) {
|
|
15179
|
-
this.filePath =
|
|
15180
|
-
this.graphFilePath =
|
|
15834
|
+
this.filePath = path10.join(sessionDir, "_knowledge_graph");
|
|
15835
|
+
this.graphFilePath = path10.join(this.filePath, "graph.jsonl");
|
|
15181
15836
|
}
|
|
15182
15837
|
// ── Write ──────────────────────────────────────────────────────────────
|
|
15183
15838
|
/**
|
|
@@ -16807,7 +17462,15 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
|
|
|
16807
17462
|
stop() {
|
|
16808
17463
|
if (!this.running) return;
|
|
16809
17464
|
this.running = false;
|
|
16810
|
-
console.error(
|
|
17465
|
+
console.error(
|
|
17466
|
+
JSON.stringify({
|
|
17467
|
+
level: "error",
|
|
17468
|
+
event: "autonomous_coordinator.stop_signal",
|
|
17469
|
+
message: "stop signal received \u2014 shutting down",
|
|
17470
|
+
iteration: this.iterationCount,
|
|
17471
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17472
|
+
})
|
|
17473
|
+
);
|
|
16811
17474
|
}
|
|
16812
17475
|
/**
|
|
16813
17476
|
* Report that a terminal worker (not a Director subagent) completed a claimed
|
|
@@ -16957,17 +17620,17 @@ ${input.detail}`
|
|
|
16957
17620
|
_waitForDagProgress(timeoutMs) {
|
|
16958
17621
|
const before = this._dagProgressKey();
|
|
16959
17622
|
if (this.dag.isDone()) return Promise.resolve();
|
|
16960
|
-
return new Promise((
|
|
17623
|
+
return new Promise((resolve7) => {
|
|
16961
17624
|
let off;
|
|
16962
17625
|
const timer = setTimeout(() => {
|
|
16963
17626
|
off?.();
|
|
16964
|
-
|
|
17627
|
+
resolve7();
|
|
16965
17628
|
}, timeoutMs);
|
|
16966
17629
|
off = this.dag.onEvent(() => {
|
|
16967
17630
|
if (this._dagProgressKey() === before) return;
|
|
16968
17631
|
clearTimeout(timer);
|
|
16969
17632
|
off?.();
|
|
16970
|
-
|
|
17633
|
+
resolve7();
|
|
16971
17634
|
});
|
|
16972
17635
|
});
|
|
16973
17636
|
}
|
|
@@ -17242,6 +17905,6 @@ ${input.detail}`
|
|
|
17242
17905
|
}
|
|
17243
17906
|
};
|
|
17244
17907
|
|
|
17245
|
-
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AdaptiveConcurrencyController, AgentMonitorService, AutonomousBrain, AutonomousCoordinator, BUG_HUNTER_AGENT, BUILD_AGENTS, BrainDecisionQueue, BrainMonitor, BudgetExceededError, BudgetThresholdSignal, ChangeManager, CollabSession, ConsensusProtocol, DECISION_TIMEOUT_MS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_QUALITY_CHECKS, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultBrainArbiter, DefaultMailbox, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetSupervisor, FleetUsageAggregator, GlobalMailbox, HEAVY_BUDGET, HumanEscalatingBrainArbiter, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, KnowledgeGraph, LIGHT_BUDGET, LargeAnswerStore, MAILBOX_BRIDGE_LOCK_FILENAME, MAILBOX_BRIDGE_TOKEN_FILENAME, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, MATRIX_PHASE_KEYS, MEDIUM_BUDGET, META_AGENTS, MailboxHealthWatchdog, NULL_FLEET_BUS, ObservableBrainArbiter, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, TIMEOUT_PREEMPT_FRACTION, TaskAuctioneer, TaskDAG, VERIFY_AGENTS, WorktreeIntegrationError, acquireOrJoin, actionToAckInput, applyRosterBudget, attachAutoExtend, attachDepWatcherBridge, buildDownAlert, buildRecoveryAlert, composeDirectorPrompt, composeSubagentPrompt, createAgentMonitorService, createDelegateTool, createMailboxHooks, createMessage, detectEcosystem, dispatchAgent, finalize, formatHumanPrompt, getAgentDefinition, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, isValidMatrixKey, mailboxSessionTag, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetTool as makeFleetHealthTool, makeFleetTool as makeFleetSessionTool, makeFleetStatusTool, makeFleetTool, makeFleetTool as makeFleetUsageTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeQualityGateTool, makeRollUpTool, makeSpawnTool, makeTerminateAllTool, makeTerminateTool, makeWorkCompleteTool, matrixKeyKind, normalizeRecipient, phaseForRole, readLiveLock, recordPackageAction, release, resolveImplementationModelTarget, resolveMailboxIdentity, resolveModelMatrix, resolveModelMatrixResolution, resolveModelTargetFromEntry, resolveProjectDir, resolveSubagentModelTarget, resolveSubagentWorktreeDecision, roleNeedsIndependentReviewModel, rosterSummaryFromConfigs, sameModelReference, scoreAgents, startPackageOutdatedWatcher, subagentNeedsWorktree, updatePackageOutdatedStatus, validateWatchdogOptions, withDisabledToolFiltering, wrapSubagentRunnerWithWorktrees };
|
|
17908
|
+
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AdaptiveConcurrencyController, AgentMonitorService, AutonomousBrain, AutonomousCoordinator, BUG_HUNTER_AGENT, BUILD_AGENTS, BrainDecisionQueue, BrainMonitor, BudgetExceededError, BudgetThresholdSignal, ChangeManager, CollabSession, ConsensusProtocol, DECISION_TIMEOUT_MS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_QUALITY_CHECKS, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultBrainArbiter, DefaultMailbox, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetSupervisor, FleetUsageAggregator, GlobalMailbox, HEAVY_BUDGET, HumanEscalatingBrainArbiter, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, KnowledgeGraph, LIGHT_BUDGET, LargeAnswerStore, MAILBOX_BRIDGE_LOCK_FILENAME, MAILBOX_BRIDGE_TOKEN_FILENAME, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, MATRIX_PHASE_KEYS, MEDIUM_BUDGET, META_AGENTS, MailboxHealthWatchdog, NULL_FLEET_BUS, ObservableBrainArbiter, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, TIMEOUT_PREEMPT_FRACTION, TaskAuctioneer, TaskDAG, VERIFY_AGENTS, WorktreeIntegrationError, acquireOrJoin, actionToAckInput, applyRosterBudget, attachAutoExtend, attachDepWatcherBridge, buildDownAlert, buildRecoveryAlert, composeDirectorPrompt, composeSubagentPrompt, createAgentMonitorService, createDelegateTool, createMailboxHooks, createMessage, detectEcosystem, dispatchAgent, finalize, formatHumanPrompt, getAgentDefinition, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, isValidMatrixKey, mailboxSessionTag, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetTool as makeFleetHealthTool, makeFleetTool as makeFleetSessionTool, makeFleetStatusTool, makeFleetTool, makeFleetTool as makeFleetUsageTool, makeKanbanQueueTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeQualityGateTool, makeRollUpTool, makeSpawnTool, makeTerminateAllTool, makeTerminateTool, makeWorkCompleteTool, matrixKeyKind, normalizeRecipient, phaseForRole, readLiveLock, recordPackageAction, release, resolveImplementationModelTarget, resolveMailboxIdentity, resolveModelMatrix, resolveModelMatrixResolution, resolveModelTargetFromEntry, resolveProjectDir, resolveSubagentModelTarget, resolveSubagentWorktreeDecision, roleNeedsIndependentReviewModel, rosterSummaryFromConfigs, sameModelReference, scoreAgents, startPackageOutdatedWatcher, subagentNeedsWorktree, updatePackageOutdatedStatus, validateWatchdogOptions, withDisabledToolFiltering, wrapSubagentRunnerWithWorktrees };
|
|
17246
17909
|
//# sourceMappingURL=index.js.map
|
|
17247
17910
|
//# sourceMappingURL=index.js.map
|