@wrongstack/core 0.87.0 → 0.89.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/dist/{agent-bridge-C9P_HPez.d.ts → agent-bridge-B8F2ORwg.d.ts} +1 -1
- package/dist/{agent-subagent-runner-2Aq0jOSj.d.ts → agent-subagent-runner-CQaLFNnA.d.ts} +3 -2
- package/dist/coordination/index.d.ts +7 -7
- package/dist/coordination/index.js +183 -56
- package/dist/coordination/index.js.map +1 -1
- package/dist/{default-config-DEXI4jsl.d.ts → default-config-CXsDvOmP.d.ts} +3 -1
- package/dist/defaults/index.d.ts +10 -10
- package/dist/defaults/index.js +268 -68
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-DnRqXaZ3.d.ts → events-DzyLtja6.d.ts} +6 -0
- package/dist/execution/index.d.ts +5 -5
- package/dist/execution/index.js +56 -19
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +2 -2
- package/dist/{index-BNOLadHw.d.ts → index-Ca_lOmKl.d.ts} +2 -2
- package/dist/{index-N0_c4bHQ.d.ts → index-Dx-CnrDN.d.ts} +3 -1
- package/dist/index.d.ts +24 -21
- package/dist/index.js +448 -179
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +2 -2
- package/dist/infrastructure/index.js +12 -3
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +3 -3
- package/dist/kernel/index.js +17 -0
- package/dist/kernel/index.js.map +1 -1
- package/dist/models/index.js.map +1 -1
- package/dist/{multi-agent-coordinator-DllpCVkF.d.ts → multi-agent-coordinator-Da9nd8Ic.d.ts} +1 -1
- package/dist/{null-fleet-bus-BY0AN-sr.d.ts → null-fleet-bus-CHJOXv3t.d.ts} +11 -5
- package/dist/observability/index.d.ts +1 -1
- package/dist/{parallel-eternal-engine-D402RASp.d.ts → parallel-eternal-engine-DyMCj2Pw.d.ts} +4 -3
- package/dist/{path-resolver-UPFTsDyD.d.ts → path-resolver-TjBlRKyH.d.ts} +1 -1
- package/dist/{plan-templates-DRvPgkfZ.d.ts → plan-templates-D9UhwoGh.d.ts} +1 -1
- package/dist/{provider-runner-COAJM8tC.d.ts → provider-runner-BEPWwkxH.d.ts} +1 -1
- package/dist/sdd/index.d.ts +3 -3
- package/dist/sdd/index.js +89 -19
- package/dist/sdd/index.js.map +1 -1
- package/dist/security/index.js +18 -2
- package/dist/security/index.js.map +1 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +4 -4
- package/dist/storage/index.js +149 -90
- package/dist/storage/index.js.map +1 -1
- package/dist/types/index.d.ts +10 -10
- package/dist/types/index.js +44 -7
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +6 -1
- package/dist/utils/index.js +51 -3
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/defaults/index.js
CHANGED
|
@@ -29,7 +29,8 @@ var __export = (target, all) => {
|
|
|
29
29
|
var atomic_write_exports = {};
|
|
30
30
|
__export(atomic_write_exports, {
|
|
31
31
|
atomicWrite: () => atomicWrite,
|
|
32
|
-
ensureDir: () => ensureDir
|
|
32
|
+
ensureDir: () => ensureDir,
|
|
33
|
+
withFileLock: () => withFileLock
|
|
33
34
|
});
|
|
34
35
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
35
36
|
const dir = path3.dirname(targetPath);
|
|
@@ -52,8 +53,8 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
52
53
|
}
|
|
53
54
|
let mode;
|
|
54
55
|
try {
|
|
55
|
-
const
|
|
56
|
-
mode =
|
|
56
|
+
const stat6 = await fsp.stat(targetPath);
|
|
57
|
+
mode = stat6.mode & 511;
|
|
57
58
|
} catch {
|
|
58
59
|
mode = opts.mode;
|
|
59
60
|
}
|
|
@@ -72,6 +73,49 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
72
73
|
async function ensureDir(dir) {
|
|
73
74
|
await fsp.mkdir(dir, { recursive: true });
|
|
74
75
|
}
|
|
76
|
+
async function withFileLock(targetPath, fn, opts = {}) {
|
|
77
|
+
const dir = path3.dirname(targetPath);
|
|
78
|
+
await fsp.mkdir(dir, { recursive: true });
|
|
79
|
+
const lockPath = path3.join(dir, `.${path3.basename(targetPath)}.lock`);
|
|
80
|
+
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
81
|
+
const staleMs = opts.staleMs ?? 3e4;
|
|
82
|
+
const started = Date.now();
|
|
83
|
+
let handle;
|
|
84
|
+
for (; ; ) {
|
|
85
|
+
try {
|
|
86
|
+
handle = await fsp.open(lockPath, "wx");
|
|
87
|
+
await handle.writeFile(`${process.pid}:${Date.now()}`);
|
|
88
|
+
break;
|
|
89
|
+
} catch (err) {
|
|
90
|
+
if (err.code !== "EEXIST") throw err;
|
|
91
|
+
try {
|
|
92
|
+
const stat6 = await fsp.stat(lockPath);
|
|
93
|
+
if (Date.now() - stat6.mtimeMs > staleMs) {
|
|
94
|
+
await fsp.unlink(lockPath);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (Date.now() - started >= timeoutMs) {
|
|
101
|
+
throw new Error(`Timed out waiting for file lock: ${targetPath}`);
|
|
102
|
+
}
|
|
103
|
+
await new Promise((resolve5) => setTimeout(resolve5, 25));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
return await fn();
|
|
108
|
+
} finally {
|
|
109
|
+
try {
|
|
110
|
+
await handle?.close();
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
await fsp.unlink(lockPath);
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
75
119
|
async function renameWithRetry(from, to) {
|
|
76
120
|
if (process.platform !== "win32") {
|
|
77
121
|
await fsp.rename(from, to);
|
|
@@ -119,10 +163,15 @@ function writeErr(s, stream = process.stderr) {
|
|
|
119
163
|
|
|
120
164
|
// src/utils/color.ts
|
|
121
165
|
var isColorTty = () => {
|
|
122
|
-
if (process.env.NO_COLOR) return false;
|
|
123
|
-
if (process.env.FORCE_COLOR) return true;
|
|
166
|
+
if (envFlag(process.env.NO_COLOR)) return false;
|
|
167
|
+
if (envFlag(process.env.FORCE_COLOR)) return true;
|
|
124
168
|
return isStdoutTTY();
|
|
125
169
|
};
|
|
170
|
+
function envFlag(value) {
|
|
171
|
+
if (value === void 0) return false;
|
|
172
|
+
if (value.trim() === "") return false;
|
|
173
|
+
return !/^(0|false|no|off)$/i.test(value.trim());
|
|
174
|
+
}
|
|
126
175
|
var COLOR = isColorTty();
|
|
127
176
|
var wrap = (open3, close) => (s) => COLOR ? `\x1B[${open3}m${s}\x1B[${close}m` : s;
|
|
128
177
|
var color = {
|
|
@@ -159,6 +208,7 @@ var COLORS = {
|
|
|
159
208
|
debug: color.gray,
|
|
160
209
|
trace: color.dim
|
|
161
210
|
};
|
|
211
|
+
var LOG_LEVELS = /* @__PURE__ */ new Set(["error", "warn", "info", "debug", "trace"]);
|
|
162
212
|
var DefaultLogger = class _DefaultLogger {
|
|
163
213
|
level;
|
|
164
214
|
file;
|
|
@@ -166,7 +216,7 @@ var DefaultLogger = class _DefaultLogger {
|
|
|
166
216
|
pretty;
|
|
167
217
|
stderr;
|
|
168
218
|
constructor(opts = {}) {
|
|
169
|
-
this.level = opts.level ?? process.env.WRONGSTACK_LOG_LEVEL
|
|
219
|
+
this.level = opts.level ?? parseLogLevel(process.env.WRONGSTACK_LOG_LEVEL);
|
|
170
220
|
this.file = opts.file;
|
|
171
221
|
this.bindings = opts.bindings ?? {};
|
|
172
222
|
this.pretty = opts.pretty ?? true;
|
|
@@ -231,6 +281,9 @@ var DefaultLogger = class _DefaultLogger {
|
|
|
231
281
|
}
|
|
232
282
|
}
|
|
233
283
|
};
|
|
284
|
+
function parseLogLevel(raw) {
|
|
285
|
+
return raw && LOG_LEVELS.has(raw) ? raw : "info";
|
|
286
|
+
}
|
|
234
287
|
function formatCtx(ctx) {
|
|
235
288
|
if (ctx instanceof Error) return color.dim(ctx.message);
|
|
236
289
|
if (typeof ctx === "string") return color.dim(ctx);
|
|
@@ -614,8 +667,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
614
667
|
return JSON.parse(raw);
|
|
615
668
|
} catch {
|
|
616
669
|
const full = this.sessionPath(id, ".jsonl");
|
|
617
|
-
const
|
|
618
|
-
const summary = await this.summarize(id,
|
|
670
|
+
const stat6 = await fsp.stat(full);
|
|
671
|
+
const summary = await this.summarize(id, stat6.mtime.toISOString());
|
|
619
672
|
await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
|
|
620
673
|
console.warn(
|
|
621
674
|
`[session-store] Failed to write manifest for "${id}":`,
|
|
@@ -663,8 +716,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
663
716
|
if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
|
|
664
717
|
const jsonlPath = path3.join(dateDir, file.name);
|
|
665
718
|
try {
|
|
666
|
-
const
|
|
667
|
-
if (
|
|
719
|
+
const stat6 = await fsp.stat(jsonlPath);
|
|
720
|
+
if (stat6.mtimeMs >= cutoff) continue;
|
|
668
721
|
} catch {
|
|
669
722
|
continue;
|
|
670
723
|
}
|
|
@@ -1774,6 +1827,13 @@ var BEHAVIOR_DEFAULTS = {
|
|
|
1774
1827
|
function envBool(v) {
|
|
1775
1828
|
return !/^(0|false|no|off)$/i.test(v.trim());
|
|
1776
1829
|
}
|
|
1830
|
+
function envBoolOptional(v) {
|
|
1831
|
+
return v !== void 0 && envBool(v);
|
|
1832
|
+
}
|
|
1833
|
+
var LOG_LEVELS2 = /* @__PURE__ */ new Set(["error", "warn", "info", "debug", "trace"]);
|
|
1834
|
+
function envLogLevel(v) {
|
|
1835
|
+
return LOG_LEVELS2.has(v) ? v : "info";
|
|
1836
|
+
}
|
|
1777
1837
|
var ENV_MAP = {
|
|
1778
1838
|
WRONGSTACK_PROVIDER: (c, v) => {
|
|
1779
1839
|
c.provider = v;
|
|
@@ -1797,7 +1857,7 @@ var ENV_MAP = {
|
|
|
1797
1857
|
},
|
|
1798
1858
|
WRONGSTACK_LOG_LEVEL: (c, v) => {
|
|
1799
1859
|
if (!c.log) c.log = { level: "info" };
|
|
1800
|
-
c.log.level = v;
|
|
1860
|
+
c.log.level = envLogLevel(v);
|
|
1801
1861
|
},
|
|
1802
1862
|
WRONGSTACK_INDEX_ON_START: (c, v) => {
|
|
1803
1863
|
c.indexing = { ...defaultIndexing, ...c.indexing, onSessionStart: envBool(v) };
|
|
@@ -1839,7 +1899,7 @@ function deepMerge(base, patch) {
|
|
|
1839
1899
|
out[k] = [.../* @__PURE__ */ new Set([...existing, ...v])];
|
|
1840
1900
|
} else {
|
|
1841
1901
|
out[k] = v;
|
|
1842
|
-
if (process.env.WRONGSTACK_DEBUG_CONFIG) {
|
|
1902
|
+
if (envBoolOptional(process.env.WRONGSTACK_DEBUG_CONFIG)) {
|
|
1843
1903
|
console.warn(
|
|
1844
1904
|
`[config] Non-primitive array for "${k}" replaced (global + local config merge). Global entries: ${existing?.length ?? 0}, local entries: ${v.length}.`
|
|
1845
1905
|
);
|
|
@@ -3467,9 +3527,18 @@ async function restrictFilePermissions(filePath, opts) {
|
|
|
3467
3527
|
const { execFile: execFile2 } = await import('child_process');
|
|
3468
3528
|
const { promisify: promisify2 } = await import('util');
|
|
3469
3529
|
const execFileAsync = promisify2(execFile2);
|
|
3470
|
-
|
|
3530
|
+
const user = windowsAccountName();
|
|
3531
|
+
if (!user) {
|
|
3532
|
+
warn(
|
|
3533
|
+
`[secret-vault] Could not determine the current Windows user for ${filePath}; skipping icacls hardening.`
|
|
3534
|
+
);
|
|
3535
|
+
return;
|
|
3536
|
+
}
|
|
3537
|
+
await execFileAsync("icacls", [filePath, "/inheritance:r", "/grant:r", `${user}:(F)`]);
|
|
3471
3538
|
} catch {
|
|
3472
|
-
warn(
|
|
3539
|
+
warn(
|
|
3540
|
+
`[secret-vault] Could not restrict permissions on ${filePath} \u2014 config file may be readable by other users on this system.`
|
|
3541
|
+
);
|
|
3473
3542
|
}
|
|
3474
3543
|
} else {
|
|
3475
3544
|
try {
|
|
@@ -3478,6 +3547,13 @@ async function restrictFilePermissions(filePath, opts) {
|
|
|
3478
3547
|
}
|
|
3479
3548
|
}
|
|
3480
3549
|
}
|
|
3550
|
+
function windowsAccountName() {
|
|
3551
|
+
const username = process.env.USERNAME || process.env.USER;
|
|
3552
|
+
if (!username || username.includes("\0")) return void 0;
|
|
3553
|
+
const domain = process.env.USERDOMAIN;
|
|
3554
|
+
if (domain && !domain.includes("\0")) return `${domain}\\${username}`;
|
|
3555
|
+
return username;
|
|
3556
|
+
}
|
|
3481
3557
|
function walkCount(node, vault, counter) {
|
|
3482
3558
|
if (node === null || node === void 0) return node;
|
|
3483
3559
|
if (typeof node !== "object") return node;
|
|
@@ -4542,6 +4618,7 @@ function tryParse(s) {
|
|
|
4542
4618
|
}
|
|
4543
4619
|
|
|
4544
4620
|
// src/core/streaming-response-builder.ts
|
|
4621
|
+
var STREAM_DRAIN_TIMEOUT_MS = 500;
|
|
4545
4622
|
function buildResponse(state) {
|
|
4546
4623
|
const content = [];
|
|
4547
4624
|
for (const b of state.blockOrder) {
|
|
@@ -4754,7 +4831,7 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
|
|
|
4754
4831
|
await Promise.race([
|
|
4755
4832
|
Promise.resolve(iter.return?.()),
|
|
4756
4833
|
new Promise((resolve5) => {
|
|
4757
|
-
drainTimer = setTimeout(resolve5,
|
|
4834
|
+
drainTimer = setTimeout(resolve5, STREAM_DRAIN_TIMEOUT_MS);
|
|
4758
4835
|
})
|
|
4759
4836
|
]);
|
|
4760
4837
|
} finally {
|
|
@@ -6086,6 +6163,7 @@ var ToolExecutor = class {
|
|
|
6086
6163
|
this.registry = registry;
|
|
6087
6164
|
this.opts = opts;
|
|
6088
6165
|
this.iterationTimeoutMs = opts.iterationTimeoutMs ?? 3e5;
|
|
6166
|
+
this.maxToolTimeoutMs = opts.maxToolTimeoutMs ?? 3e5;
|
|
6089
6167
|
this.serializer = createToolOutputSerializer({
|
|
6090
6168
|
perIterationOutputCapBytes: opts.perIterationOutputCapBytes ?? 1e5
|
|
6091
6169
|
});
|
|
@@ -6094,6 +6172,7 @@ var ToolExecutor = class {
|
|
|
6094
6172
|
opts;
|
|
6095
6173
|
serializer;
|
|
6096
6174
|
iterationTimeoutMs;
|
|
6175
|
+
maxToolTimeoutMs;
|
|
6097
6176
|
/**
|
|
6098
6177
|
* Clear the interactive confirm awaiter so the executor returns
|
|
6099
6178
|
* `ToolConfirmPendingResult` instead of blocking on stdin. Used by
|
|
@@ -6331,7 +6410,10 @@ ${post.additionalContext}` };
|
|
|
6331
6410
|
if (parentSignal.reason instanceof Error) throw parentSignal.reason;
|
|
6332
6411
|
throw new Error(typeof parentSignal.reason === "string" ? parentSignal.reason : "aborted");
|
|
6333
6412
|
}
|
|
6334
|
-
const timeoutMs =
|
|
6413
|
+
const timeoutMs = clampTimeoutMs(
|
|
6414
|
+
tool.timeoutMs ?? this.iterationTimeoutMs,
|
|
6415
|
+
this.maxToolTimeoutMs
|
|
6416
|
+
);
|
|
6335
6417
|
const ctrl = new AbortController();
|
|
6336
6418
|
const timer = setTimeout(() => ctrl.abort(new Error("tool timeout")), timeoutMs);
|
|
6337
6419
|
const combined = AbortSignal.any([parentSignal, ctrl.signal]);
|
|
@@ -6466,6 +6548,12 @@ ${excerpt}`;
|
|
|
6466
6548
|
return void 0;
|
|
6467
6549
|
}
|
|
6468
6550
|
};
|
|
6551
|
+
function clampTimeoutMs(timeoutMs, maxTimeoutMs) {
|
|
6552
|
+
const fallback = 3e5;
|
|
6553
|
+
const finiteTimeout = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : fallback;
|
|
6554
|
+
const finiteMax = Number.isFinite(maxTimeoutMs) && maxTimeoutMs > 0 ? maxTimeoutMs : fallback;
|
|
6555
|
+
return Math.max(1, Math.min(finiteTimeout, finiteMax));
|
|
6556
|
+
}
|
|
6469
6557
|
var MALFORMED_ARG_MARKERS = ["__raw", "__raw_arguments", "_raw"];
|
|
6470
6558
|
function hasMalformedArguments(input) {
|
|
6471
6559
|
if (!input || typeof input !== "object" || Array.isArray(input)) return false;
|
|
@@ -7278,6 +7366,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
7278
7366
|
};
|
|
7279
7367
|
|
|
7280
7368
|
// src/coordination/subagent-budget.ts
|
|
7369
|
+
var TIMEOUT_PREEMPT_FRACTION = 0.85;
|
|
7281
7370
|
var BudgetExceededError = class extends Error {
|
|
7282
7371
|
kind;
|
|
7283
7372
|
limit;
|
|
@@ -10079,16 +10168,17 @@ Do not add prose, markdown, or code fences.`;
|
|
|
10079
10168
|
const raw = (await complete(prompt)).trim();
|
|
10080
10169
|
const match = raw.match(/\{[\s\S]*\}/);
|
|
10081
10170
|
if (!match) return null;
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10171
|
+
const parsed = safeParse(
|
|
10172
|
+
match[0]
|
|
10173
|
+
);
|
|
10174
|
+
if (!parsed.ok || !parsed.value || typeof parsed.value.role !== "string") return null;
|
|
10175
|
+
const role = parsed.value.role.trim();
|
|
10176
|
+
const valid = candidates.some((c) => c.role === role);
|
|
10177
|
+
if (!valid) return null;
|
|
10178
|
+
return {
|
|
10179
|
+
role,
|
|
10180
|
+
reason: typeof parsed.value.reason === "string" ? parsed.value.reason : void 0
|
|
10181
|
+
};
|
|
10092
10182
|
};
|
|
10093
10183
|
}
|
|
10094
10184
|
|
|
@@ -11043,15 +11133,38 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11043
11133
|
}
|
|
11044
11134
|
const start = Date.now();
|
|
11045
11135
|
let timer = null;
|
|
11136
|
+
let preemptedForLimit = null;
|
|
11046
11137
|
const timeoutPromise = new Promise((_, reject) => {
|
|
11047
11138
|
const armFor = (ms) => {
|
|
11048
11139
|
if (timer) clearTimeout(timer);
|
|
11049
11140
|
timer = setTimeout(onTick, Math.max(0, ms));
|
|
11050
11141
|
};
|
|
11051
11142
|
const scheduleNext = () => {
|
|
11052
|
-
const
|
|
11143
|
+
const wallLimit = budget.limits.timeoutMs ?? initialTimeoutMs;
|
|
11144
|
+
const wallRemaining = initialTimeoutMs === void 0 ? Number.POSITIVE_INFINITY : wallLimit - (Date.now() - start);
|
|
11053
11145
|
const idleRemaining = idleLimitMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();
|
|
11054
|
-
|
|
11146
|
+
const preemptRemaining = initialTimeoutMs === void 0 || preemptedForLimit === wallLimit ? Number.POSITIVE_INFINITY : wallLimit * TIMEOUT_PREEMPT_FRACTION - (Date.now() - start);
|
|
11147
|
+
armFor(Math.max(25, Math.min(wallRemaining, idleRemaining, preemptRemaining)));
|
|
11148
|
+
};
|
|
11149
|
+
const negotiateTimeout = async (used, limit) => {
|
|
11150
|
+
const handler = budget.onThreshold;
|
|
11151
|
+
if (!handler) return "stop";
|
|
11152
|
+
const result = handler({
|
|
11153
|
+
kind: "timeout",
|
|
11154
|
+
used,
|
|
11155
|
+
limit,
|
|
11156
|
+
requestDecision: () => new Promise((resolveDecision) => {
|
|
11157
|
+
budget._events?.emit("budget.threshold_reached", {
|
|
11158
|
+
kind: "timeout",
|
|
11159
|
+
used,
|
|
11160
|
+
limit,
|
|
11161
|
+
timeoutMs: 6e4,
|
|
11162
|
+
extend: (extra) => resolveDecision({ extend: extra }),
|
|
11163
|
+
deny: () => resolveDecision("stop")
|
|
11164
|
+
});
|
|
11165
|
+
})
|
|
11166
|
+
});
|
|
11167
|
+
return typeof result === "string" ? result : await result;
|
|
11055
11168
|
};
|
|
11056
11169
|
const onTick = async () => {
|
|
11057
11170
|
const elapsed = Date.now() - start;
|
|
@@ -11064,6 +11177,21 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11064
11177
|
reject(new BudgetExceededError("timeout", idleLimit ?? 0, budget.idleMs()));
|
|
11065
11178
|
return;
|
|
11066
11179
|
}
|
|
11180
|
+
if (wallLimit !== void 0 && !wallExceeded && budget.onThreshold && preemptedForLimit !== wallLimit && elapsed >= wallLimit * TIMEOUT_PREEMPT_FRACTION) {
|
|
11181
|
+
try {
|
|
11182
|
+
const decision = await negotiateTimeout(elapsed, wallLimit);
|
|
11183
|
+
if (typeof decision !== "string" && decision.extend.timeoutMs !== void 0) {
|
|
11184
|
+
budget.limits.timeoutMs = decision.extend.timeoutMs;
|
|
11185
|
+
preemptedForLimit = null;
|
|
11186
|
+
} else {
|
|
11187
|
+
preemptedForLimit = wallLimit;
|
|
11188
|
+
}
|
|
11189
|
+
} catch {
|
|
11190
|
+
preemptedForLimit = wallLimit;
|
|
11191
|
+
}
|
|
11192
|
+
scheduleNext();
|
|
11193
|
+
return;
|
|
11194
|
+
}
|
|
11067
11195
|
if (!wallExceeded) {
|
|
11068
11196
|
scheduleNext();
|
|
11069
11197
|
return;
|
|
@@ -11075,28 +11203,15 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11075
11203
|
return;
|
|
11076
11204
|
}
|
|
11077
11205
|
try {
|
|
11078
|
-
const
|
|
11079
|
-
kind: "timeout",
|
|
11080
|
-
used: elapsed,
|
|
11081
|
-
limit,
|
|
11082
|
-
requestDecision: () => new Promise((resolveDecision) => {
|
|
11083
|
-
budget._events?.emit("budget.threshold_reached", {
|
|
11084
|
-
kind: "timeout",
|
|
11085
|
-
used: elapsed,
|
|
11086
|
-
limit,
|
|
11087
|
-
timeoutMs: 6e4,
|
|
11088
|
-
extend: (extra) => resolveDecision({ extend: extra }),
|
|
11089
|
-
deny: () => resolveDecision("stop")
|
|
11090
|
-
});
|
|
11091
|
-
})
|
|
11092
|
-
});
|
|
11093
|
-
const decision = typeof result === "string" ? result : await result;
|
|
11206
|
+
const decision = await negotiateTimeout(elapsed, limit);
|
|
11094
11207
|
if (decision === "continue" || decision === "throw" || decision === "stop") {
|
|
11208
|
+
preemptedForLimit = null;
|
|
11095
11209
|
armFor(Math.max(1e3, limit));
|
|
11096
11210
|
return;
|
|
11097
11211
|
}
|
|
11098
11212
|
if (decision.extend.timeoutMs !== void 0) {
|
|
11099
11213
|
budget.limits.timeoutMs = decision.extend.timeoutMs;
|
|
11214
|
+
preemptedForLimit = null;
|
|
11100
11215
|
scheduleNext();
|
|
11101
11216
|
return;
|
|
11102
11217
|
}
|
|
@@ -12004,8 +12119,8 @@ async function expandGlob(pattern) {
|
|
|
12004
12119
|
for (const e of entries) {
|
|
12005
12120
|
const full = `${dir}${SEP}${e}`;
|
|
12006
12121
|
try {
|
|
12007
|
-
const
|
|
12008
|
-
if (
|
|
12122
|
+
const stat6 = await fsp.stat(full);
|
|
12123
|
+
if (stat6.isDirectory()) await walk4(full, rest);
|
|
12009
12124
|
} catch {
|
|
12010
12125
|
}
|
|
12011
12126
|
}
|
|
@@ -12022,8 +12137,8 @@ async function expandGlob(pattern) {
|
|
|
12022
12137
|
if (entries.includes(seg)) {
|
|
12023
12138
|
const full = `${dir}${SEP}${seg}`;
|
|
12024
12139
|
try {
|
|
12025
|
-
const
|
|
12026
|
-
if (
|
|
12140
|
+
const stat6 = await fsp.stat(full);
|
|
12141
|
+
if (stat6.isDirectory()) await walk4(full, rest);
|
|
12027
12142
|
} catch {
|
|
12028
12143
|
}
|
|
12029
12144
|
}
|
|
@@ -12051,6 +12166,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12051
12166
|
timeoutMs;
|
|
12052
12167
|
cancelled = false;
|
|
12053
12168
|
alerts = [];
|
|
12169
|
+
snapshotWarnings = [];
|
|
12054
12170
|
/** Tracks tool call counts per subagent for progress-based timeout decisions. */
|
|
12055
12171
|
progressBySubagent = /* @__PURE__ */ new Map();
|
|
12056
12172
|
/** Last tool call count when a timeout warning was handled. */
|
|
@@ -12120,10 +12236,19 @@ var CollabSession = class extends EventEmitter {
|
|
|
12120
12236
|
}
|
|
12121
12237
|
for (const filePath of allFiles) {
|
|
12122
12238
|
try {
|
|
12123
|
-
const content = await
|
|
12239
|
+
const [content, stat6] = await Promise.all([
|
|
12240
|
+
fsp.readFile(filePath, "utf8"),
|
|
12241
|
+
fsp.stat(filePath)
|
|
12242
|
+
]);
|
|
12124
12243
|
const ext = filePath.split(".").pop() ?? "";
|
|
12125
12244
|
const language = ext === "ts" || ext === "tsx" ? "typescript" : ext === "js" || ext === "jsx" ? "javascript" : ext === "md" ? "markdown" : ext === "json" ? "json" : void 0;
|
|
12126
|
-
this.snapshot.files.push({
|
|
12245
|
+
this.snapshot.files.push({
|
|
12246
|
+
path: filePath,
|
|
12247
|
+
content,
|
|
12248
|
+
language,
|
|
12249
|
+
snapshotMtimeMs: stat6.mtimeMs,
|
|
12250
|
+
snapshotSizeBytes: stat6.size
|
|
12251
|
+
});
|
|
12127
12252
|
} catch {
|
|
12128
12253
|
this.snapshot.files.push({ path: filePath, content: "", language: void 0 });
|
|
12129
12254
|
}
|
|
@@ -12146,7 +12271,11 @@ var CollabSession = class extends EventEmitter {
|
|
|
12146
12271
|
subagentId: this.director.id,
|
|
12147
12272
|
ts: Date.now(),
|
|
12148
12273
|
type: "director.cancel_collab",
|
|
12149
|
-
payload: {
|
|
12274
|
+
payload: {
|
|
12275
|
+
sessionId: this.sessionId,
|
|
12276
|
+
reason,
|
|
12277
|
+
cancelledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12278
|
+
}
|
|
12150
12279
|
});
|
|
12151
12280
|
this.fleetBus.emit({
|
|
12152
12281
|
subagentId: this.director.id,
|
|
@@ -12197,6 +12326,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12197
12326
|
for (const result of results?.flat() ?? []) {
|
|
12198
12327
|
await this.parseAndEmit(result);
|
|
12199
12328
|
}
|
|
12329
|
+
this.snapshotWarnings = await this.checkSnapshotFreshness();
|
|
12200
12330
|
const report = this.assembleReport();
|
|
12201
12331
|
this.cleanup();
|
|
12202
12332
|
this.emit("session.done", report);
|
|
@@ -12260,7 +12390,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12260
12390
|
const defaults = {
|
|
12261
12391
|
"bug-hunter": { maxIterations: 2e3, maxToolCalls: 5e3, timeoutMs: 10 * 60 * 1e3 },
|
|
12262
12392
|
"refactor-planner": { maxIterations: 1500, maxToolCalls: 4e3, timeoutMs: 8 * 60 * 1e3 },
|
|
12263
|
-
|
|
12393
|
+
critic: { maxIterations: 1e3, maxToolCalls: 3e3, timeoutMs: 6 * 60 * 1e3 }
|
|
12264
12394
|
};
|
|
12265
12395
|
return defaults[role] ?? { maxIterations: 1500, maxToolCalls: 4e3, timeoutMs: 8 * 60 * 1e3 };
|
|
12266
12396
|
}
|
|
@@ -12340,7 +12470,10 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
12340
12470
|
}
|
|
12341
12471
|
wireFleetBus() {
|
|
12342
12472
|
const dTool = this.fleetBus.filter("tool.executed", (e) => {
|
|
12343
|
-
this.progressBySubagent.set(
|
|
12473
|
+
this.progressBySubagent.set(
|
|
12474
|
+
e.subagentId,
|
|
12475
|
+
(this.progressBySubagent.get(e.subagentId) ?? 0) + 1
|
|
12476
|
+
);
|
|
12344
12477
|
});
|
|
12345
12478
|
this.disposers.push(dTool);
|
|
12346
12479
|
const dBudget = this.fleetBus.filter("budget.threshold_reached", (e) => {
|
|
@@ -12379,7 +12512,10 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
12379
12512
|
return;
|
|
12380
12513
|
}
|
|
12381
12514
|
this.lastTimeoutProgress.set(e.subagentId, progress);
|
|
12382
|
-
const newLimit = Math.min(
|
|
12515
|
+
const newLimit = Math.min(
|
|
12516
|
+
Math.ceil((payload.timeoutMs ?? payload.limit) * 2),
|
|
12517
|
+
24 * 60 * 6e4
|
|
12518
|
+
);
|
|
12383
12519
|
setImmediate(() => {
|
|
12384
12520
|
payload.extend({ timeoutMs: newLimit });
|
|
12385
12521
|
});
|
|
@@ -12489,15 +12625,18 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
12489
12625
|
needs_revision: 1,
|
|
12490
12626
|
reject: 2
|
|
12491
12627
|
};
|
|
12492
|
-
const overallVerdict = evalList.reduce(
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
|
|
12628
|
+
const overallVerdict = evalList.reduce((worst, eval_) => {
|
|
12629
|
+
const w = verdictOrder[worst];
|
|
12630
|
+
const c = verdictOrder[eval_.verdict];
|
|
12631
|
+
return c > w ? eval_.verdict : worst;
|
|
12632
|
+
}, "approve");
|
|
12633
|
+
const summary = this.buildMarkdownSummary(
|
|
12634
|
+
bugList,
|
|
12635
|
+
planList,
|
|
12636
|
+
evalList,
|
|
12637
|
+
overallVerdict,
|
|
12638
|
+
disposition
|
|
12499
12639
|
);
|
|
12500
|
-
const summary = this.buildMarkdownSummary(bugList, planList, evalList, overallVerdict, disposition);
|
|
12501
12640
|
return {
|
|
12502
12641
|
sessionId: this.sessionId,
|
|
12503
12642
|
startedAt: this.snapshot.createdAt,
|
|
@@ -12508,10 +12647,28 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
12508
12647
|
refactorPlans: planList,
|
|
12509
12648
|
evaluations: evalList,
|
|
12510
12649
|
alerts: [...this.alerts],
|
|
12650
|
+
...this.snapshotWarnings.length > 0 ? { snapshotWarnings: this.snapshotWarnings } : {},
|
|
12511
12651
|
overallVerdict,
|
|
12512
12652
|
summary
|
|
12513
12653
|
};
|
|
12514
12654
|
}
|
|
12655
|
+
async checkSnapshotFreshness() {
|
|
12656
|
+
const warnings = [];
|
|
12657
|
+
for (const file of this.snapshot.files) {
|
|
12658
|
+
if (file.snapshotMtimeMs === void 0 && file.snapshotSizeBytes === void 0) continue;
|
|
12659
|
+
try {
|
|
12660
|
+
const stat6 = await fsp.stat(file.path);
|
|
12661
|
+
const mtimeChanged = file.snapshotMtimeMs !== void 0 && stat6.mtimeMs > file.snapshotMtimeMs + 1;
|
|
12662
|
+
const sizeChanged = file.snapshotSizeBytes !== void 0 && stat6.size !== file.snapshotSizeBytes;
|
|
12663
|
+
if (mtimeChanged || sizeChanged) {
|
|
12664
|
+
warnings.push(`${file.path} changed after the collab snapshot was captured.`);
|
|
12665
|
+
}
|
|
12666
|
+
} catch {
|
|
12667
|
+
warnings.push(`${file.path} could not be checked after the collab snapshot was captured.`);
|
|
12668
|
+
}
|
|
12669
|
+
}
|
|
12670
|
+
return warnings;
|
|
12671
|
+
}
|
|
12515
12672
|
buildMarkdownSummary(bugs, plans, evals, overallVerdict, disposition) {
|
|
12516
12673
|
const lines = [
|
|
12517
12674
|
`## Collaborative Debugging Report \u2014 ${this.sessionId}`,
|
|
@@ -12528,10 +12685,19 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
12528
12685
|
}
|
|
12529
12686
|
lines.push("");
|
|
12530
12687
|
}
|
|
12688
|
+
if (this.snapshotWarnings.length > 0) {
|
|
12689
|
+
lines.push("### Snapshot Warnings", "");
|
|
12690
|
+
for (const warning of this.snapshotWarnings) {
|
|
12691
|
+
lines.push(`- ${warning}`);
|
|
12692
|
+
}
|
|
12693
|
+
lines.push("");
|
|
12694
|
+
}
|
|
12531
12695
|
if (bugs.length > 0) {
|
|
12532
12696
|
lines.push("### Bugs Found", "");
|
|
12533
12697
|
for (const b of bugs) {
|
|
12534
|
-
lines.push(
|
|
12698
|
+
lines.push(
|
|
12699
|
+
`- **[${b.severity.toUpperCase()}]** \`${b.location.file}:${b.location.line}\` \u2014 ${b.description}`
|
|
12700
|
+
);
|
|
12535
12701
|
}
|
|
12536
12702
|
lines.push("");
|
|
12537
12703
|
}
|
|
@@ -13134,6 +13300,7 @@ var FleetBus = class {
|
|
|
13134
13300
|
set.add(handler);
|
|
13135
13301
|
return () => {
|
|
13136
13302
|
set.delete(handler);
|
|
13303
|
+
if (set.size === 0) this.byId.delete(subagentId);
|
|
13137
13304
|
};
|
|
13138
13305
|
}
|
|
13139
13306
|
/** Subscribe to one event type across all subagents. */
|
|
@@ -13146,6 +13313,7 @@ var FleetBus = class {
|
|
|
13146
13313
|
set.add(handler);
|
|
13147
13314
|
return () => {
|
|
13148
13315
|
set.delete(handler);
|
|
13316
|
+
if (set.size === 0) this.byType.delete(type);
|
|
13149
13317
|
};
|
|
13150
13318
|
}
|
|
13151
13319
|
/** Subscribe to literally everything. The fleet roll-up uses this. */
|
|
@@ -13179,6 +13347,11 @@ var FleetBus = class {
|
|
|
13179
13347
|
}
|
|
13180
13348
|
}
|
|
13181
13349
|
}
|
|
13350
|
+
clear() {
|
|
13351
|
+
this.byId.clear();
|
|
13352
|
+
this.byType.clear();
|
|
13353
|
+
this.any.clear();
|
|
13354
|
+
}
|
|
13182
13355
|
};
|
|
13183
13356
|
var FleetUsageAggregator = class {
|
|
13184
13357
|
constructor(bus, priceLookup, metaLookup) {
|
|
@@ -14411,7 +14584,9 @@ var Director = class _Director {
|
|
|
14411
14584
|
let toolUses = 0;
|
|
14412
14585
|
for (const line of targetLines) {
|
|
14413
14586
|
try {
|
|
14414
|
-
const
|
|
14587
|
+
const parsed = safeParse(line);
|
|
14588
|
+
if (!parsed.ok || !parsed.value) continue;
|
|
14589
|
+
const ev = parsed.value;
|
|
14415
14590
|
if (ev.type === "assistant" && typeof ev.text === "string") {
|
|
14416
14591
|
lastAssistantText = ev.text;
|
|
14417
14592
|
} else if (ev.type === "stop" && ev.stopReason) {
|
|
@@ -14725,7 +14900,7 @@ function createDelegateTool(opts) {
|
|
|
14725
14900
|
const offIter = dir.fleet.filter("iteration.started", bump);
|
|
14726
14901
|
const offProgress = dir.fleet.filter("tool.progress", bump);
|
|
14727
14902
|
arm();
|
|
14728
|
-
dir.awaitTasks([taskId]).then((r) => finish(r[0] ?? {
|
|
14903
|
+
dir.awaitTasks([taskId]).then((r) => finish(r[0] ?? { __emptyResult: true })).catch(() => finish({ __timeout: true }));
|
|
14729
14904
|
});
|
|
14730
14905
|
if ("__timeout" in result) {
|
|
14731
14906
|
const partial2 = await readSubagentPartial(opts, subagentId);
|
|
@@ -14750,6 +14925,29 @@ function createDelegateTool(opts) {
|
|
|
14750
14925
|
partial: partial2
|
|
14751
14926
|
};
|
|
14752
14927
|
}
|
|
14928
|
+
if ("__emptyResult" in result) {
|
|
14929
|
+
const partial2 = await readSubagentPartial(opts, subagentId);
|
|
14930
|
+
opts.events?.emit("delegate.completed", {
|
|
14931
|
+
target,
|
|
14932
|
+
task: i.task,
|
|
14933
|
+
ok: false,
|
|
14934
|
+
status: "empty_result",
|
|
14935
|
+
summary: `[${target}] completed without a task result`,
|
|
14936
|
+
durationMs: 0,
|
|
14937
|
+
iterations: partial2?.events ?? 0,
|
|
14938
|
+
toolCalls: partial2?.toolUsesObserved ?? 0,
|
|
14939
|
+
subagentId
|
|
14940
|
+
});
|
|
14941
|
+
return {
|
|
14942
|
+
ok: false,
|
|
14943
|
+
stopReason: "error",
|
|
14944
|
+
error: "Director returned no task result for the delegated task.",
|
|
14945
|
+
hint: "Check fleet state with /fleet status, then retry or reassign the task.",
|
|
14946
|
+
subagentId,
|
|
14947
|
+
taskId,
|
|
14948
|
+
partial: partial2
|
|
14949
|
+
};
|
|
14950
|
+
}
|
|
14753
14951
|
const baseStopReason = result.status === "success" ? "end_turn" : result.status === "timeout" ? "subagent_timeout" : result.status === "stopped" ? "aborted" : "budget_exhausted";
|
|
14754
14952
|
const partial = result.status === "success" ? void 0 : await readSubagentPartial(opts, subagentId);
|
|
14755
14953
|
const errorKind = result.error?.kind;
|
|
@@ -14922,7 +15120,9 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
14922
15120
|
let toolUses = 0;
|
|
14923
15121
|
for (const line of lines) {
|
|
14924
15122
|
try {
|
|
14925
|
-
const
|
|
15123
|
+
const parsed = safeParse(line);
|
|
15124
|
+
if (!parsed.ok || !parsed.value) continue;
|
|
15125
|
+
const ev = parsed.value;
|
|
14926
15126
|
if (ev.type === "tool_use") toolUses += 1;
|
|
14927
15127
|
if (ev.type === "llm_response") {
|
|
14928
15128
|
if (typeof ev.stopReason === "string") lastStopReason = ev.stopReason;
|
|
@@ -15694,8 +15894,8 @@ async function loadProjectModes(modesDir) {
|
|
|
15694
15894
|
for (const entry of entries) {
|
|
15695
15895
|
if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
|
|
15696
15896
|
const filePath = path3.join(modesDir, entry);
|
|
15697
|
-
const
|
|
15698
|
-
if (!
|
|
15897
|
+
const stat6 = await fsp.stat(filePath);
|
|
15898
|
+
if (!stat6.isFile()) continue;
|
|
15699
15899
|
const content = await fsp.readFile(filePath, "utf8");
|
|
15700
15900
|
const id = path3.basename(entry, path3.extname(entry));
|
|
15701
15901
|
modes.push({
|