@wrongstack/core 0.265.1 → 0.268.0
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-DrkBxszZ.d.ts → agent-bridge-UhojbpWx.d.ts} +1 -1
- package/dist/{agent-subagent-runner-DM2pP-B6.d.ts → agent-subagent-runner-Bvtf1o9K.d.ts} +25 -7
- package/dist/{brain-BXd_61kQ.d.ts → brain-69wzMKp1.d.ts} +73 -1
- package/dist/{compactor-B8pOf45Y.d.ts → compactor-CBQAJoDc.d.ts} +19 -1
- package/dist/{config-BMCj_XDs.d.ts → config-VKfOZ-6X.d.ts} +122 -3
- package/dist/{context-MRk5PhNv.d.ts → context-C0U8B9NF.d.ts} +88 -1
- package/dist/coordination/index.d.ts +57 -161
- package/dist/coordination/index.js +471 -177
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +26 -25
- package/dist/defaults/index.js +1818 -844
- package/dist/defaults/index.js.map +1 -1
- package/dist/execution/index.d.ts +72 -16
- package/dist/execution/index.js +1270 -265
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +1 -1
- package/dist/extension/index.d.ts +7 -6
- package/dist/global-mailbox-KByEFFBa.d.ts +663 -0
- package/dist/{goal-preamble-DvHDSKSe.d.ts → goal-preamble-CrYjmdw4.d.ts} +28 -11
- package/dist/{goal-store-DtLMySNb.d.ts → goal-store-Y_zdLZ3q.d.ts} +1 -1
- package/dist/hq/index.d.ts +195 -0
- package/dist/hq/index.js +1884 -0
- package/dist/hq/index.js.map +1 -0
- package/dist/index-BfaS-f_m.d.ts +82 -0
- package/dist/{index-B-ch8K9C.d.ts → index-CtQnmkaS.d.ts} +8 -8
- package/dist/{index-CEDeNodM.d.ts → index-gCv830d7.d.ts} +5 -5
- package/dist/index.d.ts +124 -47
- package/dist/index.js +5600 -2662
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +117 -19
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +10 -9
- package/dist/kernel/index.js.map +1 -1
- package/dist/{pipeline-DPDxH_7m.d.ts → mailbox-types-Ct2hJq0P.d.ts} +1 -244
- package/dist/{mcp-servers-2x4w6Jn9.d.ts → mcp-servers-HT3Fi7Bl.d.ts} +10 -4
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +33 -3
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-DmJlKuNp.d.ts → models-registry-Bvcl3Vaa.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-DyCkCZnU.d.ts → multi-agent-coordinator-BACjsmkC.d.ts} +1 -1
- package/dist/{null-fleet-bus-CG9QY2aP.d.ts → null-fleet-bus-DA7fvhUg.d.ts} +14 -9
- package/dist/observability/index.d.ts +2 -2
- package/dist/{parallel-eternal-engine-Jw9uhEoT.d.ts → parallel-eternal-engine-Ci71gYu_.d.ts} +11 -15
- package/dist/{path-resolver-Dy2ej-gE.d.ts → path-resolver-O1IJnmKE.d.ts} +4 -3
- package/dist/{permission-B9SB45lp.d.ts → permission-Bd-57Lbl.d.ts} +1 -1
- package/dist/{permission-policy-CkjSXabK.d.ts → permission-policy-uNXC6Kge.d.ts} +2 -3
- package/dist/pipeline-BDNvENyV.d.ts +245 -0
- package/dist/{plan-templates-CzD9GnAU.d.ts → plan-templates-EMsalEtN.d.ts} +5 -5
- package/dist/{llm-selector-C0tfTCUe.d.ts → provider-model-resolve-CEb9x886.d.ts} +40 -3
- package/dist/{provider-runner-DMa70ODu.d.ts → provider-runner-DWJbpo70.d.ts} +3 -3
- package/dist/{retry-policy-CN0khdlj.d.ts → retry-policy-C3s_lvdK.d.ts} +1 -1
- package/dist/sdd/index.d.ts +9 -8
- package/dist/sdd/index.js +44 -14
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-vault-B2yw84VT.d.ts → secret-vault-Cgduf5xL.d.ts} +2 -2
- package/dist/security/index.d.ts +5 -67
- package/dist/security/index.js +129 -99
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-CzHh_igB.d.ts → selector-47LBnBVk.d.ts} +1 -1
- package/dist/{session-event-bridge-BUI6Jf-4.d.ts → session-event-bridge-Cw7oqmW2.d.ts} +1 -1
- package/dist/{session-reader-CMgdMSRP.d.ts → session-reader-DD4v2Obw.d.ts} +1 -1
- package/dist/storage/index.d.ts +14 -12
- package/dist/storage/index.js +144 -120
- package/dist/storage/index.js.map +1 -1
- package/dist/tools/index.d.ts +4 -2
- package/dist/tools/index.js +166 -31
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +20 -19
- package/dist/types/index.js +1358 -476
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +472 -405
- package/dist/utils/index.js +2321 -1193
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -1
package/dist/defaults/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as crypto2 from 'crypto';
|
|
2
2
|
import { randomBytes, createCipheriv, createDecipheriv, randomUUID, createHash } from 'crypto';
|
|
3
3
|
import * as fsp2 from 'fs/promises';
|
|
4
|
-
import * as
|
|
4
|
+
import * as path4 from 'path';
|
|
5
5
|
import { isAbsolute, resolve } from 'path';
|
|
6
6
|
import * as fs4 from 'fs';
|
|
7
7
|
import * as os from 'os';
|
|
@@ -33,9 +33,9 @@ __export(atomic_write_exports, {
|
|
|
33
33
|
withFileLock: () => withFileLock
|
|
34
34
|
});
|
|
35
35
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
36
|
-
const dir =
|
|
36
|
+
const dir = path4.dirname(targetPath);
|
|
37
37
|
await fsp2.mkdir(dir, { recursive: true });
|
|
38
|
-
const tmp =
|
|
38
|
+
const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
39
39
|
try {
|
|
40
40
|
if (typeof content === "string") {
|
|
41
41
|
await fsp2.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
@@ -74,9 +74,9 @@ async function ensureDir(dir) {
|
|
|
74
74
|
await fsp2.mkdir(dir, { recursive: true });
|
|
75
75
|
}
|
|
76
76
|
async function withFileLock(targetPath, fn, opts = {}) {
|
|
77
|
-
const dir =
|
|
77
|
+
const dir = path4.dirname(targetPath);
|
|
78
78
|
await fsp2.mkdir(dir, { recursive: true });
|
|
79
|
-
const lockPath =
|
|
79
|
+
const lockPath = path4.join(dir, `.${path4.basename(targetPath)}.lock`);
|
|
80
80
|
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
81
81
|
const staleMs = opts.staleMs ?? 3e4;
|
|
82
82
|
const started = Date.now();
|
|
@@ -105,7 +105,7 @@ async function withFileLock(targetPath, fn, opts = {}) {
|
|
|
105
105
|
if (Date.now() - started >= timeoutMs) {
|
|
106
106
|
throw new Error(`Timed out waiting for file lock: ${targetPath}`);
|
|
107
107
|
}
|
|
108
|
-
await new Promise((
|
|
108
|
+
await new Promise((resolve6) => setTimeout(resolve6, 25));
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
try {
|
|
@@ -138,7 +138,7 @@ async function renameWithRetry(from, to) {
|
|
|
138
138
|
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
139
139
|
throw err;
|
|
140
140
|
}
|
|
141
|
-
await new Promise((
|
|
141
|
+
await new Promise((resolve6) => setTimeout(resolve6, delays[i]));
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
throw lastErr;
|
|
@@ -234,7 +234,7 @@ var DefaultLogger = class _DefaultLogger {
|
|
|
234
234
|
this.maxFileBytes = opts.maxFileBytes ?? 10 * 1024 * 1024;
|
|
235
235
|
if (this.file) {
|
|
236
236
|
try {
|
|
237
|
-
fs4.mkdirSync(
|
|
237
|
+
fs4.mkdirSync(path4.dirname(this.file), { recursive: true });
|
|
238
238
|
} catch {
|
|
239
239
|
}
|
|
240
240
|
}
|
|
@@ -436,32 +436,268 @@ function isEmptyMessage(msg) {
|
|
|
436
436
|
return msg.content.length === 0;
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
+
// src/utils/assert-never.ts
|
|
440
|
+
function assertNever(x, message) {
|
|
441
|
+
const err = new Error(
|
|
442
|
+
`Unhandled case: ${JSON.stringify(x)}`
|
|
443
|
+
);
|
|
444
|
+
err.name = "AssertNeverError";
|
|
445
|
+
throw err;
|
|
446
|
+
}
|
|
447
|
+
|
|
439
448
|
// src/utils/index.ts
|
|
440
449
|
init_atomic_write();
|
|
450
|
+
var MAX_DIGEST_CHARS = 4e3;
|
|
451
|
+
function createContextEvidenceState() {
|
|
452
|
+
return {
|
|
453
|
+
sessionGoals: [],
|
|
454
|
+
implicitFacts: [],
|
|
455
|
+
activeErrors: [],
|
|
456
|
+
toolCalls: [],
|
|
457
|
+
fileGraph: {},
|
|
458
|
+
repeatedReads: [],
|
|
459
|
+
updatedAt: Date.now()
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function buildContextEvidenceDigest(ctx) {
|
|
463
|
+
const state = ensureEvidence(ctx);
|
|
464
|
+
const lines = [];
|
|
465
|
+
if (state.currentIntent?.text) {
|
|
466
|
+
lines.push(`intent: ${state.currentIntent.text}`);
|
|
467
|
+
}
|
|
468
|
+
const goals = state.sessionGoals.slice(-3);
|
|
469
|
+
if (goals.length > 0) {
|
|
470
|
+
lines.push("session_goals:");
|
|
471
|
+
for (const goal of goals) lines.push(`- ${goal}`);
|
|
472
|
+
}
|
|
473
|
+
const activeErrors = state.activeErrors.slice(-5);
|
|
474
|
+
if (activeErrors.length > 0) {
|
|
475
|
+
lines.push("active_errors:");
|
|
476
|
+
for (const err of activeErrors) lines.push(`- ${err}`);
|
|
477
|
+
}
|
|
478
|
+
const files = Object.values(state.fileGraph).sort((a, b) => b.writes - a.writes || b.reads - a.reads || a.path.localeCompare(b.path)).slice(0, 12);
|
|
479
|
+
if (files.length > 0) {
|
|
480
|
+
lines.push("dependency_graph:");
|
|
481
|
+
for (const file of files) {
|
|
482
|
+
const actions = [
|
|
483
|
+
file.reads > 0 ? `read ${file.reads}x` : "",
|
|
484
|
+
file.writes > 0 ? `write ${file.writes}x` : ""
|
|
485
|
+
].filter(Boolean).join(", ");
|
|
486
|
+
const refs = file.referenced ? "; referenced by assistant" : "";
|
|
487
|
+
const via = file.lastToolUseId ? `; last via ${file.lastToolUseId}` : "";
|
|
488
|
+
lines.push(`- ${file.path} (${actions || "seen"}${refs}${via})`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const referenced = state.toolCalls.filter((tool) => tool.status === "referenced").slice(-10);
|
|
492
|
+
const recentSeen = state.toolCalls.filter((tool) => tool.status === "seen").slice(-5);
|
|
493
|
+
const trail = [...referenced, ...recentSeen];
|
|
494
|
+
if (trail.length > 0) {
|
|
495
|
+
lines.push("tool_trail:");
|
|
496
|
+
for (const tool of trail) {
|
|
497
|
+
const size = tool.outputTokens ? `; ~${tool.outputTokens} tokens` : "";
|
|
498
|
+
const filesText = tool.files.length > 0 ? `; files=${tool.files.slice(0, 4).join(", ")}` : "";
|
|
499
|
+
const symbolsText = tool.symbols.length > 0 ? `; symbols=${tool.symbols.slice(0, 4).join(", ")}` : "";
|
|
500
|
+
lines.push(
|
|
501
|
+
`- ${tool.toolUseId} ${tool.toolName} ${tool.status}: ${tool.summary}${filesText}${symbolsText}${size}`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const facts = state.implicitFacts.slice(-8);
|
|
506
|
+
if (facts.length > 0) {
|
|
507
|
+
lines.push("implicit_facts:");
|
|
508
|
+
for (const fact of facts) lines.push(`- ${fact}`);
|
|
509
|
+
}
|
|
510
|
+
const digest = lines.join("\n");
|
|
511
|
+
if (digest.length <= MAX_DIGEST_CHARS) return digest;
|
|
512
|
+
return `${digest.slice(0, MAX_DIGEST_CHARS)}... [+${digest.length - MAX_DIGEST_CHARS} chars]`;
|
|
513
|
+
}
|
|
514
|
+
function repeatedReadPressure(ctx) {
|
|
515
|
+
return ensureEvidence(ctx).repeatedReads.reduce((max, item) => Math.max(max, item.count), 0);
|
|
516
|
+
}
|
|
517
|
+
function ensureEvidence(ctx) {
|
|
518
|
+
if (!ctx.contextEvidence) {
|
|
519
|
+
ctx.contextEvidence = createContextEvidenceState();
|
|
520
|
+
}
|
|
521
|
+
return ctx.contextEvidence;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// src/utils/deep-merge.ts
|
|
525
|
+
var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
|
|
526
|
+
"__proto__",
|
|
527
|
+
"constructor",
|
|
528
|
+
"prototype",
|
|
529
|
+
"__defineGetter__",
|
|
530
|
+
"__defineSetter__",
|
|
531
|
+
"__lookupGetter__",
|
|
532
|
+
"__lookupSetter__"
|
|
533
|
+
]);
|
|
534
|
+
function isPrimitiveArray(a) {
|
|
535
|
+
return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
|
|
536
|
+
}
|
|
537
|
+
function deepMerge(base, patch, options = {}) {
|
|
538
|
+
const {
|
|
539
|
+
conflictResolution = "prefer-patch",
|
|
540
|
+
arrayMode = "replace",
|
|
541
|
+
protectProto = true,
|
|
542
|
+
onNonPrimitiveArrayReplace
|
|
543
|
+
} = options;
|
|
544
|
+
if (typeof base !== "object" || base === null) {
|
|
545
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
546
|
+
}
|
|
547
|
+
if (typeof patch !== "object" || patch === null) {
|
|
548
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
549
|
+
}
|
|
550
|
+
if (Array.isArray(base) && Array.isArray(patch)) {
|
|
551
|
+
if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
|
|
552
|
+
return [.../* @__PURE__ */ new Set([...base, ...patch])];
|
|
553
|
+
}
|
|
554
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
555
|
+
}
|
|
556
|
+
if (Array.isArray(base) || Array.isArray(patch)) {
|
|
557
|
+
return conflictResolution === "prefer-patch" ? patch : base;
|
|
558
|
+
}
|
|
559
|
+
const baseObj = base;
|
|
560
|
+
const patchObj = patch;
|
|
561
|
+
const out = { ...baseObj };
|
|
562
|
+
for (const [k, v] of Object.entries(patchObj)) {
|
|
563
|
+
if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
|
|
564
|
+
const existing = out[k];
|
|
565
|
+
if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
|
|
566
|
+
out[k] = deepMerge(existing, v, options);
|
|
567
|
+
} else if (Array.isArray(v) && Array.isArray(existing)) {
|
|
568
|
+
if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
|
|
569
|
+
onNonPrimitiveArrayReplace(k, existing.length, v.length);
|
|
570
|
+
}
|
|
571
|
+
out[k] = deepMerge(existing, v, options);
|
|
572
|
+
} else if (v !== void 0) {
|
|
573
|
+
if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
|
|
574
|
+
const existingLen = Array.isArray(existing) ? existing.length : 0;
|
|
575
|
+
onNonPrimitiveArrayReplace(k, existingLen, v.length);
|
|
576
|
+
}
|
|
577
|
+
out[k] = v;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return out;
|
|
581
|
+
}
|
|
441
582
|
|
|
442
583
|
// src/utils/error.ts
|
|
443
584
|
function toErrorMessage(err) {
|
|
444
585
|
return err instanceof Error ? err.message : String(err);
|
|
445
586
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
587
|
+
var GLOB_CHARS = /* @__PURE__ */ new Set(["*", "?", "["]);
|
|
588
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
589
|
+
var SEP = IS_WINDOWS ? "\\" : "/";
|
|
590
|
+
function isGlob(p) {
|
|
591
|
+
for (const c of p) {
|
|
592
|
+
if (GLOB_CHARS.has(c)) return true;
|
|
451
593
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
function globToRegex(pat) {
|
|
597
|
+
let i = 0;
|
|
598
|
+
let re = "^";
|
|
599
|
+
while (i < pat.length) {
|
|
600
|
+
const c = expectDefined(pat[i]);
|
|
601
|
+
if (c === "*") {
|
|
602
|
+
if (pat[i + 1] === "*") {
|
|
603
|
+
re += ".*";
|
|
604
|
+
i += 2;
|
|
605
|
+
if (pat[i] === "/") i++;
|
|
606
|
+
} else {
|
|
607
|
+
re += "[^/\\\\]*";
|
|
608
|
+
i++;
|
|
609
|
+
}
|
|
610
|
+
} else if (c === "?") {
|
|
611
|
+
re += "[^/\\\\]";
|
|
612
|
+
i++;
|
|
613
|
+
} else if (c === "[") {
|
|
614
|
+
let cls = "[";
|
|
615
|
+
i++;
|
|
616
|
+
if (pat[i] === "!" || pat[i] === "^") {
|
|
617
|
+
cls += "^";
|
|
618
|
+
i++;
|
|
619
|
+
}
|
|
620
|
+
while (i < pat.length && pat[i] !== "]") {
|
|
621
|
+
const ch = pat[i] ?? "";
|
|
622
|
+
if (ch === "\\") cls += "\\\\";
|
|
623
|
+
else if (ch === "]" || ch === "^") cls += `\\${ch}`;
|
|
624
|
+
else cls += ch;
|
|
625
|
+
i++;
|
|
626
|
+
}
|
|
627
|
+
cls += "]";
|
|
628
|
+
re += cls;
|
|
629
|
+
i++;
|
|
630
|
+
} else {
|
|
631
|
+
re += c.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
632
|
+
i++;
|
|
633
|
+
}
|
|
459
634
|
}
|
|
635
|
+
return new RegExp(re + "$");
|
|
460
636
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
637
|
+
function baseDir(pat) {
|
|
638
|
+
let i = pat.length - 1;
|
|
639
|
+
while (i >= 0 && !GLOB_CHARS.has(expectDefined(pat[i])) && pat[i] !== SEP && pat[i] !== "/") i--;
|
|
640
|
+
const cut = i >= 0 ? pat.lastIndexOf(SEP, i) : pat.lastIndexOf("/", i);
|
|
641
|
+
return cut < 0 ? "." : pat.slice(0, cut);
|
|
642
|
+
}
|
|
643
|
+
async function expandGlob(pattern) {
|
|
644
|
+
if (!isGlob(pattern)) return [pattern];
|
|
645
|
+
const results = /* @__PURE__ */ new Set();
|
|
646
|
+
const abs = isAbsolute(pattern);
|
|
647
|
+
const base = abs ? baseDir(pattern) : baseDir(pattern);
|
|
648
|
+
const relPat = base === "." ? pattern : pattern.slice(base.length + 1);
|
|
649
|
+
async function walk3(dir, pat) {
|
|
650
|
+
let entries;
|
|
651
|
+
try {
|
|
652
|
+
entries = await fsp2.readdir(dir);
|
|
653
|
+
} catch {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
const firstGlob = pat.search(/[*?[[]/);
|
|
657
|
+
if (firstGlob < 0) {
|
|
658
|
+
const re = globToRegex(pat);
|
|
659
|
+
for (const e of entries) {
|
|
660
|
+
if (re.test(e)) {
|
|
661
|
+
const full = `${dir}${SEP}${e}`;
|
|
662
|
+
results.add(abs ? resolve(full) : full);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
const before = pat.slice(0, firstGlob);
|
|
668
|
+
const rest = pat.slice(firstGlob);
|
|
669
|
+
if (before.endsWith("**")) {
|
|
670
|
+
await walk3(dir, rest);
|
|
671
|
+
for (const e of entries) {
|
|
672
|
+
const full = `${dir}${SEP}${e}`;
|
|
673
|
+
try {
|
|
674
|
+
const stat6 = await fsp2.stat(full);
|
|
675
|
+
if (stat6.isDirectory()) await walk3(full, rest);
|
|
676
|
+
} catch {
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
} else if (before === "") {
|
|
680
|
+
const re = globToRegex(rest);
|
|
681
|
+
for (const e of entries) {
|
|
682
|
+
if (re.test(e)) {
|
|
683
|
+
const full = `${dir}${SEP}${e}`;
|
|
684
|
+
results.add(abs ? resolve(full) : full);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
const seg = before.replace(/[*?[\]]/g, "").replace(/\/$/, "");
|
|
689
|
+
if (entries.includes(seg)) {
|
|
690
|
+
const full = `${dir}${SEP}${seg}`;
|
|
691
|
+
try {
|
|
692
|
+
const stat6 = await fsp2.stat(full);
|
|
693
|
+
if (stat6.isDirectory()) await walk3(full, rest);
|
|
694
|
+
} catch {
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
await walk3(base === "." ? "." : base, relPat);
|
|
700
|
+
return [...results];
|
|
465
701
|
}
|
|
466
702
|
|
|
467
703
|
// src/utils/glob-match.ts
|
|
@@ -539,232 +775,475 @@ function matchGlob(pattern, input) {
|
|
|
539
775
|
function matchAny(patterns, input) {
|
|
540
776
|
return patterns.some((p) => matchGlob(p, input));
|
|
541
777
|
}
|
|
542
|
-
function projectHash(absRoot) {
|
|
543
|
-
return createHash("sha256").update(path3.resolve(absRoot)).digest("hex").slice(0, 12);
|
|
544
|
-
}
|
|
545
|
-
function projectSlug(absRoot) {
|
|
546
|
-
const base = slugify(path3.basename(absRoot));
|
|
547
|
-
const hash = createHash("sha256").update(path3.resolve(absRoot)).digest("hex").slice(0, 6);
|
|
548
|
-
return `${base}-${hash}`;
|
|
549
|
-
}
|
|
550
|
-
function slugify(name) {
|
|
551
|
-
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
|
|
552
|
-
}
|
|
553
|
-
function wstackGlobalRoot() {
|
|
554
|
-
const fromEnv = process.env["WRONGSTACK_HOME"];
|
|
555
|
-
if (fromEnv && fromEnv.trim().length > 0) return path3.resolve(fromEnv);
|
|
556
|
-
return path3.join(os.homedir(), ".wrongstack");
|
|
557
|
-
}
|
|
558
|
-
function resolveWstackPaths(opts) {
|
|
559
|
-
const globalRoot = opts.globalRoot ?? (opts.userHome ? path3.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
560
|
-
const hash = projectHash(opts.projectRoot);
|
|
561
|
-
const slug = projectSlug(opts.projectRoot);
|
|
562
|
-
const projectDir = path3.join(globalRoot, "projects", slug);
|
|
563
|
-
return {
|
|
564
|
-
globalRoot,
|
|
565
|
-
configDir: globalRoot,
|
|
566
|
-
globalConfig: path3.join(globalRoot, "config.json"),
|
|
567
|
-
secretsKey: path3.join(globalRoot, ".key"),
|
|
568
|
-
globalMemory: path3.join(globalRoot, "memory.md"),
|
|
569
|
-
globalSkills: path3.join(globalRoot, "skills"),
|
|
570
|
-
globalPrompts: path3.join(globalRoot, "prompts"),
|
|
571
|
-
cacheDir: path3.join(globalRoot, "cache"),
|
|
572
|
-
modelsCache: path3.join(globalRoot, "cache", "models.dev.json"),
|
|
573
|
-
modelsOverlayCache: path3.join(globalRoot, "cache", "models-overlay.json"),
|
|
574
|
-
historyFile: path3.join(globalRoot, "history"),
|
|
575
|
-
logFile: path3.join(globalRoot, "logs", "wrongstack.log"),
|
|
576
|
-
projectDir,
|
|
577
|
-
projectCodebaseIndex: path3.join(projectDir, "codebase-index"),
|
|
578
|
-
projectMemory: path3.join(projectDir, "memory.md"),
|
|
579
|
-
projectSessions: path3.join(projectDir, "sessions"),
|
|
580
|
-
projectTrust: path3.join(projectDir, "trust.json"),
|
|
581
|
-
projectMeta: path3.join(projectDir, "meta.json"),
|
|
582
|
-
projectLocalConfig: path3.join(projectDir, "config.local.json"),
|
|
583
|
-
inProjectConfig: path3.join(opts.projectRoot, ".wrongstack", "config.json"),
|
|
584
|
-
inProjectAgentsFile: path3.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
585
|
-
inProjectSkills: path3.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
586
|
-
inProjectWorktrees: path3.join(opts.projectRoot, ".wrongstack", "worktrees"),
|
|
587
|
-
projectHash: hash,
|
|
588
|
-
projectSlug: slug,
|
|
589
|
-
projectGoal: path3.join(projectDir, "goal.json"),
|
|
590
|
-
projectSpecs: path3.join(projectDir, "specs"),
|
|
591
|
-
projectTaskGraphs: path3.join(projectDir, "task-graphs"),
|
|
592
|
-
projectSddSession: path3.join(projectDir, "sdd-session.json"),
|
|
593
|
-
projectPlan: path3.join(projectDir, "plan.json"),
|
|
594
|
-
projectAutophase: path3.join(projectDir, "autophase"),
|
|
595
|
-
syncConfig: path3.join(globalRoot, "sync.json"),
|
|
596
|
-
projectStatus: (projectHash2) => path3.join(globalRoot, "projects", projectHash2, "status.json")
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// src/utils/sleep.ts
|
|
601
|
-
function sleep(ms) {
|
|
602
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
603
|
-
}
|
|
604
778
|
|
|
605
|
-
// src/utils/
|
|
606
|
-
function
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
);
|
|
610
|
-
err.name = "AssertNeverError";
|
|
611
|
-
throw err;
|
|
779
|
+
// src/utils/json-repair.ts
|
|
780
|
+
function completePartialObject(s) {
|
|
781
|
+
if (!s.trim().startsWith("{")) return s;
|
|
782
|
+
if (tryParse(s).ok) return s;
|
|
783
|
+
return repairTruncated(s);
|
|
612
784
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
"
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
785
|
+
function repairTruncated(s) {
|
|
786
|
+
const stack = [];
|
|
787
|
+
let inString = false;
|
|
788
|
+
let escaped = false;
|
|
789
|
+
let sawKey = false;
|
|
790
|
+
let prevSig = "";
|
|
791
|
+
let contentEnd = 0;
|
|
792
|
+
let stringBraceDepth = 0;
|
|
793
|
+
for (let i = 0; i < s.length; i++) {
|
|
794
|
+
const ch = expectDefined(s[i]);
|
|
795
|
+
if (inString) {
|
|
796
|
+
contentEnd = i + 1;
|
|
797
|
+
if (escaped) {
|
|
798
|
+
escaped = false;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (ch === "\\") {
|
|
802
|
+
escaped = true;
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
if (ch === '"') {
|
|
806
|
+
inString = false;
|
|
807
|
+
prevSig = '"';
|
|
808
|
+
stringBraceDepth = 0;
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
if (ch === "{") stringBraceDepth++;
|
|
812
|
+
else if (ch === "}" && stringBraceDepth > 0) stringBraceDepth--;
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") continue;
|
|
816
|
+
contentEnd = i + 1;
|
|
817
|
+
if (ch === '"') {
|
|
818
|
+
inString = true;
|
|
819
|
+
sawKey = true;
|
|
820
|
+
stringBraceDepth = 0;
|
|
821
|
+
prevSig = '"';
|
|
822
|
+
} else if (ch === "{" || ch === "[") {
|
|
823
|
+
stack.push(ch);
|
|
824
|
+
prevSig = ch;
|
|
825
|
+
} else if (ch === "}" || ch === "]") {
|
|
826
|
+
stack.pop();
|
|
827
|
+
prevSig = ch;
|
|
828
|
+
} else {
|
|
829
|
+
prevSig = ch;
|
|
830
|
+
}
|
|
639
831
|
}
|
|
640
|
-
if (
|
|
641
|
-
|
|
642
|
-
|
|
832
|
+
if (!sawKey && !inString) return s;
|
|
833
|
+
let result = s.slice(0, contentEnd);
|
|
834
|
+
if (inString) {
|
|
835
|
+
if (escaped) {
|
|
836
|
+
result = result.slice(0, -1);
|
|
837
|
+
} else if (endsWithInvalidEscape(result)) {
|
|
838
|
+
result = result.slice(0, -2);
|
|
643
839
|
}
|
|
644
|
-
|
|
840
|
+
if (stringBraceDepth > 0) result += "}".repeat(stringBraceDepth);
|
|
841
|
+
result += '"';
|
|
842
|
+
} else if (prevSig === ":") {
|
|
843
|
+
result += "null";
|
|
645
844
|
}
|
|
646
|
-
|
|
647
|
-
|
|
845
|
+
for (let k = stack.length - 1; k >= 0; k--) {
|
|
846
|
+
result += stack[k] === "{" ? "}" : "]";
|
|
648
847
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
848
|
+
if (!tryParse(result).ok) {
|
|
849
|
+
const patched = result.replace(/:(\s*)([}\]])/g, ":null$2");
|
|
850
|
+
if (tryParse(patched).ok) result = patched;
|
|
851
|
+
}
|
|
852
|
+
return result;
|
|
853
|
+
}
|
|
854
|
+
var VALID_ESCAPE = /* @__PURE__ */ new Set(['"', "\\", "/", "b", "f", "n", "r", "t", "u"]);
|
|
855
|
+
function endsWithInvalidEscape(str) {
|
|
856
|
+
const last = str[str.length - 1];
|
|
857
|
+
if (str[str.length - 2] !== "\\" || last === void 0) return false;
|
|
858
|
+
if (VALID_ESCAPE.has(last)) return false;
|
|
859
|
+
let backslashes = 0;
|
|
860
|
+
for (let k = str.length - 2; k >= 0 && str[k] === "\\"; k--) backslashes++;
|
|
861
|
+
return backslashes % 2 === 1;
|
|
862
|
+
}
|
|
863
|
+
function tryParse(s) {
|
|
864
|
+
try {
|
|
865
|
+
return { ok: true, value: JSON.parse(s) };
|
|
866
|
+
} catch {
|
|
867
|
+
return { ok: false };
|
|
669
868
|
}
|
|
670
|
-
return out;
|
|
671
869
|
}
|
|
672
870
|
|
|
673
|
-
// src/utils/
|
|
674
|
-
function
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
} catch {
|
|
688
|
-
return String(value);
|
|
689
|
-
}
|
|
871
|
+
// src/utils/json-schema-validate.ts
|
|
872
|
+
function validateAgainstSchema(value, schema) {
|
|
873
|
+
const errors = [];
|
|
874
|
+
walk(value, schema, "", errors);
|
|
875
|
+
return { ok: errors.length === 0, errors };
|
|
876
|
+
}
|
|
877
|
+
function walk(value, schema, path21, errors) {
|
|
878
|
+
if (schema.enum !== void 0) {
|
|
879
|
+
if (!schema.enum.some((e) => deepEqual(e, value))) {
|
|
880
|
+
errors.push({
|
|
881
|
+
path: path21 || "<root>",
|
|
882
|
+
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
883
|
+
});
|
|
884
|
+
return;
|
|
690
885
|
}
|
|
691
|
-
return String(value);
|
|
692
886
|
}
|
|
693
|
-
|
|
694
|
-
if (
|
|
695
|
-
|
|
887
|
+
if (typeof schema.type === "string") {
|
|
888
|
+
if (!checkType(value, schema.type)) {
|
|
889
|
+
errors.push({
|
|
890
|
+
path: path21 || "<root>",
|
|
891
|
+
message: `expected ${schema.type}, got ${describeType(value)}`
|
|
892
|
+
});
|
|
893
|
+
return;
|
|
696
894
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
895
|
+
}
|
|
896
|
+
if (schema.type === "object" && isPlainObject(value)) {
|
|
897
|
+
const obj = value;
|
|
898
|
+
for (const req of schema.required ?? []) {
|
|
899
|
+
if (!(req in obj)) {
|
|
900
|
+
errors.push({ path: joinPath(path21, req), message: "required property missing" });
|
|
901
|
+
}
|
|
700
902
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
903
|
+
if (schema.properties) {
|
|
904
|
+
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
905
|
+
if (key in obj) {
|
|
906
|
+
walk(obj[key], subSchema, joinPath(path21, key), errors);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
708
909
|
}
|
|
709
|
-
const half = Math.floor(available / 2);
|
|
710
|
-
const first = text.slice(0, half);
|
|
711
|
-
const second = text.slice(text.length - half);
|
|
712
|
-
return { text: `${first}${marker}${second}`, newBudget: 0 };
|
|
713
|
-
}
|
|
714
|
-
return { serialize, enforceCap, capBytes };
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
// src/utils/token-estimate.ts
|
|
718
|
-
var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
|
|
719
|
-
var CALIBRATION_GLOBAL_KEY = "__global__";
|
|
720
|
-
var _cals = /* @__PURE__ */ new Map();
|
|
721
|
-
function calState(key) {
|
|
722
|
-
let state = _cals.get(key);
|
|
723
|
-
if (!state) {
|
|
724
|
-
state = { ratio: 1, count: 0, prevEst: 0 };
|
|
725
|
-
_cals.set(key, state);
|
|
726
910
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
|
|
731
|
-
var ESTIMATE_CACHE_MAX_SIZE = 1e4;
|
|
732
|
-
function getCachedEstimate(key, compute) {
|
|
733
|
-
const existing = ESTIMATE_CACHE.get(key);
|
|
734
|
-
if (existing !== void 0) return existing;
|
|
735
|
-
if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
|
|
736
|
-
for (const k of ESTIMATE_CACHE.keys()) {
|
|
737
|
-
if (ESTIMATE_CACHE.size <= Math.floor(ESTIMATE_CACHE_MAX_SIZE / 2)) break;
|
|
738
|
-
ESTIMATE_CACHE.delete(k);
|
|
911
|
+
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
912
|
+
for (let i = 0; i < value.length; i++) {
|
|
913
|
+
walk(value[i], schema.items, `${path21}[${i}]`, errors);
|
|
739
914
|
}
|
|
740
915
|
}
|
|
741
|
-
const estimate = compute(key);
|
|
742
|
-
ESTIMATE_CACHE.set(key, estimate);
|
|
743
|
-
return estimate;
|
|
744
916
|
}
|
|
745
|
-
function
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
917
|
+
function checkType(value, type) {
|
|
918
|
+
switch (type) {
|
|
919
|
+
case "string":
|
|
920
|
+
return typeof value === "string";
|
|
921
|
+
case "number":
|
|
922
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
923
|
+
case "integer":
|
|
924
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
925
|
+
case "boolean":
|
|
926
|
+
return typeof value === "boolean";
|
|
927
|
+
case "null":
|
|
928
|
+
return value === null;
|
|
929
|
+
case "array":
|
|
930
|
+
return Array.isArray(value);
|
|
931
|
+
case "object":
|
|
932
|
+
return isPlainObject(value);
|
|
933
|
+
default:
|
|
934
|
+
return true;
|
|
749
935
|
}
|
|
750
|
-
return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
|
|
751
936
|
}
|
|
752
|
-
function
|
|
753
|
-
|
|
754
|
-
return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
|
|
937
|
+
function isPlainObject(v) {
|
|
938
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
755
939
|
}
|
|
756
|
-
function
|
|
757
|
-
|
|
940
|
+
function describeType(v) {
|
|
941
|
+
if (v === null) return "null";
|
|
942
|
+
if (Array.isArray(v)) return "array";
|
|
943
|
+
return typeof v;
|
|
758
944
|
}
|
|
759
|
-
function
|
|
760
|
-
if (
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
945
|
+
function joinPath(parent, key) {
|
|
946
|
+
if (!parent) return key;
|
|
947
|
+
return `${parent}.${key}`;
|
|
948
|
+
}
|
|
949
|
+
function deepEqual(a, b) {
|
|
950
|
+
if (a === b) return true;
|
|
951
|
+
if (typeof a !== typeof b) return false;
|
|
952
|
+
if (a === null || b === null) return a === b;
|
|
953
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
954
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
955
|
+
}
|
|
956
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
957
|
+
const ak = Object.keys(a);
|
|
958
|
+
const bk = Object.keys(b);
|
|
959
|
+
if (ak.length !== bk.length) return false;
|
|
960
|
+
return ak.every(
|
|
961
|
+
(k) => deepEqual(a[k], b[k])
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
return false;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/utils/merge-models-payload.ts
|
|
968
|
+
function mergeModelsPayload(base, overlay) {
|
|
969
|
+
const out = {};
|
|
970
|
+
for (const [id, provider] of Object.entries(base)) {
|
|
971
|
+
out[id] = cloneProvider(provider);
|
|
972
|
+
}
|
|
973
|
+
for (const [id, ovProvider] of Object.entries(overlay)) {
|
|
974
|
+
const existing = out[id];
|
|
975
|
+
out[id] = existing ? mergeProvider(existing, ovProvider) : cloneProvider(ovProvider);
|
|
976
|
+
}
|
|
977
|
+
return out;
|
|
978
|
+
}
|
|
979
|
+
function mergeProvider(base, overlay) {
|
|
980
|
+
const models = {};
|
|
981
|
+
for (const [mid, m] of Object.entries(base.models ?? {})) {
|
|
982
|
+
models[mid] = { ...m };
|
|
983
|
+
}
|
|
984
|
+
for (const [mid, ovModel] of Object.entries(overlay.models ?? {})) {
|
|
985
|
+
const existing = models[mid];
|
|
986
|
+
models[mid] = existing ? mergeModel(existing, ovModel) : { ...ovModel };
|
|
987
|
+
}
|
|
988
|
+
return {
|
|
989
|
+
...base,
|
|
990
|
+
// Overlay scalar fields win when explicitly provided; otherwise keep base.
|
|
991
|
+
...stripUndefined({
|
|
992
|
+
id: overlay.id,
|
|
993
|
+
name: overlay.name,
|
|
994
|
+
npm: overlay.npm,
|
|
995
|
+
api: overlay.api,
|
|
996
|
+
env: overlay.env,
|
|
997
|
+
doc: overlay.doc
|
|
998
|
+
}),
|
|
999
|
+
models
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
function mergeModel(base, overlay) {
|
|
1003
|
+
const merged = { ...base, ...overlay };
|
|
1004
|
+
if (base.limit || overlay.limit) {
|
|
1005
|
+
merged.limit = { ...base.limit, ...overlay.limit };
|
|
1006
|
+
}
|
|
1007
|
+
if (base.cost || overlay.cost) {
|
|
1008
|
+
merged.cost = { ...base.cost, ...overlay.cost };
|
|
1009
|
+
}
|
|
1010
|
+
if (base.modalities || overlay.modalities) {
|
|
1011
|
+
merged.modalities = { ...base.modalities, ...overlay.modalities };
|
|
1012
|
+
}
|
|
1013
|
+
return merged;
|
|
1014
|
+
}
|
|
1015
|
+
function cloneProvider(p) {
|
|
1016
|
+
const models = {};
|
|
1017
|
+
for (const [mid, m] of Object.entries(p.models ?? {})) {
|
|
1018
|
+
models[mid] = { ...m };
|
|
1019
|
+
}
|
|
1020
|
+
return { ...p, models };
|
|
1021
|
+
}
|
|
1022
|
+
function stripUndefined(obj) {
|
|
1023
|
+
const out = {};
|
|
1024
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
1025
|
+
if (v !== void 0) out[k] = v;
|
|
1026
|
+
}
|
|
1027
|
+
return out;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// src/utils/regex-guard.ts
|
|
1031
|
+
var MAX_PATTERN_LEN = 512;
|
|
1032
|
+
var DANGEROUS_PATTERNS = [
|
|
1033
|
+
/(\([^)]*[+*][^)]*\))[+*]/,
|
|
1034
|
+
// (a+)+, (.*)+, etc
|
|
1035
|
+
/(\(\?:[^)]*[+*][^)]*\))[+*]/
|
|
1036
|
+
// same, with non-capturing group
|
|
1037
|
+
];
|
|
1038
|
+
function compileUserRegex(pattern, flags) {
|
|
1039
|
+
if (typeof pattern !== "string") {
|
|
1040
|
+
return { ok: false, reason: "pattern must be a string" };
|
|
1041
|
+
}
|
|
1042
|
+
if (pattern.length === 0) {
|
|
1043
|
+
return { ok: false, reason: "pattern is empty" };
|
|
1044
|
+
}
|
|
1045
|
+
if (pattern.length > MAX_PATTERN_LEN) {
|
|
1046
|
+
return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
|
|
1047
|
+
}
|
|
1048
|
+
for (const rx of DANGEROUS_PATTERNS) {
|
|
1049
|
+
if (rx.test(pattern)) {
|
|
1050
|
+
return {
|
|
1051
|
+
ok: false,
|
|
1052
|
+
reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
try {
|
|
1057
|
+
return { ok: true, regex: new RegExp(pattern, flags) };
|
|
1058
|
+
} catch (err) {
|
|
1059
|
+
return {
|
|
1060
|
+
ok: false,
|
|
1061
|
+
reason: err instanceof Error ? err.message : "invalid regex"
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// src/utils/safe-json.ts
|
|
1067
|
+
function safeParse(input, maxBytes = 5e6) {
|
|
1068
|
+
if (input.length > maxBytes) {
|
|
1069
|
+
return { ok: false, error: `Input exceeds limit (${maxBytes} bytes)` };
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
return { ok: true, value: JSON.parse(input) };
|
|
1073
|
+
} catch (err) {
|
|
1074
|
+
return {
|
|
1075
|
+
ok: false,
|
|
1076
|
+
error: toErrorMessage(err)
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// src/utils/sleep.ts
|
|
1082
|
+
function sleep(ms) {
|
|
1083
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// src/utils/string.ts
|
|
1087
|
+
function truncate(s, max) {
|
|
1088
|
+
return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
// src/utils/tool-subject.ts
|
|
1092
|
+
var GLOB_METACHARACTERS = /[*?[\]]/g;
|
|
1093
|
+
function escapeGlobSubject(value) {
|
|
1094
|
+
return value.replace(GLOB_METACHARACTERS, (char) => `\\${char}`);
|
|
1095
|
+
}
|
|
1096
|
+
function normalizePathSubject(value) {
|
|
1097
|
+
return escapeGlobSubject(value.replace(/\\/g, "/"));
|
|
1098
|
+
}
|
|
1099
|
+
function isPathSubjectKey(subjectKey) {
|
|
1100
|
+
return subjectKey === "path" || subjectKey === "file" || subjectKey === "files";
|
|
1101
|
+
}
|
|
1102
|
+
function subjectForToolInput(toolName, input, subjectKey) {
|
|
1103
|
+
if (!input || typeof input !== "object") return void 0;
|
|
1104
|
+
const obj = input;
|
|
1105
|
+
if (subjectKey) {
|
|
1106
|
+
const value = obj[subjectKey];
|
|
1107
|
+
if (typeof value === "string") {
|
|
1108
|
+
return isPathSubjectKey(subjectKey) ? normalizePathSubject(value) : escapeGlobSubject(value);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (toolName === "bash" && typeof obj.command === "string") {
|
|
1112
|
+
return escapeGlobSubject(obj.command);
|
|
1113
|
+
}
|
|
1114
|
+
if (typeof obj.path === "string") {
|
|
1115
|
+
return normalizePathSubject(obj.path);
|
|
1116
|
+
}
|
|
1117
|
+
if (typeof obj.url === "string") {
|
|
1118
|
+
return escapeGlobSubject(obj.url);
|
|
1119
|
+
}
|
|
1120
|
+
if (typeof obj.name === "string") {
|
|
1121
|
+
return escapeGlobSubject(obj.name);
|
|
1122
|
+
}
|
|
1123
|
+
return void 0;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/utils/tool-wire-compact.ts
|
|
1127
|
+
var TOOL_DESCRIPTION_MAX_CHARS = 640;
|
|
1128
|
+
var SCHEMA_DESCRIPTION_MAX_CHARS = 180;
|
|
1129
|
+
var compactCache = /* @__PURE__ */ new WeakMap();
|
|
1130
|
+
function compactToolDefinitionForWire(tool, opts = {}) {
|
|
1131
|
+
const useDefaultOptions = opts.descriptionMaxChars === void 0 && opts.schemaDescriptionMaxChars === void 0;
|
|
1132
|
+
if (useDefaultOptions && typeof tool === "object" && tool !== null) {
|
|
1133
|
+
const cached = compactCache.get(tool);
|
|
1134
|
+
if (cached) return cached;
|
|
1135
|
+
}
|
|
1136
|
+
const compact = {
|
|
1137
|
+
name: tool.name,
|
|
1138
|
+
description: compactDescription(
|
|
1139
|
+
tool.description ?? "",
|
|
1140
|
+
opts.descriptionMaxChars ?? TOOL_DESCRIPTION_MAX_CHARS
|
|
1141
|
+
),
|
|
1142
|
+
inputSchema: compactSchemaDescriptions(
|
|
1143
|
+
tool.inputSchema,
|
|
1144
|
+
opts.schemaDescriptionMaxChars ?? SCHEMA_DESCRIPTION_MAX_CHARS
|
|
1145
|
+
)
|
|
1146
|
+
};
|
|
1147
|
+
if (useDefaultOptions && typeof tool === "object" && tool !== null) {
|
|
1148
|
+
compactCache.set(tool, compact);
|
|
1149
|
+
}
|
|
1150
|
+
return compact;
|
|
1151
|
+
}
|
|
1152
|
+
function compactSchemaDescriptions(schema, maxDescriptionChars = SCHEMA_DESCRIPTION_MAX_CHARS) {
|
|
1153
|
+
const compact = compactSchemaNode(schema, maxDescriptionChars);
|
|
1154
|
+
return isRecord(compact) ? compact : { type: "object", properties: {} };
|
|
1155
|
+
}
|
|
1156
|
+
function compactSchemaNode(node, maxDescriptionChars) {
|
|
1157
|
+
if (Array.isArray(node)) {
|
|
1158
|
+
return node.map((item) => compactSchemaNode(item, maxDescriptionChars));
|
|
1159
|
+
}
|
|
1160
|
+
if (!isRecord(node)) return node;
|
|
1161
|
+
const out = {};
|
|
1162
|
+
for (const [key, value] of Object.entries(node)) {
|
|
1163
|
+
if (key === "description" && typeof value === "string") {
|
|
1164
|
+
out[key] = compactDescription(value, maxDescriptionChars);
|
|
1165
|
+
} else {
|
|
1166
|
+
out[key] = compactSchemaNode(value, maxDescriptionChars);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return out;
|
|
1170
|
+
}
|
|
1171
|
+
function compactDescription(text, maxChars) {
|
|
1172
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
1173
|
+
if (normalized.length <= maxChars) return normalized;
|
|
1174
|
+
if (maxChars <= 20) return normalized.slice(0, maxChars);
|
|
1175
|
+
const hardLimit = maxChars - 12;
|
|
1176
|
+
const boundary = findSemanticBoundary(normalized, hardLimit);
|
|
1177
|
+
const head = normalized.slice(0, boundary > 0 ? boundary : hardLimit).trimEnd();
|
|
1178
|
+
return `${head} ...`;
|
|
1179
|
+
}
|
|
1180
|
+
function findSemanticBoundary(text, limit) {
|
|
1181
|
+
const punctuation = Math.max(
|
|
1182
|
+
text.lastIndexOf(". ", limit),
|
|
1183
|
+
text.lastIndexOf("; ", limit),
|
|
1184
|
+
text.lastIndexOf(": ", limit)
|
|
1185
|
+
);
|
|
1186
|
+
if (punctuation >= Math.floor(limit * 0.45)) return punctuation + 1;
|
|
1187
|
+
const comma = text.lastIndexOf(", ", limit);
|
|
1188
|
+
if (comma >= Math.floor(limit * 0.6)) return comma + 1;
|
|
1189
|
+
const space = text.lastIndexOf(" ", limit);
|
|
1190
|
+
return space >= Math.floor(limit * 0.6) ? space : limit;
|
|
1191
|
+
}
|
|
1192
|
+
function isRecord(value) {
|
|
1193
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// src/utils/token-estimate.ts
|
|
1197
|
+
var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
|
|
1198
|
+
var CALIBRATION_GLOBAL_KEY = "__global__";
|
|
1199
|
+
var _cals = /* @__PURE__ */ new Map();
|
|
1200
|
+
function calState(key) {
|
|
1201
|
+
let state = _cals.get(key);
|
|
1202
|
+
if (!state) {
|
|
1203
|
+
state = { ratio: 1, count: 0, prevEst: 0 };
|
|
1204
|
+
_cals.set(key, state);
|
|
1205
|
+
}
|
|
1206
|
+
return state;
|
|
1207
|
+
}
|
|
1208
|
+
var MIN_SAMPLES_FOR_CALIBRATION = 3;
|
|
1209
|
+
var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
|
|
1210
|
+
var ESTIMATE_CACHE_MAX_SIZE = 1e4;
|
|
1211
|
+
function getCachedEstimate(key, compute) {
|
|
1212
|
+
const existing = ESTIMATE_CACHE.get(key);
|
|
1213
|
+
if (existing !== void 0) return existing;
|
|
1214
|
+
if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
|
|
1215
|
+
for (const k of ESTIMATE_CACHE.keys()) {
|
|
1216
|
+
if (ESTIMATE_CACHE.size <= Math.floor(ESTIMATE_CACHE_MAX_SIZE / 2)) break;
|
|
1217
|
+
ESTIMATE_CACHE.delete(k);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
const estimate = compute(key);
|
|
1221
|
+
ESTIMATE_CACHE.set(key, estimate);
|
|
1222
|
+
return estimate;
|
|
1223
|
+
}
|
|
1224
|
+
function estimateToolInputTokens(input) {
|
|
1225
|
+
if (typeof input === "string") return RoughTokenEstimate(input);
|
|
1226
|
+
if (input === null || typeof input !== "object") {
|
|
1227
|
+
return RoughTokenEstimate(String(input));
|
|
1228
|
+
}
|
|
1229
|
+
return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
|
|
1230
|
+
}
|
|
1231
|
+
function estimateToolResultTokens(content) {
|
|
1232
|
+
if (typeof content === "string") return RoughTokenEstimate(content);
|
|
1233
|
+
return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
|
|
1234
|
+
}
|
|
1235
|
+
function estimateTextTokens(text) {
|
|
1236
|
+
return RoughTokenEstimate(text);
|
|
1237
|
+
}
|
|
1238
|
+
function computeMessageTokens(msg) {
|
|
1239
|
+
if (typeof msg.content === "string") return estimateTextTokens(msg.content);
|
|
1240
|
+
let total = 0;
|
|
1241
|
+
for (const b of msg.content) {
|
|
1242
|
+
if (b.type === "text") total += estimateTextTokens(b.text);
|
|
1243
|
+
else if (b.type === "tool_use") total += estimateToolInputTokens(b.input);
|
|
1244
|
+
else if (b.type === "tool_result") total += estimateToolResultTokens(b.content);
|
|
1245
|
+
else total += RoughTokenEstimate(JSON.stringify(b));
|
|
1246
|
+
}
|
|
768
1247
|
return total;
|
|
769
1248
|
}
|
|
770
1249
|
function estimateMessageTokens(messages) {
|
|
@@ -781,7 +1260,8 @@ function estimateMessageTokens(messages) {
|
|
|
781
1260
|
function estimateToolDefTokens(tool) {
|
|
782
1261
|
const cached = tool._estDefTokens;
|
|
783
1262
|
if (typeof cached === "number" && cached > 0) return cached;
|
|
784
|
-
|
|
1263
|
+
const compact = compactToolDefinitionForWire(tool);
|
|
1264
|
+
return RoughTokenEstimate(tool.name) + RoughTokenEstimate(compact.description) + RoughTokenEstimate(JSON.stringify(compact.inputSchema));
|
|
785
1265
|
}
|
|
786
1266
|
function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = CALIBRATION_GLOBAL_KEY) {
|
|
787
1267
|
let messagesTokens = 0;
|
|
@@ -858,406 +1338,702 @@ function estimateRequestTokensCalibrated(messages, systemPrompt, tools, calibrat
|
|
|
858
1338
|
return result;
|
|
859
1339
|
}
|
|
860
1340
|
|
|
861
|
-
// src/utils/
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1341
|
+
// src/utils/tool-output-serializer.ts
|
|
1342
|
+
var DEFAULT_LIST_LIMIT = 500;
|
|
1343
|
+
var LOG_ENTRY_LIMIT = 200;
|
|
1344
|
+
var INLINE_LIMIT = 240;
|
|
1345
|
+
var GREP_FILE_LIMIT = 80;
|
|
1346
|
+
var GREP_MATCHES_PER_FILE = 3;
|
|
1347
|
+
var DIFF_INLINE_LINE_LIMIT = 260;
|
|
1348
|
+
var DIFF_HUNK_LIMIT = 8;
|
|
1349
|
+
var DIFF_HUNK_CONTEXT = 14;
|
|
1350
|
+
function createToolOutputSerializer(opts = {}) {
|
|
1351
|
+
const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
|
|
1352
|
+
function serialize(value, context = {}) {
|
|
1353
|
+
if (typeof value === "string") return value;
|
|
1354
|
+
if (value === null || value === void 0) return "";
|
|
1355
|
+
if (typeof value === "object") {
|
|
1356
|
+
if (Array.isArray(value)) return value.map((item) => serialize(item)).join("\n");
|
|
1357
|
+
if (context.toolName) {
|
|
1358
|
+
const compact = renderToolObject(context.toolName, value, context.input);
|
|
1359
|
+
if (compact !== void 0) return compact;
|
|
1360
|
+
return renderGenericToolObject(context.toolName, value);
|
|
1361
|
+
}
|
|
1362
|
+
if ("text" in value) {
|
|
1363
|
+
const t = value.text;
|
|
1364
|
+
return typeof t === "string" ? t : JSON.stringify(value, null, 2);
|
|
1365
|
+
}
|
|
1366
|
+
try {
|
|
1367
|
+
return JSON.stringify(value, null, 2);
|
|
1368
|
+
} catch {
|
|
1369
|
+
return String(value);
|
|
1370
|
+
}
|
|
875
1371
|
}
|
|
1372
|
+
return String(value);
|
|
876
1373
|
}
|
|
877
|
-
|
|
878
|
-
if (
|
|
879
|
-
|
|
880
|
-
path: path19 || "<root>",
|
|
881
|
-
message: `expected ${schema.type}, got ${describeType(value)}`
|
|
882
|
-
});
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
if (schema.type === "object" && isPlainObject(value)) {
|
|
887
|
-
const obj = value;
|
|
888
|
-
for (const req of schema.required ?? []) {
|
|
889
|
-
if (!(req in obj)) {
|
|
890
|
-
errors.push({ path: joinPath(path19, req), message: "required property missing" });
|
|
891
|
-
}
|
|
1374
|
+
function enforceCap(text, remainingBudget) {
|
|
1375
|
+
if (remainingBudget <= 0) {
|
|
1376
|
+
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
892
1377
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
walk(obj[key], subSchema, joinPath(path19, key), errors);
|
|
897
|
-
}
|
|
898
|
-
}
|
|
1378
|
+
const textBytes = Buffer.byteLength(text, "utf8");
|
|
1379
|
+
if (textBytes <= remainingBudget) {
|
|
1380
|
+
return { text, newBudget: remainingBudget - textBytes };
|
|
899
1381
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1382
|
+
const marker = `
|
|
1383
|
+
\u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
|
|
1384
|
+
`;
|
|
1385
|
+
const markerBytes = Buffer.byteLength(marker, "utf8");
|
|
1386
|
+
const available = remainingBudget - markerBytes;
|
|
1387
|
+
if (available <= 0) {
|
|
1388
|
+
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
904
1389
|
}
|
|
1390
|
+
const half = Math.floor(available / 2);
|
|
1391
|
+
const first = text.slice(0, half);
|
|
1392
|
+
const second = text.slice(text.length - half);
|
|
1393
|
+
return { text: `${first}${marker}${second}`, newBudget: 0 };
|
|
905
1394
|
}
|
|
1395
|
+
return { serialize, enforceCap, capBytes };
|
|
906
1396
|
}
|
|
907
|
-
function
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
return true;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
function isPlainObject(v) {
|
|
928
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
929
|
-
}
|
|
930
|
-
function describeType(v) {
|
|
931
|
-
if (v === null) return "null";
|
|
932
|
-
if (Array.isArray(v)) return "array";
|
|
933
|
-
return typeof v;
|
|
934
|
-
}
|
|
935
|
-
function joinPath(parent, key) {
|
|
936
|
-
if (!parent) return key;
|
|
937
|
-
return `${parent}.${key}`;
|
|
938
|
-
}
|
|
939
|
-
function deepEqual(a, b) {
|
|
940
|
-
if (a === b) return true;
|
|
941
|
-
if (typeof a !== typeof b) return false;
|
|
942
|
-
if (a === null || b === null) return a === b;
|
|
943
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
944
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
945
|
-
}
|
|
946
|
-
if (typeof a === "object" && typeof b === "object") {
|
|
947
|
-
const ak = Object.keys(a);
|
|
948
|
-
const bk = Object.keys(b);
|
|
949
|
-
if (ak.length !== bk.length) return false;
|
|
950
|
-
return ak.every(
|
|
951
|
-
(k) => deepEqual(a[k], b[k])
|
|
952
|
-
);
|
|
953
|
-
}
|
|
954
|
-
return false;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
// src/utils/regex-guard.ts
|
|
958
|
-
var MAX_PATTERN_LEN = 512;
|
|
959
|
-
var DANGEROUS_PATTERNS = [
|
|
960
|
-
/(\([^)]*[+*][^)]*\))[+*]/,
|
|
961
|
-
// (a+)+, (.*)+, etc
|
|
962
|
-
/(\(\?:[^)]*[+*][^)]*\))[+*]/
|
|
963
|
-
// same, with non-capturing group
|
|
964
|
-
];
|
|
965
|
-
function compileUserRegex(pattern, flags) {
|
|
966
|
-
if (typeof pattern !== "string") {
|
|
967
|
-
return { ok: false, reason: "pattern must be a string" };
|
|
968
|
-
}
|
|
969
|
-
if (pattern.length === 0) {
|
|
970
|
-
return { ok: false, reason: "pattern is empty" };
|
|
971
|
-
}
|
|
972
|
-
if (pattern.length > MAX_PATTERN_LEN) {
|
|
973
|
-
return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
|
|
974
|
-
}
|
|
975
|
-
for (const rx of DANGEROUS_PATTERNS) {
|
|
976
|
-
if (rx.test(pattern)) {
|
|
977
|
-
return {
|
|
978
|
-
ok: false,
|
|
979
|
-
reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
|
|
980
|
-
};
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
try {
|
|
984
|
-
return { ok: true, regex: new RegExp(pattern, flags) };
|
|
985
|
-
} catch (err) {
|
|
986
|
-
return {
|
|
987
|
-
ok: false,
|
|
988
|
-
reason: err instanceof Error ? err.message : "invalid regex"
|
|
989
|
-
};
|
|
1397
|
+
function renderToolObject(toolName, obj, input) {
|
|
1398
|
+
if (toolName === "read" && typeof obj["text"] === "string") {
|
|
1399
|
+
return joinSections([
|
|
1400
|
+
renderHeader(
|
|
1401
|
+
`read: ${stringFromInput(input, "path") ?? stringField(obj, "path") ?? "<unknown>"}`,
|
|
1402
|
+
{
|
|
1403
|
+
offset: numberFromInput(input, "offset"),
|
|
1404
|
+
limit: numberFromInput(input, "limit"),
|
|
1405
|
+
total_lines: obj["total_lines"],
|
|
1406
|
+
encoding: obj["encoding"],
|
|
1407
|
+
truncated: obj["truncated"],
|
|
1408
|
+
cached: obj["cached"],
|
|
1409
|
+
note: obj["note"]
|
|
1410
|
+
}
|
|
1411
|
+
),
|
|
1412
|
+
obj["text"]
|
|
1413
|
+
]);
|
|
990
1414
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1415
|
+
if (toolName === "grep" && Array.isArray(obj["matches"])) {
|
|
1416
|
+
const matches = stringArrayField(obj, "matches");
|
|
1417
|
+
return joinSections([
|
|
1418
|
+
renderHeader(`grep: ${stringFromInput(input, "pattern") ?? "<pattern>"}`, {
|
|
1419
|
+
path: stringFromInput(input, "path"),
|
|
1420
|
+
glob: stringFromInput(input, "glob"),
|
|
1421
|
+
mode: stringFromInput(input, "output_mode"),
|
|
1422
|
+
count: obj["count"],
|
|
1423
|
+
shown: matches.length,
|
|
1424
|
+
truncated: obj["truncated"],
|
|
1425
|
+
used: obj["used"]
|
|
1426
|
+
}),
|
|
1427
|
+
renderGrepMatches(matches, stringFromInput(input, "output_mode"))
|
|
1428
|
+
]);
|
|
998
1429
|
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
i++;
|
|
1014
|
-
}
|
|
1015
|
-
} else if (c === "?") {
|
|
1016
|
-
re += "[^/\\\\]";
|
|
1017
|
-
i++;
|
|
1018
|
-
} else if (c === "[") {
|
|
1019
|
-
let cls = "[";
|
|
1020
|
-
i++;
|
|
1021
|
-
if (pat[i] === "!" || pat[i] === "^") {
|
|
1022
|
-
cls += "^";
|
|
1023
|
-
i++;
|
|
1024
|
-
}
|
|
1025
|
-
while (i < pat.length && pat[i] !== "]") {
|
|
1026
|
-
const ch = pat[i] ?? "";
|
|
1027
|
-
if (ch === "\\") cls += "\\\\";
|
|
1028
|
-
else if (ch === "]" || ch === "^") cls += `\\${ch}`;
|
|
1029
|
-
else cls += ch;
|
|
1030
|
-
i++;
|
|
1031
|
-
}
|
|
1032
|
-
cls += "]";
|
|
1033
|
-
re += cls;
|
|
1034
|
-
i++;
|
|
1035
|
-
} else {
|
|
1036
|
-
re += c.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
1037
|
-
i++;
|
|
1038
|
-
}
|
|
1430
|
+
if (toolName === "patch" && Array.isArray(obj["files"])) {
|
|
1431
|
+
const files = stringArrayField(obj, "files");
|
|
1432
|
+
return joinSections([
|
|
1433
|
+
renderHeader("patch", {
|
|
1434
|
+
applied: obj["applied"],
|
|
1435
|
+
rejected: obj["rejected"],
|
|
1436
|
+
files: files.length,
|
|
1437
|
+
dry_run: obj["dry_run"]
|
|
1438
|
+
}),
|
|
1439
|
+
typeof obj["message"] === "string" ? `message:
|
|
1440
|
+
${obj["message"]}` : void 0,
|
|
1441
|
+
files.length > 0 ? `files:
|
|
1442
|
+
${renderStringList(files)}` : void 0
|
|
1443
|
+
]);
|
|
1039
1444
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
if (!isGlob(pattern)) return [pattern];
|
|
1050
|
-
const results = /* @__PURE__ */ new Set();
|
|
1051
|
-
const abs = isAbsolute(pattern);
|
|
1052
|
-
const base = abs ? baseDir(pattern) : baseDir(pattern);
|
|
1053
|
-
const relPat = base === "." ? pattern : pattern.slice(base.length + 1);
|
|
1054
|
-
async function walk3(dir, pat) {
|
|
1055
|
-
let entries;
|
|
1056
|
-
try {
|
|
1057
|
-
entries = await fsp2.readdir(dir);
|
|
1058
|
-
} catch {
|
|
1059
|
-
return;
|
|
1060
|
-
}
|
|
1061
|
-
const firstGlob = pat.search(/[*?[[]/);
|
|
1062
|
-
if (firstGlob < 0) {
|
|
1063
|
-
const re = globToRegex(pat);
|
|
1064
|
-
for (const e of entries) {
|
|
1065
|
-
if (re.test(e)) {
|
|
1066
|
-
const full = `${dir}${SEP}${e}`;
|
|
1067
|
-
results.add(abs ? resolve(full) : full);
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
const before = pat.slice(0, firstGlob);
|
|
1073
|
-
const rest = pat.slice(firstGlob);
|
|
1074
|
-
if (before.endsWith("**")) {
|
|
1075
|
-
await walk3(dir, rest);
|
|
1076
|
-
for (const e of entries) {
|
|
1077
|
-
const full = `${dir}${SEP}${e}`;
|
|
1078
|
-
try {
|
|
1079
|
-
const stat6 = await fsp2.stat(full);
|
|
1080
|
-
if (stat6.isDirectory()) await walk3(full, rest);
|
|
1081
|
-
} catch {
|
|
1445
|
+
if (toolName === "glob" && Array.isArray(obj["files"])) {
|
|
1446
|
+
const files = stringArrayField(obj, "files");
|
|
1447
|
+
return joinSections([
|
|
1448
|
+
renderHeader(
|
|
1449
|
+
`${toolName}: ${stringFromInput(input, "pattern") ?? stringFromInput(input, "files") ?? stringFromInput(input, "path") ?? ""}`.trim(),
|
|
1450
|
+
{
|
|
1451
|
+
path: stringFromInput(input, "path"),
|
|
1452
|
+
files: files.length,
|
|
1453
|
+
truncated: obj["truncated"]
|
|
1082
1454
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1455
|
+
),
|
|
1456
|
+
renderStringList(files, "(no files)")
|
|
1457
|
+
]);
|
|
1458
|
+
}
|
|
1459
|
+
if (toolName === "tree" && typeof obj["tree"] === "string") {
|
|
1460
|
+
return joinSections([
|
|
1461
|
+
renderHeader(
|
|
1462
|
+
`tree: ${stringField(obj, "path") ?? stringFromInput(input, "path") ?? "<cwd>"}`,
|
|
1463
|
+
{
|
|
1464
|
+
total_files: obj["total_files"],
|
|
1465
|
+
total_dirs: obj["total_dirs"],
|
|
1466
|
+
truncated: obj["truncated"]
|
|
1090
1467
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1468
|
+
),
|
|
1469
|
+
obj["tree"]
|
|
1470
|
+
]);
|
|
1471
|
+
}
|
|
1472
|
+
if (toolName === "fetch" && typeof obj["content"] === "string") {
|
|
1473
|
+
return joinSections([
|
|
1474
|
+
renderHeader(
|
|
1475
|
+
`fetch: ${stringField(obj, "url") ?? stringFromInput(input, "url") ?? "<url>"}`,
|
|
1476
|
+
{
|
|
1477
|
+
status: obj["status"],
|
|
1478
|
+
content_type: obj["content_type"]
|
|
1100
1479
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1480
|
+
),
|
|
1481
|
+
obj["content"]
|
|
1482
|
+
]);
|
|
1103
1483
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
for (let i = 0; i < s.length; i++) {
|
|
1123
|
-
const ch = expectDefined(s[i]);
|
|
1124
|
-
if (inString) {
|
|
1125
|
-
contentEnd = i + 1;
|
|
1126
|
-
if (escaped) {
|
|
1127
|
-
escaped = false;
|
|
1128
|
-
continue;
|
|
1129
|
-
}
|
|
1130
|
-
if (ch === "\\") {
|
|
1131
|
-
escaped = true;
|
|
1132
|
-
continue;
|
|
1133
|
-
}
|
|
1134
|
-
if (ch === '"') {
|
|
1135
|
-
inString = false;
|
|
1136
|
-
prevSig = '"';
|
|
1137
|
-
stringBraceDepth = 0;
|
|
1138
|
-
continue;
|
|
1139
|
-
}
|
|
1140
|
-
if (ch === "{") stringBraceDepth++;
|
|
1141
|
-
else if (ch === "}" && stringBraceDepth > 0) stringBraceDepth--;
|
|
1142
|
-
continue;
|
|
1143
|
-
}
|
|
1144
|
-
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") continue;
|
|
1145
|
-
contentEnd = i + 1;
|
|
1146
|
-
if (ch === '"') {
|
|
1147
|
-
inString = true;
|
|
1148
|
-
sawKey = true;
|
|
1149
|
-
stringBraceDepth = 0;
|
|
1150
|
-
prevSig = '"';
|
|
1151
|
-
} else if (ch === "{" || ch === "[") {
|
|
1152
|
-
stack.push(ch);
|
|
1153
|
-
prevSig = ch;
|
|
1154
|
-
} else if (ch === "}" || ch === "]") {
|
|
1155
|
-
stack.pop();
|
|
1156
|
-
prevSig = ch;
|
|
1157
|
-
} else {
|
|
1158
|
-
prevSig = ch;
|
|
1484
|
+
if (toolName === "replace" && Array.isArray(obj["results"])) {
|
|
1485
|
+
const results = obj["results"].filter(isRecord2);
|
|
1486
|
+
const sections = [
|
|
1487
|
+
renderHeader("replace", {
|
|
1488
|
+
files_modified: obj["files_modified"],
|
|
1489
|
+
total_replacements: obj["total_replacements"],
|
|
1490
|
+
dry_run: obj["dry_run"]
|
|
1491
|
+
})
|
|
1492
|
+
];
|
|
1493
|
+
for (const r of results.slice(0, DEFAULT_LIST_LIMIT)) {
|
|
1494
|
+
sections.push(
|
|
1495
|
+
joinSections([
|
|
1496
|
+
renderHeader(`file: ${stringField(r, "path") ?? "<unknown>"}`, {
|
|
1497
|
+
replacements: r["replacements"]
|
|
1498
|
+
}),
|
|
1499
|
+
typeof r["diff"] === "string" ? r["diff"] : void 0
|
|
1500
|
+
])
|
|
1501
|
+
);
|
|
1159
1502
|
}
|
|
1503
|
+
if (results.length > DEFAULT_LIST_LIMIT) {
|
|
1504
|
+
sections.push(`[serializer omitted ${results.length - DEFAULT_LIST_LIMIT} result item(s)]`);
|
|
1505
|
+
}
|
|
1506
|
+
return joinSections(sections);
|
|
1507
|
+
}
|
|
1508
|
+
if (typeof obj["diff"] === "string") {
|
|
1509
|
+
const diff = obj["diff"];
|
|
1510
|
+
return joinSections([
|
|
1511
|
+
renderHeader(toolName, {
|
|
1512
|
+
path: obj["path"],
|
|
1513
|
+
replacements: obj["replacements"],
|
|
1514
|
+
bytes_written: obj["bytes_written"],
|
|
1515
|
+
created: obj["created"],
|
|
1516
|
+
note: obj["note"],
|
|
1517
|
+
files: Array.isArray(obj["files"]) ? obj["files"].length : void 0,
|
|
1518
|
+
truncated: obj["truncated"],
|
|
1519
|
+
mode: obj["mode"]
|
|
1520
|
+
}),
|
|
1521
|
+
compactDiff(diff)
|
|
1522
|
+
]);
|
|
1160
1523
|
}
|
|
1161
|
-
if (
|
|
1162
|
-
|
|
1163
|
-
if (inString) {
|
|
1164
|
-
if (escaped) {
|
|
1165
|
-
result = result.slice(0, -1);
|
|
1166
|
-
} else if (endsWithInvalidEscape(result)) {
|
|
1167
|
-
result = result.slice(0, -2);
|
|
1168
|
-
}
|
|
1169
|
-
if (stringBraceDepth > 0) result += "}".repeat(stringBraceDepth);
|
|
1170
|
-
result += '"';
|
|
1171
|
-
} else if (prevSig === ":") {
|
|
1172
|
-
result += "null";
|
|
1524
|
+
if (toolName === "test" && typeof obj["output"] === "string") {
|
|
1525
|
+
return renderTestOutput(obj, input);
|
|
1173
1526
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1527
|
+
if ((toolName === "typecheck" || toolName === "lint" || toolName === "format") && typeof obj["output"] === "string") {
|
|
1528
|
+
return renderVerifierOutput(toolName, obj, input);
|
|
1176
1529
|
}
|
|
1177
|
-
if (
|
|
1178
|
-
|
|
1179
|
-
if (tryParse(patched).ok) result = patched;
|
|
1530
|
+
if (hasCommandOutputShape(obj)) {
|
|
1531
|
+
return renderCommandOutput(toolName, obj, input);
|
|
1180
1532
|
}
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
}
|
|
1192
|
-
function tryParse(s) {
|
|
1193
|
-
try {
|
|
1194
|
-
return { ok: true, value: JSON.parse(s) };
|
|
1195
|
-
} catch {
|
|
1196
|
-
return { ok: false };
|
|
1533
|
+
if (toolName === "json" && typeof obj["formatted"] === "string") {
|
|
1534
|
+
return joinSections([
|
|
1535
|
+
renderHeader("json", {
|
|
1536
|
+
type: obj["type"],
|
|
1537
|
+
keys: Array.isArray(obj["keys"]) ? obj["keys"].length : void 0,
|
|
1538
|
+
query: stringFromInput(input, "query"),
|
|
1539
|
+
error: obj["error"]
|
|
1540
|
+
}),
|
|
1541
|
+
obj["formatted"]
|
|
1542
|
+
]);
|
|
1197
1543
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1544
|
+
if (toolName === "logs" && Array.isArray(obj["entries"])) {
|
|
1545
|
+
const entries = obj["entries"].filter(isRecord2);
|
|
1546
|
+
const lines = entries.slice(0, LOG_ENTRY_LIMIT).map((entry) => {
|
|
1547
|
+
const ts = stringField(entry, "timestamp") ?? "";
|
|
1548
|
+
const level = stringField(entry, "level") ?? "info";
|
|
1549
|
+
const message = stringField(entry, "message") ?? "";
|
|
1550
|
+
const source = stringField(entry, "source");
|
|
1551
|
+
return [ts, level, source, message].filter(Boolean).join(" ");
|
|
1552
|
+
});
|
|
1553
|
+
if (entries.length > LOG_ENTRY_LIMIT) {
|
|
1554
|
+
lines.push(`[serializer omitted ${entries.length - LOG_ENTRY_LIMIT} log entry item(s)]`);
|
|
1555
|
+
}
|
|
1556
|
+
return joinSections([
|
|
1557
|
+
renderHeader(`logs: ${stringField(obj, "source") ?? "<source>"}`, {
|
|
1558
|
+
total: obj["total"],
|
|
1559
|
+
shown: Math.min(entries.length, LOG_ENTRY_LIMIT),
|
|
1560
|
+
truncated: obj["truncated"],
|
|
1561
|
+
stream_mode: obj["stream_mode"]
|
|
1562
|
+
}),
|
|
1563
|
+
lines.length > 0 ? lines.join("\n") : "(no log entries)"
|
|
1564
|
+
]);
|
|
1205
1565
|
}
|
|
1206
|
-
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1566
|
+
if (toolName === "audit" && Array.isArray(obj["vulnerabilities"])) {
|
|
1567
|
+
const vulns = obj["vulnerabilities"].filter(isRecord2);
|
|
1568
|
+
const lines = vulns.slice(0, DEFAULT_LIST_LIMIT).map((v) => {
|
|
1569
|
+
const severity = stringField(v, "severity") ?? "unknown";
|
|
1570
|
+
const pkg = stringField(v, "package") ?? "<package>";
|
|
1571
|
+
const title = stringField(v, "title") ?? "";
|
|
1572
|
+
const url = stringField(v, "url");
|
|
1573
|
+
return [severity, pkg, title, url].filter(Boolean).join(" | ");
|
|
1574
|
+
});
|
|
1575
|
+
if (vulns.length > DEFAULT_LIST_LIMIT) {
|
|
1576
|
+
lines.push(`[serializer omitted ${vulns.length - DEFAULT_LIST_LIMIT} vulnerability item(s)]`);
|
|
1577
|
+
}
|
|
1578
|
+
return joinSections([
|
|
1579
|
+
renderHeader("audit", {
|
|
1580
|
+
exit_code: obj["exit_code"],
|
|
1581
|
+
total: obj["total"],
|
|
1582
|
+
summary: obj["summary"],
|
|
1583
|
+
truncated: obj["truncated"]
|
|
1584
|
+
}),
|
|
1585
|
+
lines.length > 0 ? lines.join("\n") : stringField(obj, "output")
|
|
1586
|
+
]);
|
|
1209
1587
|
}
|
|
1210
|
-
|
|
1588
|
+
if (toolName === "outdated" && Array.isArray(obj["packages"])) {
|
|
1589
|
+
const packages = obj["packages"].filter(isRecord2);
|
|
1590
|
+
const lines = packages.slice(0, DEFAULT_LIST_LIMIT).map(
|
|
1591
|
+
(p) => [
|
|
1592
|
+
stringField(p, "name") ?? "<package>",
|
|
1593
|
+
`current=${stringField(p, "current") ?? "unknown"}`,
|
|
1594
|
+
`wanted=${stringField(p, "wanted") ?? "unknown"}`,
|
|
1595
|
+
`latest=${stringField(p, "latest") ?? "unknown"}`,
|
|
1596
|
+
stringField(p, "type")
|
|
1597
|
+
].filter(Boolean).join(" | ")
|
|
1598
|
+
);
|
|
1599
|
+
if (packages.length > DEFAULT_LIST_LIMIT) {
|
|
1600
|
+
lines.push(`[serializer omitted ${packages.length - DEFAULT_LIST_LIMIT} package item(s)]`);
|
|
1601
|
+
}
|
|
1602
|
+
return joinSections([
|
|
1603
|
+
renderHeader("outdated", {
|
|
1604
|
+
exit_code: obj["exit_code"],
|
|
1605
|
+
total: obj["total"],
|
|
1606
|
+
truncated: obj["truncated"]
|
|
1607
|
+
}),
|
|
1608
|
+
lines.length > 0 ? lines.join("\n") : stringField(obj, "output")
|
|
1609
|
+
]);
|
|
1610
|
+
}
|
|
1611
|
+
return void 0;
|
|
1211
1612
|
}
|
|
1212
|
-
function
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1613
|
+
function renderTestOutput(obj, input) {
|
|
1614
|
+
const exitCode = numberField(obj, "exit_code") ?? 0;
|
|
1615
|
+
const failed = numberField(obj, "failed") ?? 0;
|
|
1616
|
+
const output = stringField(obj, "output") ?? "";
|
|
1617
|
+
const header = renderHeader(`test: ${stringField(obj, "runner") ?? "runner"}`, {
|
|
1618
|
+
exit_code: obj["exit_code"],
|
|
1619
|
+
tests_run: obj["tests_run"],
|
|
1620
|
+
passed: obj["passed"],
|
|
1621
|
+
failed: obj["failed"],
|
|
1622
|
+
duration_ms: obj["duration_ms"],
|
|
1623
|
+
truncated: obj["truncated"],
|
|
1624
|
+
files: inputListSummary(input, "files"),
|
|
1625
|
+
grep: stringFromInput(input, "grep")
|
|
1626
|
+
});
|
|
1627
|
+
if (exitCode === 0 && failed === 0) {
|
|
1628
|
+
return joinSections([
|
|
1629
|
+
header,
|
|
1630
|
+
joinSections([
|
|
1631
|
+
"report:",
|
|
1632
|
+
`status=passed`,
|
|
1633
|
+
`tests_run=${obj["tests_run"] ?? 0}`,
|
|
1634
|
+
`passed=${obj["passed"] ?? 0}`,
|
|
1635
|
+
`failed=${obj["failed"] ?? 0}`,
|
|
1636
|
+
`duration_ms=${obj["duration_ms"] ?? 0}`,
|
|
1637
|
+
extractSpoolNote(output)
|
|
1638
|
+
])
|
|
1639
|
+
]);
|
|
1216
1640
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1641
|
+
return joinSections([
|
|
1642
|
+
header,
|
|
1643
|
+
`error_context:
|
|
1644
|
+
${compactFailureOutput(output || "(no runner output)")}`
|
|
1645
|
+
]);
|
|
1646
|
+
}
|
|
1647
|
+
function renderVerifierOutput(toolName, obj, input) {
|
|
1648
|
+
const exitCode = numberField(obj, "exit_code") ?? 0;
|
|
1649
|
+
const errors = numberField(obj, "errors") ?? 0;
|
|
1650
|
+
const warnings = numberField(obj, "warnings") ?? 0;
|
|
1651
|
+
const output = stringField(obj, "output") ?? "";
|
|
1652
|
+
const changed = numberField(obj, "files_changed") ?? 0;
|
|
1653
|
+
const header = renderHeader(toolName, {
|
|
1654
|
+
exit_code: obj["exit_code"],
|
|
1655
|
+
errors: obj["errors"],
|
|
1656
|
+
warnings: obj["warnings"],
|
|
1657
|
+
files_checked: obj["files_checked"],
|
|
1658
|
+
files_changed: obj["files_changed"],
|
|
1659
|
+
fix_applied: obj["fix_applied"],
|
|
1660
|
+
fixer: obj["fixer"],
|
|
1661
|
+
linter: obj["linter"],
|
|
1662
|
+
project: obj["project"],
|
|
1663
|
+
truncated: obj["truncated"],
|
|
1664
|
+
files: inputListSummary(input, "files"),
|
|
1665
|
+
cwd: stringFromInput(input, "cwd")
|
|
1666
|
+
});
|
|
1667
|
+
if (exitCode === 0 && errors === 0 && (toolName !== "format" || changed === 0)) {
|
|
1668
|
+
return joinSections([
|
|
1669
|
+
header,
|
|
1670
|
+
joinSections([
|
|
1671
|
+
"report:",
|
|
1672
|
+
"status=passed",
|
|
1673
|
+
`errors=${errors}`,
|
|
1674
|
+
`warnings=${warnings}`,
|
|
1675
|
+
toolName === "format" ? `files_changed=${changed}` : void 0,
|
|
1676
|
+
extractSpoolNote(output)
|
|
1677
|
+
])
|
|
1678
|
+
]);
|
|
1220
1679
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1680
|
+
if (exitCode === 0 && toolName === "format") {
|
|
1681
|
+
return joinSections([
|
|
1682
|
+
header,
|
|
1683
|
+
joinSections([
|
|
1684
|
+
"report:",
|
|
1685
|
+
"status=changed",
|
|
1686
|
+
`files_changed=${changed}`,
|
|
1687
|
+
extractSpoolNote(output)
|
|
1688
|
+
])
|
|
1689
|
+
]);
|
|
1690
|
+
}
|
|
1691
|
+
return joinSections([
|
|
1692
|
+
header,
|
|
1693
|
+
`error_context:
|
|
1694
|
+
${compactFailureOutput(output || "(no verifier output)")}`
|
|
1695
|
+
]);
|
|
1234
1696
|
}
|
|
1235
|
-
function
|
|
1236
|
-
|
|
1237
|
-
if (
|
|
1238
|
-
|
|
1697
|
+
function renderGrepMatches(matches, mode) {
|
|
1698
|
+
if (matches.length === 0) return "(no matches)";
|
|
1699
|
+
if (mode === "files_with_matches") return renderStringList(matches, "(no files)");
|
|
1700
|
+
if (mode === "count") return renderStringList(matches, "(no counts)");
|
|
1701
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1702
|
+
const passthrough = [];
|
|
1703
|
+
for (const match of matches) {
|
|
1704
|
+
const parsed = parseGrepContentLine(match);
|
|
1705
|
+
if (!parsed) {
|
|
1706
|
+
passthrough.push(match);
|
|
1707
|
+
continue;
|
|
1708
|
+
}
|
|
1709
|
+
const list = groups.get(parsed.file) ?? [];
|
|
1710
|
+
list.push(`${parsed.line}:${parsed.text}`);
|
|
1711
|
+
groups.set(parsed.file, list);
|
|
1239
1712
|
}
|
|
1240
|
-
if (
|
|
1241
|
-
|
|
1713
|
+
if (groups.size === 0) return renderStringList(matches, "(no matches)");
|
|
1714
|
+
const sections = [];
|
|
1715
|
+
let fileIndex = 0;
|
|
1716
|
+
for (const [file, lines] of groups) {
|
|
1717
|
+
fileIndex++;
|
|
1718
|
+
if (fileIndex > GREP_FILE_LIMIT) break;
|
|
1719
|
+
const shown = lines.slice(0, GREP_MATCHES_PER_FILE);
|
|
1720
|
+
sections.push(
|
|
1721
|
+
`${file} (${lines.length} match(es), showing ${shown.length})
|
|
1722
|
+
${shown.join("\n")}`
|
|
1723
|
+
);
|
|
1242
1724
|
}
|
|
1243
|
-
if (
|
|
1244
|
-
|
|
1725
|
+
if (groups.size > GREP_FILE_LIMIT) {
|
|
1726
|
+
sections.push(`[serializer omitted ${groups.size - GREP_FILE_LIMIT} file group(s)]`);
|
|
1727
|
+
}
|
|
1728
|
+
if (passthrough.length > 0) {
|
|
1729
|
+
sections.push(`ungrouped:
|
|
1730
|
+
${renderStringList(passthrough, "", 50)}`);
|
|
1731
|
+
}
|
|
1732
|
+
return sections.join("\n");
|
|
1733
|
+
}
|
|
1734
|
+
function parseGrepContentLine(line) {
|
|
1735
|
+
const match = /^(.+?):(\d+):(.*)$/.exec(line);
|
|
1736
|
+
if (!match?.[1] || !match[2]) return void 0;
|
|
1737
|
+
return { file: match[1], line: match[2], text: match[3] ?? "" };
|
|
1738
|
+
}
|
|
1739
|
+
function compactDiff(diff) {
|
|
1740
|
+
const lines = diff.split(/\r?\n/);
|
|
1741
|
+
if (lines.length <= DIFF_INLINE_LINE_LIMIT) return diff;
|
|
1742
|
+
const fileCount = Math.max(
|
|
1743
|
+
new Set(
|
|
1744
|
+
lines.map(
|
|
1745
|
+
(line) => /^diff --git\s+a\/(.+?)\s+b\//.exec(line)?.[1] ?? /^---\s+(.+)/.exec(line)?.[1]
|
|
1746
|
+
).filter(Boolean)
|
|
1747
|
+
).size,
|
|
1748
|
+
0
|
|
1749
|
+
);
|
|
1750
|
+
const hunks = lines.filter((line) => line.startsWith("@@")).length;
|
|
1751
|
+
const added = lines.filter((line) => line.startsWith("+") && !line.startsWith("+++")).length;
|
|
1752
|
+
const removed = lines.filter((line) => line.startsWith("-") && !line.startsWith("---")).length;
|
|
1753
|
+
const selected = /* @__PURE__ */ new Set();
|
|
1754
|
+
let hunkCount = 0;
|
|
1755
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1756
|
+
const line = lines[i] ?? "";
|
|
1757
|
+
if (line.startsWith("diff --git") || line.startsWith("--- ") || line.startsWith("+++ ")) {
|
|
1758
|
+
selected.add(i);
|
|
1759
|
+
continue;
|
|
1760
|
+
}
|
|
1761
|
+
if (!line.startsWith("@@")) continue;
|
|
1762
|
+
if (hunkCount >= DIFF_HUNK_LIMIT) continue;
|
|
1763
|
+
hunkCount++;
|
|
1764
|
+
for (let j = i; j <= Math.min(lines.length - 1, i + DIFF_HUNK_CONTEXT); j++) {
|
|
1765
|
+
selected.add(j);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
if (selected.size === 0) {
|
|
1769
|
+
return joinSections([
|
|
1770
|
+
renderHeader("diff_summary", {
|
|
1771
|
+
files: fileCount,
|
|
1772
|
+
hunks,
|
|
1773
|
+
added,
|
|
1774
|
+
removed,
|
|
1775
|
+
lines: lines.length
|
|
1776
|
+
}),
|
|
1777
|
+
lines.slice(0, DIFF_INLINE_LINE_LIMIT).join("\n"),
|
|
1778
|
+
`[serializer omitted ${Math.max(0, lines.length - DIFF_INLINE_LINE_LIMIT)} diff line(s)]`
|
|
1779
|
+
]);
|
|
1245
1780
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1781
|
+
const excerpt = [];
|
|
1782
|
+
let previous = -1;
|
|
1783
|
+
for (const index of [...selected].sort((a, b) => a - b)) {
|
|
1784
|
+
if (index > previous + 1) {
|
|
1785
|
+
const omitted = previous === -1 ? index : index - previous - 1;
|
|
1786
|
+
excerpt.push(`[serializer omitted ${omitted} diff line(s)]`);
|
|
1787
|
+
}
|
|
1788
|
+
excerpt.push(lines[index] ?? "");
|
|
1789
|
+
previous = index;
|
|
1790
|
+
}
|
|
1791
|
+
const trailing = lines.length - previous - 1;
|
|
1792
|
+
if (trailing > 0) excerpt.push(`[serializer omitted ${trailing} trailing diff line(s)]`);
|
|
1793
|
+
return joinSections([
|
|
1794
|
+
renderHeader("diff_summary", {
|
|
1795
|
+
files: fileCount,
|
|
1796
|
+
hunks,
|
|
1797
|
+
shown_hunks: Math.min(hunks, DIFF_HUNK_LIMIT),
|
|
1798
|
+
added,
|
|
1799
|
+
removed,
|
|
1800
|
+
lines: lines.length
|
|
1801
|
+
}),
|
|
1802
|
+
excerpt.join("\n")
|
|
1803
|
+
]);
|
|
1804
|
+
}
|
|
1805
|
+
function compactFailureOutput(output) {
|
|
1806
|
+
const lines = output.split(/\r?\n/);
|
|
1807
|
+
if (lines.length <= 260) return output.trimEnd();
|
|
1808
|
+
const selected = /* @__PURE__ */ new Set();
|
|
1809
|
+
const marker = /\b(fail|failed|failure|error|exception|assertionerror|expected|received|actual|timeout|stack)\b/i;
|
|
1810
|
+
let markerHits = 0;
|
|
1811
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1812
|
+
if (!marker.test(lines[i] ?? "")) continue;
|
|
1813
|
+
markerHits++;
|
|
1814
|
+
for (let j = Math.max(0, i - 4); j <= Math.min(lines.length - 1, i + 10); j++) {
|
|
1815
|
+
selected.add(j);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
if (markerHits === 0) {
|
|
1819
|
+
return lines.slice(-220).join("\n").trimEnd();
|
|
1820
|
+
}
|
|
1821
|
+
const ordered = [...selected].sort((a, b) => a - b);
|
|
1822
|
+
const out = [];
|
|
1823
|
+
let previous = -1;
|
|
1824
|
+
for (const index of ordered) {
|
|
1825
|
+
if (index > previous + 1) {
|
|
1826
|
+
const omitted = previous === -1 ? index : index - previous - 1;
|
|
1827
|
+
out.push(`[serializer omitted ${omitted} line(s)]`);
|
|
1828
|
+
}
|
|
1829
|
+
out.push(lines[index] ?? "");
|
|
1830
|
+
previous = index;
|
|
1831
|
+
}
|
|
1832
|
+
return out.join("\n").trimEnd();
|
|
1833
|
+
}
|
|
1834
|
+
function extractSpoolNote(output) {
|
|
1835
|
+
return output.split(/\r?\n/).find((line) => line.startsWith("[output truncated") && line.includes("full"));
|
|
1836
|
+
}
|
|
1837
|
+
function hasCommandOutputShape(obj) {
|
|
1838
|
+
return typeof obj["stdout"] === "string" || typeof obj["stderr"] === "string" || typeof obj["output"] === "string" || typeof obj["exitCode"] === "number" || typeof obj["exit_code"] === "number";
|
|
1839
|
+
}
|
|
1840
|
+
function renderCommandOutput(toolName, obj, input) {
|
|
1841
|
+
const command = stringField(obj, "command") ?? stringFromInput(input, "command");
|
|
1842
|
+
const args = stringArrayField(obj, "args");
|
|
1843
|
+
const commandLine = command ? [command, ...args].join(" ") : void 0;
|
|
1844
|
+
const output = stringField(obj, "output");
|
|
1845
|
+
const stdout = stringField(obj, "stdout");
|
|
1846
|
+
const stderr = stringField(obj, "stderr");
|
|
1847
|
+
return joinSections([
|
|
1848
|
+
renderHeader(commandLine ? `${toolName}: ${commandLine}` : toolName, {
|
|
1849
|
+
exit_code: obj["exit_code"] ?? obj["exitCode"],
|
|
1850
|
+
timed_out: obj["timed_out"],
|
|
1851
|
+
pid: obj["pid"],
|
|
1852
|
+
allowed: obj["allowed"],
|
|
1853
|
+
truncated: obj["truncated"],
|
|
1854
|
+
runner: obj["runner"],
|
|
1855
|
+
linter: obj["linter"],
|
|
1856
|
+
fixer: obj["fixer"],
|
|
1857
|
+
project: obj["project"],
|
|
1858
|
+
tests_run: obj["tests_run"],
|
|
1859
|
+
passed: obj["passed"],
|
|
1860
|
+
failed: obj["failed"],
|
|
1861
|
+
duration_ms: obj["duration_ms"],
|
|
1862
|
+
errors: obj["errors"],
|
|
1863
|
+
warnings: obj["warnings"],
|
|
1864
|
+
files_checked: obj["files_checked"],
|
|
1865
|
+
files_changed: obj["files_changed"],
|
|
1866
|
+
fix_applied: obj["fix_applied"]
|
|
1867
|
+
}),
|
|
1868
|
+
stringField(obj, "error") ? `error:
|
|
1869
|
+
${stringField(obj, "error")}` : void 0,
|
|
1870
|
+
output ? `output:
|
|
1871
|
+
${output}` : void 0,
|
|
1872
|
+
stdout ? `stdout:
|
|
1873
|
+
${stdout}` : void 0,
|
|
1874
|
+
stderr ? `stderr:
|
|
1875
|
+
${stderr}` : void 0
|
|
1876
|
+
]);
|
|
1877
|
+
}
|
|
1878
|
+
function renderGenericToolObject(toolName, obj) {
|
|
1879
|
+
const scalars = {};
|
|
1880
|
+
const blocks = [];
|
|
1881
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1882
|
+
if (value === void 0) continue;
|
|
1883
|
+
if (isScalar(value)) {
|
|
1884
|
+
const inline = String(value);
|
|
1885
|
+
if (inline.length <= INLINE_LIMIT && !inline.includes("\n")) {
|
|
1886
|
+
scalars[key] = value;
|
|
1887
|
+
} else {
|
|
1888
|
+
blocks.push(`${key}:
|
|
1889
|
+
${inline}`);
|
|
1890
|
+
}
|
|
1891
|
+
continue;
|
|
1892
|
+
}
|
|
1893
|
+
if (Array.isArray(value)) {
|
|
1894
|
+
if (value.every((item) => typeof item === "string")) {
|
|
1895
|
+
blocks.push(`${key}:
|
|
1896
|
+
${renderStringList(value)}`);
|
|
1897
|
+
} else {
|
|
1898
|
+
blocks.push(`${key}:
|
|
1899
|
+
${renderUnknownList(value)}`);
|
|
1900
|
+
}
|
|
1901
|
+
continue;
|
|
1902
|
+
}
|
|
1903
|
+
blocks.push(`${key}: ${clipInline(oneLineJson(value))}`);
|
|
1252
1904
|
}
|
|
1253
|
-
return
|
|
1905
|
+
return joinSections([renderHeader(toolName, scalars), ...blocks]);
|
|
1254
1906
|
}
|
|
1255
|
-
function
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1258
|
-
|
|
1907
|
+
function renderHeader(label, fields) {
|
|
1908
|
+
const parts = Object.entries(fields).filter(([, value]) => value !== void 0 && value !== null && value !== "").map(([key, value]) => `${key}=${clipInline(formatInlineValue(value))}`);
|
|
1909
|
+
return parts.length > 0 ? `${label} (${parts.join(" ")})` : label;
|
|
1910
|
+
}
|
|
1911
|
+
function renderStringList(items, empty = "", limit = DEFAULT_LIST_LIMIT) {
|
|
1912
|
+
if (items.length === 0) return empty;
|
|
1913
|
+
const shown = items.slice(0, limit);
|
|
1914
|
+
const omitted = items.length - shown.length;
|
|
1915
|
+
return [
|
|
1916
|
+
...shown,
|
|
1917
|
+
...omitted > 0 ? [`[serializer omitted ${omitted} item(s); narrow the request for more]`] : []
|
|
1918
|
+
].join("\n");
|
|
1919
|
+
}
|
|
1920
|
+
function renderUnknownList(items, limit = DEFAULT_LIST_LIMIT) {
|
|
1921
|
+
const shown = items.slice(0, limit).map((item) => clipInline(oneLineJson(item), 1e3));
|
|
1922
|
+
const omitted = items.length - shown.length;
|
|
1923
|
+
if (omitted > 0)
|
|
1924
|
+
shown.push(`[serializer omitted ${omitted} item(s); narrow the request for more]`);
|
|
1925
|
+
return shown.join("\n");
|
|
1926
|
+
}
|
|
1927
|
+
function joinSections(sections) {
|
|
1928
|
+
return sections.map((section) => typeof section === "string" ? section.trimEnd() : void 0).filter((section) => !!section).join("\n");
|
|
1929
|
+
}
|
|
1930
|
+
function formatInlineValue(value) {
|
|
1931
|
+
if (Array.isArray(value)) return `[${value.map(formatInlineValue).join(",")}]`;
|
|
1932
|
+
if (isScalar(value)) return String(value);
|
|
1933
|
+
return oneLineJson(value);
|
|
1934
|
+
}
|
|
1935
|
+
function clipInline(value, max = INLINE_LIMIT) {
|
|
1936
|
+
const compact = value.replace(/\s+/g, " ").trim();
|
|
1937
|
+
return compact.length <= max ? compact : `${compact.slice(0, max - 15)}...(${compact.length} chars)`;
|
|
1938
|
+
}
|
|
1939
|
+
function oneLineJson(value) {
|
|
1940
|
+
try {
|
|
1941
|
+
return JSON.stringify(value);
|
|
1942
|
+
} catch {
|
|
1943
|
+
return String(value);
|
|
1259
1944
|
}
|
|
1260
|
-
|
|
1945
|
+
}
|
|
1946
|
+
function stringField(obj, key) {
|
|
1947
|
+
const value = obj[key];
|
|
1948
|
+
return typeof value === "string" ? value : void 0;
|
|
1949
|
+
}
|
|
1950
|
+
function numberField(obj, key) {
|
|
1951
|
+
const value = obj[key];
|
|
1952
|
+
return typeof value === "number" ? value : void 0;
|
|
1953
|
+
}
|
|
1954
|
+
function stringArrayField(obj, key) {
|
|
1955
|
+
const value = obj[key];
|
|
1956
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
1957
|
+
}
|
|
1958
|
+
function stringFromInput(input, key) {
|
|
1959
|
+
if (!isRecord2(input)) return void 0;
|
|
1960
|
+
const value = input[key];
|
|
1961
|
+
return typeof value === "string" ? value : void 0;
|
|
1962
|
+
}
|
|
1963
|
+
function numberFromInput(input, key) {
|
|
1964
|
+
if (!isRecord2(input)) return void 0;
|
|
1965
|
+
const value = input[key];
|
|
1966
|
+
return typeof value === "number" ? value : void 0;
|
|
1967
|
+
}
|
|
1968
|
+
function inputListSummary(input, key) {
|
|
1969
|
+
if (!isRecord2(input)) return void 0;
|
|
1970
|
+
const value = input[key];
|
|
1971
|
+
if (typeof value === "string") return value;
|
|
1972
|
+
if (Array.isArray(value)) return value.filter((item) => typeof item === "string").join(",");
|
|
1973
|
+
return void 0;
|
|
1974
|
+
}
|
|
1975
|
+
function isRecord2(value) {
|
|
1976
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1977
|
+
}
|
|
1978
|
+
function isScalar(value) {
|
|
1979
|
+
return value === null || ["string", "number", "boolean"].includes(typeof value);
|
|
1980
|
+
}
|
|
1981
|
+
function projectHash(absRoot) {
|
|
1982
|
+
return createHash("sha256").update(path4.resolve(absRoot)).digest("hex").slice(0, 12);
|
|
1983
|
+
}
|
|
1984
|
+
function projectSlug(absRoot) {
|
|
1985
|
+
const base = slugify(path4.basename(absRoot));
|
|
1986
|
+
const hash = createHash("sha256").update(path4.resolve(absRoot)).digest("hex").slice(0, 6);
|
|
1987
|
+
return `${base}-${hash}`;
|
|
1988
|
+
}
|
|
1989
|
+
function slugify(name) {
|
|
1990
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
|
|
1991
|
+
}
|
|
1992
|
+
function wstackGlobalRoot() {
|
|
1993
|
+
const fromEnv = process.env["WRONGSTACK_HOME"];
|
|
1994
|
+
if (fromEnv && fromEnv.trim().length > 0) return path4.resolve(fromEnv);
|
|
1995
|
+
return path4.join(os.homedir(), ".wrongstack");
|
|
1996
|
+
}
|
|
1997
|
+
function resolveWstackPaths(opts) {
|
|
1998
|
+
const globalRoot = opts.globalRoot ?? (opts.userHome ? path4.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
1999
|
+
const hash = projectHash(opts.projectRoot);
|
|
2000
|
+
const slug = projectSlug(opts.projectRoot);
|
|
2001
|
+
const projectDir = path4.join(globalRoot, "projects", slug);
|
|
2002
|
+
return {
|
|
2003
|
+
globalRoot,
|
|
2004
|
+
configDir: globalRoot,
|
|
2005
|
+
globalConfig: path4.join(globalRoot, "config.json"),
|
|
2006
|
+
secretsKey: path4.join(globalRoot, ".key"),
|
|
2007
|
+
globalMemory: path4.join(globalRoot, "memory.md"),
|
|
2008
|
+
globalSkills: path4.join(globalRoot, "skills"),
|
|
2009
|
+
globalPrompts: path4.join(globalRoot, "prompts"),
|
|
2010
|
+
cacheDir: path4.join(globalRoot, "cache"),
|
|
2011
|
+
modelsCache: path4.join(globalRoot, "cache", "models.dev.json"),
|
|
2012
|
+
modelsOverlayCache: path4.join(globalRoot, "cache", "models-overlay.json"),
|
|
2013
|
+
historyFile: path4.join(globalRoot, "history"),
|
|
2014
|
+
logFile: path4.join(globalRoot, "logs", "wrongstack.log"),
|
|
2015
|
+
projectDir,
|
|
2016
|
+
projectCodebaseIndex: path4.join(projectDir, "codebase-index"),
|
|
2017
|
+
projectMemory: path4.join(projectDir, "memory.md"),
|
|
2018
|
+
projectSessions: path4.join(projectDir, "sessions"),
|
|
2019
|
+
projectTrust: path4.join(projectDir, "trust.json"),
|
|
2020
|
+
projectMeta: path4.join(projectDir, "meta.json"),
|
|
2021
|
+
projectLocalConfig: path4.join(projectDir, "config.local.json"),
|
|
2022
|
+
inProjectConfig: path4.join(opts.projectRoot, ".wrongstack", "config.json"),
|
|
2023
|
+
inProjectAgentsFile: path4.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
2024
|
+
inProjectSkills: path4.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
2025
|
+
inProjectWorktrees: path4.join(opts.projectRoot, ".wrongstack", "worktrees"),
|
|
2026
|
+
projectHash: hash,
|
|
2027
|
+
projectSlug: slug,
|
|
2028
|
+
projectGoal: path4.join(projectDir, "goal.json"),
|
|
2029
|
+
projectSpecs: path4.join(projectDir, "specs"),
|
|
2030
|
+
projectTaskGraphs: path4.join(projectDir, "task-graphs"),
|
|
2031
|
+
projectSddSession: path4.join(projectDir, "sdd-session.json"),
|
|
2032
|
+
projectPlan: path4.join(projectDir, "plan.json"),
|
|
2033
|
+
projectAutophase: path4.join(projectDir, "autophase"),
|
|
2034
|
+
syncConfig: path4.join(globalRoot, "sync.json"),
|
|
2035
|
+
projectStatus: (projectHash2) => path4.join(globalRoot, "projects", projectHash2, "status.json")
|
|
2036
|
+
};
|
|
1261
2037
|
}
|
|
1262
2038
|
|
|
1263
2039
|
// src/storage/session-store.ts
|
|
@@ -1339,11 +2115,11 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1339
2115
|
}
|
|
1340
2116
|
/** Absolute path to the session index file. */
|
|
1341
2117
|
get indexFile() {
|
|
1342
|
-
return
|
|
2118
|
+
return path4.join(this.dir, "_index.jsonl");
|
|
1343
2119
|
}
|
|
1344
2120
|
/** Join session ID to its absolute path within the store directory. */
|
|
1345
2121
|
sessionPath(id, ext) {
|
|
1346
|
-
return
|
|
2122
|
+
return path4.join(this.dir, `${id}${ext}`);
|
|
1347
2123
|
}
|
|
1348
2124
|
/**
|
|
1349
2125
|
* Ensure the directory implied by the session ID exists. When the ID
|
|
@@ -1351,7 +2127,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1351
2127
|
* subdirectory so sessions group naturally by day.
|
|
1352
2128
|
*/
|
|
1353
2129
|
async ensureShardDir(id) {
|
|
1354
|
-
const dirPath =
|
|
2130
|
+
const dirPath = path4.dirname(path4.join(this.dir, id));
|
|
1355
2131
|
await ensureDir(dirPath);
|
|
1356
2132
|
return dirPath;
|
|
1357
2133
|
}
|
|
@@ -1359,7 +2135,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1359
2135
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1360
2136
|
const id = meta.id && meta.id.length > 0 ? meta.id : generateSessionId(startedAt, meta.model ?? meta.provider);
|
|
1361
2137
|
const shardDir = await this.ensureShardDir(id);
|
|
1362
|
-
const file =
|
|
2138
|
+
const file = path4.join(shardDir, `${path4.basename(id)}.jsonl`);
|
|
1363
2139
|
const t0 = Date.now();
|
|
1364
2140
|
let handle;
|
|
1365
2141
|
try {
|
|
@@ -1421,7 +2197,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1421
2197
|
// Shard directory (sessions/<date>/) — must match create() so the
|
|
1422
2198
|
// .summary.json sidecar lands next to the JSONL instead of the
|
|
1423
2199
|
// sessions root (where summaryFor() would never find it).
|
|
1424
|
-
dir:
|
|
2200
|
+
dir: path4.dirname(file),
|
|
1425
2201
|
filePath: file,
|
|
1426
2202
|
secretScrubber: this.secretScrubber,
|
|
1427
2203
|
onClose: (s) => this.appendToIndex(s)
|
|
@@ -1457,6 +2233,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1457
2233
|
const cached = this._loadCache.get(id);
|
|
1458
2234
|
if (cached && cached.mtimeMs === stat6.mtimeMs && cached.size === stat6.size) {
|
|
1459
2235
|
cacheHit = true;
|
|
2236
|
+
this._loadCache.delete(id);
|
|
2237
|
+
this._loadCache.set(id, cached);
|
|
1460
2238
|
return cached.data;
|
|
1461
2239
|
}
|
|
1462
2240
|
const raw = await fsp2.readFile(file, "utf8");
|
|
@@ -1645,7 +2423,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1645
2423
|
continue;
|
|
1646
2424
|
if (entry.isDirectory()) {
|
|
1647
2425
|
const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
|
|
1648
|
-
ids.push(...await this.collectSessionIds(
|
|
2426
|
+
ids.push(...await this.collectSessionIds(path4.join(dir, entry.name), childPrefix, depth + 1));
|
|
1649
2427
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
1650
2428
|
if (entry.name === "_index.jsonl") continue;
|
|
1651
2429
|
const base = entry.name.replace(/\.jsonl$/, "");
|
|
@@ -1696,14 +2474,14 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1696
2474
|
async deleteSession(id) {
|
|
1697
2475
|
const jsonlPath = this.sessionPath(id, ".jsonl");
|
|
1698
2476
|
const summaryPath = this.sessionPath(id, ".summary.json");
|
|
1699
|
-
const shardDir =
|
|
1700
|
-
const base =
|
|
1701
|
-
const sessDir =
|
|
2477
|
+
const shardDir = path4.dirname(path4.join(this.dir, id));
|
|
2478
|
+
const base = path4.basename(id);
|
|
2479
|
+
const sessDir = path4.join(shardDir, base);
|
|
1702
2480
|
const deletions = [
|
|
1703
2481
|
fsp2.unlink(jsonlPath),
|
|
1704
2482
|
fsp2.unlink(summaryPath),
|
|
1705
|
-
fsp2.unlink(
|
|
1706
|
-
fsp2.unlink(
|
|
2483
|
+
fsp2.unlink(path4.join(shardDir, `${base}.plan.json`)),
|
|
2484
|
+
fsp2.unlink(path4.join(shardDir, `${base}.todos.json`))
|
|
1707
2485
|
];
|
|
1708
2486
|
const results = await Promise.allSettled(deletions);
|
|
1709
2487
|
for (const r of results) {
|
|
@@ -1739,14 +2517,14 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1739
2517
|
let deleted = 0;
|
|
1740
2518
|
let activeSessionId = null;
|
|
1741
2519
|
try {
|
|
1742
|
-
const raw = await fsp2.readFile(
|
|
2520
|
+
const raw = await fsp2.readFile(path4.join(this.dir, "active.json"), "utf8");
|
|
1743
2521
|
const active = JSON.parse(raw);
|
|
1744
2522
|
activeSessionId = active.sessionId ?? null;
|
|
1745
2523
|
} catch {
|
|
1746
2524
|
}
|
|
1747
2525
|
const isPrunableJsonl = (name) => name.endsWith(".jsonl") && name !== "_index.jsonl" && name !== "_mailbox.jsonl" && !name.endsWith(".replay.jsonl") && !name.endsWith(".audit.jsonl");
|
|
1748
2526
|
const pruneFile = async (dir, name, prefix) => {
|
|
1749
|
-
const jsonlPath =
|
|
2527
|
+
const jsonlPath = path4.join(dir, name);
|
|
1750
2528
|
try {
|
|
1751
2529
|
const stat6 = await fsp2.stat(jsonlPath);
|
|
1752
2530
|
if (stat6.mtimeMs >= cutoff) return;
|
|
@@ -1766,7 +2544,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1766
2544
|
continue;
|
|
1767
2545
|
}
|
|
1768
2546
|
if (!entry.isDirectory()) continue;
|
|
1769
|
-
const dateDir =
|
|
2547
|
+
const dateDir = path4.join(this.dir, entry.name);
|
|
1770
2548
|
const files = await fsp2.readdir(dateDir, { withFileTypes: true }).catch(() => []);
|
|
1771
2549
|
for (const file of files) {
|
|
1772
2550
|
if (!file.isFile() || !isPrunableJsonl(file.name)) continue;
|
|
@@ -1778,7 +2556,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
1778
2556
|
}
|
|
1779
2557
|
for (const entry of entries) {
|
|
1780
2558
|
if (!entry.isDirectory()) continue;
|
|
1781
|
-
const dateDir =
|
|
2559
|
+
const dateDir = path4.join(this.dir, entry.name);
|
|
1782
2560
|
try {
|
|
1783
2561
|
const remaining = await fsp2.readdir(dateDir);
|
|
1784
2562
|
if (remaining.length === 0) {
|
|
@@ -1953,7 +2731,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1953
2731
|
this.meta = meta;
|
|
1954
2732
|
this.events = events;
|
|
1955
2733
|
this.resumed = opts.resumed ?? false;
|
|
1956
|
-
this.manifestFile = opts.dir ?
|
|
2734
|
+
this.manifestFile = opts.dir ? path4.join(opts.dir, `${path4.basename(id)}.summary.json`) : "";
|
|
1957
2735
|
this.filePath = opts.filePath ?? "";
|
|
1958
2736
|
this.secretScrubber = opts.secretScrubber;
|
|
1959
2737
|
this.onCloseCb = opts.onClose;
|
|
@@ -2457,7 +3235,7 @@ var QueueStore = class {
|
|
|
2457
3235
|
events;
|
|
2458
3236
|
traceId;
|
|
2459
3237
|
constructor(opts) {
|
|
2460
|
-
this.file =
|
|
3238
|
+
this.file = path4.join(opts.dir, "queue.json");
|
|
2461
3239
|
this.events = opts.events;
|
|
2462
3240
|
this.traceId = opts.traceId;
|
|
2463
3241
|
}
|
|
@@ -2644,7 +3422,7 @@ var DefaultAttachmentStore = class {
|
|
|
2644
3422
|
let data = input.data;
|
|
2645
3423
|
if (this.spoolDir && bytes >= this.spoolThreshold) {
|
|
2646
3424
|
await fsp2.mkdir(this.spoolDir, { recursive: true });
|
|
2647
|
-
spooledPath =
|
|
3425
|
+
spooledPath = path4.join(this.spoolDir, `${id}.bin`);
|
|
2648
3426
|
await atomicWrite(spooledPath, input.data, {
|
|
2649
3427
|
encoding: input.kind === "image" ? "base64" : "utf8"
|
|
2650
3428
|
});
|
|
@@ -2856,7 +3634,7 @@ var FileMemoryBackend = class {
|
|
|
2856
3634
|
}
|
|
2857
3635
|
async remember(scope, entry, filePath) {
|
|
2858
3636
|
const file = this.resolveFile(filePath, scope);
|
|
2859
|
-
await ensureDir(
|
|
3637
|
+
await ensureDir(path4.dirname(file));
|
|
2860
3638
|
let existing = "";
|
|
2861
3639
|
try {
|
|
2862
3640
|
existing = await fsp2.readFile(file, "utf8");
|
|
@@ -3472,9 +4250,9 @@ ${body.trim()}`);
|
|
|
3472
4250
|
if (!this.persistBackup || scope === "project-agents") return;
|
|
3473
4251
|
try {
|
|
3474
4252
|
const content = await this.backend.readAll(scope, this.files[scope]);
|
|
3475
|
-
const { writeFile:
|
|
3476
|
-
await
|
|
3477
|
-
await
|
|
4253
|
+
const { writeFile: writeFile5, mkdir: mkdir7 } = await import('fs/promises');
|
|
4254
|
+
await mkdir7(this.backupDir, { recursive: true });
|
|
4255
|
+
await writeFile5(`${this.backupDir}/${scope}.md`, content, "utf8");
|
|
3478
4256
|
} catch {
|
|
3479
4257
|
}
|
|
3480
4258
|
}
|
|
@@ -3824,7 +4602,7 @@ var DefaultSecretVault = class {
|
|
|
3824
4602
|
KEY_FILE_MAGIC.copy(keyFileBuf, 0);
|
|
3825
4603
|
keyFileBuf[KEY_FILE_MAGIC.length] = newVersion;
|
|
3826
4604
|
newKey.copy(keyFileBuf, KEY_FILE_MAGIC.length + 1);
|
|
3827
|
-
fs4.mkdirSync(
|
|
4605
|
+
fs4.mkdirSync(path4.dirname(this.keyFile), { recursive: true });
|
|
3828
4606
|
fs4.writeFileSync(this.keyFile, keyFileBuf, { mode: 384 });
|
|
3829
4607
|
checkKeyFilePermissions(this.keyFile);
|
|
3830
4608
|
this.key = newKey;
|
|
@@ -3872,7 +4650,7 @@ var DefaultSecretVault = class {
|
|
|
3872
4650
|
} catch (err) {
|
|
3873
4651
|
if (err.code !== "ENOENT") throw err;
|
|
3874
4652
|
}
|
|
3875
|
-
fs4.mkdirSync(
|
|
4653
|
+
fs4.mkdirSync(path4.dirname(this.keyFile), { recursive: true });
|
|
3876
4654
|
const key = randomBytes(KEY_BYTES);
|
|
3877
4655
|
try {
|
|
3878
4656
|
fs4.writeFileSync(this.keyFile, key, { mode: 384, flag: "wx" });
|
|
@@ -3962,7 +4740,7 @@ async function rewriteConfigEncrypted(configPath, vault, patch) {
|
|
|
3962
4740
|
}
|
|
3963
4741
|
const merged = deepMerge(current, patch ?? {});
|
|
3964
4742
|
const encrypted = encryptConfigSecrets(merged, vault);
|
|
3965
|
-
await fsp2.mkdir(
|
|
4743
|
+
await fsp2.mkdir(path4.dirname(configPath), { recursive: true });
|
|
3966
4744
|
await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3967
4745
|
await restrictFilePermissions(configPath);
|
|
3968
4746
|
}
|
|
@@ -4159,6 +4937,7 @@ var BEHAVIOR_DEFAULTS = {
|
|
|
4159
4937
|
modelsRegistry: true,
|
|
4160
4938
|
skills: true
|
|
4161
4939
|
},
|
|
4940
|
+
mcpServers: {},
|
|
4162
4941
|
indexing: {
|
|
4163
4942
|
onSessionStart: true,
|
|
4164
4943
|
onEdit: true,
|
|
@@ -4592,7 +5371,7 @@ var RecoveryLock = class {
|
|
|
4592
5371
|
sessionStore;
|
|
4593
5372
|
probe;
|
|
4594
5373
|
constructor(opts) {
|
|
4595
|
-
this.file =
|
|
5374
|
+
this.file = path4.join(opts.dir, LOCK_FILE);
|
|
4596
5375
|
this.pid = opts.pid ?? process.pid;
|
|
4597
5376
|
this.hostname = opts.hostname ?? os.hostname();
|
|
4598
5377
|
this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
@@ -4653,7 +5432,7 @@ var RecoveryLock = class {
|
|
|
4653
5432
|
* null return before calling this.
|
|
4654
5433
|
*/
|
|
4655
5434
|
async write(sessionId) {
|
|
4656
|
-
await ensureDir(
|
|
5435
|
+
await ensureDir(path4.dirname(this.file));
|
|
4657
5436
|
const lock = {
|
|
4658
5437
|
v: 1,
|
|
4659
5438
|
sessionId,
|
|
@@ -6073,9 +6852,9 @@ function getInputString(input, key) {
|
|
|
6073
6852
|
function pathLooksInsideProject(rawPath, projectRoot) {
|
|
6074
6853
|
if (!projectRoot) return false;
|
|
6075
6854
|
if (rawPath === "~" || rawPath.startsWith("~/") || rawPath.startsWith("~\\")) return false;
|
|
6076
|
-
const resolved =
|
|
6077
|
-
const
|
|
6078
|
-
return !!
|
|
6855
|
+
const resolved = path4.resolve(projectRoot, rawPath);
|
|
6856
|
+
const relative3 = path4.relative(projectRoot, resolved);
|
|
6857
|
+
return !!relative3 && !relative3.startsWith("..") && !path4.isAbsolute(relative3);
|
|
6079
6858
|
}
|
|
6080
6859
|
function tokenizeShell(command) {
|
|
6081
6860
|
return command.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, "")) ?? [];
|
|
@@ -6085,7 +6864,7 @@ function pathTokenIsOutsideProject(token, projectRoot) {
|
|
|
6085
6864
|
if (token === "/" || token === "~" || token === "." || token === "..") return token !== ".";
|
|
6086
6865
|
if (token.includes("*")) return true;
|
|
6087
6866
|
if (token.startsWith("..") || token.includes("../") || token.includes("..\\")) return true;
|
|
6088
|
-
if (
|
|
6867
|
+
if (path4.isAbsolute(token) || token.startsWith("~/")) return !pathLooksInsideProject(token, projectRoot);
|
|
6089
6868
|
return false;
|
|
6090
6869
|
}
|
|
6091
6870
|
function hasDangerousDeleteTarget(tokens, start, projectRoot) {
|
|
@@ -6250,7 +7029,7 @@ var DefaultPermissionPolicy = class {
|
|
|
6250
7029
|
if (!this.loaded) await this.reload();
|
|
6251
7030
|
const namespaceEntry = this.findNamespaceEntry(tool.name);
|
|
6252
7031
|
const entry = this.policy[tool.name] ?? namespaceEntry;
|
|
6253
|
-
const subject =
|
|
7032
|
+
const subject = subjectForToolInput(tool.name, input, tool.subjectKey);
|
|
6254
7033
|
const cacheKey = `${tool.name}::${subject ?? tool.name}`;
|
|
6255
7034
|
if (tool.name !== "write") {
|
|
6256
7035
|
const cached = this._evalCache.get(cacheKey);
|
|
@@ -6432,32 +7211,6 @@ var DefaultPermissionPolicy = class {
|
|
|
6432
7211
|
this.sessionAllowed.set(`${rule.tool}::${rule.pattern}`, true);
|
|
6433
7212
|
this._evalCache.clear();
|
|
6434
7213
|
}
|
|
6435
|
-
subjectFor(toolName, input, subjectKey) {
|
|
6436
|
-
if (!input || typeof input !== "object") return void 0;
|
|
6437
|
-
const obj = input;
|
|
6438
|
-
const globChars = /[*?[\]]/g;
|
|
6439
|
-
const escapeGlob = (s) => s.replace(globChars, (c) => `\\${c}`);
|
|
6440
|
-
const normalizePath = (s) => escapeGlob(s.replace(/\\/g, "/"));
|
|
6441
|
-
if (subjectKey) {
|
|
6442
|
-
const v = obj[subjectKey];
|
|
6443
|
-
if (typeof v === "string") {
|
|
6444
|
-
return subjectKey === "path" || subjectKey === "file" || subjectKey === "files" ? normalizePath(v) : escapeGlob(v);
|
|
6445
|
-
}
|
|
6446
|
-
}
|
|
6447
|
-
if (toolName === "bash" && typeof obj.command === "string") {
|
|
6448
|
-
return escapeGlob(obj.command);
|
|
6449
|
-
}
|
|
6450
|
-
if (typeof obj.path === "string") {
|
|
6451
|
-
return normalizePath(obj.path);
|
|
6452
|
-
}
|
|
6453
|
-
if (typeof obj.url === "string") {
|
|
6454
|
-
return escapeGlob(obj.url);
|
|
6455
|
-
}
|
|
6456
|
-
if (typeof obj.name === "string") {
|
|
6457
|
-
return escapeGlob(obj.name);
|
|
6458
|
-
}
|
|
6459
|
-
return void 0;
|
|
6460
|
-
}
|
|
6461
7214
|
findNamespaceEntry(toolName) {
|
|
6462
7215
|
for (const { pattern, value } of this.wildcardEntries) {
|
|
6463
7216
|
if (matchGlob(pattern, toolName)) return value;
|
|
@@ -6480,9 +7233,13 @@ var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
|
|
|
6480
7233
|
const caps = tool.capabilities ?? [];
|
|
6481
7234
|
const hasAllowedCap = caps.some((c) => this.allowedCapabilities.includes(c));
|
|
6482
7235
|
const isMcp = _AutoApprovePermissionPolicy.isMcpTool(tool.name);
|
|
6483
|
-
const
|
|
7236
|
+
const mcpProxyAllowed = this.allowedCapabilities.includes(ToolCapabilities.MCP_PROXY);
|
|
7237
|
+
const dangerousNotAllowed = getDangerousCapabilities(tool).filter(
|
|
7238
|
+
(c) => !this.allowedCapabilities.includes(c)
|
|
7239
|
+
);
|
|
7240
|
+
const blocked = tool.permission === "deny" || isMcp && !mcpProxyAllowed || !hasAllowedCap || dangerousNotAllowed.length > 0;
|
|
6484
7241
|
if (blocked) {
|
|
6485
|
-
const reason = isMcp ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow
|
|
7242
|
+
const reason = isMcp && !mcpProxyAllowed ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow mcp.proxy explicitly` : tool.permission === "deny" ? "tool default deny" : dangerousNotAllowed.length > 0 ? `tool requires un-granted dangerous capability (needs: ${dangerousNotAllowed.join(", ")}, allowed: ${this.allowedCapabilities.join(", ")})` : `tool lacks allowed capability (has: ${caps.join(", ") || "none"}, allowed: ${this.allowedCapabilities.join(", ")})`;
|
|
6486
7243
|
return {
|
|
6487
7244
|
permission: "deny",
|
|
6488
7245
|
source: "subagent_guard",
|
|
@@ -6742,7 +7499,7 @@ var DefaultSkillLoader = class {
|
|
|
6742
7499
|
const entries = await fsp2.readdir(dir, { withFileTypes: true });
|
|
6743
7500
|
for (const e of entries) {
|
|
6744
7501
|
if (!e.isDirectory()) continue;
|
|
6745
|
-
const skillFile =
|
|
7502
|
+
const skillFile = path4.join(dir, e.name, "SKILL.md");
|
|
6746
7503
|
try {
|
|
6747
7504
|
const raw = await fsp2.readFile(skillFile, "utf8");
|
|
6748
7505
|
const meta = parseFrontmatter(raw);
|
|
@@ -6813,7 +7570,7 @@ var DefaultSkillLoader = class {
|
|
|
6813
7570
|
if (cached !== void 0) return cached;
|
|
6814
7571
|
const m = await this.find(name);
|
|
6815
7572
|
if (!m) throw new Error(`Skill "${name}" not found`);
|
|
6816
|
-
const savePath =
|
|
7573
|
+
const savePath = path4.join(path4.dirname(m.path), "SKILL.save.md");
|
|
6817
7574
|
let result;
|
|
6818
7575
|
try {
|
|
6819
7576
|
result = await fsp2.readFile(savePath, "utf8");
|
|
@@ -7127,8 +7884,8 @@ async function streamProviderToResponse(provider, req, signal, ctx, events, logg
|
|
|
7127
7884
|
});
|
|
7128
7885
|
await Promise.race([
|
|
7129
7886
|
drainPromise,
|
|
7130
|
-
new Promise((
|
|
7131
|
-
drainTimer = setTimeout(
|
|
7887
|
+
new Promise((resolve6) => {
|
|
7888
|
+
drainTimer = setTimeout(resolve6, STREAM_DRAIN_TIMEOUT_MS);
|
|
7132
7889
|
})
|
|
7133
7890
|
]);
|
|
7134
7891
|
} finally {
|
|
@@ -7234,26 +7991,29 @@ async function runProviderWithRetry(opts) {
|
|
|
7234
7991
|
description
|
|
7235
7992
|
});
|
|
7236
7993
|
}
|
|
7237
|
-
await new Promise((
|
|
7994
|
+
await new Promise((resolve6, reject) => {
|
|
7238
7995
|
let settled = false;
|
|
7996
|
+
const cleanup = () => {
|
|
7997
|
+
clearTimeout(t);
|
|
7998
|
+
signal.removeEventListener("abort", onAbort);
|
|
7999
|
+
};
|
|
7239
8000
|
const onAbort = () => {
|
|
7240
8001
|
if (settled) return;
|
|
7241
8002
|
settled = true;
|
|
7242
|
-
|
|
8003
|
+
cleanup();
|
|
7243
8004
|
reject(new Error("aborted"));
|
|
7244
8005
|
};
|
|
7245
8006
|
const t = setTimeout(() => {
|
|
7246
8007
|
if (settled) return;
|
|
7247
8008
|
settled = true;
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
resolve5();
|
|
8009
|
+
cleanup();
|
|
8010
|
+
resolve6();
|
|
7251
8011
|
}, delay);
|
|
7252
8012
|
if (signal.aborted) {
|
|
7253
8013
|
onAbort();
|
|
7254
8014
|
return;
|
|
7255
8015
|
}
|
|
7256
|
-
signal.addEventListener("abort", onAbort
|
|
8016
|
+
signal.addEventListener("abort", onAbort);
|
|
7257
8017
|
});
|
|
7258
8018
|
attempt++;
|
|
7259
8019
|
}
|
|
@@ -7312,25 +8072,26 @@ function findPreserveStart(messages, preserveK) {
|
|
|
7312
8072
|
preserveStart = i;
|
|
7313
8073
|
}
|
|
7314
8074
|
}
|
|
7315
|
-
let
|
|
7316
|
-
let
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
const
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
8075
|
+
let pairRepairIterations = 0;
|
|
8076
|
+
let pairRepairInnerIterations = 0;
|
|
8077
|
+
while (preserveStart > 0) {
|
|
8078
|
+
pairRepairIterations++;
|
|
8079
|
+
const first = messages[preserveStart];
|
|
8080
|
+
const prev = messages[preserveStart - 1];
|
|
8081
|
+
if (!first || !prev || first.role !== "user" || prev.role !== "assistant") break;
|
|
8082
|
+
if (typeof first.content === "string" || typeof prev.content === "string") break;
|
|
8083
|
+
const resultIds = /* @__PURE__ */ new Set();
|
|
8084
|
+
for (const block of first.content) {
|
|
8085
|
+
pairRepairInnerIterations++;
|
|
8086
|
+
if (block.type === "tool_result") resultIds.add(block.tool_use_id);
|
|
8087
|
+
}
|
|
8088
|
+
if (resultIds.size === 0) break;
|
|
8089
|
+
const hasMatchingUse = prev.content.some((block) => {
|
|
8090
|
+
pairRepairInnerIterations++;
|
|
8091
|
+
return block.type === "tool_use" && resultIds.has(block.id);
|
|
7324
8092
|
});
|
|
7325
|
-
if (
|
|
7326
|
-
|
|
7327
|
-
if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => {
|
|
7328
|
-
forwardWalkInnerIterations++;
|
|
7329
|
-
return b.type === "tool_result";
|
|
7330
|
-
})) {
|
|
7331
|
-
preserveStart = i + 1;
|
|
7332
|
-
}
|
|
7333
|
-
}
|
|
8093
|
+
if (!hasMatchingUse) break;
|
|
8094
|
+
preserveStart--;
|
|
7334
8095
|
}
|
|
7335
8096
|
if (compactionDebugEnabled()) {
|
|
7336
8097
|
console.log(
|
|
@@ -7340,9 +8101,9 @@ function findPreserveStart(messages, preserveK) {
|
|
|
7340
8101
|
messageCount: messages.length,
|
|
7341
8102
|
preserveK,
|
|
7342
8103
|
preserveStart,
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
8104
|
+
pairRepairIterations,
|
|
8105
|
+
pairRepairInnerIterations,
|
|
8106
|
+
pairRepairInnerPerOuter: pairRepairIterations > 0 ? pairRepairInnerIterations / pairRepairIterations : 0
|
|
7346
8107
|
})
|
|
7347
8108
|
);
|
|
7348
8109
|
}
|
|
@@ -7359,7 +8120,8 @@ function eliseOldToolResults(messages, opts) {
|
|
|
7359
8120
|
if (!msg || !Array.isArray(msg.content)) continue;
|
|
7360
8121
|
for (const b of msg.content) {
|
|
7361
8122
|
fastPathInnerIterations++;
|
|
7362
|
-
|
|
8123
|
+
const oversized = b.type === "tool_result" && estimateToolResultTokens(b.content) >= opts.eliseThreshold || b.type === "tool_use" && estimateToolInputTokens(b.input) >= opts.eliseThreshold;
|
|
8124
|
+
if (oversized) {
|
|
7363
8125
|
hasOversized = true;
|
|
7364
8126
|
break;
|
|
7365
8127
|
}
|
|
@@ -7393,6 +8155,13 @@ function eliseOldToolResults(messages, opts) {
|
|
|
7393
8155
|
}
|
|
7394
8156
|
const original = msg.content;
|
|
7395
8157
|
const newContent = original.map((b) => {
|
|
8158
|
+
if (b.type === "tool_use") {
|
|
8159
|
+
const tokens2 = estimateToolInputTokens(b.input);
|
|
8160
|
+
if (tokens2 < opts.eliseThreshold) return b;
|
|
8161
|
+
const elidedInput = summarizeToolUseInputElision(b, tokens2);
|
|
8162
|
+
saved += Math.max(0, tokens2 - estimateToolInputTokens(elidedInput));
|
|
8163
|
+
return { ...b, input: elidedInput };
|
|
8164
|
+
}
|
|
7396
8165
|
if (b.type !== "tool_result") return b;
|
|
7397
8166
|
const tokens = estimateToolResultTokens(b.content);
|
|
7398
8167
|
if (tokens < opts.eliseThreshold) return b;
|
|
@@ -7400,7 +8169,7 @@ function eliseOldToolResults(messages, opts) {
|
|
|
7400
8169
|
const elided = {
|
|
7401
8170
|
type: "tool_result",
|
|
7402
8171
|
tool_use_id: b.tool_use_id,
|
|
7403
|
-
content:
|
|
8172
|
+
content: summarizeToolResultElision(b, tokens),
|
|
7404
8173
|
is_error: b.is_error
|
|
7405
8174
|
};
|
|
7406
8175
|
return elided;
|
|
@@ -7440,6 +8209,65 @@ function eliseOldToolResults(messages, opts) {
|
|
|
7440
8209
|
});
|
|
7441
8210
|
return { messages: changed ? next : messages, saved, changed };
|
|
7442
8211
|
}
|
|
8212
|
+
function summarizeToolUseInputElision(block, tokens) {
|
|
8213
|
+
const fields = {};
|
|
8214
|
+
for (const [key, value] of Object.entries(block.input ?? {})) {
|
|
8215
|
+
fields[key] = summarizeToolUseInputValue(value);
|
|
8216
|
+
}
|
|
8217
|
+
return {
|
|
8218
|
+
__elided_tool_input: `~${tokens} tokens; original arguments are in the session log`,
|
|
8219
|
+
tool: block.name,
|
|
8220
|
+
fields
|
|
8221
|
+
};
|
|
8222
|
+
}
|
|
8223
|
+
function summarizeToolUseInputValue(value) {
|
|
8224
|
+
if (value === null || value === void 0) return value;
|
|
8225
|
+
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
8226
|
+
if (typeof value === "string") {
|
|
8227
|
+
const oneLine = value.replace(/\s+/g, " ").trim();
|
|
8228
|
+
return oneLine.length <= 160 ? oneLine : `${oneLine.slice(0, 120)}...(${oneLine.length} chars)`;
|
|
8229
|
+
}
|
|
8230
|
+
if (Array.isArray(value)) {
|
|
8231
|
+
return `[array:${value.length}]`;
|
|
8232
|
+
}
|
|
8233
|
+
if (typeof value === "object") {
|
|
8234
|
+
const keys = Object.keys(value);
|
|
8235
|
+
return `[object:${keys.slice(0, 8).join(",")}${keys.length > 8 ? ",..." : ""}]`;
|
|
8236
|
+
}
|
|
8237
|
+
return String(value);
|
|
8238
|
+
}
|
|
8239
|
+
function summarizeToolResultElision(block, tokens) {
|
|
8240
|
+
const parts = [`elided: ~${tokens} tokens`];
|
|
8241
|
+
if (block.name) parts.push(`tool=${block.name}`);
|
|
8242
|
+
const files = extractPathHints(block.content).slice(0, 5);
|
|
8243
|
+
if (files.length > 0) parts.push(`files=${files.join(", ")}`);
|
|
8244
|
+
const error = firstErrorLine(block.content);
|
|
8245
|
+
if (error) parts.push(`error=${error}`);
|
|
8246
|
+
return `[${parts.join("; ")}]`;
|
|
8247
|
+
}
|
|
8248
|
+
function extractPathHints(content) {
|
|
8249
|
+
const text = typeof content === "string" ? content : JSON.stringify(content);
|
|
8250
|
+
const out = /* @__PURE__ */ new Set();
|
|
8251
|
+
const re = /(?:(?:[A-Za-z]:)?[./\\]?[\w@.-]+(?:[\\/][\w@(). -]+)+\.[A-Za-z0-9]{1,12})/g;
|
|
8252
|
+
for (const match of text.matchAll(re)) {
|
|
8253
|
+
const clean = match[0]?.replace(/\\/g, "/").replace(/^["'`]+|["'`),;:]+$/g, "");
|
|
8254
|
+
if (clean && clean.length <= 220) out.add(clean);
|
|
8255
|
+
if (out.size >= 5) break;
|
|
8256
|
+
}
|
|
8257
|
+
return [...out];
|
|
8258
|
+
}
|
|
8259
|
+
function firstErrorLine(content) {
|
|
8260
|
+
const text = typeof content === "string" ? content : JSON.stringify(content);
|
|
8261
|
+
for (const line of text.split(/\r?\n/)) {
|
|
8262
|
+
if (!/\b(error|exception|failed|failure|fatal|panic|timeout|denied|enoent|eacces|eperm)\b/i.test(
|
|
8263
|
+
line
|
|
8264
|
+
))
|
|
8265
|
+
continue;
|
|
8266
|
+
const trimmed = line.replace(/\s+/g, " ").trim();
|
|
8267
|
+
if (trimmed) return trimmed.slice(0, 180);
|
|
8268
|
+
}
|
|
8269
|
+
return void 0;
|
|
8270
|
+
}
|
|
7443
8271
|
function buildLosslessDigest(messages) {
|
|
7444
8272
|
const lines = [];
|
|
7445
8273
|
for (const m of messages) {
|
|
@@ -7550,15 +8378,15 @@ function buildSmartDigest(messages) {
|
|
|
7550
8378
|
lines.push(`[${m.role}]: ${display}${marker}`);
|
|
7551
8379
|
}
|
|
7552
8380
|
if (noiseCount > 0) {
|
|
7553
|
-
lines.push(
|
|
8381
|
+
lines.push(
|
|
8382
|
+
`[system]: ${noiseCount} low-importance turn(s) collapsed (repeated failures / pure tool I/O)`
|
|
8383
|
+
);
|
|
7554
8384
|
}
|
|
7555
8385
|
return lines.join("\n");
|
|
7556
8386
|
}
|
|
7557
8387
|
function countToolBlocks(m) {
|
|
7558
8388
|
if (typeof m.content === "string") return 0;
|
|
7559
|
-
return m.content.filter(
|
|
7560
|
-
(b) => b.type === "tool_use" || b.type === "tool_result"
|
|
7561
|
-
).length;
|
|
8389
|
+
return m.content.filter((b) => b.type === "tool_use" || b.type === "tool_result").length;
|
|
7562
8390
|
}
|
|
7563
8391
|
function firstSentence(text) {
|
|
7564
8392
|
const trimmed = text.trim();
|
|
@@ -7627,10 +8455,12 @@ var HybridCompactor = class {
|
|
|
7627
8455
|
if (elide.changed) ctx.state.replaceMessages(elide.messages);
|
|
7628
8456
|
if (elide.saved > 0) reductions.push({ phase: "elision", saved: elide.saved });
|
|
7629
8457
|
let collapsedDigest;
|
|
8458
|
+
let evidenceDigest;
|
|
7630
8459
|
if (opts.aggressive) {
|
|
7631
8460
|
const phase2 = this.collapseAncientTurns(ctx, preserveK);
|
|
7632
8461
|
if (phase2.saved > 0) reductions.push({ phase: "summary", saved: phase2.saved });
|
|
7633
8462
|
collapsedDigest = phase2.digest;
|
|
8463
|
+
evidenceDigest = phase2.evidenceDigest;
|
|
7634
8464
|
}
|
|
7635
8465
|
const repaired = repairToolUseAdjacency(ctx.messages);
|
|
7636
8466
|
if (repaired.report.changed) {
|
|
@@ -7638,6 +8468,11 @@ var HybridCompactor = class {
|
|
|
7638
8468
|
}
|
|
7639
8469
|
const afterTokens = estimateMessages(ctx.messages);
|
|
7640
8470
|
const afterFull = this.estimateFullRequest(ctx);
|
|
8471
|
+
const quality = checkCompactionQuality(ctx, {
|
|
8472
|
+
collapsedDigest,
|
|
8473
|
+
evidenceDigest,
|
|
8474
|
+
reduced: beforeTokens > afterTokens || beforeFull > afterFull
|
|
8475
|
+
});
|
|
7641
8476
|
return {
|
|
7642
8477
|
before: beforeTokens,
|
|
7643
8478
|
after: afterTokens,
|
|
@@ -7645,6 +8480,8 @@ var HybridCompactor = class {
|
|
|
7645
8480
|
fullRequestTokensAfter: afterFull,
|
|
7646
8481
|
reductions,
|
|
7647
8482
|
collapsedDigest,
|
|
8483
|
+
evidenceDigest,
|
|
8484
|
+
quality,
|
|
7648
8485
|
repaired: repaired.report.changed ? {
|
|
7649
8486
|
removedToolUses: repaired.report.removedToolUses,
|
|
7650
8487
|
removedToolResults: repaired.report.removedToolResults,
|
|
@@ -7686,7 +8523,13 @@ var HybridCompactor = class {
|
|
|
7686
8523
|
if (boundary <= 0) return { saved: 0 };
|
|
7687
8524
|
const removed = messages.slice(0, boundary);
|
|
7688
8525
|
const removedTokens = estimateMessages(removed);
|
|
7689
|
-
const
|
|
8526
|
+
const historyDigest = this.smart ? buildSmartDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted; see session log)` : buildLosslessDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted; see session log)`;
|
|
8527
|
+
const evidenceDigest = buildContextEvidenceDigest(ctx);
|
|
8528
|
+
const digest = evidenceDigest ? `[context_state]
|
|
8529
|
+
${evidenceDigest}
|
|
8530
|
+
|
|
8531
|
+
[prior_history]
|
|
8532
|
+
${historyDigest}` : historyDigest;
|
|
7690
8533
|
const summaryMsg = {
|
|
7691
8534
|
role: "system",
|
|
7692
8535
|
content: `[prior_turns_digest: ${digest}]`
|
|
@@ -7695,10 +8538,29 @@ var HybridCompactor = class {
|
|
|
7695
8538
|
ctx.state.replaceMessages([summaryMsg, ...tail]);
|
|
7696
8539
|
return {
|
|
7697
8540
|
saved: Math.max(0, removedTokens - estimateMessages([summaryMsg])),
|
|
7698
|
-
digest
|
|
8541
|
+
digest,
|
|
8542
|
+
evidenceDigest: evidenceDigest || void 0
|
|
7699
8543
|
};
|
|
7700
8544
|
}
|
|
7701
8545
|
};
|
|
8546
|
+
function checkCompactionQuality(ctx, opts) {
|
|
8547
|
+
const evidence = ctx.contextEvidence;
|
|
8548
|
+
const digest = `${opts.collapsedDigest ?? ""}
|
|
8549
|
+
${opts.evidenceDigest ?? ""}`;
|
|
8550
|
+
const hasIntent = Boolean(evidence?.currentIntent?.text || /\b(intent|goal|session_goals)\b/i.test(digest));
|
|
8551
|
+
const hasPathTrail = Boolean(
|
|
8552
|
+
Object.keys(evidence?.fileGraph ?? {}).length > 0 || (evidence?.toolCalls.length ?? 0) > 0 || /\b(dependency_graph|tool_trail|files=)\b/i.test(digest)
|
|
8553
|
+
);
|
|
8554
|
+
const issues = [];
|
|
8555
|
+
if (opts.reduced && !hasIntent) issues.push("missing intent anchor");
|
|
8556
|
+
if (opts.reduced && !hasPathTrail) issues.push("missing tool/path trail");
|
|
8557
|
+
return {
|
|
8558
|
+
ok: issues.length === 0,
|
|
8559
|
+
hasIntent,
|
|
8560
|
+
hasPathTrail,
|
|
8561
|
+
issues
|
|
8562
|
+
};
|
|
8563
|
+
}
|
|
7702
8564
|
function readContextWindowPolicy(ctx) {
|
|
7703
8565
|
const policy = ctx.meta?.["contextWindowPolicy"];
|
|
7704
8566
|
if (!policy || typeof policy !== "object") return null;
|
|
@@ -8057,10 +8919,10 @@ var SelectiveCompactor = class {
|
|
|
8057
8919
|
this.maxContext = opts.maxContext ?? 128e3;
|
|
8058
8920
|
this.preserveK = opts.preserveK ?? 4;
|
|
8059
8921
|
this.eliseThreshold = opts.eliseThreshold ?? 500;
|
|
8060
|
-
this.summarizerModel = opts.summarizerModel ?? opts.selectorModel
|
|
8061
|
-
if (this.summarizerModel ===
|
|
8922
|
+
this.summarizerModel = opts.summarizerModel ?? opts.selectorModel;
|
|
8923
|
+
if (this.summarizerModel === void 0 && (process.env["NODE_ENV"] === "development" || process.env["WRONGSTACK_DEBUG"] === "1")) {
|
|
8062
8924
|
console.warn(
|
|
8063
|
-
"[SelectiveCompactor] summarizerModel not set \u2014 will
|
|
8925
|
+
"[SelectiveCompactor] summarizerModel not set \u2014 will fall back to ctx.model at summarize time. Set `summarizerModel` explicitly to silence this warning."
|
|
8064
8926
|
);
|
|
8065
8927
|
}
|
|
8066
8928
|
this.summarizerPrompt = opts.summarizerPrompt ?? "You are a context summarizer. Given a list of messages, produce a concise summary that preserves all factual information, decisions, file changes, and state changes. Do not add commentary or opinions.";
|
|
@@ -8168,7 +9030,7 @@ var SelectiveCompactor = class {
|
|
|
8168
9030
|
Summarize the following message range:`;
|
|
8169
9031
|
const body = messages.map((m, i) => `[${i}] ${m.role}: ${this.messagePreview(m)}`).join("\n");
|
|
8170
9032
|
const req = {
|
|
8171
|
-
model: this.summarizerModel,
|
|
9033
|
+
model: this.summarizerModel ?? ctx.model,
|
|
8172
9034
|
system: [{ type: "text", text: systemText }],
|
|
8173
9035
|
messages: [{ role: "user", content: body }],
|
|
8174
9036
|
maxTokens: 512
|
|
@@ -8235,27 +9097,16 @@ Summarize the following message range:`;
|
|
|
8235
9097
|
if (typeof m.content === "string") return m.content.trim().length > 0;
|
|
8236
9098
|
return m.content.some((b) => b.type === "text" && b.text.trim().length > 0);
|
|
8237
9099
|
}
|
|
9100
|
+
/**
|
|
9101
|
+
* Estimate message-array tokens via the shared `estimateMessages` primitive
|
|
9102
|
+
* so SelectiveCompactor's before/after/load figures agree with the
|
|
9103
|
+
* middleware threshold math and the other compactors. Previously this used a
|
|
9104
|
+
* private `ceil(len/3.5)` walk that diverged from the calibrated shared
|
|
9105
|
+
* estimator, causing the selective `load`/`targetBudget` comparison to mix
|
|
9106
|
+
* two incompatible token scales.
|
|
9107
|
+
*/
|
|
8238
9108
|
estimateTokens(messages) {
|
|
8239
|
-
|
|
8240
|
-
for (const m of messages) {
|
|
8241
|
-
if (typeof m.content === "string") {
|
|
8242
|
-
total += this.roughTokenEstimate(m.content);
|
|
8243
|
-
} else {
|
|
8244
|
-
for (const b of m.content) {
|
|
8245
|
-
if (b.type === "text") total += this.roughTokenEstimate(b.text);
|
|
8246
|
-
else if (b.type === "tool_use") total += this.roughTokenEstimate(JSON.stringify(b.input));
|
|
8247
|
-
else if (b.type === "tool_result") {
|
|
8248
|
-
total += this.roughTokenEstimate(
|
|
8249
|
-
typeof b.content === "string" ? b.content : JSON.stringify(b.content)
|
|
8250
|
-
);
|
|
8251
|
-
}
|
|
8252
|
-
}
|
|
8253
|
-
}
|
|
8254
|
-
}
|
|
8255
|
-
return total;
|
|
8256
|
-
}
|
|
8257
|
-
roughTokenEstimate(text) {
|
|
8258
|
-
return Math.max(1, Math.ceil(text.length / 3.5));
|
|
9109
|
+
return estimateMessages(messages);
|
|
8259
9110
|
}
|
|
8260
9111
|
};
|
|
8261
9112
|
|
|
@@ -8446,15 +9297,20 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
8446
9297
|
this._cachedMsgCount = msgCount;
|
|
8447
9298
|
this._cachedToolCount = toolCount;
|
|
8448
9299
|
}
|
|
8449
|
-
const
|
|
9300
|
+
const budget = computeContextWindowBudget(ctx, tokens, this._maxContext);
|
|
9301
|
+
const load = budget.load;
|
|
8450
9302
|
const policy = this.policyProvider?.(ctx);
|
|
8451
9303
|
const thresholds = policy?.thresholds ?? {
|
|
8452
9304
|
warn: this.warnThreshold,
|
|
8453
9305
|
soft: this.softThreshold,
|
|
8454
9306
|
hard: this.hardThreshold
|
|
8455
9307
|
};
|
|
9308
|
+
const repetition = repeatedReadPressure(ctx);
|
|
9309
|
+
const adaptiveThresholds = adaptThresholdsForSignals(thresholds, {
|
|
9310
|
+
repeatedReadCount: repetition
|
|
9311
|
+
});
|
|
8456
9312
|
const aggressiveOn = policy?.aggressiveOn ?? this.aggressiveOn;
|
|
8457
|
-
const level = load >=
|
|
9313
|
+
const level = load >= adaptiveThresholds.hard ? "hard" : load >= adaptiveThresholds.soft ? "soft" : load >= adaptiveThresholds.warn ? "warn" : null;
|
|
8458
9314
|
if (!level) {
|
|
8459
9315
|
this.lastNoopAttempt = null;
|
|
8460
9316
|
return next(ctx);
|
|
@@ -8463,7 +9319,13 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
8463
9319
|
return next(ctx);
|
|
8464
9320
|
}
|
|
8465
9321
|
const aggressive = level === "hard" ? true : level === "soft" ? aggressiveOn !== "hard" : aggressiveOn === "warn";
|
|
8466
|
-
await this.compact(ctx, aggressive, {
|
|
9322
|
+
await this.compact(ctx, aggressive, {
|
|
9323
|
+
level,
|
|
9324
|
+
tokens,
|
|
9325
|
+
load,
|
|
9326
|
+
budget,
|
|
9327
|
+
signals: { repeatedReadCount: repetition }
|
|
9328
|
+
});
|
|
8467
9329
|
return next(ctx);
|
|
8468
9330
|
};
|
|
8469
9331
|
}
|
|
@@ -8516,6 +9378,8 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
8516
9378
|
tokens: pressure.tokens,
|
|
8517
9379
|
load: pressure.load,
|
|
8518
9380
|
maxContext: this._maxContext,
|
|
9381
|
+
budget: pressure.budget,
|
|
9382
|
+
signals: pressure.signals,
|
|
8519
9383
|
report,
|
|
8520
9384
|
aggressive
|
|
8521
9385
|
});
|
|
@@ -8527,6 +9391,8 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
8527
9391
|
level: pressure.level,
|
|
8528
9392
|
aggressive,
|
|
8529
9393
|
reductions: report.reductions?.map((r) => ({ phase: r.phase, saved: r.saved })),
|
|
9394
|
+
budget: pressure.budget,
|
|
9395
|
+
signals: pressure.signals,
|
|
8530
9396
|
// Record what was collapsed so the audit trail shows the preserved
|
|
8531
9397
|
// content, not just token counts. Bounded to keep the log line small;
|
|
8532
9398
|
// the full original turns are already in the session JSONL.
|
|
@@ -8542,6 +9408,8 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
8542
9408
|
level: pressure.level,
|
|
8543
9409
|
tokens: pressure.tokens,
|
|
8544
9410
|
maxContext: this._maxContext,
|
|
9411
|
+
budget: pressure.budget,
|
|
9412
|
+
signals: pressure.signals,
|
|
8545
9413
|
load: pressure.load,
|
|
8546
9414
|
fatal
|
|
8547
9415
|
});
|
|
@@ -8561,8 +9429,37 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
8561
9429
|
}
|
|
8562
9430
|
}
|
|
8563
9431
|
};
|
|
8564
|
-
|
|
8565
|
-
|
|
9432
|
+
function computeContextWindowBudget(ctx, inputTokens, maxContext) {
|
|
9433
|
+
const reservedOutputTokens = readPositiveMetaNumber(ctx, "contextOutputReserveTokens") ?? Math.floor(Math.min(8192, maxContext * 0.08));
|
|
9434
|
+
const reservedSafetyTokens = readPositiveMetaNumber(ctx, "contextSafetyBufferTokens") ?? Math.floor(Math.min(4096, maxContext * 0.02));
|
|
9435
|
+
const availableInputTokens = Math.max(
|
|
9436
|
+
1,
|
|
9437
|
+
maxContext - reservedOutputTokens - reservedSafetyTokens
|
|
9438
|
+
);
|
|
9439
|
+
const remainingInputTokens = availableInputTokens - inputTokens;
|
|
9440
|
+
return {
|
|
9441
|
+
maxContext,
|
|
9442
|
+
inputTokens,
|
|
9443
|
+
availableInputTokens,
|
|
9444
|
+
remainingInputTokens,
|
|
9445
|
+
reservedOutputTokens,
|
|
9446
|
+
reservedSafetyTokens,
|
|
9447
|
+
load: inputTokens / availableInputTokens,
|
|
9448
|
+
overflowTokens: Math.max(0, -remainingInputTokens)
|
|
9449
|
+
};
|
|
9450
|
+
}
|
|
9451
|
+
function readPositiveMetaNumber(ctx, key) {
|
|
9452
|
+
const value = ctx.meta?.[key];
|
|
9453
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : void 0;
|
|
9454
|
+
}
|
|
9455
|
+
function adaptThresholdsForSignals(thresholds, signals) {
|
|
9456
|
+
if (signals.repeatedReadCount < 3) return thresholds;
|
|
9457
|
+
return {
|
|
9458
|
+
warn: Math.max(0.25, thresholds.warn - 0.08),
|
|
9459
|
+
soft: Math.max(0.35, thresholds.soft - 0.04),
|
|
9460
|
+
hard: thresholds.hard
|
|
9461
|
+
};
|
|
9462
|
+
}
|
|
8566
9463
|
var ToolExecutor = class _ToolExecutor {
|
|
8567
9464
|
constructor(registry, opts) {
|
|
8568
9465
|
this.registry = registry;
|
|
@@ -8659,7 +9556,8 @@ ${errorDetails}`,
|
|
|
8659
9556
|
let effectivePermission = decision.permission;
|
|
8660
9557
|
const policy = this.opts.permissionPolicy;
|
|
8661
9558
|
const yolo = policy.getYolo?.() === true || policy.getYoloDestructive?.() === true;
|
|
8662
|
-
|
|
9559
|
+
const authoritativeAuto = decision.source === "yolo";
|
|
9560
|
+
if (toolDangerousCaps.length > 0 && effectivePermission === "auto" && !yolo && !authoritativeAuto) {
|
|
8663
9561
|
effectivePermission = "confirm";
|
|
8664
9562
|
}
|
|
8665
9563
|
if (effectivePermission === "deny") {
|
|
@@ -8681,7 +9579,7 @@ ${errorDetails}`,
|
|
|
8681
9579
|
return { result, tool, durationMs: Date.now() - start };
|
|
8682
9580
|
}
|
|
8683
9581
|
} else {
|
|
8684
|
-
const suggestedPattern =
|
|
9582
|
+
const suggestedPattern = subjectForToolInput(tool.name, use.input, tool.subjectKey) ?? tool.name;
|
|
8685
9583
|
const pending = {
|
|
8686
9584
|
type: "tool_confirm_pending",
|
|
8687
9585
|
toolUseId: use.id,
|
|
@@ -8801,9 +9699,10 @@ ${post.additionalContext}`;
|
|
|
8801
9699
|
});
|
|
8802
9700
|
this.opts.renderer?.writeToolCall(tool.name, use.input);
|
|
8803
9701
|
const output = await this.runWithTimeout(tool, use.input, ctx.signal, ctx, use.id);
|
|
8804
|
-
const text = this.serializer.serialize(output);
|
|
9702
|
+
const text = this.serializer.serialize(output, { toolName: tool.name, input: use.input });
|
|
8805
9703
|
const scrubbed = this.opts.secretScrubber.scrub(text);
|
|
8806
|
-
const
|
|
9704
|
+
const withArtifact = await maybePersistLargeToolOutput(tool.name, scrubbed, budget);
|
|
9705
|
+
const { text: capped, newBudget } = this.serializer.enforceCap(withArtifact, budget);
|
|
8807
9706
|
this.opts.renderer?.writeToolResult(tool.name, capped, false);
|
|
8808
9707
|
return {
|
|
8809
9708
|
block: {
|
|
@@ -8828,38 +9727,27 @@ ${post.additionalContext}`;
|
|
|
8828
9727
|
tool.timeoutMs ?? this.iterationTimeoutMs,
|
|
8829
9728
|
this.maxToolTimeoutMs
|
|
8830
9729
|
);
|
|
8831
|
-
const
|
|
8832
|
-
const
|
|
8833
|
-
|
|
8834
|
-
let cleanupCalled = false;
|
|
8835
|
-
let caught = false;
|
|
9730
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
9731
|
+
const combined = AbortSignal.any([parentSignal, timeoutSignal]);
|
|
9732
|
+
let output;
|
|
8836
9733
|
try {
|
|
8837
|
-
|
|
8838
|
-
return await this.runStreamedTool(tool, input, ctx, combined, toolUseId);
|
|
8839
|
-
}
|
|
8840
|
-
return await tool.execute(input, ctx, { signal: combined });
|
|
9734
|
+
output = typeof tool.executeStream === "function" ? await this.runStreamedTool(tool, input, ctx, combined, toolUseId) : await tool.execute(input, ctx, { signal: combined });
|
|
8841
9735
|
} catch (err) {
|
|
8842
|
-
|
|
8843
|
-
if (combined.aborted && typeof tool.cleanup === "function") {
|
|
8844
|
-
cleanupCalled = true;
|
|
8845
|
-
try {
|
|
8846
|
-
await tool.cleanup(input, ctx);
|
|
8847
|
-
} catch {
|
|
8848
|
-
}
|
|
8849
|
-
}
|
|
9736
|
+
if (combined.aborted) await this.runToolCleanup(tool, input, ctx);
|
|
8850
9737
|
throw err;
|
|
8851
|
-
}
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
9738
|
+
}
|
|
9739
|
+
if (combined.aborted) {
|
|
9740
|
+
await this.runToolCleanup(tool, input, ctx);
|
|
9741
|
+
throw combined.reason instanceof Error ? combined.reason : new Error(typeof combined.reason === "string" ? combined.reason : "tool timeout");
|
|
9742
|
+
}
|
|
9743
|
+
return output;
|
|
9744
|
+
}
|
|
9745
|
+
/** Best-effort tool cleanup; never let it mask the original error. */
|
|
9746
|
+
async runToolCleanup(tool, input, ctx) {
|
|
9747
|
+
if (typeof tool.cleanup !== "function") return;
|
|
9748
|
+
try {
|
|
9749
|
+
await tool.cleanup(input, ctx);
|
|
9750
|
+
} catch {
|
|
8863
9751
|
}
|
|
8864
9752
|
}
|
|
8865
9753
|
async runStreamedTool(tool, input, ctx, signal, toolUseId) {
|
|
@@ -8970,38 +9858,6 @@ ${excerpt}`;
|
|
|
8970
9858
|
budgetForString(content, budget) {
|
|
8971
9859
|
return Math.max(0, budget - Buffer.byteLength(content, "utf8"));
|
|
8972
9860
|
}
|
|
8973
|
-
/**
|
|
8974
|
-
* Compute the suggestedPattern string for a tool+input pair.
|
|
8975
|
-
* Matches the logic in DefaultPermissionPolicy so the TUI shows the
|
|
8976
|
-
* same subject that the trust file would use.
|
|
8977
|
-
*/
|
|
8978
|
-
subjectFor(toolName, input, subjectKey) {
|
|
8979
|
-
if (!input || typeof input !== "object") return void 0;
|
|
8980
|
-
const obj = input;
|
|
8981
|
-
const globChars = /[*?[\]]/g;
|
|
8982
|
-
const escapeGlob = (s) => s.replace(globChars, (c) => `\\${c}`);
|
|
8983
|
-
const normalizePath = (s) => escapeGlob(s.replace(/\\/g, "/"));
|
|
8984
|
-
if (subjectKey) {
|
|
8985
|
-
const v = obj[subjectKey];
|
|
8986
|
-
if (typeof v === "string") {
|
|
8987
|
-
const isPathKey = subjectKey === "path" || subjectKey === "file" || subjectKey === "files";
|
|
8988
|
-
return isPathKey ? normalizePath(v) : escapeGlob(v);
|
|
8989
|
-
}
|
|
8990
|
-
}
|
|
8991
|
-
if (toolName === "bash" && typeof obj.command === "string") {
|
|
8992
|
-
return escapeGlob(obj.command);
|
|
8993
|
-
}
|
|
8994
|
-
if (typeof obj.path === "string") {
|
|
8995
|
-
return normalizePath(obj.path);
|
|
8996
|
-
}
|
|
8997
|
-
if (typeof obj.url === "string") {
|
|
8998
|
-
return escapeGlob(obj.url);
|
|
8999
|
-
}
|
|
9000
|
-
if (typeof obj.name === "string") {
|
|
9001
|
-
return escapeGlob(obj.name);
|
|
9002
|
-
}
|
|
9003
|
-
return void 0;
|
|
9004
|
-
}
|
|
9005
9861
|
};
|
|
9006
9862
|
function clampTimeoutMs(timeoutMs, maxTimeoutMs) {
|
|
9007
9863
|
const fallback = 3e5;
|
|
@@ -9028,6 +9884,25 @@ function extractMalformedRaw(input) {
|
|
|
9028
9884
|
return String(value);
|
|
9029
9885
|
}
|
|
9030
9886
|
}
|
|
9887
|
+
var TOOL_OUTPUT_ARTIFACT_THRESHOLD_BYTES = 64 * 1024;
|
|
9888
|
+
async function maybePersistLargeToolOutput(toolName, content, budget) {
|
|
9889
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
9890
|
+
if (bytes <= Math.min(TOOL_OUTPUT_ARTIFACT_THRESHOLD_BYTES, Math.max(0, budget))) {
|
|
9891
|
+
return content;
|
|
9892
|
+
}
|
|
9893
|
+
try {
|
|
9894
|
+
const dir = path4.join(wstackGlobalRoot(), "tool-output");
|
|
9895
|
+
await fsp2.mkdir(dir, { recursive: true });
|
|
9896
|
+
const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
|
|
9897
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9898
|
+
const filePath = path4.join(dir, `${stamp}-${safeTool}-${randomUUID()}.log`);
|
|
9899
|
+
await fsp2.writeFile(filePath, content, "utf8");
|
|
9900
|
+
return content + `
|
|
9901
|
+
[full tool output: ${bytes} bytes at ${filePath}; read/grep that file selectively instead of re-running or requesting more output]`;
|
|
9902
|
+
} catch {
|
|
9903
|
+
return content;
|
|
9904
|
+
}
|
|
9905
|
+
}
|
|
9031
9906
|
|
|
9032
9907
|
// src/execution/autonomous-runner.ts
|
|
9033
9908
|
var DoneConditionChecker = class {
|
|
@@ -10339,13 +11214,13 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
10339
11214
|
if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
|
|
10340
11215
|
return Promise.resolve("stop");
|
|
10341
11216
|
}
|
|
10342
|
-
return new Promise((
|
|
11217
|
+
return new Promise((resolve6) => {
|
|
10343
11218
|
let resolved = false;
|
|
10344
11219
|
const respond = (d) => {
|
|
10345
11220
|
if (resolved) return;
|
|
10346
11221
|
resolved = true;
|
|
10347
11222
|
clearTimeout(fallback);
|
|
10348
|
-
|
|
11223
|
+
resolve6(d);
|
|
10349
11224
|
};
|
|
10350
11225
|
const fallback = setTimeout(() => respond("stop"), _SubagentBudget.DECISION_TIMEOUT_MS);
|
|
10351
11226
|
bus.emit("budget.threshold_reached", {
|
|
@@ -12808,7 +13683,27 @@ Working rules:
|
|
|
12808
13683
|
id: "devops",
|
|
12809
13684
|
name: "DevOps",
|
|
12810
13685
|
role: "devops",
|
|
12811
|
-
tools: [
|
|
13686
|
+
tools: [
|
|
13687
|
+
...TOOLS.build,
|
|
13688
|
+
"mcp__ssh__ssh_list_servers",
|
|
13689
|
+
"mcp__ssh__ssh_connection_status",
|
|
13690
|
+
"mcp__ssh__ssh_execute",
|
|
13691
|
+
"mcp__ssh__ssh_execute_sudo",
|
|
13692
|
+
"mcp__ssh__ssh_upload",
|
|
13693
|
+
"mcp__ssh__ssh_download",
|
|
13694
|
+
"mcp__ssh__ssh_sync",
|
|
13695
|
+
"mcp__ssh__ssh_deploy",
|
|
13696
|
+
"mcp__ssh__ssh_health_check",
|
|
13697
|
+
"mcp__ssh__ssh_service_status",
|
|
13698
|
+
"mcp__ssh__ssh_process_manager",
|
|
13699
|
+
"mcp__ssh__ssh_tunnel",
|
|
13700
|
+
"mcp__ssh__ssh_backup_create",
|
|
13701
|
+
"mcp__ssh__ssh_backup_list",
|
|
13702
|
+
"mcp__ssh__ssh_backup_restore",
|
|
13703
|
+
"mcp__ssh__ssh_db_list",
|
|
13704
|
+
"mcp__ssh__ssh_db_query",
|
|
13705
|
+
"mcp__ssh__ssh_profile"
|
|
13706
|
+
],
|
|
12812
13707
|
prompt: `You are the DevOps agent. Your job is CI/CD, containerization, and
|
|
12813
13708
|
deployment configuration: make builds reproducible and deploys safe.
|
|
12814
13709
|
|
|
@@ -12817,6 +13712,7 @@ Scope:
|
|
|
12817
13712
|
- Write Dockerfiles/compose and optimize image size and layer caching
|
|
12818
13713
|
- Configure deployment (env, secrets handling, health checks, rollback)
|
|
12819
13714
|
- Diagnose flaky/broken pipelines
|
|
13715
|
+
- Use optional SSH MCP tools for remote hosts when the 'ssh' MCP server is enabled: list servers, run health checks, inspect services, transfer/deploy files, and open tunnels
|
|
12820
13716
|
|
|
12821
13717
|
Input format you accept:
|
|
12822
13718
|
{ "task": "ci | container | deploy | fix-pipeline", "platform": "github-actions | gitlab | docker | k8s", "target": "<what>" }
|
|
@@ -12831,7 +13727,8 @@ Working rules:
|
|
|
12831
13727
|
- Never hardcode secrets in config; reference the secret store
|
|
12832
13728
|
- Pin versions for reproducible builds; avoid floating :latest
|
|
12833
13729
|
- Every deploy path needs a rollback and a health check
|
|
12834
|
-
- Treat CI/CD changes as high-risk \u2014 explain blast radius before applying
|
|
13730
|
+
- Treat CI/CD changes as high-risk \u2014 explain blast radius before applying
|
|
13731
|
+
- For remote SSH work, start with ssh_list_servers / ssh_connection_status, prefer read-only checks first, and do not run destructive commands without explicit user approval`
|
|
12835
13732
|
},
|
|
12836
13733
|
budget: MEDIUM_BUDGET,
|
|
12837
13734
|
capability: {
|
|
@@ -12848,6 +13745,13 @@ Working rules:
|
|
|
12848
13745
|
"kubernetes",
|
|
12849
13746
|
"k8s",
|
|
12850
13747
|
"deploy",
|
|
13748
|
+
"ssh",
|
|
13749
|
+
"remote ssh",
|
|
13750
|
+
"remote server",
|
|
13751
|
+
"sftp",
|
|
13752
|
+
"tunnel",
|
|
13753
|
+
"bastion",
|
|
13754
|
+
"jump host",
|
|
12851
13755
|
"github actions",
|
|
12852
13756
|
"container"
|
|
12853
13757
|
]
|
|
@@ -14156,7 +15060,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
14156
15060
|
taskIds.map((id) => {
|
|
14157
15061
|
const cached = this.completedResults.find((r) => r.taskId === id);
|
|
14158
15062
|
if (cached) return cached;
|
|
14159
|
-
return new Promise((
|
|
15063
|
+
return new Promise((resolve6, reject) => {
|
|
14160
15064
|
const timeout = setTimeout(() => {
|
|
14161
15065
|
this.off("task.completed", handler);
|
|
14162
15066
|
reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
|
|
@@ -14165,7 +15069,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
14165
15069
|
if (result.taskId === id) {
|
|
14166
15070
|
clearTimeout(timeout);
|
|
14167
15071
|
this.off("task.completed", handler);
|
|
14168
|
-
|
|
15072
|
+
resolve6(result);
|
|
14169
15073
|
}
|
|
14170
15074
|
};
|
|
14171
15075
|
this.on("task.completed", handler);
|
|
@@ -14433,12 +15337,12 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
14433
15337
|
}
|
|
14434
15338
|
return new Promise((resolveDecision) => {
|
|
14435
15339
|
let settled = false;
|
|
14436
|
-
const
|
|
15340
|
+
const resolve6 = (d) => {
|
|
14437
15341
|
if (settled) return;
|
|
14438
15342
|
settled = true;
|
|
14439
15343
|
resolveDecision(d);
|
|
14440
15344
|
};
|
|
14441
|
-
const fallback = setTimeout(() =>
|
|
15345
|
+
const fallback = setTimeout(() => resolve6("stop"), DECISION_TIMEOUT_MS);
|
|
14442
15346
|
budget._events?.emit("budget.threshold_reached", {
|
|
14443
15347
|
kind: "timeout",
|
|
14444
15348
|
used,
|
|
@@ -14454,11 +15358,11 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
14454
15358
|
// disagreeing, resolves as a stop). Async grants still resolve.
|
|
14455
15359
|
extend: (extra) => {
|
|
14456
15360
|
clearTimeout(fallback);
|
|
14457
|
-
queueMicrotask(() =>
|
|
15361
|
+
queueMicrotask(() => resolve6({ extend: extra }));
|
|
14458
15362
|
},
|
|
14459
15363
|
deny: () => {
|
|
14460
15364
|
clearTimeout(fallback);
|
|
14461
|
-
|
|
15365
|
+
resolve6("stop");
|
|
14462
15366
|
}
|
|
14463
15367
|
});
|
|
14464
15368
|
});
|
|
@@ -14619,6 +15523,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
14619
15523
|
subagentId: result.subagentId,
|
|
14620
15524
|
taskId: result.taskId,
|
|
14621
15525
|
status: result.status,
|
|
15526
|
+
result: result.result,
|
|
14622
15527
|
iterations: result.iterations,
|
|
14623
15528
|
toolCalls: result.toolCalls,
|
|
14624
15529
|
durationMs: result.durationMs
|
|
@@ -15346,7 +16251,7 @@ var InMemoryAgentBridge = class {
|
|
|
15346
16251
|
});
|
|
15347
16252
|
}
|
|
15348
16253
|
this.inflightGuards.add(correlationId);
|
|
15349
|
-
return new Promise((
|
|
16254
|
+
return new Promise((resolve6, reject) => {
|
|
15350
16255
|
const timer = setTimeout(() => {
|
|
15351
16256
|
this.inflightGuards.delete(correlationId);
|
|
15352
16257
|
this.pendingRequests.delete(correlationId);
|
|
@@ -15365,7 +16270,7 @@ var InMemoryAgentBridge = class {
|
|
|
15365
16270
|
return;
|
|
15366
16271
|
}
|
|
15367
16272
|
this.pendingRequests.set(correlationId, {
|
|
15368
|
-
resolve:
|
|
16273
|
+
resolve: resolve6,
|
|
15369
16274
|
reject,
|
|
15370
16275
|
timer
|
|
15371
16276
|
});
|
|
@@ -16037,6 +16942,24 @@ Working rules:
|
|
|
16037
16942
|
var DEFAULT_SUBAGENT_BASELINE = `You are a subagent operating under a Director. You were spawned to handle
|
|
16038
16943
|
a specific slice of a larger plan \u2014 do that slice well and report back.
|
|
16039
16944
|
|
|
16945
|
+
Capabilities & operating rules:
|
|
16946
|
+
- You have full developer tools for your task: read, write/edit, search,
|
|
16947
|
+
shell + build (lint, format, typecheck, test), and dependency install.
|
|
16948
|
+
Use them directly to finish the task end-to-end. You run non-interactively
|
|
16949
|
+
\u2014 there is no human to approve individual tool calls, so routine work is
|
|
16950
|
+
pre-authorized; do not stop to ask for permission to read, edit, or build.
|
|
16951
|
+
- Stay inside the project root. Do not write files outside the repository,
|
|
16952
|
+
and do not touch machine config, credentials, or global state \u2014 those
|
|
16953
|
+
require an explicit grant you do not have.
|
|
16954
|
+
- Prefer the least-destructive path. Do not run irreversible or destructive
|
|
16955
|
+
commands (e.g. \`rm -rf\`, \`git push --force\`, history rewrites, dropping
|
|
16956
|
+
databases, mass deletes) unless the task explicitly requires it and names
|
|
16957
|
+
the target.
|
|
16958
|
+
- When you change code, verify it: run the relevant build / typecheck / tests
|
|
16959
|
+
and fix what you broke before reporting done.
|
|
16960
|
+
- Make only the changes the task calls for \u2014 don't refactor or reformat
|
|
16961
|
+
unrelated code.
|
|
16962
|
+
|
|
16040
16963
|
Bridge contract:
|
|
16041
16964
|
- You have a parent (the Director). You may call \`request\` on the
|
|
16042
16965
|
parent bridge to ask a clarifying question. Use this sparingly; the
|
|
@@ -16994,6 +17917,8 @@ var Director = class _Director {
|
|
|
16994
17917
|
sessionsRoot;
|
|
16995
17918
|
/** Director run id for JSONL path resolution. */
|
|
16996
17919
|
directorRunId;
|
|
17920
|
+
/** Optional logger for structured logging. Falls back to noop when omitted. */
|
|
17921
|
+
logger;
|
|
16997
17922
|
/** Resolves task descriptions back from `assign()` so completion events
|
|
16998
17923
|
* can also carry a human-readable title. */
|
|
16999
17924
|
taskDescriptions = /* @__PURE__ */ new Map();
|
|
@@ -17082,6 +18007,7 @@ var Director = class _Director {
|
|
|
17082
18007
|
opts.checkpointDebounceMs ?? 250
|
|
17083
18008
|
) : null;
|
|
17084
18009
|
this.fleetManager = opts.fleetManager;
|
|
18010
|
+
this.logger = opts.logger;
|
|
17085
18011
|
if (this.sharedScratchpadPath) {
|
|
17086
18012
|
void fsp2.mkdir(this.sharedScratchpadPath, { recursive: true }).catch((err) => this.logShutdownError("shared_scratchpad_mkdir", err));
|
|
17087
18013
|
}
|
|
@@ -17381,7 +18307,10 @@ var Director = class _Director {
|
|
|
17381
18307
|
entry.session.cancel(reason);
|
|
17382
18308
|
for (const [_role, subagentId] of entry.session.getSubagentIds()) {
|
|
17383
18309
|
this.coordinator.stop(subagentId).catch((err) => {
|
|
17384
|
-
|
|
18310
|
+
this.logger?.debug(`stop subagent ${subagentId} failed (may have already completed)`, {
|
|
18311
|
+
subagentId,
|
|
18312
|
+
err: err instanceof Error ? err.message : String(err)
|
|
18313
|
+
});
|
|
17385
18314
|
});
|
|
17386
18315
|
}
|
|
17387
18316
|
}
|
|
@@ -17441,7 +18370,7 @@ var Director = class _Director {
|
|
|
17441
18370
|
* Caller-supplied `priceLookup` is optional but recommended — without
|
|
17442
18371
|
* it the `cost` column in `usage.snapshot()` stays at 0.
|
|
17443
18372
|
*/
|
|
17444
|
-
async spawn(
|
|
18373
|
+
async spawn(callerConfig, priceLookup) {
|
|
17445
18374
|
if (this.workCompleteFlag) {
|
|
17446
18375
|
throw new FleetSpawnBudgetError(
|
|
17447
18376
|
"max_spawns",
|
|
@@ -17450,6 +18379,7 @@ var Director = class _Director {
|
|
|
17450
18379
|
"workComplete() has been called \u2014 director closed further spawning"
|
|
17451
18380
|
);
|
|
17452
18381
|
}
|
|
18382
|
+
const config = { ...callerConfig };
|
|
17453
18383
|
if (!config.model && this.modelMatrix) {
|
|
17454
18384
|
const matrix = typeof this.modelMatrix === "function" ? this.modelMatrix() : this.modelMatrix;
|
|
17455
18385
|
const entry = resolveModelMatrix(matrix, config.role);
|
|
@@ -17675,7 +18605,7 @@ var Director = class _Director {
|
|
|
17675
18605
|
})),
|
|
17676
18606
|
usage: this.usage.snapshot()
|
|
17677
18607
|
};
|
|
17678
|
-
await fsp2.mkdir(
|
|
18608
|
+
await fsp2.mkdir(path4.dirname(this.manifestPath), { recursive: true });
|
|
17679
18609
|
await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
|
|
17680
18610
|
return this.manifestPath;
|
|
17681
18611
|
}
|
|
@@ -17802,11 +18732,11 @@ var Director = class _Director {
|
|
|
17802
18732
|
if (cached) return cached;
|
|
17803
18733
|
const existing = this.taskWaiters.get(id);
|
|
17804
18734
|
if (existing) return existing.promise;
|
|
17805
|
-
let
|
|
18735
|
+
let resolve6;
|
|
17806
18736
|
const promise = new Promise((res) => {
|
|
17807
|
-
|
|
18737
|
+
resolve6 = res;
|
|
17808
18738
|
});
|
|
17809
|
-
this.taskWaiters.set(id, { promise, resolve:
|
|
18739
|
+
this.taskWaiters.set(id, { promise, resolve: resolve6 });
|
|
17810
18740
|
return promise;
|
|
17811
18741
|
})
|
|
17812
18742
|
);
|
|
@@ -17889,7 +18819,7 @@ var Director = class _Director {
|
|
|
17889
18819
|
*/
|
|
17890
18820
|
async readSession(subagentId, tail) {
|
|
17891
18821
|
if (!this.sessionsRoot) return null;
|
|
17892
|
-
const filePath =
|
|
18822
|
+
const filePath = path4.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
|
|
17893
18823
|
let raw;
|
|
17894
18824
|
try {
|
|
17895
18825
|
raw = await fsp2.readFile(filePath, "utf8");
|
|
@@ -18202,7 +19132,7 @@ function createDelegateTool(opts) {
|
|
|
18202
19132
|
subagentId
|
|
18203
19133
|
});
|
|
18204
19134
|
const dir = director;
|
|
18205
|
-
const result = await new Promise((
|
|
19135
|
+
const result = await new Promise((resolve6) => {
|
|
18206
19136
|
let settled = false;
|
|
18207
19137
|
let timer;
|
|
18208
19138
|
const finish = (value) => {
|
|
@@ -18212,7 +19142,7 @@ function createDelegateTool(opts) {
|
|
|
18212
19142
|
offTool();
|
|
18213
19143
|
offIter();
|
|
18214
19144
|
offProgress();
|
|
18215
|
-
|
|
19145
|
+
resolve6(value);
|
|
18216
19146
|
};
|
|
18217
19147
|
const arm = () => {
|
|
18218
19148
|
if (timer) clearTimeout(timer);
|
|
@@ -18419,13 +19349,13 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
18419
19349
|
if (!opts.sessionsRoot) return void 0;
|
|
18420
19350
|
const candidates = [];
|
|
18421
19351
|
if (opts.directorRunId) {
|
|
18422
|
-
candidates.push(
|
|
19352
|
+
candidates.push(path4.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
|
|
18423
19353
|
} else {
|
|
18424
19354
|
try {
|
|
18425
19355
|
const entries = await fsp2.readdir(opts.sessionsRoot, { withFileTypes: true });
|
|
18426
19356
|
for (const entry of entries) {
|
|
18427
19357
|
if (entry.isDirectory()) {
|
|
18428
|
-
candidates.push(
|
|
19358
|
+
candidates.push(path4.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
|
|
18429
19359
|
}
|
|
18430
19360
|
}
|
|
18431
19361
|
} catch {
|
|
@@ -18475,9 +19405,9 @@ function makeDirectorSessionFactory(opts) {
|
|
|
18475
19405
|
let dir;
|
|
18476
19406
|
if (opts.store) {
|
|
18477
19407
|
store = opts.store;
|
|
18478
|
-
dir = opts.sessionsRoot ?
|
|
19408
|
+
dir = opts.sessionsRoot ? path4.join(opts.sessionsRoot, runId) : "(caller-managed)";
|
|
18479
19409
|
} else if (opts.sessionsRoot) {
|
|
18480
|
-
dir =
|
|
19410
|
+
dir = path4.join(opts.sessionsRoot, runId);
|
|
18481
19411
|
store = new DefaultSessionStore({ dir });
|
|
18482
19412
|
} else {
|
|
18483
19413
|
throw new Error("makeDirectorSessionFactory requires either `store` or `sessionsRoot`");
|
|
@@ -18627,7 +19557,7 @@ var DefaultModelsRegistry = class {
|
|
|
18627
19557
|
this.overlay = opts.overlay;
|
|
18628
19558
|
this.overlayUrl = opts.overlayUrl;
|
|
18629
19559
|
this.overlayFile = opts.overlayFile;
|
|
18630
|
-
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ?
|
|
19560
|
+
this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path4.join(path4.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
|
|
18631
19561
|
}
|
|
18632
19562
|
async load(opts = {}) {
|
|
18633
19563
|
if (this.payload && !opts.force) return this.payload;
|
|
@@ -18786,10 +19716,11 @@ var DefaultModelsRegistry = class {
|
|
|
18786
19716
|
capabilities: {
|
|
18787
19717
|
tools: model.tool_call ?? false,
|
|
18788
19718
|
vision: Boolean(model.modalities?.input?.includes("image")),
|
|
18789
|
-
reasoning: model.reasoning ??
|
|
19719
|
+
reasoning: model.reasoning ?? model.reasoningConfig !== void 0,
|
|
18790
19720
|
maxContext: model.limit?.context ?? 0,
|
|
18791
19721
|
maxOutput: model.limit?.output,
|
|
18792
|
-
knowledge: model.knowledge
|
|
19722
|
+
knowledge: model.knowledge,
|
|
19723
|
+
reasoningConfig: model.reasoningConfig
|
|
18793
19724
|
},
|
|
18794
19725
|
cost: model.cost
|
|
18795
19726
|
};
|
|
@@ -18840,7 +19771,7 @@ var DefaultModelsRegistry = class {
|
|
|
18840
19771
|
}
|
|
18841
19772
|
/** Used by `wstack models refresh` to expose where the cache lives. */
|
|
18842
19773
|
cacheLocation() {
|
|
18843
|
-
return
|
|
19774
|
+
return path4.resolve(this.cacheFile);
|
|
18844
19775
|
}
|
|
18845
19776
|
};
|
|
18846
19777
|
function hasEntries(payload) {
|
|
@@ -19207,7 +20138,7 @@ var DefaultModeStore = class {
|
|
|
19207
20138
|
}
|
|
19208
20139
|
async loadActiveMode() {
|
|
19209
20140
|
try {
|
|
19210
|
-
const configPath =
|
|
20141
|
+
const configPath = path4.join(this.configDir, "mode.json");
|
|
19211
20142
|
const content = await fsp2.readFile(configPath, "utf8");
|
|
19212
20143
|
const data = JSON.parse(content);
|
|
19213
20144
|
this.activeModeId = data.activeMode ?? null;
|
|
@@ -19218,7 +20149,7 @@ var DefaultModeStore = class {
|
|
|
19218
20149
|
async saveActiveMode() {
|
|
19219
20150
|
try {
|
|
19220
20151
|
await fsp2.mkdir(this.configDir, { recursive: true });
|
|
19221
|
-
const configPath =
|
|
20152
|
+
const configPath = path4.join(this.configDir, "mode.json");
|
|
19222
20153
|
await atomicWrite(
|
|
19223
20154
|
configPath,
|
|
19224
20155
|
JSON.stringify({ activeMode: this.activeModeId }, null, 2)
|
|
@@ -19233,11 +20164,11 @@ async function loadProjectModes(modesDir) {
|
|
|
19233
20164
|
const entries = await fsp2.readdir(modesDir);
|
|
19234
20165
|
for (const entry of entries) {
|
|
19235
20166
|
if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
|
|
19236
|
-
const filePath =
|
|
20167
|
+
const filePath = path4.join(modesDir, entry);
|
|
19237
20168
|
const stat6 = await fsp2.stat(filePath);
|
|
19238
20169
|
if (!stat6.isFile()) continue;
|
|
19239
20170
|
const content = await fsp2.readFile(filePath, "utf8");
|
|
19240
|
-
const id =
|
|
20171
|
+
const id = path4.basename(entry, path4.extname(entry));
|
|
19241
20172
|
modes.push({
|
|
19242
20173
|
id,
|
|
19243
20174
|
name: id.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
@@ -19253,7 +20184,7 @@ async function loadProjectModes(modesDir) {
|
|
|
19253
20184
|
async function loadUserModes(modesDir) {
|
|
19254
20185
|
const modes = [];
|
|
19255
20186
|
try {
|
|
19256
|
-
const manifestPath =
|
|
20187
|
+
const manifestPath = path4.join(modesDir, "modes.json");
|
|
19257
20188
|
const content = await fsp2.readFile(manifestPath, "utf8");
|
|
19258
20189
|
const manifest = JSON.parse(content);
|
|
19259
20190
|
for (const mode of manifest.modes) {
|
|
@@ -19264,6 +20195,35 @@ async function loadUserModes(modesDir) {
|
|
|
19264
20195
|
return modes;
|
|
19265
20196
|
}
|
|
19266
20197
|
|
|
20198
|
+
// src/models/provider-model-resolve.ts
|
|
20199
|
+
function describeCatalogModel(m) {
|
|
20200
|
+
return {
|
|
20201
|
+
id: m.id,
|
|
20202
|
+
name: m.name,
|
|
20203
|
+
releaseDate: m.release_date,
|
|
20204
|
+
contextWindow: m.limit?.context,
|
|
20205
|
+
inputCost: m.cost?.input,
|
|
20206
|
+
outputCost: m.cost?.output,
|
|
20207
|
+
capabilities: [
|
|
20208
|
+
...m.tool_call ? ["tools"] : [],
|
|
20209
|
+
...m.reasoning ? ["reasoning"] : [],
|
|
20210
|
+
...m.modalities?.input?.includes("image") ? ["vision"] : [],
|
|
20211
|
+
...m.open_weights ? ["open_weights"] : []
|
|
20212
|
+
]
|
|
20213
|
+
};
|
|
20214
|
+
}
|
|
20215
|
+
function resolveProviderModelList(savedModels, catalog) {
|
|
20216
|
+
if (savedModels && savedModels.length > 0) {
|
|
20217
|
+
const byId = new Map((catalog?.models ?? []).map((m) => [m.id, m]));
|
|
20218
|
+
return savedModels.map((id) => {
|
|
20219
|
+
const hit = byId.get(id);
|
|
20220
|
+
return hit ? describeCatalogModel(hit) : { id, name: id, capabilities: [] };
|
|
20221
|
+
});
|
|
20222
|
+
}
|
|
20223
|
+
if (catalog) return catalog.models.map(describeCatalogModel);
|
|
20224
|
+
return [];
|
|
20225
|
+
}
|
|
20226
|
+
|
|
19267
20227
|
// src/sdd/spec-parser.ts
|
|
19268
20228
|
var SpecParser = class {
|
|
19269
20229
|
parse(content) {
|
|
@@ -20205,7 +21165,7 @@ var SpecStore = class {
|
|
|
20205
21165
|
indexPath;
|
|
20206
21166
|
constructor(opts) {
|
|
20207
21167
|
this.baseDir = opts.baseDir;
|
|
20208
|
-
this.indexPath =
|
|
21168
|
+
this.indexPath = path4.join(this.baseDir, "_index.json");
|
|
20209
21169
|
}
|
|
20210
21170
|
async save(spec) {
|
|
20211
21171
|
await ensureDir(this.baseDir);
|
|
@@ -20274,7 +21234,7 @@ var SpecStore = class {
|
|
|
20274
21234
|
return updated;
|
|
20275
21235
|
}
|
|
20276
21236
|
filePath(id) {
|
|
20277
|
-
return
|
|
21237
|
+
return path4.join(this.baseDir, `${id}.json`);
|
|
20278
21238
|
}
|
|
20279
21239
|
async readIndex() {
|
|
20280
21240
|
try {
|
|
@@ -20331,7 +21291,7 @@ var TaskGraphStore = class {
|
|
|
20331
21291
|
indexPath;
|
|
20332
21292
|
constructor(opts) {
|
|
20333
21293
|
this.baseDir = opts.baseDir;
|
|
20334
|
-
this.indexPath =
|
|
21294
|
+
this.indexPath = path4.join(this.baseDir, "_index.json");
|
|
20335
21295
|
}
|
|
20336
21296
|
async save(graph) {
|
|
20337
21297
|
await ensureDir(this.baseDir);
|
|
@@ -20369,7 +21329,7 @@ var TaskGraphStore = class {
|
|
|
20369
21329
|
}
|
|
20370
21330
|
}
|
|
20371
21331
|
filePath(id) {
|
|
20372
|
-
return
|
|
21332
|
+
return path4.join(this.baseDir, `${id}.json`);
|
|
20373
21333
|
}
|
|
20374
21334
|
async readIndex() {
|
|
20375
21335
|
try {
|
|
@@ -20614,9 +21574,9 @@ var AISpecBuilder = class {
|
|
|
20614
21574
|
if (!this.sessionPath) return;
|
|
20615
21575
|
try {
|
|
20616
21576
|
const fsp16 = await import('fs/promises');
|
|
20617
|
-
const
|
|
21577
|
+
const path21 = await import('path');
|
|
20618
21578
|
const { atomicWrite: atomicWrite2 } = await Promise.resolve().then(() => (init_atomic_write(), atomic_write_exports));
|
|
20619
|
-
await fsp16.mkdir(
|
|
21579
|
+
await fsp16.mkdir(path21.dirname(this.sessionPath), { recursive: true });
|
|
20620
21580
|
await atomicWrite2(this.sessionPath, JSON.stringify(this.session, null, 2));
|
|
20621
21581
|
} catch {
|
|
20622
21582
|
}
|
|
@@ -21343,15 +22303,15 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
|
|
|
21343
22303
|
maxId = id;
|
|
21344
22304
|
}
|
|
21345
22305
|
}
|
|
21346
|
-
const
|
|
22306
|
+
const path21 = [];
|
|
21347
22307
|
let current = maxId;
|
|
21348
22308
|
const visited = /* @__PURE__ */ new Set();
|
|
21349
22309
|
while (current && !visited.has(current)) {
|
|
21350
22310
|
visited.add(current);
|
|
21351
|
-
|
|
22311
|
+
path21.unshift(current);
|
|
21352
22312
|
current = prev.get(current) ?? null;
|
|
21353
22313
|
}
|
|
21354
|
-
return
|
|
22314
|
+
return path21;
|
|
21355
22315
|
}
|
|
21356
22316
|
function computeParallelGroups(graph, blockedByMap) {
|
|
21357
22317
|
const groups = [];
|
|
@@ -22174,9 +23134,9 @@ var DefaultHealthRegistry = class {
|
|
|
22174
23134
|
}
|
|
22175
23135
|
async runOne(check) {
|
|
22176
23136
|
let timer = null;
|
|
22177
|
-
const timeout = new Promise((
|
|
23137
|
+
const timeout = new Promise((resolve6) => {
|
|
22178
23138
|
timer = setTimeout(
|
|
22179
|
-
() =>
|
|
23139
|
+
() => resolve6({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
|
|
22180
23140
|
this.timeoutMs
|
|
22181
23141
|
);
|
|
22182
23142
|
});
|
|
@@ -22359,7 +23319,7 @@ async function startMetricsServer(opts) {
|
|
|
22359
23319
|
const tls = opts.tls;
|
|
22360
23320
|
const useHttps = !!(tls?.cert && tls?.key);
|
|
22361
23321
|
const host = opts.host ?? "127.0.0.1";
|
|
22362
|
-
const
|
|
23322
|
+
const path21 = opts.path ?? "/metrics";
|
|
22363
23323
|
const healthPath = opts.healthPath ?? "/healthz";
|
|
22364
23324
|
const healthRegistry = opts.healthRegistry;
|
|
22365
23325
|
const listener = (req, res) => {
|
|
@@ -22369,7 +23329,7 @@ async function startMetricsServer(opts) {
|
|
|
22369
23329
|
return;
|
|
22370
23330
|
}
|
|
22371
23331
|
const url = req.url.split("?")[0];
|
|
22372
|
-
if (url ===
|
|
23332
|
+
if (url === path21) {
|
|
22373
23333
|
let body;
|
|
22374
23334
|
try {
|
|
22375
23335
|
body = renderPrometheus(opts.sink.snapshot());
|
|
@@ -22415,14 +23375,14 @@ async function startMetricsServer(opts) {
|
|
|
22415
23375
|
const { createServer } = await import('http');
|
|
22416
23376
|
server = createServer(listener);
|
|
22417
23377
|
}
|
|
22418
|
-
await new Promise((
|
|
23378
|
+
await new Promise((resolve6, reject) => {
|
|
22419
23379
|
const onError = (err) => {
|
|
22420
23380
|
server.off("listening", onListening);
|
|
22421
23381
|
reject(err);
|
|
22422
23382
|
};
|
|
22423
23383
|
const onListening = () => {
|
|
22424
23384
|
server.off("error", onError);
|
|
22425
|
-
|
|
23385
|
+
resolve6();
|
|
22426
23386
|
};
|
|
22427
23387
|
server.once("error", onError);
|
|
22428
23388
|
server.once("listening", onListening);
|
|
@@ -22433,9 +23393,9 @@ async function startMetricsServer(opts) {
|
|
|
22433
23393
|
const protocol = useHttps ? "https" : "http";
|
|
22434
23394
|
return {
|
|
22435
23395
|
port: boundPort,
|
|
22436
|
-
url: `${protocol}://${host}:${boundPort}${
|
|
22437
|
-
close: () => new Promise((
|
|
22438
|
-
server.close((err) => err ? reject(err) :
|
|
23396
|
+
url: `${protocol}://${host}:${boundPort}${path21}`,
|
|
23397
|
+
close: () => new Promise((resolve6, reject) => {
|
|
23398
|
+
server.close((err) => err ? reject(err) : resolve6());
|
|
22439
23399
|
})
|
|
22440
23400
|
};
|
|
22441
23401
|
}
|
|
@@ -23077,6 +24037,19 @@ var miniMaxVisionServer = () => ({
|
|
|
23077
24037
|
allowedTools: ["understand_image"],
|
|
23078
24038
|
permission: "auto"
|
|
23079
24039
|
});
|
|
24040
|
+
var sshManagerServer = () => ({
|
|
24041
|
+
name: "ssh",
|
|
24042
|
+
description: "Remote SSH management \u2014 execute commands, transfer files, tunnels, health checks (mcp-ssh-manager)",
|
|
24043
|
+
transport: "stdio",
|
|
24044
|
+
command: "npx",
|
|
24045
|
+
args: ["-y", "mcp-ssh-manager"],
|
|
24046
|
+
env: {
|
|
24047
|
+
MCP_SSH_COMPACT_JSON: "true",
|
|
24048
|
+
MCP_SSH_DEFAULT_TIMEOUT: "120000"
|
|
24049
|
+
},
|
|
24050
|
+
permission: "confirm",
|
|
24051
|
+
requestTimeoutMs: 18e4
|
|
24052
|
+
});
|
|
23080
24053
|
var allServers = () => ({
|
|
23081
24054
|
filesystem: { ...filesystemServer(), enabled: false },
|
|
23082
24055
|
github: { ...githubServer(), enabled: false },
|
|
@@ -23090,9 +24063,10 @@ var allServers = () => ({
|
|
|
23090
24063
|
sentinel: { ...sentinelServer(), enabled: false },
|
|
23091
24064
|
"zai-vision": { ...zaiVisionServer(), enabled: false },
|
|
23092
24065
|
"minimax-vision": { ...miniMaxVisionServer(), enabled: false },
|
|
23093
|
-
playwright: { ...playwrightServer(), enabled: false }
|
|
24066
|
+
playwright: { ...playwrightServer(), enabled: false },
|
|
24067
|
+
ssh: { ...sshManagerServer(), enabled: false }
|
|
23094
24068
|
});
|
|
23095
24069
|
|
|
23096
|
-
export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SddParallelRun, SddTaskDecomposer, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, createSessionEventBridge, createStrategyCompactor, decryptConfigSecrets, deriveTodosFromPlanItem, dispatchAgent, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getAgentDefinition, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, resolveAuditLevel, resolveSessionLoggingConfig, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, scoreAgents, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
|
|
24070
|
+
export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SddParallelRun, SddTaskDecomposer, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, createSessionEventBridge, createStrategyCompactor, decryptConfigSecrets, deriveTodosFromPlanItem, describeCatalogModel, dispatchAgent, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getAgentDefinition, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, migratePlaintextSecrets, miniMaxVisionServer, playwrightServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, resolveAuditLevel, resolveProviderModelList, resolveSessionLoggingConfig, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, scoreAgents, sentinelServer, setPlanItemStatus, slackServer, sshManagerServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
|
|
23097
24071
|
//# sourceMappingURL=index.js.map
|
|
23098
24072
|
//# sourceMappingURL=index.js.map
|