@wrongstack/core 0.54.1 → 0.66.13
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-Dnhw4tnM.d.ts → agent-bridge-D-j6OOBT.d.ts} +1 -1
- package/dist/agent-subagent-runner-DRZ9-NnR.d.ts +1042 -0
- package/dist/{compactor-Duhsf0ge.d.ts → compactor-D_ExJajC.d.ts} +1 -1
- package/dist/{config-bht0txXS.d.ts → config--86aHSln.d.ts} +112 -2
- package/dist/{context-DtPKqKYV.d.ts → context-y87Jc5ei.d.ts} +8 -8
- package/dist/coordination/index.d.ts +12 -12
- package/dist/coordination/index.js +87 -69
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +22 -22
- package/dist/defaults/index.js +365 -174
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-CbHTS4ZZ.d.ts → events-CIplI98R.d.ts} +20 -1
- package/dist/execution/index.d.ts +16 -385
- package/dist/execution/index.js +129 -61
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +7 -7
- package/dist/goal-store-C7jcumEh.d.ts +96 -0
- package/dist/index-DKUvyTvV.d.ts +560 -0
- package/dist/{index-ge5F2dnc.d.ts → index-b5uhfTSl.d.ts} +10 -8
- package/dist/index.d.ts +59 -33
- package/dist/index.js +1138 -733
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +1 -1
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +9 -9
- package/dist/kernel/index.js +3 -1
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-DE6gzBry.d.ts → mcp-servers-DwoNBf6r.d.ts} +3 -3
- package/dist/models/index.d.ts +2 -2
- package/dist/{multi-agent-coordinator-CjNX4uBD.d.ts → multi-agent-coordinator-CWnH-CiX.d.ts} +10 -2
- package/dist/{null-fleet-bus-BNiSlTna.d.ts → null-fleet-bus-VApKRxcp.d.ts} +6 -7
- package/dist/observability/index.d.ts +2 -2
- package/dist/parallel-eternal-engine-0UwotoSx.d.ts +483 -0
- package/dist/{path-resolver-Bax85amb.d.ts → path-resolver-DVkEcIw8.d.ts} +2 -2
- package/dist/{permission-Drm7LpPo.d.ts → permission-C1A5whY5.d.ts} +17 -1
- package/dist/{permission-policy-CU6sqWxF.d.ts → permission-policy-B2dK-T5N.d.ts} +28 -7
- package/dist/{plan-templates-CLRcurWN.d.ts → plan-templates-Bprrzhbu.d.ts} +4 -4
- package/dist/{provider-runner-BikCxGCx.d.ts → provider-runner-mXvXGSIw.d.ts} +3 -3
- package/dist/{retry-policy-Chtlvr5b.d.ts → retry-policy-CG3qvH_e.d.ts} +1 -1
- package/dist/sdd/index.d.ts +9 -9
- package/dist/sdd/index.js +59 -52
- package/dist/sdd/index.js.map +1 -1
- package/dist/security/index.d.ts +3 -3
- package/dist/security/index.js +144 -33
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-BvSPdJj6.d.ts → selector-RvBR_YRW.d.ts} +1 -1
- package/dist/session-event-bridge-CDHxcmQU.d.ts +93 -0
- package/dist/{session-reader-BGhzMir4.d.ts → session-reader-BIpwM60D.d.ts} +1 -1
- package/dist/storage/index.d.ts +7 -6
- package/dist/{system-prompt-dtzV_mLm.d.ts → system-prompt-b61lOd49.d.ts} +32 -2
- package/dist/types/index.d.ts +23 -14
- package/dist/types/index.js +62 -6
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/multi-agent/SKILL.md +0 -2
- package/dist/agent-subagent-runner-By7jruZ_.d.ts +0 -182
- package/dist/goal-store-DwcTDDiX.d.ts +0 -188
- package/dist/index-CI271MjL.d.ts +0 -903
- package/dist/multi-agent-BmC_xiog.d.ts +0 -554
- package/dist/tool-executor-CgU0yWpB.d.ts +0 -110
package/dist/defaults/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as crypto2 from 'crypto';
|
|
2
2
|
import { randomBytes, randomUUID, createCipheriv, createDecipheriv, createHash } from 'crypto';
|
|
3
3
|
import * as fsp from 'fs/promises';
|
|
4
|
-
import * as
|
|
4
|
+
import * as path16 from 'path';
|
|
5
5
|
import { isAbsolute, resolve } from 'path';
|
|
6
6
|
import * as fs5 from 'fs';
|
|
7
7
|
import * as os from 'os';
|
|
@@ -32,9 +32,9 @@ __export(atomic_write_exports, {
|
|
|
32
32
|
ensureDir: () => ensureDir
|
|
33
33
|
});
|
|
34
34
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
35
|
-
const dir =
|
|
35
|
+
const dir = path16.dirname(targetPath);
|
|
36
36
|
await fsp.mkdir(dir, { recursive: true });
|
|
37
|
-
const tmp =
|
|
37
|
+
const tmp = path16.join(dir, `.${path16.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
38
38
|
try {
|
|
39
39
|
if (typeof content === "string") {
|
|
40
40
|
await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
@@ -89,7 +89,7 @@ async function renameWithRetry(from, to) {
|
|
|
89
89
|
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
90
90
|
throw err;
|
|
91
91
|
}
|
|
92
|
-
await new Promise((
|
|
92
|
+
await new Promise((resolve5) => setTimeout(resolve5, delays[i]));
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
throw lastErr;
|
|
@@ -169,7 +169,7 @@ var DefaultLogger = class _DefaultLogger {
|
|
|
169
169
|
this.pretty = opts.pretty ?? true;
|
|
170
170
|
if (this.file) {
|
|
171
171
|
try {
|
|
172
|
-
fs5.mkdirSync(
|
|
172
|
+
fs5.mkdirSync(path16.dirname(this.file), { recursive: true });
|
|
173
173
|
} catch {
|
|
174
174
|
}
|
|
175
175
|
}
|
|
@@ -342,7 +342,7 @@ var DefaultSessionStore = class {
|
|
|
342
342
|
}
|
|
343
343
|
/** Join session ID to its absolute path within the store directory. */
|
|
344
344
|
sessionPath(id, ext) {
|
|
345
|
-
return
|
|
345
|
+
return path16.join(this.dir, `${id}${ext}`);
|
|
346
346
|
}
|
|
347
347
|
async ensureShardDir(_id) {
|
|
348
348
|
await ensureDir(this.dir);
|
|
@@ -352,7 +352,7 @@ var DefaultSessionStore = class {
|
|
|
352
352
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
353
353
|
const id = meta.id ?? `${startedAt.replace(/[:.]/g, "-")}-${randomBytes(2).toString("hex")}`;
|
|
354
354
|
const shardDir = await this.ensureShardDir(id);
|
|
355
|
-
const file =
|
|
355
|
+
const file = path16.join(shardDir, `${id}.jsonl`);
|
|
356
356
|
let handle;
|
|
357
357
|
try {
|
|
358
358
|
handle = await fsp.open(file, "a", 384);
|
|
@@ -445,7 +445,7 @@ var DefaultSessionStore = class {
|
|
|
445
445
|
const ids = [];
|
|
446
446
|
const entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
447
447
|
for (const entry of entries) {
|
|
448
|
-
const full =
|
|
448
|
+
const full = path16.join(dir, entry.name);
|
|
449
449
|
if (entry.isDirectory()) {
|
|
450
450
|
ids.push(...await this.collectSessionIds(full));
|
|
451
451
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
@@ -601,7 +601,7 @@ var FileSessionWriter = class {
|
|
|
601
601
|
this.meta = meta;
|
|
602
602
|
this.events = events;
|
|
603
603
|
this.resumed = opts.resumed ?? false;
|
|
604
|
-
this.manifestFile = opts.dir ?
|
|
604
|
+
this.manifestFile = opts.dir ? path16.join(opts.dir, `${id}.summary.json`) : "";
|
|
605
605
|
this.filePath = opts.filePath ?? "";
|
|
606
606
|
this.secretScrubber = opts.secretScrubber;
|
|
607
607
|
this.summary = {
|
|
@@ -883,7 +883,7 @@ init_atomic_write();
|
|
|
883
883
|
var QueueStore = class {
|
|
884
884
|
file;
|
|
885
885
|
constructor(opts) {
|
|
886
|
-
this.file =
|
|
886
|
+
this.file = path16.join(opts.dir, "queue.json");
|
|
887
887
|
}
|
|
888
888
|
async write(items) {
|
|
889
889
|
if (items.length === 0) {
|
|
@@ -953,7 +953,7 @@ var DefaultAttachmentStore = class {
|
|
|
953
953
|
let data = input.data;
|
|
954
954
|
if (this.spoolDir && bytes >= this.spoolThreshold) {
|
|
955
955
|
await fsp.mkdir(this.spoolDir, { recursive: true });
|
|
956
|
-
spooledPath =
|
|
956
|
+
spooledPath = path16.join(this.spoolDir, `${id}.bin`);
|
|
957
957
|
await atomicWrite(spooledPath, input.data, {
|
|
958
958
|
encoding: input.kind === "image" ? "base64" : "utf8"
|
|
959
959
|
});
|
|
@@ -1141,7 +1141,7 @@ ${body.trim()}`);
|
|
|
1141
1141
|
async remember(text, scope = "project-memory") {
|
|
1142
1142
|
return this.runSerialized(scope, async () => {
|
|
1143
1143
|
const file = this.files[scope];
|
|
1144
|
-
await ensureDir(
|
|
1144
|
+
await ensureDir(path16.dirname(file));
|
|
1145
1145
|
let existing = "";
|
|
1146
1146
|
try {
|
|
1147
1147
|
existing = await fsp.readFile(file, "utf8");
|
|
@@ -1765,7 +1765,7 @@ var RecoveryLock = class {
|
|
|
1765
1765
|
sessionStore;
|
|
1766
1766
|
probe;
|
|
1767
1767
|
constructor(opts) {
|
|
1768
|
-
this.file =
|
|
1768
|
+
this.file = path16.join(opts.dir, LOCK_FILE);
|
|
1769
1769
|
this.pid = opts.pid ?? process.pid;
|
|
1770
1770
|
this.hostname = opts.hostname ?? os.hostname();
|
|
1771
1771
|
this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
@@ -1823,7 +1823,7 @@ var RecoveryLock = class {
|
|
|
1823
1823
|
* null return before calling this.
|
|
1824
1824
|
*/
|
|
1825
1825
|
async write(sessionId) {
|
|
1826
|
-
await ensureDir(
|
|
1826
|
+
await ensureDir(path16.dirname(this.file));
|
|
1827
1827
|
const lock = {
|
|
1828
1828
|
v: 1,
|
|
1829
1829
|
sessionId,
|
|
@@ -3050,7 +3050,7 @@ var DefaultSecretVault = class {
|
|
|
3050
3050
|
} catch (err) {
|
|
3051
3051
|
if (err.code !== "ENOENT") throw err;
|
|
3052
3052
|
}
|
|
3053
|
-
fs5.mkdirSync(
|
|
3053
|
+
fs5.mkdirSync(path16.dirname(this.keyFile), { recursive: true });
|
|
3054
3054
|
const key = randomBytes(KEY_BYTES);
|
|
3055
3055
|
try {
|
|
3056
3056
|
fs5.writeFileSync(this.keyFile, key, { mode: 384, flag: "wx" });
|
|
@@ -3119,7 +3119,7 @@ async function rewriteConfigEncrypted(configPath, vault, patch) {
|
|
|
3119
3119
|
}
|
|
3120
3120
|
const merged = deepMerge2(current, patch ?? {});
|
|
3121
3121
|
const encrypted = encryptConfigSecrets(merged, vault);
|
|
3122
|
-
await fsp.mkdir(
|
|
3122
|
+
await fsp.mkdir(path16.dirname(configPath), { recursive: true });
|
|
3123
3123
|
await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3124
3124
|
await restrictFilePermissions(configPath);
|
|
3125
3125
|
}
|
|
@@ -3321,6 +3321,87 @@ function matchGlob(pattern, input) {
|
|
|
3321
3321
|
function matchAny(patterns, input) {
|
|
3322
3322
|
return patterns.some((p) => matchGlob(p, input));
|
|
3323
3323
|
}
|
|
3324
|
+
var DESTRUCTIVE_BASH_PATTERNS = [
|
|
3325
|
+
/\bgit\s+(?:clean\s+-[^\s]*[xdf]|reset\s+--hard)\b/i,
|
|
3326
|
+
/\b(?:drop|truncate)\s+(?:table|database|schema)\b/i,
|
|
3327
|
+
/\bdelete\s+from\b/i,
|
|
3328
|
+
/\b(?:mkfs|format|diskpart|shutdown|reboot)\b/i,
|
|
3329
|
+
/\bchmod\s+-R\s+777\b/i,
|
|
3330
|
+
/\bchown\s+-R\b/i,
|
|
3331
|
+
/\b(?:curl|wget)\b.*\|\s*(?:sh|bash|zsh|pwsh|powershell)\b/i,
|
|
3332
|
+
/\b(?:powershell|pwsh)\b.*(?:-encodedcommand|-enc)\b/i,
|
|
3333
|
+
/:\(\)\s*\{\s*:\|:&\s*}\s*;/
|
|
3334
|
+
];
|
|
3335
|
+
var PROJECT_ESCAPE_PATTERN = /(?:^|[\s"'])\.\.(?:[\\/]|$)/;
|
|
3336
|
+
var ABSOLUTE_PATH_PATTERN = /(?:^|[\s"'])(?:~[\\/]|\/[A-Za-z0-9_.-]|[A-Za-z]:[\\/])/;
|
|
3337
|
+
var SHELL_OPERATORS = /* @__PURE__ */ new Set(["&&", "||", "|", ";", ">", ">>", "<", "2>", "2>>"]);
|
|
3338
|
+
function getInputString(input, key) {
|
|
3339
|
+
if (!input || typeof input !== "object") return void 0;
|
|
3340
|
+
const value = input[key];
|
|
3341
|
+
return typeof value === "string" ? value : void 0;
|
|
3342
|
+
}
|
|
3343
|
+
function pathLooksInsideProject(rawPath, projectRoot) {
|
|
3344
|
+
if (!projectRoot) return false;
|
|
3345
|
+
if (rawPath === "~" || rawPath.startsWith("~/") || rawPath.startsWith("~\\")) return false;
|
|
3346
|
+
const resolved = path16.resolve(projectRoot, rawPath);
|
|
3347
|
+
const relative2 = path16.relative(projectRoot, resolved);
|
|
3348
|
+
return !!relative2 && !relative2.startsWith("..") && !path16.isAbsolute(relative2);
|
|
3349
|
+
}
|
|
3350
|
+
function tokenizeShell(command) {
|
|
3351
|
+
return command.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, "")) ?? [];
|
|
3352
|
+
}
|
|
3353
|
+
function pathTokenIsOutsideProject(token, projectRoot) {
|
|
3354
|
+
if (!token || SHELL_OPERATORS.has(token) || token.startsWith("-")) return false;
|
|
3355
|
+
if (token === "/" || token === "~" || token === "." || token === "..") return token !== ".";
|
|
3356
|
+
if (token.includes("*")) return true;
|
|
3357
|
+
if (token.startsWith("..") || token.includes("../") || token.includes("..\\")) return true;
|
|
3358
|
+
if (path16.isAbsolute(token) || token.startsWith("~/")) return !pathLooksInsideProject(token, projectRoot);
|
|
3359
|
+
return false;
|
|
3360
|
+
}
|
|
3361
|
+
function hasDangerousDeleteTarget(tokens, start, projectRoot) {
|
|
3362
|
+
const targets = tokens.slice(start).filter((token) => !token.startsWith("-") && !SHELL_OPERATORS.has(token));
|
|
3363
|
+
if (targets.length === 0) return true;
|
|
3364
|
+
return targets.some((target) => pathTokenIsOutsideProject(target, projectRoot));
|
|
3365
|
+
}
|
|
3366
|
+
function hasDestructiveDelete(command, projectRoot) {
|
|
3367
|
+
const tokens = tokenizeShell(command);
|
|
3368
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
3369
|
+
const token = tokens[i]?.toLowerCase();
|
|
3370
|
+
if (!token) continue;
|
|
3371
|
+
if (token === "rm") {
|
|
3372
|
+
const args = tokens.slice(i + 1);
|
|
3373
|
+
const recursiveOrForce = args.some(
|
|
3374
|
+
(arg) => /^-[^-]*[rf]/i.test(arg) || arg === "--recursive" || arg === "--force"
|
|
3375
|
+
);
|
|
3376
|
+
if (recursiveOrForce && hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
|
|
3377
|
+
}
|
|
3378
|
+
if (token === "rmdir" || token === "rd") {
|
|
3379
|
+
const args = tokens.slice(i + 1);
|
|
3380
|
+
const recursive = args.some((arg) => arg.toLowerCase() === "/s");
|
|
3381
|
+
if (recursive && hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
|
|
3382
|
+
}
|
|
3383
|
+
if (token === "del" || token === "erase") {
|
|
3384
|
+
if (hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
|
|
3385
|
+
}
|
|
3386
|
+
if (token === "remove-item") {
|
|
3387
|
+
const args = tokens.slice(i + 1).map((arg) => arg.toLowerCase());
|
|
3388
|
+
const recursiveOrForce = args.includes("-recurse") || args.includes("-force");
|
|
3389
|
+
if (recursiveOrForce && hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
return false;
|
|
3393
|
+
}
|
|
3394
|
+
function isClearlyDestructiveBashCommand(command, projectRoot) {
|
|
3395
|
+
const trimmed = command.trim();
|
|
3396
|
+
if (!trimmed) return false;
|
|
3397
|
+
if (hasDestructiveDelete(trimmed, projectRoot)) return true;
|
|
3398
|
+
if (DESTRUCTIVE_BASH_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
|
|
3399
|
+
if (/\bcd\s+(?:\.\.|~|\/|[A-Za-z]:[\\/])/i.test(trimmed)) return true;
|
|
3400
|
+
if (PROJECT_ESCAPE_PATTERN.test(trimmed)) return true;
|
|
3401
|
+
const absolute = trimmed.match(ABSOLUTE_PATH_PATTERN)?.[0]?.trim().replace(/^['"]|['"]$/g, "");
|
|
3402
|
+
if (absolute && !pathLooksInsideProject(absolute, projectRoot)) return true;
|
|
3403
|
+
return false;
|
|
3404
|
+
}
|
|
3324
3405
|
|
|
3325
3406
|
// src/security/permission-policy.ts
|
|
3326
3407
|
var DefaultPermissionPolicy = class {
|
|
@@ -3328,7 +3409,9 @@ var DefaultPermissionPolicy = class {
|
|
|
3328
3409
|
loaded = false;
|
|
3329
3410
|
trustFile;
|
|
3330
3411
|
yolo;
|
|
3331
|
-
|
|
3412
|
+
yoloDestructive;
|
|
3413
|
+
/** When true, destructive ops still require confirmation even in YOLO mode. */
|
|
3414
|
+
confirmDestructive;
|
|
3332
3415
|
/**
|
|
3333
3416
|
* Session-scoped "soft deny" map. When the user presses 'n' (block once),
|
|
3334
3417
|
* the tool+pattern is added here. If the LLM retries in the same session,
|
|
@@ -3361,7 +3444,8 @@ var DefaultPermissionPolicy = class {
|
|
|
3361
3444
|
constructor(opts) {
|
|
3362
3445
|
this.trustFile = opts.trustFile;
|
|
3363
3446
|
this.yolo = opts.yolo ?? false;
|
|
3364
|
-
this.
|
|
3447
|
+
this.yoloDestructive = opts.yoloDestructive ?? opts.forceAllYolo ?? false;
|
|
3448
|
+
this.confirmDestructive = opts.confirmDestructive ?? false;
|
|
3365
3449
|
this.promptDelegate = opts.promptDelegate;
|
|
3366
3450
|
}
|
|
3367
3451
|
/**
|
|
@@ -3381,13 +3465,29 @@ var DefaultPermissionPolicy = class {
|
|
|
3381
3465
|
getYolo() {
|
|
3382
3466
|
return this.yolo;
|
|
3383
3467
|
}
|
|
3384
|
-
/** Toggle
|
|
3468
|
+
/** Toggle the destructive YOLO override at runtime. */
|
|
3469
|
+
setYoloDestructive(enabled) {
|
|
3470
|
+
this.yoloDestructive = enabled;
|
|
3471
|
+
}
|
|
3472
|
+
/** Check whether the destructive YOLO override is active. */
|
|
3473
|
+
getYoloDestructive() {
|
|
3474
|
+
return this.yoloDestructive;
|
|
3475
|
+
}
|
|
3476
|
+
/** Toggle destructive confirmation gate (only meaningful when yolo is active). */
|
|
3477
|
+
setConfirmDestructive(enabled) {
|
|
3478
|
+
this.confirmDestructive = enabled;
|
|
3479
|
+
}
|
|
3480
|
+
/** Check whether destructive confirmation gate is active. */
|
|
3481
|
+
getConfirmDestructive() {
|
|
3482
|
+
return this.confirmDestructive;
|
|
3483
|
+
}
|
|
3484
|
+
/** @deprecated Use `setYoloDestructive`. */
|
|
3385
3485
|
setForceAllYolo(enabled) {
|
|
3386
|
-
this.
|
|
3486
|
+
this.setYoloDestructive(enabled);
|
|
3387
3487
|
}
|
|
3388
|
-
/**
|
|
3488
|
+
/** @deprecated Use `getYoloDestructive`. */
|
|
3389
3489
|
getForceAllYolo() {
|
|
3390
|
-
return this.
|
|
3490
|
+
return this.getYoloDestructive();
|
|
3391
3491
|
}
|
|
3392
3492
|
async reload() {
|
|
3393
3493
|
try {
|
|
@@ -3434,29 +3534,28 @@ var DefaultPermissionPolicy = class {
|
|
|
3434
3534
|
return { permission: "auto", source: "trust" };
|
|
3435
3535
|
}
|
|
3436
3536
|
if (this.yolo) {
|
|
3437
|
-
if (
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
if (
|
|
3441
|
-
await this.
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
source: "user",
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
return { permission: "
|
|
3537
|
+
if (this.confirmDestructive) {
|
|
3538
|
+
const destructive = this.isDestructiveYoloCall(tool, input, ctx);
|
|
3539
|
+
if (destructive) {
|
|
3540
|
+
if (this.promptDelegate) {
|
|
3541
|
+
const decision = await this.promptDelegate(tool, input, subject ?? tool.name);
|
|
3542
|
+
if (decision === "always") {
|
|
3543
|
+
await this.trust({ tool: tool.name, pattern: subject ?? tool.name });
|
|
3544
|
+
return { permission: "auto", source: "user", reason: "destructive yolo always-allowed" };
|
|
3545
|
+
}
|
|
3546
|
+
if (decision === "deny") {
|
|
3547
|
+
await this.deny({ tool: tool.name, pattern: subject ?? tool.name });
|
|
3548
|
+
return { permission: "deny", source: "user", reason: "user denied destructive yolo" };
|
|
3549
|
+
}
|
|
3550
|
+
return { permission: decision === "yes" ? "auto" : "deny", source: "user" };
|
|
3451
3551
|
}
|
|
3452
|
-
return {
|
|
3552
|
+
return {
|
|
3553
|
+
permission: "confirm",
|
|
3554
|
+
source: "yolo_destructive",
|
|
3555
|
+
riskTier: "destructive",
|
|
3556
|
+
reason: "destructive tool needs explicit approval (confirmDestructive is on)"
|
|
3557
|
+
};
|
|
3453
3558
|
}
|
|
3454
|
-
return {
|
|
3455
|
-
permission: "confirm",
|
|
3456
|
-
source: "yolo_destructive",
|
|
3457
|
-
riskTier: "destructive",
|
|
3458
|
-
reason: "destructive tool needs explicit approval even in yolo mode"
|
|
3459
|
-
};
|
|
3460
3559
|
}
|
|
3461
3560
|
return { permission: "auto", source: "yolo" };
|
|
3462
3561
|
}
|
|
@@ -3486,6 +3585,18 @@ var DefaultPermissionPolicy = class {
|
|
|
3486
3585
|
}
|
|
3487
3586
|
return { permission: "confirm", source: "default" };
|
|
3488
3587
|
}
|
|
3588
|
+
isDestructiveYoloCall(tool, input, ctx) {
|
|
3589
|
+
if (tool.name === "bash") {
|
|
3590
|
+
const command = getInputString(input, "command");
|
|
3591
|
+
return command ? isClearlyDestructiveBashCommand(command, ctx.projectRoot) : true;
|
|
3592
|
+
}
|
|
3593
|
+
if (tool.name === "write" || tool.name === "edit" || tool.name === "replace" || tool.name === "patch") {
|
|
3594
|
+
const targetPath = getInputString(input, "path") ?? getInputString(input, "file");
|
|
3595
|
+
if (!targetPath || !ctx.projectRoot) return false;
|
|
3596
|
+
return !pathLooksInsideProject(targetPath, ctx.projectRoot);
|
|
3597
|
+
}
|
|
3598
|
+
return tool.riskTier === "destructive";
|
|
3599
|
+
}
|
|
3489
3600
|
async trust(rule) {
|
|
3490
3601
|
if (!this.loaded) await this.reload();
|
|
3491
3602
|
const entry = this.policy[rule.tool] ?? {};
|
|
@@ -3803,7 +3914,7 @@ var DefaultRetryPolicy = class {
|
|
|
3803
3914
|
};
|
|
3804
3915
|
|
|
3805
3916
|
// src/execution/error-handler.ts
|
|
3806
|
-
var CONTEXT_OVERFLOW_RE = /context|too long|tokens/i;
|
|
3917
|
+
var CONTEXT_OVERFLOW_RE = /context|too long|tokens|exceeds the context window|context window/i;
|
|
3807
3918
|
function buildRecoveryStrategies(opts) {
|
|
3808
3919
|
return [
|
|
3809
3920
|
{
|
|
@@ -3811,7 +3922,7 @@ function buildRecoveryStrategies(opts) {
|
|
|
3811
3922
|
compactor: opts?.compactor,
|
|
3812
3923
|
async attempt(err, ctx) {
|
|
3813
3924
|
if (!(err instanceof ProviderError)) return null;
|
|
3814
|
-
if (err.status !== 413 && !
|
|
3925
|
+
if (err.status !== 413 && !isContextOverflowError(err)) return null;
|
|
3815
3926
|
if (this.compactor) {
|
|
3816
3927
|
try {
|
|
3817
3928
|
const report = await this.compactor.compact(ctx, { aggressive: true });
|
|
@@ -3845,6 +3956,14 @@ function buildRecoveryStrategies(opts) {
|
|
|
3845
3956
|
];
|
|
3846
3957
|
}
|
|
3847
3958
|
var DEFAULT_RECOVERY_STRATEGIES = buildRecoveryStrategies();
|
|
3959
|
+
function isContextOverflowError(err) {
|
|
3960
|
+
return CONTEXT_OVERFLOW_RE.test([
|
|
3961
|
+
err.message,
|
|
3962
|
+
err.body?.message,
|
|
3963
|
+
err.body?.type,
|
|
3964
|
+
err.body?.raw
|
|
3965
|
+
].filter(Boolean).join("\n"));
|
|
3966
|
+
}
|
|
3848
3967
|
var DefaultErrorHandler = class {
|
|
3849
3968
|
strategies;
|
|
3850
3969
|
constructor(strategies = DEFAULT_RECOVERY_STRATEGIES) {
|
|
@@ -3861,7 +3980,7 @@ var DefaultErrorHandler = class {
|
|
|
3861
3980
|
if (err.status === 429) return { kind: "rate_limit", retryable: true };
|
|
3862
3981
|
if (err.status === 529) return { kind: "overloaded", retryable: true };
|
|
3863
3982
|
if (err.status >= 500) return { kind: "server", retryable: true };
|
|
3864
|
-
if (err.status === 413 ||
|
|
3983
|
+
if (err.status === 413 || isContextOverflowError(err)) {
|
|
3865
3984
|
return { kind: "context_overflow", retryable: false };
|
|
3866
3985
|
}
|
|
3867
3986
|
if (err.status >= 400) return { kind: "client", retryable: false };
|
|
@@ -3900,7 +4019,7 @@ var DefaultSkillLoader = class {
|
|
|
3900
4019
|
const entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
3901
4020
|
for (const e of entries) {
|
|
3902
4021
|
if (!e.isDirectory()) continue;
|
|
3903
|
-
const skillFile =
|
|
4022
|
+
const skillFile = path16.join(dir, e.name, "SKILL.md");
|
|
3904
4023
|
try {
|
|
3905
4024
|
const raw = await fsp.readFile(skillFile, "utf8");
|
|
3906
4025
|
const meta = parseFrontmatter(raw);
|
|
@@ -4312,8 +4431,8 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
|
|
|
4312
4431
|
try {
|
|
4313
4432
|
await Promise.race([
|
|
4314
4433
|
Promise.resolve(iter.return?.()),
|
|
4315
|
-
new Promise((
|
|
4316
|
-
drainTimer = setTimeout(
|
|
4434
|
+
new Promise((resolve5) => {
|
|
4435
|
+
drainTimer = setTimeout(resolve5, 500);
|
|
4317
4436
|
})
|
|
4318
4437
|
]);
|
|
4319
4438
|
} finally {
|
|
@@ -4374,7 +4493,7 @@ async function runProviderWithRetry(opts) {
|
|
|
4374
4493
|
description
|
|
4375
4494
|
});
|
|
4376
4495
|
}
|
|
4377
|
-
await new Promise((
|
|
4496
|
+
await new Promise((resolve5, reject) => {
|
|
4378
4497
|
let settled = false;
|
|
4379
4498
|
const onAbort = () => {
|
|
4380
4499
|
if (settled) return;
|
|
@@ -4387,7 +4506,7 @@ async function runProviderWithRetry(opts) {
|
|
|
4387
4506
|
settled = true;
|
|
4388
4507
|
clearTimeout(t);
|
|
4389
4508
|
signal.removeEventListener("abort", onAbort);
|
|
4390
|
-
|
|
4509
|
+
resolve5();
|
|
4391
4510
|
}, delay);
|
|
4392
4511
|
if (signal.aborted) {
|
|
4393
4512
|
onAbort();
|
|
@@ -5488,11 +5607,11 @@ function validateAgainstSchema(value, schema) {
|
|
|
5488
5607
|
walk3(value, schema, "", errors);
|
|
5489
5608
|
return { ok: errors.length === 0, errors };
|
|
5490
5609
|
}
|
|
5491
|
-
function walk3(value, schema,
|
|
5610
|
+
function walk3(value, schema, path19, errors) {
|
|
5492
5611
|
if (schema.enum !== void 0) {
|
|
5493
5612
|
if (!schema.enum.some((e) => deepEqual(e, value))) {
|
|
5494
5613
|
errors.push({
|
|
5495
|
-
path:
|
|
5614
|
+
path: path19 || "<root>",
|
|
5496
5615
|
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
5497
5616
|
});
|
|
5498
5617
|
return;
|
|
@@ -5501,7 +5620,7 @@ function walk3(value, schema, path18, errors) {
|
|
|
5501
5620
|
if (typeof schema.type === "string") {
|
|
5502
5621
|
if (!checkType(value, schema.type)) {
|
|
5503
5622
|
errors.push({
|
|
5504
|
-
path:
|
|
5623
|
+
path: path19 || "<root>",
|
|
5505
5624
|
message: `expected ${schema.type}, got ${describeType(value)}`
|
|
5506
5625
|
});
|
|
5507
5626
|
return;
|
|
@@ -5511,19 +5630,19 @@ function walk3(value, schema, path18, errors) {
|
|
|
5511
5630
|
const obj = value;
|
|
5512
5631
|
for (const req of schema.required ?? []) {
|
|
5513
5632
|
if (!(req in obj)) {
|
|
5514
|
-
errors.push({ path: joinPath(
|
|
5633
|
+
errors.push({ path: joinPath(path19, req), message: "required property missing" });
|
|
5515
5634
|
}
|
|
5516
5635
|
}
|
|
5517
5636
|
if (schema.properties) {
|
|
5518
5637
|
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
5519
5638
|
if (key in obj) {
|
|
5520
|
-
walk3(obj[key], subSchema, joinPath(
|
|
5639
|
+
walk3(obj[key], subSchema, joinPath(path19, key), errors);
|
|
5521
5640
|
}
|
|
5522
5641
|
}
|
|
5523
5642
|
}
|
|
5524
5643
|
}
|
|
5525
5644
|
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
5526
|
-
value.forEach((item, i) => walk3(item, schema.items, `${
|
|
5645
|
+
value.forEach((item, i) => walk3(item, schema.items, `${path19}[${i}]`, errors));
|
|
5527
5646
|
}
|
|
5528
5647
|
}
|
|
5529
5648
|
function checkType(value, type) {
|
|
@@ -5649,8 +5768,9 @@ var ToolExecutor = class {
|
|
|
5649
5768
|
*/
|
|
5650
5769
|
async executeBatch(toolUses, ctx, strategy) {
|
|
5651
5770
|
let budget = this.opts.perIterationOutputCapBytes ?? 1e5;
|
|
5652
|
-
const runOne = async (
|
|
5771
|
+
const runOne = async (use0) => {
|
|
5653
5772
|
const start = Date.now();
|
|
5773
|
+
let use = use0;
|
|
5654
5774
|
const tool = this.registry.get(use.name);
|
|
5655
5775
|
if (!tool) {
|
|
5656
5776
|
const result = this.unknownToolResult(use, () => this.registry.list().map((t) => t.name));
|
|
@@ -5683,10 +5803,36 @@ Please call the tool again with arguments that match its inputSchema. You can us
|
|
|
5683
5803
|
budget = this.decrementBudget(result, budget);
|
|
5684
5804
|
return { result, tool, durationMs: Date.now() - start };
|
|
5685
5805
|
}
|
|
5806
|
+
if (this.opts.hookRunner?.has("PreToolUse")) {
|
|
5807
|
+
const pre = await this.opts.hookRunner.preToolUse(tool.name, use.input, ctx);
|
|
5808
|
+
if (pre.block) {
|
|
5809
|
+
const result = this.blockedByHookResult(use, pre.reason);
|
|
5810
|
+
budget = this.decrementBudget(result, budget);
|
|
5811
|
+
return { result, tool, durationMs: Date.now() - start };
|
|
5812
|
+
}
|
|
5813
|
+
if (pre.input) {
|
|
5814
|
+
const reval = validateAgainstSchema(pre.input, tool.inputSchema);
|
|
5815
|
+
if (!reval.ok) {
|
|
5816
|
+
const errorDetails = reval.errors.map((e) => ` - ${e.path || "input"}: ${e.message}`).join("\n");
|
|
5817
|
+
const result = {
|
|
5818
|
+
type: "tool_result",
|
|
5819
|
+
tool_use_id: use.id,
|
|
5820
|
+
content: `A PreToolUse hook rewrote the arguments for "${tool.name}" into an invalid shape.
|
|
5821
|
+
|
|
5822
|
+
Validation errors:
|
|
5823
|
+
${errorDetails}`,
|
|
5824
|
+
is_error: true
|
|
5825
|
+
};
|
|
5826
|
+
budget = this.decrementBudget(result, budget);
|
|
5827
|
+
return { result, tool, durationMs: Date.now() - start };
|
|
5828
|
+
}
|
|
5829
|
+
use = { ...use, input: pre.input };
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5686
5832
|
const decision = await this.opts.permissionPolicy.evaluate(tool, use.input, ctx);
|
|
5687
5833
|
let effectivePermission = decision.permission;
|
|
5688
5834
|
const policy = this.opts.permissionPolicy;
|
|
5689
|
-
const yolo = policy.getYolo?.() === true || policy.getForceAllYolo?.() === true;
|
|
5835
|
+
const yolo = policy.getYolo?.() === true || policy.getYoloDestructive?.() === true || policy.getForceAllYolo?.() === true;
|
|
5690
5836
|
if (toolDangerousCaps.length > 0 && effectivePermission === "auto" && !yolo) {
|
|
5691
5837
|
effectivePermission = "confirm";
|
|
5692
5838
|
}
|
|
@@ -5729,7 +5875,20 @@ Please call the tool again with arguments that match its inputSchema. You can us
|
|
|
5729
5875
|
"tool.has_dangerous_capabilities": toolCapsForAudit.length > 0
|
|
5730
5876
|
});
|
|
5731
5877
|
try {
|
|
5732
|
-
|
|
5878
|
+
let result = await this.executeTool(tool, use, ctx, budget);
|
|
5879
|
+
if (this.opts.hookRunner?.has("PostToolUse")) {
|
|
5880
|
+
const post = await this.opts.hookRunner.postToolUse(
|
|
5881
|
+
tool.name,
|
|
5882
|
+
use.input,
|
|
5883
|
+
{ content: String(result.content), isError: !!result.is_error },
|
|
5884
|
+
ctx
|
|
5885
|
+
);
|
|
5886
|
+
if (post.additionalContext) {
|
|
5887
|
+
result = { ...result, content: `${result.content}
|
|
5888
|
+
|
|
5889
|
+
${post.additionalContext}` };
|
|
5890
|
+
}
|
|
5891
|
+
}
|
|
5733
5892
|
budget = this.decrementBudget(result, budget);
|
|
5734
5893
|
span?.setAttribute("tool.is_error", !!result.is_error);
|
|
5735
5894
|
span?.setAttribute(
|
|
@@ -5918,6 +6077,14 @@ ${excerpt}`;
|
|
|
5918
6077
|
is_error: true
|
|
5919
6078
|
};
|
|
5920
6079
|
}
|
|
6080
|
+
blockedByHookResult(use, reason) {
|
|
6081
|
+
return {
|
|
6082
|
+
type: "tool_result",
|
|
6083
|
+
tool_use_id: use.id,
|
|
6084
|
+
content: `Tool "${use.name}" was blocked by a PreToolUse hook: ${reason ?? "no reason given"}`,
|
|
6085
|
+
is_error: true
|
|
6086
|
+
};
|
|
6087
|
+
}
|
|
5921
6088
|
decrementBudget(result, budget) {
|
|
5922
6089
|
const contentBytes = typeof result.content === "string" ? Buffer.byteLength(result.content, "utf8") : Buffer.byteLength(JSON.stringify(result.content), "utf8");
|
|
5923
6090
|
return Math.max(0, budget - contentBytes);
|
|
@@ -6144,8 +6311,8 @@ var AutonomousRunner = class {
|
|
|
6144
6311
|
init_atomic_write();
|
|
6145
6312
|
var MAX_JOURNAL_ENTRIES = 500;
|
|
6146
6313
|
function goalFilePath(projectRoot) {
|
|
6147
|
-
const hash = createHash("sha256").update(
|
|
6148
|
-
return
|
|
6314
|
+
const hash = createHash("sha256").update(path16.resolve(projectRoot)).digest("hex").slice(0, 12);
|
|
6315
|
+
return path16.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
|
|
6149
6316
|
}
|
|
6150
6317
|
async function loadGoal(filePath) {
|
|
6151
6318
|
let raw;
|
|
@@ -6631,7 +6798,8 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
6631
6798
|
" \u2022 When this iteration's Task is finished (real artifact / passing",
|
|
6632
6799
|
" test / applied diff / clean output), emit `[done]` on its own line.",
|
|
6633
6800
|
" \u2022 Do not stop on the first obstacle \u2014 try at least 3 distinct",
|
|
6634
|
-
" approaches before giving up. YOLO is active
|
|
6801
|
+
" approaches before giving up. YOLO is active for normal project work;",
|
|
6802
|
+
" destructive-gated confirmations still belong to the permission flow.",
|
|
6635
6803
|
"",
|
|
6636
6804
|
"2. UPDATE TODO STATE (when Source is `todo`)",
|
|
6637
6805
|
" \u2022 Mark this todo `in_progress` via the todos tool before tool work.",
|
|
@@ -6760,7 +6928,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
6760
6928
|
}
|
|
6761
6929
|
};
|
|
6762
6930
|
function sleep(ms) {
|
|
6763
|
-
return new Promise((
|
|
6931
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
6764
6932
|
}
|
|
6765
6933
|
|
|
6766
6934
|
// src/coordination/subagent-budget.ts
|
|
@@ -6976,12 +7144,12 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
6976
7144
|
if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
|
|
6977
7145
|
return Promise.resolve("stop");
|
|
6978
7146
|
}
|
|
6979
|
-
return new Promise((
|
|
7147
|
+
return new Promise((resolve5) => {
|
|
6980
7148
|
let resolved = false;
|
|
6981
7149
|
const respond = (d) => {
|
|
6982
7150
|
if (resolved) return;
|
|
6983
7151
|
resolved = true;
|
|
6984
|
-
|
|
7152
|
+
resolve5(d);
|
|
6985
7153
|
};
|
|
6986
7154
|
const fallback = setTimeout(
|
|
6987
7155
|
() => respond("stop"),
|
|
@@ -7052,15 +7220,22 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
7052
7220
|
void this.checkLimits();
|
|
7053
7221
|
}
|
|
7054
7222
|
/**
|
|
7055
|
-
* Wall-clock budget check.
|
|
7056
|
-
*
|
|
7057
|
-
*
|
|
7223
|
+
* Wall-clock / idle budget check. Delegates to `checkLimits(elapsed)`, so
|
|
7224
|
+
* `timeout` and `idle_timeout` follow the SAME negotiation path as the other
|
|
7225
|
+
* kinds — they are NOT a special-cased hard stop. This is deliberate: a
|
|
7226
|
+
* heartbeat-aware policy (see `attachAutoExtend` and `CollabSession`) grants
|
|
7227
|
+
* a timeout extension only while the agent is making progress and denies it
|
|
7228
|
+
* once the agent is genuinely stuck, which is safer than an unconditional
|
|
7229
|
+
* hard kill of a long-but-working agent. The runner translates the resulting
|
|
7230
|
+
* `BudgetThresholdSignal` decision (`extend` → patch limits in place,
|
|
7231
|
+
* `stop` → abort) just like every other kind.
|
|
7058
7232
|
*
|
|
7059
|
-
* Decision table:
|
|
7060
|
-
* - no `onThreshold` handler
|
|
7061
|
-
* - `mode === 'sync'` → throw `BudgetExceededError`
|
|
7062
|
-
* - `mode === 'auto'` + no listener
|
|
7063
|
-
* - `mode === 'auto'` + listener
|
|
7233
|
+
* Decision table (same as `checkLimits`):
|
|
7234
|
+
* - no `onThreshold` handler → throw `BudgetExceededError` (hard stop)
|
|
7235
|
+
* - `mode === 'sync'` → throw `BudgetExceededError` (hard stop)
|
|
7236
|
+
* - `mode === 'auto'` + no listener → throw `BudgetExceededError` (no one to ask)
|
|
7237
|
+
* - `mode === 'auto'` + listener → throw `BudgetThresholdSignal` (negotiated;
|
|
7238
|
+
* a heartbeat-aware policy may extend the timeout)
|
|
7064
7239
|
*/
|
|
7065
7240
|
checkTimeout() {
|
|
7066
7241
|
if (this.startTime === null) return;
|
|
@@ -9926,7 +10101,10 @@ var NICKNAME_POOL = {
|
|
|
9926
10101
|
"lavoisier": { name: "Lavoisier", domain: "chemistry" },
|
|
9927
10102
|
"mendeleev": { name: "Mendeleev", domain: "chemistry" }
|
|
9928
10103
|
};
|
|
9929
|
-
var ALL_NICKNAMES = Object.
|
|
10104
|
+
var ALL_NICKNAMES = Object.entries(NICKNAME_POOL);
|
|
10105
|
+
var NAME_TO_KEY = Object.fromEntries(
|
|
10106
|
+
ALL_NICKNAMES.map(([key, entry]) => [entry.name, key])
|
|
10107
|
+
);
|
|
9930
10108
|
var DOMAIN_PREFERENCES = {
|
|
9931
10109
|
"security": ["shannon", "turing", "lamarr", "stallman"],
|
|
9932
10110
|
"bug-hunter": ["darwin", "curie", "feynman", "fermi"],
|
|
@@ -9959,17 +10137,23 @@ function assignNickname(role, used) {
|
|
|
9959
10137
|
for (const key of preferences) {
|
|
9960
10138
|
const entry = NICKNAME_POOL[key];
|
|
9961
10139
|
if (entry && !used.has(key)) {
|
|
9962
|
-
return `${entry.name} (${formatRole(role)})
|
|
10140
|
+
return { key, display: `${entry.name} (${formatRole(role)})` };
|
|
9963
10141
|
}
|
|
9964
10142
|
}
|
|
9965
|
-
for (const entry of ALL_NICKNAMES) {
|
|
9966
|
-
|
|
9967
|
-
|
|
9968
|
-
return `${entry.name} (${formatRole(role)})`;
|
|
10143
|
+
for (const [key, entry] of ALL_NICKNAMES) {
|
|
10144
|
+
if (!used.has(key)) {
|
|
10145
|
+
return { key, display: `${entry.name} (${formatRole(role)})` };
|
|
9969
10146
|
}
|
|
9970
10147
|
}
|
|
9971
10148
|
const counter = used.size + 1;
|
|
9972
|
-
return `Scientist #${counter} (${formatRole(role)})
|
|
10149
|
+
return { key: `scientist-${counter}`, display: `Scientist #${counter} (${formatRole(role)})` };
|
|
10150
|
+
}
|
|
10151
|
+
function nicknameKeyFromDisplay(display) {
|
|
10152
|
+
const base = display.replace(/\s*\([^)]*\)\s*$/, "").trim();
|
|
10153
|
+
const key = NAME_TO_KEY[base];
|
|
10154
|
+
if (key) return key;
|
|
10155
|
+
const synthesized = base.match(/^Scientist #(\d+)$/);
|
|
10156
|
+
return synthesized ? `scientist-${synthesized[1]}` : void 0;
|
|
9973
10157
|
}
|
|
9974
10158
|
function formatRole(role) {
|
|
9975
10159
|
return role.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
@@ -10056,11 +10240,10 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10056
10240
|
const name = subagent.name?.trim() ?? "";
|
|
10057
10241
|
const isPlaceholder = name === "" || name.toLowerCase() === role.toLowerCase() || name === "subagent" || name === "adhoc" || name === "generic" || /^slot-/.test(name);
|
|
10058
10242
|
if (!isPlaceholder) return subagent;
|
|
10059
|
-
const
|
|
10060
|
-
|
|
10061
|
-
this.
|
|
10062
|
-
|
|
10063
|
-
return { ...subagent, name: nickname };
|
|
10243
|
+
const { key, display } = assignNickname(role, this.usedNicknames);
|
|
10244
|
+
this.usedNicknames.add(key);
|
|
10245
|
+
this.subagentNicknames.set(subagentId, key);
|
|
10246
|
+
return { ...subagent, name: display };
|
|
10064
10247
|
}
|
|
10065
10248
|
async spawn(subagent) {
|
|
10066
10249
|
const id = subagent.id || randomUUID();
|
|
@@ -10208,7 +10391,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10208
10391
|
taskIds.map((id) => {
|
|
10209
10392
|
const cached = this.completedResults.find((r) => r.taskId === id);
|
|
10210
10393
|
if (cached) return cached;
|
|
10211
|
-
return new Promise((
|
|
10394
|
+
return new Promise((resolve5, reject) => {
|
|
10212
10395
|
const timeout = setTimeout(() => {
|
|
10213
10396
|
this.off("task.completed", handler);
|
|
10214
10397
|
reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
|
|
@@ -10217,7 +10400,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10217
10400
|
if (result.taskId === id) {
|
|
10218
10401
|
clearTimeout(timeout);
|
|
10219
10402
|
this.off("task.completed", handler);
|
|
10220
|
-
|
|
10403
|
+
resolve5(result);
|
|
10221
10404
|
}
|
|
10222
10405
|
};
|
|
10223
10406
|
this.on("task.completed", handler);
|
|
@@ -10312,23 +10495,32 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10312
10495
|
*/
|
|
10313
10496
|
drainPendingAsAborted(message) {
|
|
10314
10497
|
const dropped = this.pendingTasks.splice(0, this.pendingTasks.length);
|
|
10315
|
-
for (const t of dropped)
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10498
|
+
for (const t of dropped) this.emitPendingAborted(t, message);
|
|
10499
|
+
}
|
|
10500
|
+
/**
|
|
10501
|
+
* Emit a synthetic `stopped`/`aborted_by_parent` completion for a single
|
|
10502
|
+
* PENDING task — one that was never counted in `inFlight`. This MUST bypass
|
|
10503
|
+
* `recordCompletion`: that path does `inFlight--`, which for a pending task
|
|
10504
|
+
* steals a decrement from a genuinely in-flight task and trips the underflow
|
|
10505
|
+
* guard — suppressing that real task's `task.completed` and hanging its
|
|
10506
|
+
* `awaitTasks()` caller. Pushes the result and fires the event directly.
|
|
10507
|
+
*/
|
|
10508
|
+
emitPendingAborted(task, message) {
|
|
10509
|
+
const synthetic = {
|
|
10510
|
+
subagentId: task.subagentId ?? "unassigned",
|
|
10511
|
+
taskId: task.id,
|
|
10512
|
+
status: "stopped",
|
|
10513
|
+
error: {
|
|
10514
|
+
kind: "aborted_by_parent",
|
|
10515
|
+
message,
|
|
10516
|
+
retryable: false
|
|
10517
|
+
},
|
|
10518
|
+
iterations: 0,
|
|
10519
|
+
toolCalls: 0,
|
|
10520
|
+
durationMs: 0
|
|
10521
|
+
};
|
|
10522
|
+
this.completedResults.push(synthetic);
|
|
10523
|
+
this.emit("task.completed", { task, result: synthetic });
|
|
10332
10524
|
}
|
|
10333
10525
|
async runDispatched(subagentId, task) {
|
|
10334
10526
|
const subagent = this.subagents.get(subagentId);
|
|
@@ -10589,20 +10781,10 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10589
10781
|
const orphaned = this.pendingTasks.filter((t) => t.subagentId === subagentId);
|
|
10590
10782
|
this.pendingTasks = this.pendingTasks.filter((t) => t.subagentId !== subagentId);
|
|
10591
10783
|
for (const t of orphaned) {
|
|
10592
|
-
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10596
|
-
error: {
|
|
10597
|
-
kind: "aborted_by_parent",
|
|
10598
|
-
message: `Subagent "${subagentId}" was removed while task "${t.id}" was pending`,
|
|
10599
|
-
retryable: false
|
|
10600
|
-
},
|
|
10601
|
-
iterations: 0,
|
|
10602
|
-
toolCalls: 0,
|
|
10603
|
-
durationMs: 0
|
|
10604
|
-
};
|
|
10605
|
-
this.recordCompletion(synthetic);
|
|
10784
|
+
this.emitPendingAborted(
|
|
10785
|
+
t,
|
|
10786
|
+
`Subagent "${subagentId}" was removed while task "${t.id}" was pending`
|
|
10787
|
+
);
|
|
10606
10788
|
}
|
|
10607
10789
|
this.fleetBus?.emit({
|
|
10608
10790
|
subagentId,
|
|
@@ -10720,7 +10902,7 @@ function providerErrorToSubagentError(err, message, cause) {
|
|
|
10720
10902
|
|
|
10721
10903
|
// src/execution/parallel-eternal-engine.ts
|
|
10722
10904
|
function sleep2(ms) {
|
|
10723
|
-
return new Promise((
|
|
10905
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
10724
10906
|
}
|
|
10725
10907
|
var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
10726
10908
|
var ParallelEternalEngine = class {
|
|
@@ -10899,7 +11081,8 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
10899
11081
|
"\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500",
|
|
10900
11082
|
"\u2022 Execute the assigned task end-to-end using multiple tool calls.",
|
|
10901
11083
|
"\u2022 Emit `[done]` on its own line when the task is complete.",
|
|
10902
|
-
"\u2022 Do not ask
|
|
11084
|
+
"\u2022 Do not ask before routine in-project tool use \u2014 YOLO is active for normal project work.",
|
|
11085
|
+
"\u2022 If a destructive-gated confirmation appears, wait for the permission flow.",
|
|
10903
11086
|
"\u2022 If the overall Mission is accomplished, emit `[GOAL_COMPLETE]` followed by a verification recipe.",
|
|
10904
11087
|
"\u2022 Keep output concise \u2014 summarize findings, do not transcribe files."
|
|
10905
11088
|
].join("\n");
|
|
@@ -10979,6 +11162,7 @@ ${personaLine}Task: ${task}
|
|
|
10979
11162
|
} catch {
|
|
10980
11163
|
results = coordinator.results().slice(-taskIds.length);
|
|
10981
11164
|
}
|
|
11165
|
+
await Promise.allSettled(subagentIds.map((id) => coordinator.remove(id)));
|
|
10982
11166
|
const allSuccessful = results.length > 0 && results.every((r) => r.status === "success");
|
|
10983
11167
|
const goalComplete = results.some(
|
|
10984
11168
|
(r) => r.status === "success" && typeof r.result === "string" && GOAL_COMPLETE_MARKER2.test(r.result)
|
|
@@ -11156,8 +11340,10 @@ ${journalTail.join("\n")}` : "Recent journal: (none \u2014 this is the first ite
|
|
|
11156
11340
|
" decide.",
|
|
11157
11341
|
"",
|
|
11158
11342
|
"### Operating principles",
|
|
11159
|
-
"- YOLO is active
|
|
11160
|
-
"
|
|
11343
|
+
"- YOLO is active for normal project work. Proceed with routine",
|
|
11344
|
+
" in-project tool use without pre-confirming; pick the best path and execute it.",
|
|
11345
|
+
" If the permission system raises a destructive-gated confirmation, wait",
|
|
11346
|
+
" for that flow instead of trying to bypass it.",
|
|
11161
11347
|
"- Use tools freely; multiple calls per turn are normal and expected.",
|
|
11162
11348
|
"- When working on a todo, mark it `in_progress` via the todos tool",
|
|
11163
11349
|
" before tool work and `completed` (or `cancelled` with a reason)",
|
|
@@ -11346,7 +11532,7 @@ var InMemoryAgentBridge = class {
|
|
|
11346
11532
|
);
|
|
11347
11533
|
}
|
|
11348
11534
|
this.inflightGuards.add(correlationId);
|
|
11349
|
-
return new Promise((
|
|
11535
|
+
return new Promise((resolve5, reject) => {
|
|
11350
11536
|
const timer = setTimeout(() => {
|
|
11351
11537
|
this.inflightGuards.delete(correlationId);
|
|
11352
11538
|
this.pendingRequests.delete(correlationId);
|
|
@@ -11358,7 +11544,7 @@ var InMemoryAgentBridge = class {
|
|
|
11358
11544
|
return;
|
|
11359
11545
|
}
|
|
11360
11546
|
this.pendingRequests.set(correlationId, {
|
|
11361
|
-
resolve:
|
|
11547
|
+
resolve: resolve5,
|
|
11362
11548
|
reject,
|
|
11363
11549
|
timer
|
|
11364
11550
|
});
|
|
@@ -12036,6 +12222,10 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
12036
12222
|
return lines.join("\n");
|
|
12037
12223
|
}
|
|
12038
12224
|
cleanup() {
|
|
12225
|
+
if (this._timeoutTimer) {
|
|
12226
|
+
clearTimeout(this._timeoutTimer);
|
|
12227
|
+
this._timeoutTimer = void 0;
|
|
12228
|
+
}
|
|
12039
12229
|
for (const dispose of this.disposers) dispose();
|
|
12040
12230
|
this.disposers.length = 0;
|
|
12041
12231
|
}
|
|
@@ -13153,18 +13343,20 @@ var Director = class _Director {
|
|
|
13153
13343
|
if (e.subagentId.startsWith("bug-hunter-") || e.subagentId.startsWith("refactor-planner-") || e.subagentId.startsWith("critic-")) {
|
|
13154
13344
|
return;
|
|
13155
13345
|
}
|
|
13156
|
-
if (payload.kind === "timeout") {
|
|
13346
|
+
if (payload.kind === "timeout" || payload.kind === "idle_timeout") {
|
|
13347
|
+
const heartbeatKey = `${e.subagentId}:${payload.kind}`;
|
|
13157
13348
|
const progress = progressBySubagent.get(e.subagentId) ?? 0;
|
|
13158
|
-
const lastProgress = lastTimeoutProgress.get(
|
|
13349
|
+
const lastProgress = lastTimeoutProgress.get(heartbeatKey) ?? -1;
|
|
13159
13350
|
if (progress <= lastProgress) {
|
|
13160
13351
|
payload.deny();
|
|
13161
13352
|
return;
|
|
13162
13353
|
}
|
|
13163
|
-
lastTimeoutProgress.set(
|
|
13354
|
+
lastTimeoutProgress.set(heartbeatKey, progress);
|
|
13355
|
+
const field = payload.kind === "timeout" ? "timeoutMs" : "idleTimeoutMs";
|
|
13164
13356
|
setImmediate(() => {
|
|
13165
13357
|
const newLimit = Math.min(Math.ceil(payload.limit * 2), 24 * 60 * 6e4);
|
|
13166
|
-
this.recordExtension(e.subagentId, e.taskId,
|
|
13167
|
-
payload.extend({
|
|
13358
|
+
this.recordExtension(e.subagentId, e.taskId, payload.kind, newLimit);
|
|
13359
|
+
payload.extend({ [field]: newLimit });
|
|
13168
13360
|
});
|
|
13169
13361
|
return;
|
|
13170
13362
|
}
|
|
@@ -13480,10 +13672,9 @@ var Director = class _Director {
|
|
|
13480
13672
|
if (this.fleetManager) {
|
|
13481
13673
|
this.fleetManager.assignNicknameAndRecord(config);
|
|
13482
13674
|
} else {
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
);
|
|
13675
|
+
const { key, display } = assignNickname(role, this._usedNicknames);
|
|
13676
|
+
config.name = display;
|
|
13677
|
+
this._usedNicknames.add(key);
|
|
13487
13678
|
}
|
|
13488
13679
|
}
|
|
13489
13680
|
result = await this.coordinator.spawn(config);
|
|
@@ -13658,7 +13849,7 @@ var Director = class _Director {
|
|
|
13658
13849
|
})),
|
|
13659
13850
|
usage: this.usage.snapshot()
|
|
13660
13851
|
};
|
|
13661
|
-
await fsp.mkdir(
|
|
13852
|
+
await fsp.mkdir(path16.dirname(this.manifestPath), { recursive: true });
|
|
13662
13853
|
await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
|
|
13663
13854
|
return this.manifestPath;
|
|
13664
13855
|
}
|
|
@@ -13777,11 +13968,11 @@ var Director = class _Director {
|
|
|
13777
13968
|
if (cached) return cached;
|
|
13778
13969
|
const existing = this.taskWaiters.get(id);
|
|
13779
13970
|
if (existing) return existing.promise;
|
|
13780
|
-
let
|
|
13971
|
+
let resolve5;
|
|
13781
13972
|
const promise = new Promise((res) => {
|
|
13782
|
-
|
|
13973
|
+
resolve5 = res;
|
|
13783
13974
|
});
|
|
13784
|
-
this.taskWaiters.set(id, { promise, resolve:
|
|
13975
|
+
this.taskWaiters.set(id, { promise, resolve: resolve5 });
|
|
13785
13976
|
return promise;
|
|
13786
13977
|
})
|
|
13787
13978
|
);
|
|
@@ -13805,8 +13996,8 @@ var Director = class _Director {
|
|
|
13805
13996
|
} else {
|
|
13806
13997
|
const entry = this.manifestEntries.get(subagentId);
|
|
13807
13998
|
if (entry?.name) {
|
|
13808
|
-
const nicknameKey = entry.name
|
|
13809
|
-
this._usedNicknames.delete(nicknameKey);
|
|
13999
|
+
const nicknameKey = nicknameKeyFromDisplay(entry.name);
|
|
14000
|
+
if (nicknameKey) this._usedNicknames.delete(nicknameKey);
|
|
13810
14001
|
}
|
|
13811
14002
|
}
|
|
13812
14003
|
this.manifestEntries.delete(subagentId);
|
|
@@ -13864,7 +14055,7 @@ var Director = class _Director {
|
|
|
13864
14055
|
*/
|
|
13865
14056
|
async readSession(subagentId, tail) {
|
|
13866
14057
|
if (!this.sessionsRoot) return null;
|
|
13867
|
-
const filePath =
|
|
14058
|
+
const filePath = path16.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
|
|
13868
14059
|
let raw;
|
|
13869
14060
|
try {
|
|
13870
14061
|
raw = await fsp.readFile(filePath, "utf8");
|
|
@@ -14166,7 +14357,7 @@ function createDelegateTool(opts) {
|
|
|
14166
14357
|
subagentId
|
|
14167
14358
|
});
|
|
14168
14359
|
const dir = director;
|
|
14169
|
-
const result = await new Promise((
|
|
14360
|
+
const result = await new Promise((resolve5) => {
|
|
14170
14361
|
let settled = false;
|
|
14171
14362
|
let timer;
|
|
14172
14363
|
const finish = (value) => {
|
|
@@ -14176,7 +14367,7 @@ function createDelegateTool(opts) {
|
|
|
14176
14367
|
offTool();
|
|
14177
14368
|
offIter();
|
|
14178
14369
|
offProgress();
|
|
14179
|
-
|
|
14370
|
+
resolve5(value);
|
|
14180
14371
|
};
|
|
14181
14372
|
const arm = () => {
|
|
14182
14373
|
if (timer) clearTimeout(timer);
|
|
@@ -14320,13 +14511,13 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
14320
14511
|
if (!opts.sessionsRoot) return void 0;
|
|
14321
14512
|
const candidates = [];
|
|
14322
14513
|
if (opts.directorRunId) {
|
|
14323
|
-
candidates.push(
|
|
14514
|
+
candidates.push(path16.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
|
|
14324
14515
|
} else {
|
|
14325
14516
|
try {
|
|
14326
14517
|
const entries = await fsp.readdir(opts.sessionsRoot, { withFileTypes: true });
|
|
14327
14518
|
for (const entry of entries) {
|
|
14328
14519
|
if (entry.isDirectory()) {
|
|
14329
|
-
candidates.push(
|
|
14520
|
+
candidates.push(path16.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
|
|
14330
14521
|
}
|
|
14331
14522
|
}
|
|
14332
14523
|
} catch {
|
|
@@ -14373,9 +14564,9 @@ function makeDirectorSessionFactory(opts) {
|
|
|
14373
14564
|
let dir;
|
|
14374
14565
|
if (opts.store) {
|
|
14375
14566
|
store = opts.store;
|
|
14376
|
-
dir = opts.sessionsRoot ?
|
|
14567
|
+
dir = opts.sessionsRoot ? path16.join(opts.sessionsRoot, runId) : "(caller-managed)";
|
|
14377
14568
|
} else if (opts.sessionsRoot) {
|
|
14378
|
-
dir =
|
|
14569
|
+
dir = path16.join(opts.sessionsRoot, runId);
|
|
14379
14570
|
store = new DefaultSessionStore({ dir });
|
|
14380
14571
|
} else {
|
|
14381
14572
|
throw new Error("makeDirectorSessionFactory requires either `store` or `sessionsRoot`");
|
|
@@ -14579,7 +14770,7 @@ var DefaultModelsRegistry = class {
|
|
|
14579
14770
|
this.overlay = opts.overlay;
|
|
14580
14771
|
this.overlayUrl = opts.overlayUrl;
|
|
14581
14772
|
this.overlayFile = opts.overlayFile;
|
|
14582
|
-
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ?
|
|
14773
|
+
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path16.join(path16.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
|
|
14583
14774
|
}
|
|
14584
14775
|
async load(opts = {}) {
|
|
14585
14776
|
if (this.payload && !opts.force) return this.payload;
|
|
@@ -14792,7 +14983,7 @@ var DefaultModelsRegistry = class {
|
|
|
14792
14983
|
}
|
|
14793
14984
|
/** Used by `wstack models refresh` to expose where the cache lives. */
|
|
14794
14985
|
cacheLocation() {
|
|
14795
|
-
return
|
|
14986
|
+
return path16.resolve(this.cacheFile);
|
|
14796
14987
|
}
|
|
14797
14988
|
};
|
|
14798
14989
|
function hasEntries(payload) {
|
|
@@ -15079,7 +15270,7 @@ var DefaultModeStore = class {
|
|
|
15079
15270
|
}
|
|
15080
15271
|
async loadActiveMode() {
|
|
15081
15272
|
try {
|
|
15082
|
-
const configPath =
|
|
15273
|
+
const configPath = path16.join(this.configDir, "mode.json");
|
|
15083
15274
|
const content = await fsp.readFile(configPath, "utf8");
|
|
15084
15275
|
const data = JSON.parse(content);
|
|
15085
15276
|
this.activeModeId = data.activeMode ?? null;
|
|
@@ -15090,7 +15281,7 @@ var DefaultModeStore = class {
|
|
|
15090
15281
|
async saveActiveMode() {
|
|
15091
15282
|
try {
|
|
15092
15283
|
await fsp.mkdir(this.configDir, { recursive: true });
|
|
15093
|
-
const configPath =
|
|
15284
|
+
const configPath = path16.join(this.configDir, "mode.json");
|
|
15094
15285
|
await atomicWrite(
|
|
15095
15286
|
configPath,
|
|
15096
15287
|
JSON.stringify({ activeMode: this.activeModeId }, null, 2)
|
|
@@ -15105,11 +15296,11 @@ async function loadProjectModes(modesDir) {
|
|
|
15105
15296
|
const entries = await fsp.readdir(modesDir);
|
|
15106
15297
|
for (const entry of entries) {
|
|
15107
15298
|
if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
|
|
15108
|
-
const filePath =
|
|
15299
|
+
const filePath = path16.join(modesDir, entry);
|
|
15109
15300
|
const stat5 = await fsp.stat(filePath);
|
|
15110
15301
|
if (!stat5.isFile()) continue;
|
|
15111
15302
|
const content = await fsp.readFile(filePath, "utf8");
|
|
15112
|
-
const id =
|
|
15303
|
+
const id = path16.basename(entry, path16.extname(entry));
|
|
15113
15304
|
modes.push({
|
|
15114
15305
|
id,
|
|
15115
15306
|
name: id.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
@@ -15125,7 +15316,7 @@ async function loadProjectModes(modesDir) {
|
|
|
15125
15316
|
async function loadUserModes(modesDir) {
|
|
15126
15317
|
const modes = [];
|
|
15127
15318
|
try {
|
|
15128
|
-
const manifestPath =
|
|
15319
|
+
const manifestPath = path16.join(modesDir, "modes.json");
|
|
15129
15320
|
const content = await fsp.readFile(manifestPath, "utf8");
|
|
15130
15321
|
const manifest = JSON.parse(content);
|
|
15131
15322
|
for (const mode of manifest.modes) {
|
|
@@ -16042,7 +16233,7 @@ var SpecStore = class {
|
|
|
16042
16233
|
indexPath;
|
|
16043
16234
|
constructor(opts) {
|
|
16044
16235
|
this.baseDir = opts.baseDir;
|
|
16045
|
-
this.indexPath =
|
|
16236
|
+
this.indexPath = path16.join(this.baseDir, "_index.json");
|
|
16046
16237
|
}
|
|
16047
16238
|
async save(spec) {
|
|
16048
16239
|
await ensureDir(this.baseDir);
|
|
@@ -16111,7 +16302,7 @@ var SpecStore = class {
|
|
|
16111
16302
|
return updated;
|
|
16112
16303
|
}
|
|
16113
16304
|
filePath(id) {
|
|
16114
|
-
return
|
|
16305
|
+
return path16.join(this.baseDir, `${id}.json`);
|
|
16115
16306
|
}
|
|
16116
16307
|
async readIndex() {
|
|
16117
16308
|
try {
|
|
@@ -16168,7 +16359,7 @@ var TaskGraphStore = class {
|
|
|
16168
16359
|
indexPath;
|
|
16169
16360
|
constructor(opts) {
|
|
16170
16361
|
this.baseDir = opts.baseDir;
|
|
16171
|
-
this.indexPath =
|
|
16362
|
+
this.indexPath = path16.join(this.baseDir, "_index.json");
|
|
16172
16363
|
}
|
|
16173
16364
|
async save(graph) {
|
|
16174
16365
|
await ensureDir(this.baseDir);
|
|
@@ -16206,7 +16397,7 @@ var TaskGraphStore = class {
|
|
|
16206
16397
|
}
|
|
16207
16398
|
}
|
|
16208
16399
|
filePath(id) {
|
|
16209
|
-
return
|
|
16400
|
+
return path16.join(this.baseDir, `${id}.json`);
|
|
16210
16401
|
}
|
|
16211
16402
|
async readIndex() {
|
|
16212
16403
|
try {
|
|
@@ -16451,9 +16642,9 @@ var AISpecBuilder = class {
|
|
|
16451
16642
|
if (!this.sessionPath) return;
|
|
16452
16643
|
try {
|
|
16453
16644
|
const fsp16 = await import('fs/promises');
|
|
16454
|
-
const
|
|
16645
|
+
const path19 = await import('path');
|
|
16455
16646
|
const { atomicWrite: atomicWrite2 } = await Promise.resolve().then(() => (init_atomic_write(), atomic_write_exports));
|
|
16456
|
-
await fsp16.mkdir(
|
|
16647
|
+
await fsp16.mkdir(path19.dirname(this.sessionPath), { recursive: true });
|
|
16457
16648
|
await atomicWrite2(this.sessionPath, JSON.stringify(this.session, null, 2));
|
|
16458
16649
|
} catch {
|
|
16459
16650
|
}
|
|
@@ -17163,15 +17354,15 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
|
|
|
17163
17354
|
maxId = id;
|
|
17164
17355
|
}
|
|
17165
17356
|
}
|
|
17166
|
-
const
|
|
17357
|
+
const path19 = [];
|
|
17167
17358
|
let current = maxId;
|
|
17168
17359
|
const visited = /* @__PURE__ */ new Set();
|
|
17169
17360
|
while (current && !visited.has(current)) {
|
|
17170
17361
|
visited.add(current);
|
|
17171
|
-
|
|
17362
|
+
path19.unshift(current);
|
|
17172
17363
|
current = prev.get(current) ?? null;
|
|
17173
17364
|
}
|
|
17174
|
-
return
|
|
17365
|
+
return path19;
|
|
17175
17366
|
}
|
|
17176
17367
|
function computeParallelGroups(graph, blockedByMap) {
|
|
17177
17368
|
const groups = [];
|
|
@@ -17721,7 +17912,7 @@ var SddParallelRun = class {
|
|
|
17721
17912
|
"\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500",
|
|
17722
17913
|
"\u2022 Execute the assigned SDD task end-to-end using multiple tool calls.",
|
|
17723
17914
|
"\u2022 Mark the task [done] in the tracker when complete.",
|
|
17724
|
-
"\u2022 Do not ask for
|
|
17915
|
+
"\u2022 Do not ask before routine in-project tool use; if a permission gate appears, wait for that flow.",
|
|
17725
17916
|
"\u2022 Keep output concise \u2014 summarize changes, do not transcribe files."
|
|
17726
17917
|
].join("\n");
|
|
17727
17918
|
const spawns = subagentIds.map(
|
|
@@ -17964,9 +18155,9 @@ var DefaultHealthRegistry = class {
|
|
|
17964
18155
|
}
|
|
17965
18156
|
async runOne(check) {
|
|
17966
18157
|
let timer = null;
|
|
17967
|
-
const timeout = new Promise((
|
|
18158
|
+
const timeout = new Promise((resolve5) => {
|
|
17968
18159
|
timer = setTimeout(
|
|
17969
|
-
() =>
|
|
18160
|
+
() => resolve5({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
|
|
17970
18161
|
this.timeoutMs
|
|
17971
18162
|
);
|
|
17972
18163
|
});
|
|
@@ -18149,7 +18340,7 @@ async function startMetricsServer(opts) {
|
|
|
18149
18340
|
const tls = opts.tls;
|
|
18150
18341
|
const useHttps = !!(tls?.cert && tls?.key);
|
|
18151
18342
|
const host = opts.host ?? "127.0.0.1";
|
|
18152
|
-
const
|
|
18343
|
+
const path19 = opts.path ?? "/metrics";
|
|
18153
18344
|
const healthPath = opts.healthPath ?? "/healthz";
|
|
18154
18345
|
const healthRegistry = opts.healthRegistry;
|
|
18155
18346
|
const listener = (req, res) => {
|
|
@@ -18159,7 +18350,7 @@ async function startMetricsServer(opts) {
|
|
|
18159
18350
|
return;
|
|
18160
18351
|
}
|
|
18161
18352
|
const url = req.url.split("?")[0];
|
|
18162
|
-
if (url ===
|
|
18353
|
+
if (url === path19) {
|
|
18163
18354
|
let body;
|
|
18164
18355
|
try {
|
|
18165
18356
|
body = renderPrometheus(opts.sink.snapshot());
|
|
@@ -18205,14 +18396,14 @@ async function startMetricsServer(opts) {
|
|
|
18205
18396
|
const { createServer } = await import('http');
|
|
18206
18397
|
server = createServer(listener);
|
|
18207
18398
|
}
|
|
18208
|
-
await new Promise((
|
|
18399
|
+
await new Promise((resolve5, reject) => {
|
|
18209
18400
|
const onError = (err) => {
|
|
18210
18401
|
server.off("listening", onListening);
|
|
18211
18402
|
reject(err);
|
|
18212
18403
|
};
|
|
18213
18404
|
const onListening = () => {
|
|
18214
18405
|
server.off("error", onError);
|
|
18215
|
-
|
|
18406
|
+
resolve5();
|
|
18216
18407
|
};
|
|
18217
18408
|
server.once("error", onError);
|
|
18218
18409
|
server.once("listening", onListening);
|
|
@@ -18223,9 +18414,9 @@ async function startMetricsServer(opts) {
|
|
|
18223
18414
|
const protocol = useHttps ? "https" : "http";
|
|
18224
18415
|
return {
|
|
18225
18416
|
port: boundPort,
|
|
18226
|
-
url: `${protocol}://${host}:${boundPort}${
|
|
18227
|
-
close: () => new Promise((
|
|
18228
|
-
server.close((err) => err ? reject(err) :
|
|
18417
|
+
url: `${protocol}://${host}:${boundPort}${path19}`,
|
|
18418
|
+
close: () => new Promise((resolve5, reject) => {
|
|
18419
|
+
server.close((err) => err ? reject(err) : resolve5());
|
|
18229
18420
|
})
|
|
18230
18421
|
};
|
|
18231
18422
|
}
|
|
@@ -18774,7 +18965,7 @@ var context7Server = () => ({
|
|
|
18774
18965
|
name: "context7",
|
|
18775
18966
|
description: "Codebase-aware documentation and Q&A (context7.ai)",
|
|
18776
18967
|
transport: "streamable-http",
|
|
18777
|
-
url: "https://
|
|
18968
|
+
url: "https://mcp.context7.com/mcp",
|
|
18778
18969
|
permission: "confirm"
|
|
18779
18970
|
});
|
|
18780
18971
|
var braveSearchServer = () => ({
|