@wrongstack/core 0.308.7 → 0.309.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/coordination/director/director-toolset.d.ts +2 -2
- package/dist/coordination/director-mutation-test-tool.d.ts +29 -0
- package/dist/coordination/director-tools.d.ts +2 -0
- package/dist/coordination/director.d.ts +9 -0
- package/dist/coordination/fleet.d.ts +12 -0
- package/dist/coordination/index.d.ts +1 -1
- package/dist/coordination/index.js +705 -48
- package/dist/coordination/mail-tools.d.ts +10 -6
- package/dist/coordination/mailbox-codecs.d.ts +31 -0
- package/dist/coordination/multi-agent-coordinator.d.ts +14 -0
- package/dist/coordination/multi-agent-timeout.d.ts +11 -1
- package/dist/coordination/mutation-engine.d.ts +74 -0
- package/dist/coordination/subagent-budget.d.ts +54 -0
- package/dist/coordination/subagent-finish.d.ts +78 -0
- package/dist/core/index.js +19 -4
- package/dist/defaults/index.js +699 -51
- package/dist/execution/index.js +238 -16
- package/dist/index.d.ts +1 -1
- package/dist/index.js +862 -178
- package/dist/kernel/events/agent-events.d.ts +31 -2
- package/dist/models/index.js +11 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +14 -0
- package/dist/types/multi-agent.d.ts +15 -0
- package/dist/types/provider.d.ts +29 -1
- package/instructions/agents/chaos-monkey.md +57 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1171,7 +1171,7 @@ __export(review_report_store_exports, {
|
|
|
1171
1171
|
REPORT_STORE_FILE: () => REPORT_STORE_FILE,
|
|
1172
1172
|
resolveReportStorePath: () => resolveReportStorePath
|
|
1173
1173
|
});
|
|
1174
|
-
import { randomUUID as
|
|
1174
|
+
import { randomUUID as randomUUID32 } from "node:crypto";
|
|
1175
1175
|
import * as fsp35 from "node:fs/promises";
|
|
1176
1176
|
import * as path76 from "node:path";
|
|
1177
1177
|
function resolveReportStorePath(projectDir) {
|
|
@@ -1238,7 +1238,7 @@ var init_review_report_store = __esm({
|
|
|
1238
1238
|
...input.evidenceChecks !== void 0 ? { evidenceChecks: input.evidenceChecks } : {}
|
|
1239
1239
|
};
|
|
1240
1240
|
const createdEvent = {
|
|
1241
|
-
id:
|
|
1241
|
+
id: randomUUID32(),
|
|
1242
1242
|
reportId: report.id,
|
|
1243
1243
|
eventType: "created",
|
|
1244
1244
|
fromLifecycle: null,
|
|
@@ -1261,7 +1261,7 @@ var init_review_report_store = __esm({
|
|
|
1261
1261
|
const from = this._materialize(entry).lifecycle;
|
|
1262
1262
|
validateReportTransition(from, to);
|
|
1263
1263
|
const event = {
|
|
1264
|
-
id:
|
|
1264
|
+
id: randomUUID32(),
|
|
1265
1265
|
reportId,
|
|
1266
1266
|
eventType: reportEventTypeFor(to),
|
|
1267
1267
|
fromLifecycle: from,
|
|
@@ -1304,7 +1304,7 @@ var init_review_report_store = __esm({
|
|
|
1304
1304
|
if (!entry) throw new Error(`Review report not found: ${reportId}`);
|
|
1305
1305
|
const materialized = this._materialize(entry);
|
|
1306
1306
|
const event = {
|
|
1307
|
-
id:
|
|
1307
|
+
id: randomUUID32(),
|
|
1308
1308
|
reportId,
|
|
1309
1309
|
eventType: "note_added",
|
|
1310
1310
|
fromLifecycle: materialized.lifecycle,
|
|
@@ -1527,7 +1527,7 @@ __export(review_finding_store_exports, {
|
|
|
1527
1527
|
JsonlFindingStore: () => JsonlFindingStore,
|
|
1528
1528
|
resolveFindingStorePath: () => resolveFindingStorePath
|
|
1529
1529
|
});
|
|
1530
|
-
import { randomUUID as
|
|
1530
|
+
import { randomUUID as randomUUID42 } from "node:crypto";
|
|
1531
1531
|
import * as fsp48 from "node:fs/promises";
|
|
1532
1532
|
import * as path105 from "node:path";
|
|
1533
1533
|
function resolveFindingStorePath(projectDir) {
|
|
@@ -1616,7 +1616,7 @@ var init_review_finding_store = __esm({
|
|
|
1616
1616
|
validateTransition(from, to);
|
|
1617
1617
|
validateResolution(to, opts?.outcome);
|
|
1618
1618
|
const event = {
|
|
1619
|
-
id:
|
|
1619
|
+
id: randomUUID42(),
|
|
1620
1620
|
findingId,
|
|
1621
1621
|
eventType: to === "resolved" ? "resolved" : to === "ignored" ? "ignored" : this._eventTypeFor(to),
|
|
1622
1622
|
fromStatus: from,
|
|
@@ -1800,7 +1800,7 @@ var init_review_finding_store = __esm({
|
|
|
1800
1800
|
}
|
|
1801
1801
|
_makeEvent(findingId, eventType, fromStatus, toStatus, context) {
|
|
1802
1802
|
return {
|
|
1803
|
-
id:
|
|
1803
|
+
id: randomUUID42(),
|
|
1804
1804
|
findingId,
|
|
1805
1805
|
eventType,
|
|
1806
1806
|
fromStatus,
|
|
@@ -19762,9 +19762,68 @@ function resourceId3(kind, value) {
|
|
|
19762
19762
|
return `${kind}_${createHash17("sha256").update(value).digest("hex").slice(0, 24)}`;
|
|
19763
19763
|
}
|
|
19764
19764
|
|
|
19765
|
+
// src/core/btw.ts
|
|
19766
|
+
var META_KEY2 = "_btwNotes";
|
|
19767
|
+
var MAX_PENDING = 20;
|
|
19768
|
+
function readQueue(ctx) {
|
|
19769
|
+
const raw = ctx.meta[META_KEY2];
|
|
19770
|
+
return Array.isArray(raw) ? raw : [];
|
|
19771
|
+
}
|
|
19772
|
+
function setBtwNote(ctx, text2) {
|
|
19773
|
+
const trimmed = text2.trim();
|
|
19774
|
+
if (!trimmed) return readQueue(ctx).length;
|
|
19775
|
+
const next = [...readQueue(ctx), trimmed].slice(-MAX_PENDING);
|
|
19776
|
+
ctx.meta[META_KEY2] = next;
|
|
19777
|
+
return next.length;
|
|
19778
|
+
}
|
|
19779
|
+
function pendingBtwCount(ctx) {
|
|
19780
|
+
return readQueue(ctx).length;
|
|
19781
|
+
}
|
|
19782
|
+
function consumeBtwNotes(ctx) {
|
|
19783
|
+
const notes = readQueue(ctx);
|
|
19784
|
+
if (notes.length > 0) delete ctx.meta[META_KEY2];
|
|
19785
|
+
return notes;
|
|
19786
|
+
}
|
|
19787
|
+
function buildBtwBlock(notes) {
|
|
19788
|
+
const body = notes.map((n) => `- ${n}`).join("\n");
|
|
19789
|
+
return [
|
|
19790
|
+
"[BY THE WAY \u2014 the user added this while you were working. Fold it into",
|
|
19791
|
+
"your current task; do not restart from scratch unless it contradicts the",
|
|
19792
|
+
"goal:",
|
|
19793
|
+
"",
|
|
19794
|
+
body,
|
|
19795
|
+
"]"
|
|
19796
|
+
].join("\n");
|
|
19797
|
+
}
|
|
19798
|
+
|
|
19765
19799
|
// src/coordination/agent-subagent-runner.ts
|
|
19766
19800
|
init_errors();
|
|
19767
19801
|
|
|
19802
|
+
// src/coordination/subagent-finish.ts
|
|
19803
|
+
var SUBAGENT_FINISH_REQUESTED_EVENT = "subagent.finish_requested";
|
|
19804
|
+
var DEFAULT_SUBAGENT_FINISH_GRACE_MS = 12e4;
|
|
19805
|
+
function resolveGracefulFinish(config) {
|
|
19806
|
+
const raw = config.gracefulFinish;
|
|
19807
|
+
if (raw === void 0 || raw === false) return void 0;
|
|
19808
|
+
if (raw === true) return { graceMs: DEFAULT_SUBAGENT_FINISH_GRACE_MS };
|
|
19809
|
+
const graceMs = typeof raw.graceMs === "number" && Number.isFinite(raw.graceMs) && raw.graceMs > 0 ? Math.floor(raw.graceMs) : DEFAULT_SUBAGENT_FINISH_GRACE_MS;
|
|
19810
|
+
return { graceMs };
|
|
19811
|
+
}
|
|
19812
|
+
function buildSubagentFinishNotice(input) {
|
|
19813
|
+
const localTime = new Date(input.deadlineMs).toISOString();
|
|
19814
|
+
const seconds = Math.max(1, Math.round(input.graceMs / 1e3));
|
|
19815
|
+
const timeLeft = input.graceMs > 0 ? `You have roughly ${seconds} seconds (until ${localTime}) of legitimate working time left.` : `Your working-time window is already spent (deadline was ${localTime}) \u2014 finish now.`;
|
|
19816
|
+
return [
|
|
19817
|
+
"[SUBAGENT FINISH] The leader agent has finished its work.",
|
|
19818
|
+
`Reason: ${input.reason}`,
|
|
19819
|
+
timeLeft,
|
|
19820
|
+
"Finish your task now, in this turn: complete the thought you are working on, stop",
|
|
19821
|
+
"starting new tool calls unless one is strictly required to finish, and write your",
|
|
19822
|
+
"final answer or report as your final output, then end your turn.",
|
|
19823
|
+
"Do not restart the task and do not begin new work."
|
|
19824
|
+
].join("\n");
|
|
19825
|
+
}
|
|
19826
|
+
|
|
19768
19827
|
// src/coordination/subagent-budget.ts
|
|
19769
19828
|
var TIMEOUT_PREEMPT_FRACTION = 0.85;
|
|
19770
19829
|
var DECISION_TIMEOUT_MS = 6e4;
|
|
@@ -19822,6 +19881,82 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
19822
19881
|
this.limits.idleTimeoutMs = ext.idleTimeoutMs;
|
|
19823
19882
|
}
|
|
19824
19883
|
}
|
|
19884
|
+
/**
|
|
19885
|
+
* Graceful-finish state (see coordination/subagent-finish.ts).
|
|
19886
|
+
* `_finishNotified` guards the single in-band emission; `_grace` records a
|
|
19887
|
+
* granted working-time extension past the original wall-clock deadline.
|
|
19888
|
+
* They are separate because the two callers want different semantics:
|
|
19889
|
+
* the watchdog grants grace at the deadline crossing (notify + extend),
|
|
19890
|
+
* while an explicit leader-finished request only notifies — a subagent
|
|
19891
|
+
* well inside its budget keeps its full legitimate working time and simply
|
|
19892
|
+
* accelerates.
|
|
19893
|
+
*/
|
|
19894
|
+
_finishNotified = false;
|
|
19895
|
+
_grace = null;
|
|
19896
|
+
/** True once the in-band finish notification has been emitted. */
|
|
19897
|
+
get finishNotified() {
|
|
19898
|
+
return this._finishNotified;
|
|
19899
|
+
}
|
|
19900
|
+
/** True once a grace window has been granted past the original deadline. */
|
|
19901
|
+
get graceGranted() {
|
|
19902
|
+
return this._grace !== null;
|
|
19903
|
+
}
|
|
19904
|
+
/**
|
|
19905
|
+
* Notify the subagent in-band to finish its task in its own turn:
|
|
19906
|
+
* `subagent.finish_requested` is emitted on the wired EventBus and the
|
|
19907
|
+
* agent loop folds the notice into the conversation between tool batches.
|
|
19908
|
+
* Nothing aborts — this is a notification, never an interrupt.
|
|
19909
|
+
*
|
|
19910
|
+
* `opts.graceMs` additionally extends the wall-clock ceiling by that window
|
|
19911
|
+
* (used by the watchdog at a deadline crossing, so the model gets working
|
|
19912
|
+
* time instead of a kill). Omit it to notify without touching the budget —
|
|
19913
|
+
* the subagent keeps its existing time budget and just accelerates.
|
|
19914
|
+
*
|
|
19915
|
+
* Returns `true` when this call did something (emitted the notification
|
|
19916
|
+
* and/or granted grace); `false` when there was nothing to do (already
|
|
19917
|
+
* notified, grace already granted, no EventBus wired, budget not started).
|
|
19918
|
+
*/
|
|
19919
|
+
notifyFinish(reason, opts, now = Date.now) {
|
|
19920
|
+
if (!this._events) return false;
|
|
19921
|
+
if (this.startTime === null) return false;
|
|
19922
|
+
const shouldEmit = !this._finishNotified;
|
|
19923
|
+
const rawGrace = opts?.graceMs;
|
|
19924
|
+
const shouldGrant = rawGrace !== void 0 && this._grace === null;
|
|
19925
|
+
if (!shouldEmit && !shouldGrant) return false;
|
|
19926
|
+
let grantedGraceMs = 0;
|
|
19927
|
+
let graceDeadlineMs;
|
|
19928
|
+
if (shouldGrant && rawGrace !== void 0) {
|
|
19929
|
+
grantedGraceMs = Number.isFinite(rawGrace) && rawGrace > 0 ? Math.floor(rawGrace) : DEFAULT_SUBAGENT_FINISH_GRACE_MS;
|
|
19930
|
+
graceDeadlineMs = now() + grantedGraceMs;
|
|
19931
|
+
this._grace = { deadlineMs: graceDeadlineMs, graceMs: grantedGraceMs };
|
|
19932
|
+
this.patchLimits({ timeoutMs: graceDeadlineMs - this.startTime });
|
|
19933
|
+
}
|
|
19934
|
+
if (shouldEmit) {
|
|
19935
|
+
this._finishNotified = true;
|
|
19936
|
+
const effectiveDeadlineMs = graceDeadlineMs ?? (this.limits.timeoutMs !== void 0 ? this.startTime + this.limits.timeoutMs : now() + DEFAULT_SUBAGENT_FINISH_GRACE_MS);
|
|
19937
|
+
const effectiveGraceMs = Math.max(0, effectiveDeadlineMs - now());
|
|
19938
|
+
const subagentId = this._subagentId;
|
|
19939
|
+
this._events.emit(SUBAGENT_FINISH_REQUESTED_EVENT, {
|
|
19940
|
+
// Omitted entirely when the budget was built without an id — an
|
|
19941
|
+
// empty string is an address that matches nothing.
|
|
19942
|
+
...subagentId !== void 0 ? { subagentId } : {},
|
|
19943
|
+
reason,
|
|
19944
|
+
deadlineMs: effectiveDeadlineMs,
|
|
19945
|
+
graceMs: effectiveGraceMs,
|
|
19946
|
+
notice: buildSubagentFinishNotice({
|
|
19947
|
+
reason,
|
|
19948
|
+
deadlineMs: effectiveDeadlineMs,
|
|
19949
|
+
graceMs: effectiveGraceMs
|
|
19950
|
+
})
|
|
19951
|
+
});
|
|
19952
|
+
}
|
|
19953
|
+
return true;
|
|
19954
|
+
}
|
|
19955
|
+
/** Epoch ms by which the subagent should have produced its final output,
|
|
19956
|
+
* once a grace window was granted. Undefined before that. */
|
|
19957
|
+
get finishDeadlineMs() {
|
|
19958
|
+
return this._grace?.deadlineMs;
|
|
19959
|
+
}
|
|
19825
19960
|
iterations = 0;
|
|
19826
19961
|
toolCalls = 0;
|
|
19827
19962
|
tokenInput = 0;
|
|
@@ -19837,6 +19972,10 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
19837
19972
|
lastActivityTime = null;
|
|
19838
19973
|
_onThreshold;
|
|
19839
19974
|
_sessionId;
|
|
19975
|
+
/** Owning subagent id — used to address the graceful-finish event. */
|
|
19976
|
+
_subagentId;
|
|
19977
|
+
/** True when only the coordinator watchdog may enforce wall-clock limits. */
|
|
19978
|
+
_wallClockWatchdogOwned;
|
|
19840
19979
|
/**
|
|
19841
19980
|
* Hard cap on how long `_negotiateExtension` waits for the coordinator to
|
|
19842
19981
|
* respond before defaulting to 'stop'. Without this fallback an absent
|
|
@@ -19908,6 +20047,8 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
19908
20047
|
constructor(limits = {}, mode = "auto", options = {}) {
|
|
19909
20048
|
this._mode = mode;
|
|
19910
20049
|
this._sessionId = options.sessionId;
|
|
20050
|
+
this._subagentId = options.subagentId;
|
|
20051
|
+
this._wallClockWatchdogOwned = options.wallClockWatchdogOwned === true;
|
|
19911
20052
|
this.limits = { ...limits };
|
|
19912
20053
|
}
|
|
19913
20054
|
currentSessionId() {
|
|
@@ -19986,7 +20127,7 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
19986
20127
|
if (this.limits.idleTimeoutMs !== void 0 && idle > this.limits.idleTimeoutMs) {
|
|
19987
20128
|
exceeded.push({ kind: "idle_timeout", used: idle, limit: this.limits.idleTimeoutMs });
|
|
19988
20129
|
}
|
|
19989
|
-
const wallOwnedByWatchdog = this._onThreshold !== void 0 && this._watchdogActive === this.limits.timeoutMs;
|
|
20130
|
+
const wallOwnedByWatchdog = this._wallClockWatchdogOwned || this._onThreshold !== void 0 && this._watchdogActive === this.limits.timeoutMs;
|
|
19990
20131
|
if (this.limits.timeoutMs !== void 0 && elapsedMs2 > this.limits.timeoutMs && !wallOwnedByWatchdog) {
|
|
19991
20132
|
exceeded.push({ kind: "timeout", used: elapsedMs2, limit: this.limits.timeoutMs });
|
|
19992
20133
|
}
|
|
@@ -20185,7 +20326,7 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
20185
20326
|
if (timeoutMs === void 0 && idleTimeoutMs === void 0) return;
|
|
20186
20327
|
const elapsed2 = Date.now() - this.startTime;
|
|
20187
20328
|
const wallSkipped = this._onThreshold !== void 0 && this._watchdogActive !== void 0 && timeoutMs !== void 0 && this._watchdogActive === timeoutMs;
|
|
20188
|
-
const wallTripped = wallSkipped ? false : timeoutMs !== void 0 && elapsed2 > timeoutMs;
|
|
20329
|
+
const wallTripped = this._wallClockWatchdogOwned || wallSkipped ? false : timeoutMs !== void 0 && elapsed2 > timeoutMs;
|
|
20189
20330
|
const idleTripped = idleTimeoutMs !== void 0 && this.idleMs() > idleTimeoutMs;
|
|
20190
20331
|
if (!wallTripped && !idleTripped) return;
|
|
20191
20332
|
void this.checkLimits(elapsed2);
|
|
@@ -20666,6 +20807,14 @@ function makeAgentSubagentRunner(opts) {
|
|
|
20666
20807
|
);
|
|
20667
20808
|
const onParentAbort = () => aborter.abort();
|
|
20668
20809
|
ctx.signal.addEventListener("abort", onParentAbort);
|
|
20810
|
+
if (resolveGracefulFinish(ctx.config)) {
|
|
20811
|
+
unsub.push(
|
|
20812
|
+
events.on("subagent.finish_requested", (e) => {
|
|
20813
|
+
if (e.subagentId && e.subagentId !== ctx.subagentId) return;
|
|
20814
|
+
setBtwNote(agent.ctx, e.notice);
|
|
20815
|
+
})
|
|
20816
|
+
);
|
|
20817
|
+
}
|
|
20669
20818
|
let result;
|
|
20670
20819
|
try {
|
|
20671
20820
|
result = await agent.run(format(task, ctx.config), { signal: aborter.signal });
|
|
@@ -29007,7 +29156,7 @@ function attachDepWatcherBridge(opts) {
|
|
|
29007
29156
|
}
|
|
29008
29157
|
|
|
29009
29158
|
// src/coordination/director.ts
|
|
29010
|
-
import { randomUUID as
|
|
29159
|
+
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
29011
29160
|
import * as fsp30 from "node:fs/promises";
|
|
29012
29161
|
|
|
29013
29162
|
// src/storage/director-state.ts
|
|
@@ -30902,7 +31051,7 @@ ${JSON.stringify(result.result, null, 2)}
|
|
|
30902
31051
|
};
|
|
30903
31052
|
|
|
30904
31053
|
// src/coordination/director-tools.ts
|
|
30905
|
-
import { randomUUID as
|
|
31054
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
30906
31055
|
import {
|
|
30907
31056
|
completeKanbanDispatch,
|
|
30908
31057
|
failKanbanDispatch,
|
|
@@ -32136,6 +32285,413 @@ function excerpt(text2, max) {
|
|
|
32136
32285
|
...(truncated)`;
|
|
32137
32286
|
}
|
|
32138
32287
|
|
|
32288
|
+
// src/coordination/director-mutation-test-tool.ts
|
|
32289
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
32290
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
32291
|
+
import { isAbsolute as isAbsolute9, join as join40 } from "node:path";
|
|
32292
|
+
|
|
32293
|
+
// src/coordination/mutation-engine.ts
|
|
32294
|
+
var TOKEN_PATTERNS = [
|
|
32295
|
+
{
|
|
32296
|
+
kind: "relax-boundary",
|
|
32297
|
+
// `>` not followed by `=` and not part of `=>` or `>>`; require code-ish
|
|
32298
|
+
// context on both sides so generic text (JSX, strings) is not touched.
|
|
32299
|
+
regex: /(?<=[\w\)\]\}'"`])\s*\x20?(?<op>>(?!=|>))/g,
|
|
32300
|
+
replace: () => ">="
|
|
32301
|
+
},
|
|
32302
|
+
{
|
|
32303
|
+
kind: "tighten-boundary",
|
|
32304
|
+
regex: /(?<=[\w\)\]\}'"`])\s*\x20?(?<op>>=)/g,
|
|
32305
|
+
replace: () => ">"
|
|
32306
|
+
},
|
|
32307
|
+
{
|
|
32308
|
+
kind: "arith-plus-to-minus",
|
|
32309
|
+
// `+` between operands (binary), not `++`, unary `+x`, or `+=`.
|
|
32310
|
+
regex: /(?<=[\w\)\]\}'"`])\s*\x20?(?<op>\+(?!\+|=))/g,
|
|
32311
|
+
replace: () => "-"
|
|
32312
|
+
},
|
|
32313
|
+
{
|
|
32314
|
+
kind: "arith-minus-to-plus",
|
|
32315
|
+
// Binary `-` between operands, not `--`, `-=` or negative-number literal.
|
|
32316
|
+
regex: /(?<=[\w\)\]\}'"`])\s*\x20?(?<op>-(?!-|=))/g,
|
|
32317
|
+
replace: () => "+"
|
|
32318
|
+
},
|
|
32319
|
+
{
|
|
32320
|
+
kind: "negate-boolean",
|
|
32321
|
+
// Standalone boolean literals used as values, not property names.
|
|
32322
|
+
regex: /(?<![.\w$])(?<op>true|false)(?![\w$])/g,
|
|
32323
|
+
replace: (m) => m === "true" ? "false" : "true"
|
|
32324
|
+
},
|
|
32325
|
+
{
|
|
32326
|
+
kind: "return-null",
|
|
32327
|
+
// `return <expr>;` where expr is not already null/undefined/void.
|
|
32328
|
+
regex: /(?<indent>\breturn\b)(?<expr>\s+[^;{}\n]+?)\s*;/g,
|
|
32329
|
+
replace: () => "return null;"
|
|
32330
|
+
}
|
|
32331
|
+
];
|
|
32332
|
+
function planMutations(file, source, opts = {}) {
|
|
32333
|
+
const maxPerFile = opts.maxPerFile ?? 25;
|
|
32334
|
+
const out = [];
|
|
32335
|
+
const lines = source.split("\n");
|
|
32336
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
32337
|
+
const line = lines[lineIdx];
|
|
32338
|
+
const t2 = line.trim();
|
|
32339
|
+
if (t2.startsWith("//") || t2.startsWith("*") || t2.startsWith("/*")) continue;
|
|
32340
|
+
for (const pattern of TOKEN_PATTERNS) {
|
|
32341
|
+
pattern.regex.lastIndex = 0;
|
|
32342
|
+
let m;
|
|
32343
|
+
while ((m = pattern.regex.exec(line)) !== null) {
|
|
32344
|
+
const token = m.groups?.["op"] ?? m[0];
|
|
32345
|
+
const tokenStart = m.index + m[0].indexOf(token);
|
|
32346
|
+
if (isMasked(line, tokenStart, token.length)) continue;
|
|
32347
|
+
const original = line.slice(tokenStart, tokenStart + token.length);
|
|
32348
|
+
const replacement = pattern.replace(token);
|
|
32349
|
+
if (replacement === original) continue;
|
|
32350
|
+
out.push({
|
|
32351
|
+
id: `${pattern.kind}#${lineIdx + 1}#${tokenStart + 1}`,
|
|
32352
|
+
kind: pattern.kind,
|
|
32353
|
+
file,
|
|
32354
|
+
line: lineIdx + 1,
|
|
32355
|
+
column: tokenStart + 1,
|
|
32356
|
+
original,
|
|
32357
|
+
replacement
|
|
32358
|
+
});
|
|
32359
|
+
}
|
|
32360
|
+
}
|
|
32361
|
+
if (out.length >= maxPerFile) break;
|
|
32362
|
+
}
|
|
32363
|
+
return out.slice(0, maxPerFile);
|
|
32364
|
+
}
|
|
32365
|
+
function isMasked(line, start, len) {
|
|
32366
|
+
let inSingle = false;
|
|
32367
|
+
let inDouble = false;
|
|
32368
|
+
for (let i = 0; i < start; i++) {
|
|
32369
|
+
const c = line[i];
|
|
32370
|
+
const prev = i > 0 ? line[i - 1] : void 0;
|
|
32371
|
+
if (c === "'" && prev !== "\\") inSingle = !inSingle;
|
|
32372
|
+
else if (c === '"' && prev !== "\\") inDouble = !inDouble;
|
|
32373
|
+
if (!inSingle && !inDouble && c === "/" && prev === "/") return true;
|
|
32374
|
+
}
|
|
32375
|
+
if (inSingle || inDouble) return true;
|
|
32376
|
+
const window = line.slice(start, start + len);
|
|
32377
|
+
return /['"]/.test(window);
|
|
32378
|
+
}
|
|
32379
|
+
function parseMutationReport(text2) {
|
|
32380
|
+
const candidates = [];
|
|
32381
|
+
const fence = text2.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
32382
|
+
if (fence?.[1]) candidates.push(fence[1].trim());
|
|
32383
|
+
const firstBrace = text2.indexOf("{");
|
|
32384
|
+
if (firstBrace >= 0) candidates.push(extractBalancedObject(text2, firstBrace));
|
|
32385
|
+
for (const candidate of candidates) {
|
|
32386
|
+
if (!candidate) continue;
|
|
32387
|
+
try {
|
|
32388
|
+
const parsed = JSON.parse(candidate);
|
|
32389
|
+
if (!Array.isArray(parsed.mutants)) continue;
|
|
32390
|
+
return {
|
|
32391
|
+
mutants: parsed.mutants.map(normalizeMutantEntry).filter((x) => Boolean(x)),
|
|
32392
|
+
summary: typeof parsed.summary === "string" ? parsed.summary : void 0
|
|
32393
|
+
};
|
|
32394
|
+
} catch {
|
|
32395
|
+
}
|
|
32396
|
+
}
|
|
32397
|
+
return void 0;
|
|
32398
|
+
}
|
|
32399
|
+
function extractBalancedObject(text2, start) {
|
|
32400
|
+
let depth = 0;
|
|
32401
|
+
let inString = false;
|
|
32402
|
+
let escaped = false;
|
|
32403
|
+
for (let i = start; i < text2.length; i++) {
|
|
32404
|
+
const c = text2[i];
|
|
32405
|
+
if (escaped) {
|
|
32406
|
+
escaped = false;
|
|
32407
|
+
continue;
|
|
32408
|
+
}
|
|
32409
|
+
if (c === "\\") {
|
|
32410
|
+
escaped = true;
|
|
32411
|
+
continue;
|
|
32412
|
+
}
|
|
32413
|
+
if (c === '"') inString = !inString;
|
|
32414
|
+
if (inString) continue;
|
|
32415
|
+
if (c === "{") depth++;
|
|
32416
|
+
else if (c === "}") {
|
|
32417
|
+
depth--;
|
|
32418
|
+
if (depth === 0) return text2.slice(start, i + 1);
|
|
32419
|
+
}
|
|
32420
|
+
}
|
|
32421
|
+
return text2.slice(start);
|
|
32422
|
+
}
|
|
32423
|
+
function normalizeMutantEntry(value) {
|
|
32424
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
32425
|
+
const rec = value;
|
|
32426
|
+
const id = typeof rec["id"] === "string" ? rec["id"] : void 0;
|
|
32427
|
+
const status = rec["status"];
|
|
32428
|
+
if (!id || status !== "killed" && status !== "survived" && status !== "skipped") {
|
|
32429
|
+
return void 0;
|
|
32430
|
+
}
|
|
32431
|
+
return {
|
|
32432
|
+
id,
|
|
32433
|
+
file: typeof rec["file"] === "string" ? rec["file"] : "",
|
|
32434
|
+
line: typeof rec["line"] === "number" ? rec["line"] : 0,
|
|
32435
|
+
kind: typeof rec["kind"] === "string" ? rec["kind"] : "",
|
|
32436
|
+
status,
|
|
32437
|
+
evidence: typeof rec["evidence"] === "string" ? rec["evidence"] : void 0
|
|
32438
|
+
};
|
|
32439
|
+
}
|
|
32440
|
+
|
|
32441
|
+
// src/coordination/director-mutation-test-tool.ts
|
|
32442
|
+
var DEFAULT_MAX_PER_FILE = 10;
|
|
32443
|
+
var DEFAULT_MAX_STRENGTHEN_ATTEMPTS = 2;
|
|
32444
|
+
var CHAOS_ROLE = "chaos-monkey";
|
|
32445
|
+
function makeMutationTestTool(director, roster, opts = {}) {
|
|
32446
|
+
return {
|
|
32447
|
+
name: "mutation_test",
|
|
32448
|
+
description: "Chaos Monkey mutation testing: deterministically sabotage boundary conditions in the target code (> to >=, + to -, boolean flips, return null), re-run the tests per mutant, and report which mutants were killed. Surviving mutants mean the tests are weak \u2014 optionally loop a strengthen-tests repair until they die.",
|
|
32449
|
+
usageHint: "Use after writing new code AND its tests, before delivering. Pass targets (files) and testCommand. Provide repairSubagentId to auto-strengthen weak tests. Survivors that persist are reported as suspected-equivalent.",
|
|
32450
|
+
permission: "auto",
|
|
32451
|
+
mutating: false,
|
|
32452
|
+
capabilities: [ToolCapabilities.SUBAGENT_SPAWN],
|
|
32453
|
+
inputSchema: {
|
|
32454
|
+
type: "object",
|
|
32455
|
+
properties: {
|
|
32456
|
+
targets: {
|
|
32457
|
+
type: "array",
|
|
32458
|
+
items: { type: "string" },
|
|
32459
|
+
description: "Project-relative (or absolute) source files to mutate. Keep to files changed by the current task."
|
|
32460
|
+
},
|
|
32461
|
+
testCommand: {
|
|
32462
|
+
type: "string",
|
|
32463
|
+
description: 'Exact command that runs the relevant tests, e.g. "pnpm exec vitest run packages/core/tests/coordination/mutation-engine.test.ts".'
|
|
32464
|
+
},
|
|
32465
|
+
cwd: { type: "string", description: "Working directory for the test command." },
|
|
32466
|
+
maxPerFile: {
|
|
32467
|
+
type: "number",
|
|
32468
|
+
minimum: 1,
|
|
32469
|
+
maximum: 25,
|
|
32470
|
+
description: "Mutant cap per file per pass. Default 10."
|
|
32471
|
+
},
|
|
32472
|
+
maxStrengthenAttempts: {
|
|
32473
|
+
type: "number",
|
|
32474
|
+
minimum: 0,
|
|
32475
|
+
maximum: 5,
|
|
32476
|
+
description: "Strengthen\u2192re-verify rounds. Default 2 when repairSubagentId is set, else 0."
|
|
32477
|
+
},
|
|
32478
|
+
repairSubagentId: {
|
|
32479
|
+
type: "string",
|
|
32480
|
+
description: "Subagent that owns the tests. When set and mutants survive, it receives a strengthen-tests task and the survivors are re-verified."
|
|
32481
|
+
},
|
|
32482
|
+
chaosWorktree: {
|
|
32483
|
+
anyOf: [{ type: "boolean" }, { type: "string", enum: ["auto", "required", "off"] }],
|
|
32484
|
+
description: "Worktree override for the chaos agent. Use 'off' when targets are uncommitted \u2014 a worktree from HEAD would not contain them."
|
|
32485
|
+
},
|
|
32486
|
+
timeoutMs: { type: "number", minimum: 1, description: "Per-task timeout for chaos/strengthen/rerun tasks." },
|
|
32487
|
+
reportOnly: {
|
|
32488
|
+
type: "boolean",
|
|
32489
|
+
description: "Skip the strengthen loop even when survivors exist. Default false."
|
|
32490
|
+
}
|
|
32491
|
+
},
|
|
32492
|
+
required: ["targets", "testCommand"],
|
|
32493
|
+
additionalProperties: false
|
|
32494
|
+
},
|
|
32495
|
+
async execute(input, ctx) {
|
|
32496
|
+
const i = normalizeMutationTestInput(input);
|
|
32497
|
+
const root = opts.projectRoot ?? ctx.projectRoot;
|
|
32498
|
+
const plan = buildPlan(i, root);
|
|
32499
|
+
if (plan.length === 0) {
|
|
32500
|
+
return {
|
|
32501
|
+
verdict: "inconclusive",
|
|
32502
|
+
passed: false,
|
|
32503
|
+
error: "No mutable sites found in the given targets (after comment/string filtering)."
|
|
32504
|
+
};
|
|
32505
|
+
}
|
|
32506
|
+
const chaosSubagentId = await director.spawn(
|
|
32507
|
+
makeChaosConfig(roster, i.chaosWorktree ?? "off")
|
|
32508
|
+
);
|
|
32509
|
+
const chaosTaskId = await director.assign({
|
|
32510
|
+
id: randomUUID14(),
|
|
32511
|
+
subagentId: chaosSubagentId,
|
|
32512
|
+
description: buildChaosTask(plan, i, 1, []),
|
|
32513
|
+
timeoutMs: i.timeoutMs
|
|
32514
|
+
});
|
|
32515
|
+
const [chaosResult] = await director.awaitTasks([chaosTaskId]);
|
|
32516
|
+
const pass1 = collectOutcomes(chaosResult, plan);
|
|
32517
|
+
const survivors = pass1.filter((m) => m.status === "survived");
|
|
32518
|
+
const maxAttempts = clamp(
|
|
32519
|
+
i.maxStrengthenAttempts ?? (i.repairSubagentId && !i.reportOnly ? DEFAULT_MAX_STRENGTHEN_ATTEMPTS : 0),
|
|
32520
|
+
0,
|
|
32521
|
+
5
|
|
32522
|
+
);
|
|
32523
|
+
const attempts = [];
|
|
32524
|
+
let current = survivors;
|
|
32525
|
+
while (current.length > 0 && attempts.length < maxAttempts && i.repairSubagentId) {
|
|
32526
|
+
const attemptNo = attempts.length + 1;
|
|
32527
|
+
const strengthenTaskId = await director.assign({
|
|
32528
|
+
id: randomUUID14(),
|
|
32529
|
+
subagentId: i.repairSubagentId,
|
|
32530
|
+
description: buildStrengthenTask(current, i, attemptNo),
|
|
32531
|
+
timeoutMs: i.timeoutMs
|
|
32532
|
+
});
|
|
32533
|
+
const [strengthenResult] = await director.awaitTasks([strengthenTaskId]);
|
|
32534
|
+
if (strengthenResult?.status !== "success") {
|
|
32535
|
+
attempts.push({
|
|
32536
|
+
attempt: attemptNo,
|
|
32537
|
+
survivorsBefore: current,
|
|
32538
|
+
strengthenResult: strengthenResult ? { taskId: strengthenResult.taskId, status: strengthenResult.status } : void 0,
|
|
32539
|
+
survivorsAfter: current,
|
|
32540
|
+
suspectedEquivalent: []
|
|
32541
|
+
});
|
|
32542
|
+
break;
|
|
32543
|
+
}
|
|
32544
|
+
const survivorPlan = plan.filter((p) => current.some((s) => s.id === p.id));
|
|
32545
|
+
const rerunSubagentId = await director.spawn(
|
|
32546
|
+
makeChaosConfig(roster, i.chaosWorktree ?? "off")
|
|
32547
|
+
);
|
|
32548
|
+
const rerunTaskId = await director.assign({
|
|
32549
|
+
id: randomUUID14(),
|
|
32550
|
+
subagentId: rerunSubagentId,
|
|
32551
|
+
description: buildChaosTask(survivorPlan, i, attemptNo + 1, current),
|
|
32552
|
+
timeoutMs: i.timeoutMs
|
|
32553
|
+
});
|
|
32554
|
+
const [rerunResult] = await director.awaitTasks([rerunTaskId]);
|
|
32555
|
+
const passN = collectOutcomes(rerunResult, survivorPlan);
|
|
32556
|
+
const stillSurviving = passN.filter((m) => m.status === "survived" || m.status === "skipped");
|
|
32557
|
+
attempts.push({
|
|
32558
|
+
attempt: attemptNo,
|
|
32559
|
+
survivorsBefore: current,
|
|
32560
|
+
strengthenResult: { taskId: strengthenResult.taskId, status: strengthenResult.status },
|
|
32561
|
+
rerunResult: { taskId: rerunTaskId, status: rerunResult?.status ?? "unknown" },
|
|
32562
|
+
survivorsAfter: stillSurviving,
|
|
32563
|
+
suspectedEquivalent: stillSurviving.filter((m) => current.some((c) => c.id === m.id)).map((m) => m.id)
|
|
32564
|
+
});
|
|
32565
|
+
current = stillSurviving.filter((m) => m.status === "survived");
|
|
32566
|
+
if (passN.every((m) => m.status === "skipped")) break;
|
|
32567
|
+
}
|
|
32568
|
+
const finalSurvivors = current;
|
|
32569
|
+
const verifiedCount = pass1.filter((m) => m.status !== "skipped").length;
|
|
32570
|
+
const skippedCount = pass1.filter((m) => m.status === "skipped").length;
|
|
32571
|
+
const score = plan.length === 0 ? 0 : pass1.filter((m) => m.status === "killed").length / plan.length;
|
|
32572
|
+
const verdict = verifiedCount === 0 ? "inconclusive" : finalSurvivors.length === 0 ? skippedCount > 0 ? "partial" : "pass" : score >= 0.8 ? "partial" : "fail";
|
|
32573
|
+
return {
|
|
32574
|
+
verdict,
|
|
32575
|
+
passed: verdict === "pass",
|
|
32576
|
+
mutationScore: Number.parseFloat(score.toFixed(3)),
|
|
32577
|
+
planned: plan.length,
|
|
32578
|
+
killed: pass1.filter((m) => m.status === "killed").length,
|
|
32579
|
+
survived: pass1.filter((m) => m.status === "survived").length,
|
|
32580
|
+
skipped: pass1.filter((m) => m.status === "skipped").length,
|
|
32581
|
+
finalSurvivors: finalSurvivors.map((m) => ({ id: m.id, file: m.file, kind: m.kind })),
|
|
32582
|
+
suspectedEquivalent: attempts.flatMap((a) => a.suspectedEquivalent),
|
|
32583
|
+
strengthenAttempts: attempts.length,
|
|
32584
|
+
attempts,
|
|
32585
|
+
chaosTaskId,
|
|
32586
|
+
nextAction: finalSurvivors.length === 0 ? "accept" : attempts.length >= maxAttempts && i.repairSubagentId ? "manual_review_survivors" : "strengthen_tests"
|
|
32587
|
+
};
|
|
32588
|
+
}
|
|
32589
|
+
};
|
|
32590
|
+
}
|
|
32591
|
+
function normalizeMutationTestInput(input) {
|
|
32592
|
+
const raw = input ?? {};
|
|
32593
|
+
const targets = stringArray2(raw["targets"]) ?? [];
|
|
32594
|
+
const testCommand = typeof raw["testCommand"] === "string" ? raw["testCommand"].trim() : "";
|
|
32595
|
+
return {
|
|
32596
|
+
targets: targets.filter(Boolean),
|
|
32597
|
+
testCommand,
|
|
32598
|
+
cwd: typeof raw["cwd"] === "string" && raw["cwd"].trim() ? raw["cwd"].trim() : void 0,
|
|
32599
|
+
maxPerFile: typeof raw["maxPerFile"] === "number" ? raw["maxPerFile"] : void 0,
|
|
32600
|
+
maxStrengthenAttempts: typeof raw["maxStrengthenAttempts"] === "number" ? raw["maxStrengthenAttempts"] : void 0,
|
|
32601
|
+
repairSubagentId: typeof raw["repairSubagentId"] === "string" && raw["repairSubagentId"].trim() ? raw["repairSubagentId"].trim() : void 0,
|
|
32602
|
+
chaosWorktree: raw["chaosWorktree"] ?? void 0,
|
|
32603
|
+
timeoutMs: typeof raw["timeoutMs"] === "number" ? raw["timeoutMs"] : void 0,
|
|
32604
|
+
reportOnly: raw["reportOnly"] === true
|
|
32605
|
+
};
|
|
32606
|
+
}
|
|
32607
|
+
function clamp(n, lo, hi) {
|
|
32608
|
+
return Math.min(hi, Math.max(lo, n));
|
|
32609
|
+
}
|
|
32610
|
+
function buildPlan(i, projectRoot) {
|
|
32611
|
+
const plan = [];
|
|
32612
|
+
for (const target of i.targets) {
|
|
32613
|
+
const abs = isAbsolute9(target) ? target : join40(projectRoot ?? process.cwd(), target);
|
|
32614
|
+
let source;
|
|
32615
|
+
try {
|
|
32616
|
+
source = readFileSync19(abs, "utf8");
|
|
32617
|
+
} catch {
|
|
32618
|
+
continue;
|
|
32619
|
+
}
|
|
32620
|
+
plan.push(...planMutations(target, source, { maxPerFile: i.maxPerFile ?? DEFAULT_MAX_PER_FILE }));
|
|
32621
|
+
}
|
|
32622
|
+
return plan;
|
|
32623
|
+
}
|
|
32624
|
+
function makeChaosConfig(roster, worktree) {
|
|
32625
|
+
const base = roster?.[CHAOS_ROLE] ?? getAgentDefinition(CHAOS_ROLE)?.config ?? { name: "Chaos Monkey", role: CHAOS_ROLE };
|
|
32626
|
+
return { ...instantiateRosterConfig(CHAOS_ROLE, base), worktree };
|
|
32627
|
+
}
|
|
32628
|
+
function buildChaosTask(plan, i, pass, priorSurvivors) {
|
|
32629
|
+
const mutants = plan.map(
|
|
32630
|
+
(m) => `- ${m.id} | ${m.file}:${m.line}:${m.column} | ${m.kind} | "${m.original}" -> "${m.replacement}"`
|
|
32631
|
+
).join("\n");
|
|
32632
|
+
const prior = priorSurvivors.length > 0 ? `
|
|
32633
|
+
These mutants survived a previous pass (pass ${pass - 1}) \u2014 re-verify them against the STRENGTHENED tests:
|
|
32634
|
+
${priorSurvivors.map((s) => `- ${s.id} (${s.kind} @ ${s.file}:${s.line})`).join("\n")}` : "";
|
|
32635
|
+
return [
|
|
32636
|
+
"Execute this deterministic mutation plan against the current checkout.",
|
|
32637
|
+
"",
|
|
32638
|
+
"For each mutant, in order:",
|
|
32639
|
+
"1. Apply ONLY that mutation at its exact (file, line, column).",
|
|
32640
|
+
`2. Run the test command: ${i.testCommand}${i.cwd ? ` (cwd: ${i.cwd})` : ""}`,
|
|
32641
|
+
"3. Record killed (tests failed \u2014 quote first failing assertion) or survived (suite green).",
|
|
32642
|
+
"4. Restore the file byte-for-byte before the next mutant.",
|
|
32643
|
+
"",
|
|
32644
|
+
"Mutants:",
|
|
32645
|
+
mutants,
|
|
32646
|
+
prior,
|
|
32647
|
+
"",
|
|
32648
|
+
"Rules: one mutation at a time; never stack; if the anchored token no longer matches, mark skipped with the drift as evidence; do not fix or refactor anything; stay inside the plan.",
|
|
32649
|
+
"Finish with submit_result, then repeat the same JSON as your final text."
|
|
32650
|
+
].join("\n");
|
|
32651
|
+
}
|
|
32652
|
+
function buildStrengthenTask(survivors, i, attempt) {
|
|
32653
|
+
return [
|
|
32654
|
+
`Strengthen the tests so these SURVIVING mutants die (attempt ${attempt}).`,
|
|
32655
|
+
"",
|
|
32656
|
+
"Each survivor below was a deliberate sabotage of production code that the current suite did NOT catch:",
|
|
32657
|
+
...survivors.map((s) => `- ${s.id} | ${s.file}:${s.line} | ${s.kind}${s.evidence ? ` | ${s.evidence}` : ""}`),
|
|
32658
|
+
"",
|
|
32659
|
+
`Test command that must fail under each mutant: ${i.testCommand}`,
|
|
32660
|
+
"",
|
|
32661
|
+
"For each survivor add or tighten exactly one assertion that pins the sabotaged boundary/behavior. Do not change production code. Do not weaken other tests. Run the suite green on clean code before finishing."
|
|
32662
|
+
].join("\n");
|
|
32663
|
+
}
|
|
32664
|
+
function collectOutcomes(result, plan) {
|
|
32665
|
+
const fromText = parseTextOutcomes(result);
|
|
32666
|
+
if (fromText.length > 0) {
|
|
32667
|
+
const planned = new Set(plan.map((p) => p.id));
|
|
32668
|
+
const matched = fromText.filter((m) => planned.has(m.id));
|
|
32669
|
+
if (matched.length > 0) return matched;
|
|
32670
|
+
}
|
|
32671
|
+
return plan.map((p) => ({
|
|
32672
|
+
id: p.id,
|
|
32673
|
+
file: p.file,
|
|
32674
|
+
line: p.line,
|
|
32675
|
+
kind: p.kind,
|
|
32676
|
+
status: "skipped",
|
|
32677
|
+
evidence: result ? `chaos task ended ${result.status}` : "chaos task produced no result"
|
|
32678
|
+
}));
|
|
32679
|
+
}
|
|
32680
|
+
function parseTextOutcomes(result) {
|
|
32681
|
+
const text2 = typeof result?.result === "string" ? result.result : void 0;
|
|
32682
|
+
if (!text2) return [];
|
|
32683
|
+
const parsed = parseMutationReport(text2);
|
|
32684
|
+
if (!parsed) return [];
|
|
32685
|
+
return parsed.mutants.map((m) => ({
|
|
32686
|
+
id: m.id,
|
|
32687
|
+
file: m.file,
|
|
32688
|
+
line: m.line,
|
|
32689
|
+
kind: m.kind,
|
|
32690
|
+
status: m.status,
|
|
32691
|
+
evidence: m.evidence
|
|
32692
|
+
}));
|
|
32693
|
+
}
|
|
32694
|
+
|
|
32139
32695
|
// src/coordination/director-tools.ts
|
|
32140
32696
|
function makeSpawnTool(director, roster) {
|
|
32141
32697
|
const dispatchCatalog = () => {
|
|
@@ -32428,7 +32984,7 @@ function makeKanbanQueueTool(director, roster) {
|
|
|
32428
32984
|
try {
|
|
32429
32985
|
const config = buildKanbanSubagentConfig(claim.task, i, roster, instantiateRosterConfig);
|
|
32430
32986
|
subagentId = await director.spawn(config);
|
|
32431
|
-
const dispatchTaskId =
|
|
32987
|
+
const dispatchTaskId = randomUUID15();
|
|
32432
32988
|
const taskSpec = {
|
|
32433
32989
|
id: dispatchTaskId,
|
|
32434
32990
|
subagentId,
|
|
@@ -32704,6 +33260,7 @@ function buildDirectorToolset(director, roster) {
|
|
|
32704
33260
|
makeAskResultTool(director),
|
|
32705
33261
|
makeRollUpTool(director),
|
|
32706
33262
|
makeQualityGateTool(director, roster),
|
|
33263
|
+
makeMutationTestTool(director, roster),
|
|
32707
33264
|
makeTerminateTool(director),
|
|
32708
33265
|
makeTerminateAllTool(director),
|
|
32709
33266
|
makeFleetTool(director),
|
|
@@ -32790,7 +33347,7 @@ import * as fsp29 from "node:fs/promises";
|
|
|
32790
33347
|
import * as path63 from "node:path";
|
|
32791
33348
|
|
|
32792
33349
|
// src/storage/session-store.ts
|
|
32793
|
-
import { randomUUID as
|
|
33350
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
32794
33351
|
import * as fsp28 from "node:fs/promises";
|
|
32795
33352
|
import * as path62 from "node:path";
|
|
32796
33353
|
init_client();
|
|
@@ -33961,7 +34518,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
33961
34518
|
// src/storage/session-checkpoint-cas.ts
|
|
33962
34519
|
init_atomic_write();
|
|
33963
34520
|
import { spawn as spawn5 } from "node:child_process";
|
|
33964
|
-
import { createHash as createHash18, randomUUID as
|
|
34521
|
+
import { createHash as createHash18, randomUUID as randomUUID16 } from "node:crypto";
|
|
33965
34522
|
import * as fsp15 from "node:fs/promises";
|
|
33966
34523
|
import * as path54 from "node:path";
|
|
33967
34524
|
init_error();
|
|
@@ -34199,7 +34756,7 @@ var SessionCheckpointCas = class {
|
|
|
34199
34756
|
}
|
|
34200
34757
|
const temp = path54.join(
|
|
34201
34758
|
path54.dirname(target),
|
|
34202
|
-
`.${path54.basename(target)}.${process.pid}.${
|
|
34759
|
+
`.${path54.basename(target)}.${process.pid}.${randomUUID16()}.tmp`
|
|
34203
34760
|
);
|
|
34204
34761
|
let handle;
|
|
34205
34762
|
try {
|
|
@@ -36007,7 +36564,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
36007
36564
|
onAppend;
|
|
36008
36565
|
onAppendBatch;
|
|
36009
36566
|
catalogClient;
|
|
36010
|
-
maintenanceHolderId =
|
|
36567
|
+
maintenanceHolderId = randomUUID17();
|
|
36011
36568
|
_loadCache = /* @__PURE__ */ new Map();
|
|
36012
36569
|
loadCache = new SessionLoadCache(this._loadCache);
|
|
36013
36570
|
_indexCache = null;
|
|
@@ -36699,7 +37256,7 @@ async function readDirectorSubagentSession(args) {
|
|
|
36699
37256
|
}
|
|
36700
37257
|
|
|
36701
37258
|
// src/core/fallback-model.ts
|
|
36702
|
-
import { randomUUID as
|
|
37259
|
+
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
36703
37260
|
|
|
36704
37261
|
// src/types/provider.ts
|
|
36705
37262
|
init_errors();
|
|
@@ -36709,6 +37266,18 @@ var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not eno
|
|
|
36709
37266
|
var ROUTE_SCOPED_QUOTA_RE = /\b(?:for|on)\s+(?:(?:this|the)\s+)?(?:route|model)\b|\b(?:route|model)(?:[-_\s]+[\w.-]+)?[-_\s]*(?:quota|limit)\b|\b(?:quota|limit).{0,24}\b(?:for|on)\s+(?:(?:this|the)\s+)?(?:route|model)\b/i;
|
|
36710
37267
|
|
|
36711
37268
|
// src/types/provider.ts
|
|
37269
|
+
var REASONING_EFFORT_LEVELS = [
|
|
37270
|
+
"none",
|
|
37271
|
+
"minimal",
|
|
37272
|
+
"low",
|
|
37273
|
+
"medium",
|
|
37274
|
+
"high",
|
|
37275
|
+
"xhigh",
|
|
37276
|
+
"max"
|
|
37277
|
+
];
|
|
37278
|
+
function isReasoningEffort(value) {
|
|
37279
|
+
return typeof value === "string" && REASONING_EFFORT_LEVELS.includes(value);
|
|
37280
|
+
}
|
|
36712
37281
|
function effectiveInputTokens(usage) {
|
|
36713
37282
|
return usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
|
|
36714
37283
|
}
|
|
@@ -37731,7 +38300,7 @@ function createFallbackModelExtension(deps) {
|
|
|
37731
38300
|
let gateRequestId;
|
|
37732
38301
|
const configuredGateSeconds = cfg.fallbackGateSeconds ?? deps.fallbackGateSeconds;
|
|
37733
38302
|
if (configuredGateSeconds !== 0 && deps.fallbackGate && usableChain.length > 0) {
|
|
37734
|
-
gateRequestId =
|
|
38303
|
+
gateRequestId = randomUUID18();
|
|
37735
38304
|
const autoSwitchSeconds = Math.max(1, configuredGateSeconds ?? 7);
|
|
37736
38305
|
const gateCandidates = usableChain.map((e) => ({
|
|
37737
38306
|
providerId: e.providerId,
|
|
@@ -38703,7 +39272,7 @@ function hashStr(s) {
|
|
|
38703
39272
|
}
|
|
38704
39273
|
|
|
38705
39274
|
// src/coordination/multi-agent-coordinator.ts
|
|
38706
|
-
import { randomUUID as
|
|
39275
|
+
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
38707
39276
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
38708
39277
|
|
|
38709
39278
|
// src/coordination/coordinator/error-classifier.ts
|
|
@@ -38828,6 +39397,20 @@ var EXPLORE_COMPANION_AGENT = {
|
|
|
38828
39397
|
textStream: "silent",
|
|
38829
39398
|
toolStream: "silent"
|
|
38830
39399
|
};
|
|
39400
|
+
var CHAOS_MONKEY_AGENT = {
|
|
39401
|
+
...defineAgent("chaos-monkey", "Chaos Monkey"),
|
|
39402
|
+
tools: [...TOOLS.build],
|
|
39403
|
+
skillNames: ["testing", "typescript-strict"],
|
|
39404
|
+
spawnBudgetExempt: true,
|
|
39405
|
+
// Follow fleet worktree policy (NOT 'required'): mutation targets are
|
|
39406
|
+
// often freshly written and uncommitted — a worktree spawned from HEAD
|
|
39407
|
+
// would not contain them and every mutant would drift. Callers pass
|
|
39408
|
+
// `worktree: 'off'` in the mutation_test input for uncommitted targets.
|
|
39409
|
+
worktree: "auto",
|
|
39410
|
+
// Report travels via submit_result + final text, not the leader's stream.
|
|
39411
|
+
textStream: "silent",
|
|
39412
|
+
toolStream: "silent"
|
|
39413
|
+
};
|
|
38831
39414
|
var CRITIC_AGENT = defineAgent("critic", "Critic");
|
|
38832
39415
|
var GENERIC_AGENT = defineAgent("generic", "Generic Project Agent");
|
|
38833
39416
|
function withDispatchMetadata(definition) {
|
|
@@ -38847,6 +39430,7 @@ var FLEET_ROSTER = {
|
|
|
38847
39430
|
generic: GENERIC_AGENT,
|
|
38848
39431
|
"shadow-agent": SHADOW_AGENT,
|
|
38849
39432
|
"explore-companion": EXPLORE_COMPANION_AGENT,
|
|
39433
|
+
"chaos-monkey": CHAOS_MONKEY_AGENT,
|
|
38850
39434
|
...Object.fromEntries(
|
|
38851
39435
|
ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, withDispatchMetadata(d)])
|
|
38852
39436
|
)
|
|
@@ -38877,6 +39461,16 @@ var FLEET_ROSTER_BUDGETS = {
|
|
|
38877
39461
|
maxTokens: 96e3,
|
|
38878
39462
|
maxCostUsd: 0.5
|
|
38879
39463
|
},
|
|
39464
|
+
"chaos-monkey": {
|
|
39465
|
+
// A mutation pass is many short apply/run/restore cycles — per-mutant
|
|
39466
|
+
// work is tiny, but a large plan (25 mutants/file × N files) needs
|
|
39467
|
+
// headroom. Idle-based reaping covers a stalled pass.
|
|
39468
|
+
idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
|
|
39469
|
+
maxIterations: 2e3,
|
|
39470
|
+
maxToolCalls: 6e3,
|
|
39471
|
+
maxTokens: 96e3,
|
|
39472
|
+
maxCostUsd: 0.5
|
|
39473
|
+
},
|
|
38880
39474
|
...Object.fromEntries(
|
|
38881
39475
|
ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.budget])
|
|
38882
39476
|
)
|
|
@@ -38939,7 +39533,8 @@ async function executeSubagentWithTimeout({
|
|
|
38939
39533
|
budget,
|
|
38940
39534
|
preemptFraction = TIMEOUT_PREEMPT_FRACTION,
|
|
38941
39535
|
abortSubagent,
|
|
38942
|
-
currentSessionId
|
|
39536
|
+
currentSessionId,
|
|
39537
|
+
gracefulFinish
|
|
38943
39538
|
}) {
|
|
38944
39539
|
const initialTimeoutMs = budget.limits.timeoutMs;
|
|
38945
39540
|
const idleLimitMs = budget.limits.idleTimeoutMs;
|
|
@@ -38970,9 +39565,17 @@ async function executeSubagentWithTimeout({
|
|
|
38970
39565
|
const scheduleNext = () => {
|
|
38971
39566
|
const wallLimit = budget.limits.timeoutMs ?? initialTimeoutMs;
|
|
38972
39567
|
const wallRemaining = initialTimeoutMs === void 0 ? Number.POSITIVE_INFINITY : wallLimit - (Date.now() - start);
|
|
38973
|
-
const idleRemaining = idleLimitMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();
|
|
38974
|
-
const preemptRemaining = initialTimeoutMs === void 0 || preemptedCeiling === wallLimit ? Number.POSITIVE_INFINITY : wallLimit * preemptFraction - (Date.now() - start);
|
|
38975
|
-
|
|
39568
|
+
const idleRemaining = idleLimitMs === void 0 || gracefulFinish !== void 0 && initialTimeoutMs !== void 0 ? Number.POSITIVE_INFINITY : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();
|
|
39569
|
+
const preemptRemaining = initialTimeoutMs === void 0 || preemptedCeiling === wallLimit || gracefulFinish !== void 0 ? Number.POSITIVE_INFINITY : wallLimit * preemptFraction - (Date.now() - start);
|
|
39570
|
+
const next = Math.min(wallRemaining, idleRemaining, preemptRemaining);
|
|
39571
|
+
if (!Number.isFinite(next)) {
|
|
39572
|
+
if (timer) {
|
|
39573
|
+
clearTimeout(timer);
|
|
39574
|
+
timer = null;
|
|
39575
|
+
}
|
|
39576
|
+
return;
|
|
39577
|
+
}
|
|
39578
|
+
armFor(Math.max(25, next));
|
|
38976
39579
|
};
|
|
38977
39580
|
const negotiateTimeout = async (used, limit) => {
|
|
38978
39581
|
const handler = budget.onThreshold;
|
|
@@ -39021,6 +39624,10 @@ async function executeSubagentWithTimeout({
|
|
|
39021
39624
|
const wallExceeded = wallLimit !== void 0 && elapsed2 >= wallLimit;
|
|
39022
39625
|
const idleExceeded = idleLimit !== void 0 && budget.idleMs() >= idleLimit;
|
|
39023
39626
|
if (idleExceeded && !wallExceeded) {
|
|
39627
|
+
if (gracefulFinish !== void 0 && initialTimeoutMs !== void 0) {
|
|
39628
|
+
scheduleNext();
|
|
39629
|
+
return;
|
|
39630
|
+
}
|
|
39024
39631
|
const sessionId = currentSessionId();
|
|
39025
39632
|
budget._events?.emit("budget.threshold_reached", {
|
|
39026
39633
|
...sessionId ? { sessionId } : {},
|
|
@@ -39037,7 +39644,7 @@ async function executeSubagentWithTimeout({
|
|
|
39037
39644
|
reject(new BudgetExceededError("idle_timeout", idleLimit ?? 0, budget.idleMs()));
|
|
39038
39645
|
return;
|
|
39039
39646
|
}
|
|
39040
|
-
if (wallLimit !== void 0 && !wallExceeded && budget.onThreshold && preemptState === "active" /* ACTIVE */ && elapsed2 >= wallLimit * preemptFraction) {
|
|
39647
|
+
if (wallLimit !== void 0 && !wallExceeded && gracefulFinish === void 0 && budget.onThreshold && preemptState === "active" /* ACTIVE */ && elapsed2 >= wallLimit * preemptFraction) {
|
|
39041
39648
|
const activityTs = Date.now() - budget.idleMs();
|
|
39042
39649
|
if (activityTs <= lastGrantActivityTs) {
|
|
39043
39650
|
preemptState = "locked" /* LOCKED */;
|
|
@@ -39071,6 +39678,22 @@ async function executeSubagentWithTimeout({
|
|
|
39071
39678
|
return;
|
|
39072
39679
|
}
|
|
39073
39680
|
const limit = wallLimit ?? 0;
|
|
39681
|
+
if (gracefulFinish !== void 0) {
|
|
39682
|
+
if (!budget.graceGranted) {
|
|
39683
|
+
const reason = `wall-clock budget of ${Math.round(limit / 1e3)}s reached`;
|
|
39684
|
+
if (budget.notifyFinish(reason, { graceMs: gracefulFinish.graceMs })) {
|
|
39685
|
+
scheduleNext();
|
|
39686
|
+
return;
|
|
39687
|
+
}
|
|
39688
|
+
abortSubagent(ctx.subagentId);
|
|
39689
|
+
reject(new BudgetExceededError("timeout", limit, elapsed2));
|
|
39690
|
+
return;
|
|
39691
|
+
} else {
|
|
39692
|
+
abortSubagent(ctx.subagentId);
|
|
39693
|
+
reject(new BudgetExceededError("timeout", limit, elapsed2));
|
|
39694
|
+
return;
|
|
39695
|
+
}
|
|
39696
|
+
}
|
|
39074
39697
|
if (!budget.onThreshold) {
|
|
39075
39698
|
abortSubagent(ctx.subagentId);
|
|
39076
39699
|
reject(new BudgetExceededError("timeout", limit, elapsed2));
|
|
@@ -39218,7 +39841,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39218
39841
|
return { ...subagent, name: display };
|
|
39219
39842
|
}
|
|
39220
39843
|
async spawn(subagent) {
|
|
39221
|
-
const id = subagent.id ||
|
|
39844
|
+
const id = subagent.id || randomUUID19();
|
|
39222
39845
|
const cfg = this.withNickname(subagent, id);
|
|
39223
39846
|
if (this.subagents.has(id)) {
|
|
39224
39847
|
throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
|
|
@@ -39455,6 +40078,32 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39455
40078
|
completeTask(result) {
|
|
39456
40079
|
this.recordCompletion(result);
|
|
39457
40080
|
}
|
|
40081
|
+
/**
|
|
40082
|
+
* Ask every RUNNING subagent that opted into `gracefulFinish` to finish its
|
|
40083
|
+
* task in its own turn (see coordination/subagent-finish.ts). This is the
|
|
40084
|
+
* leader-side entry point for "the leader agent has finished": it delivers
|
|
40085
|
+
* an in-band notification between tool batches — never an interrupt, never
|
|
40086
|
+
* an abort. Each notified subagent keeps its existing time budget and
|
|
40087
|
+
* accelerates; the watchdog still bounds the maximum lifetime.
|
|
40088
|
+
*
|
|
40089
|
+
* Subagents without the policy opted in are deliberately untouched — their
|
|
40090
|
+
* lifecycle remains the legacy watchdog contract.
|
|
40091
|
+
*
|
|
40092
|
+
* Returns the number of subagents actually notified.
|
|
40093
|
+
*/
|
|
40094
|
+
requestFinish(reason) {
|
|
40095
|
+
let notified = 0;
|
|
40096
|
+
for (const subagent of this.subagents.values()) {
|
|
40097
|
+
if (subagent.status !== "running") continue;
|
|
40098
|
+
if (!resolveGracefulFinish(subagent.config)) continue;
|
|
40099
|
+
const budget = subagent.activeBudget;
|
|
40100
|
+
if (!budget) continue;
|
|
40101
|
+
const usage = budget.usage();
|
|
40102
|
+
if (usage.iterations === 0 && usage.toolCalls === 0) continue;
|
|
40103
|
+
if (budget.notifyFinish(reason)) notified++;
|
|
40104
|
+
}
|
|
40105
|
+
return notified;
|
|
40106
|
+
}
|
|
39458
40107
|
// --- internal dispatching ---------------------------------------------
|
|
39459
40108
|
tryDispatchNext() {
|
|
39460
40109
|
while (this.canDispatch()) {
|
|
@@ -39628,7 +40277,14 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39628
40277
|
idleTimeoutMs: rawIdleTimeoutMs ?? this.config.defaultBudget?.idleTimeoutMs ?? configWithRosterDefaults.idleTimeoutMs
|
|
39629
40278
|
},
|
|
39630
40279
|
"auto",
|
|
39631
|
-
{
|
|
40280
|
+
{
|
|
40281
|
+
sessionId: () => this.currentSessionId(),
|
|
40282
|
+
subagentId,
|
|
40283
|
+
// Graceful-finish runs own wall-clock enforcement to the watchdog so
|
|
40284
|
+
// the notify-then-bound lifecycle cannot be raced by tool.progress
|
|
40285
|
+
// heartbeats calling checkTimeout() (see subagent-budget.ts).
|
|
40286
|
+
...resolveGracefulFinish(subagent.config) ? { wallClockWatchdogOwned: true } : {}
|
|
40287
|
+
}
|
|
39632
40288
|
);
|
|
39633
40289
|
subagent.activeBudget = budget;
|
|
39634
40290
|
if (!this.runner) {
|
|
@@ -39661,7 +40317,8 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39661
40317
|
task,
|
|
39662
40318
|
runCtx,
|
|
39663
40319
|
budget,
|
|
39664
|
-
subagent.config.preemptFraction
|
|
40320
|
+
subagent.config.preemptFraction,
|
|
40321
|
+
resolveGracefulFinish(subagent.config)
|
|
39665
40322
|
);
|
|
39666
40323
|
result = {
|
|
39667
40324
|
subagentId,
|
|
@@ -39691,13 +40348,14 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39691
40348
|
}
|
|
39692
40349
|
this.recordCompletion(result);
|
|
39693
40350
|
}
|
|
39694
|
-
async executeWithTimeout(runner, task, ctx, budget, preemptFraction) {
|
|
40351
|
+
async executeWithTimeout(runner, task, ctx, budget, preemptFraction, gracefulFinish) {
|
|
39695
40352
|
return executeSubagentWithTimeout({
|
|
39696
40353
|
runner,
|
|
39697
40354
|
task,
|
|
39698
40355
|
ctx,
|
|
39699
40356
|
budget,
|
|
39700
40357
|
preemptFraction,
|
|
40358
|
+
gracefulFinish,
|
|
39701
40359
|
abortSubagent: (subagentId) => this.subagents.get(subagentId)?.abortController.abort(),
|
|
39702
40360
|
currentSessionId: () => this.currentSessionId()
|
|
39703
40361
|
});
|
|
@@ -40104,7 +40762,7 @@ var Director = class _Director {
|
|
|
40104
40762
|
sessionProvider;
|
|
40105
40763
|
sessionModel;
|
|
40106
40764
|
constructor(opts) {
|
|
40107
|
-
this.id = opts.config.coordinatorId ||
|
|
40765
|
+
this.id = opts.config.coordinatorId || randomUUID20();
|
|
40108
40766
|
this.manifestPath = opts.manifestPath;
|
|
40109
40767
|
this.roster = opts.roster;
|
|
40110
40768
|
this.directorPreamble = opts.directorPreamble ?? DEFAULT_DIRECTOR_PREAMBLE;
|
|
@@ -40311,6 +40969,17 @@ var Director = class _Director {
|
|
|
40311
40969
|
isWorkComplete() {
|
|
40312
40970
|
return this.workCompleteFlag;
|
|
40313
40971
|
}
|
|
40972
|
+
/**
|
|
40973
|
+
* Ask every running background subagent that opted into `gracefulFinish`
|
|
40974
|
+
* to finish its task in its own turn. In-band notification between tool
|
|
40975
|
+
* batches — no interrupt, no abort; each subagent keeps its time budget and
|
|
40976
|
+
* accelerates. Session shutdown calls this before draining Chimera work so
|
|
40977
|
+
* the post-session reviewer is nudged to complete rather than killed.
|
|
40978
|
+
* Returns the number of subagents notified.
|
|
40979
|
+
*/
|
|
40980
|
+
requestFinish(reason) {
|
|
40981
|
+
return this.coordinator.requestFinish(reason);
|
|
40982
|
+
}
|
|
40314
40983
|
setLeaderBtwNote(note) {
|
|
40315
40984
|
return this.btwNotes.add(note);
|
|
40316
40985
|
}
|
|
@@ -40387,7 +41056,7 @@ var Director = class _Director {
|
|
|
40387
41056
|
);
|
|
40388
41057
|
}
|
|
40389
41058
|
const msg = {
|
|
40390
|
-
id:
|
|
41059
|
+
id: randomUUID20(),
|
|
40391
41060
|
type: "task",
|
|
40392
41061
|
from: this.id,
|
|
40393
41062
|
to: subagentId,
|
|
@@ -40641,7 +41310,7 @@ var Director = class _Director {
|
|
|
40641
41310
|
};
|
|
40642
41311
|
|
|
40643
41312
|
// src/coordination/fleet-manager.ts
|
|
40644
|
-
import { randomUUID as
|
|
41313
|
+
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
40645
41314
|
import * as fsp31 from "node:fs/promises";
|
|
40646
41315
|
import * as path64 from "node:path";
|
|
40647
41316
|
init_atomic_write();
|
|
@@ -40709,7 +41378,7 @@ var FleetManager = class {
|
|
|
40709
41378
|
maxContext;
|
|
40710
41379
|
constructor(opts = {}) {
|
|
40711
41380
|
this.manifestPath = opts.manifestPath;
|
|
40712
|
-
this.directorRunId = opts.directorRunId ??
|
|
41381
|
+
this.directorRunId = opts.directorRunId ?? randomUUID21();
|
|
40713
41382
|
this.maxSpawns = opts.maxSpawns ?? Number.POSITIVE_INFINITY;
|
|
40714
41383
|
this.maxSpawnDepth = resolveMaxSpawnDepth(opts.maxSpawnDepth);
|
|
40715
41384
|
this.spawnDepth = opts.spawnDepth ?? 0;
|
|
@@ -42761,7 +43430,7 @@ function makeFleetStatusTool(opts = {}) {
|
|
|
42761
43430
|
}
|
|
42762
43431
|
|
|
42763
43432
|
// src/coordination/fleet-supervisor.ts
|
|
42764
|
-
import { randomUUID as
|
|
43433
|
+
import { randomUUID as randomUUID22 } from "node:crypto";
|
|
42765
43434
|
var COLLAB_ID_PREFIXES2 = ["bug-hunter-", "refactor-planner-", "critic-"];
|
|
42766
43435
|
var DEFAULTS = {
|
|
42767
43436
|
intervalMs: 2e4,
|
|
@@ -43039,7 +43708,7 @@ var FleetSupervisor = class {
|
|
|
43039
43708
|
*/
|
|
43040
43709
|
async decide(question, context, options, risk) {
|
|
43041
43710
|
const request = {
|
|
43042
|
-
id: `fleetsup-${
|
|
43711
|
+
id: `fleetsup-${randomUUID22()}`,
|
|
43043
43712
|
sessionId: this.opts.sessionId?.(),
|
|
43044
43713
|
source: "system",
|
|
43045
43714
|
question,
|
|
@@ -43435,7 +44104,7 @@ function attachAutoExtend(events, policy = {}) {
|
|
|
43435
44104
|
}
|
|
43436
44105
|
|
|
43437
44106
|
// src/coordination/delegate-tool.ts
|
|
43438
|
-
import { randomUUID as
|
|
44107
|
+
import { randomUUID as randomUUID23 } from "node:crypto";
|
|
43439
44108
|
import * as fsp32 from "node:fs/promises";
|
|
43440
44109
|
import * as path69 from "node:path";
|
|
43441
44110
|
init_error();
|
|
@@ -43642,7 +44311,7 @@ function createDelegateTool(opts) {
|
|
|
43642
44311
|
}
|
|
43643
44312
|
const description = delegatedTask;
|
|
43644
44313
|
const taskId = await dir.assign({
|
|
43645
|
-
id:
|
|
44314
|
+
id: randomUUID23(),
|
|
43646
44315
|
description,
|
|
43647
44316
|
subagentId
|
|
43648
44317
|
});
|
|
@@ -43863,7 +44532,7 @@ async function awaitDelegateAttempt(director, subagentId, taskId, timeoutMs, abo
|
|
|
43863
44532
|
function freshHandoffConfig(cfg, role, handoffCount) {
|
|
43864
44533
|
return {
|
|
43865
44534
|
...cfg,
|
|
43866
|
-
id: role ? `${role}-${
|
|
44535
|
+
id: role ? `${role}-${randomUUID23().slice(0, 8)}` : `${cfg.name.toLowerCase().replace(/[^a-z0-9]+/g, "-") || "subagent"}-handoff-${handoffCount}-${randomUUID23().slice(0, 6)}`
|
|
43867
44536
|
};
|
|
43868
44537
|
}
|
|
43869
44538
|
function continuationFor(result, partial, config) {
|
|
@@ -43923,7 +44592,7 @@ function instantiateRosterConfig2(role, base, requestedTimeoutMs, defaultTimeout
|
|
|
43923
44592
|
timeoutMs: requestedTimeoutMs === void 0 ? rosterTimeoutMs ?? defaultTimeoutMs : void 0,
|
|
43924
44593
|
// Give each spawn a fresh id so parallel or repeated delegates
|
|
43925
44594
|
// can use the same role safely.
|
|
43926
|
-
id: `${role}-${
|
|
44595
|
+
id: `${role}-${randomUUID23().slice(0, 8)}`
|
|
43927
44596
|
};
|
|
43928
44597
|
}
|
|
43929
44598
|
function hintForKind(kind, retryable, backoffMs, partial) {
|
|
@@ -44049,7 +44718,7 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
44049
44718
|
}
|
|
44050
44719
|
|
|
44051
44720
|
// src/coordination/explore-companion.ts
|
|
44052
|
-
import { randomUUID as
|
|
44721
|
+
import { randomUUID as randomUUID24 } from "node:crypto";
|
|
44053
44722
|
var DEFAULT_EXPLORE_COMPANION_AGENT_ID = "explore-companion";
|
|
44054
44723
|
var DEFAULT_PROBE_COOLDOWN_MS = 12e4;
|
|
44055
44724
|
var DEFAULT_MAX_PENDING_PROBES = 8;
|
|
@@ -44235,7 +44904,7 @@ var ExploreCompanion = class {
|
|
|
44235
44904
|
if (e.ok && this.cfg.signals.editUnreadFile && this.cfg.fileEditTools.has(tool) && path131) {
|
|
44236
44905
|
if (!this.readSet.has(path131)) {
|
|
44237
44906
|
this.engage({
|
|
44238
|
-
id:
|
|
44907
|
+
id: randomUUID24(),
|
|
44239
44908
|
probe: `Map file ${path131}: role, exports, dependencies, and callers \u2014 the leader is about to edit it.`,
|
|
44240
44909
|
hint: { file: path131 },
|
|
44241
44910
|
context: `Leader edited ${path131} without reading it first.`,
|
|
@@ -44250,7 +44919,7 @@ var ExploreCompanion = class {
|
|
|
44250
44919
|
if (!this.readSet.has(path131)) {
|
|
44251
44920
|
this.readSet.add(path131);
|
|
44252
44921
|
this.engage({
|
|
44253
|
-
id:
|
|
44922
|
+
id: randomUUID24(),
|
|
44254
44923
|
probe: `Skeleton + callers + dependents of ${path131}: what it exports, who imports it, and how it fits the feature flow.`,
|
|
44255
44924
|
hint: { file: path131 },
|
|
44256
44925
|
context: `Leader read unfamiliar file ${path131}.`,
|
|
@@ -44265,7 +44934,7 @@ var ExploreCompanion = class {
|
|
|
44265
44934
|
const input = e.input ?? {};
|
|
44266
44935
|
const query = typeof input["query"] === "string" ? input["query"] : typeof input["pattern"] === "string" ? input["pattern"] : "";
|
|
44267
44936
|
this.engage({
|
|
44268
|
-
id:
|
|
44937
|
+
id: randomUUID24(),
|
|
44269
44938
|
probe: query ? `Locate "${query}" \u2014 the leader's ${e.name} returned no hits. Try synonyms, a refreshed index, and lexical fallbacks.` : `The leader's ${e.name} returned no results. Find where the concept actually lives.`,
|
|
44270
44939
|
hint: query ? { symbol: query } : void 0,
|
|
44271
44940
|
context: `${e.name} for "${query}" returned zero results.`,
|
|
@@ -44286,7 +44955,7 @@ var ExploreCompanion = class {
|
|
|
44286
44955
|
const mentions = extractSubjectTokens(todo.content);
|
|
44287
44956
|
const first = mentions[0];
|
|
44288
44957
|
this.engage({
|
|
44289
|
-
id:
|
|
44958
|
+
id: randomUUID24(),
|
|
44290
44959
|
probe: `Pre-map the files/symbols behind this in-progress todo: "${todo.content.slice(0, 160)}".`,
|
|
44291
44960
|
hint: first ? { [first.kind]: first.value } : void 0,
|
|
44292
44961
|
context: `Todo "${todo.content.slice(0, 120)}" flipped to in_progress.`,
|
|
@@ -44302,7 +44971,7 @@ var ExploreCompanion = class {
|
|
|
44302
44971
|
const tokens = extractSubjectTokens(err.message);
|
|
44303
44972
|
for (const token of tokens.slice(0, 2)) {
|
|
44304
44973
|
this.engage({
|
|
44305
|
-
id:
|
|
44974
|
+
id: randomUUID24(),
|
|
44306
44975
|
probe: `What is ${token.value}, where does it live, and who uses it? The leader hit an error naming it.`,
|
|
44307
44976
|
hint: { [token.kind]: token.value },
|
|
44308
44977
|
context: `Error: ${err.message.slice(0, 300)}`,
|
|
@@ -44325,7 +44994,7 @@ var ExploreCompanion = class {
|
|
|
44325
44994
|
const fromLeader = isMailboxLeader(msg.from) || lsid != null && msg.senderSessionId === lsid;
|
|
44326
44995
|
if (!fromLeader) continue;
|
|
44327
44996
|
this.engage({
|
|
44328
|
-
id:
|
|
44997
|
+
id: randomUUID24(),
|
|
44329
44998
|
probe: msg.body.trim().slice(0, 2e3) || msg.subject,
|
|
44330
44999
|
context: `Direct ask from ${msg.from}: ${msg.subject}`,
|
|
44331
45000
|
source: "mailbox_ask",
|
|
@@ -44407,6 +45076,22 @@ var SEND_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
44407
45076
|
// receiver trusts the sender-asserted `sessionId`; the boundary must
|
|
44408
45077
|
// refuse the field entirely.
|
|
44409
45078
|
]);
|
|
45079
|
+
var SEND_FORBIDDEN_FIELDS = /* @__PURE__ */ new Set([
|
|
45080
|
+
"from",
|
|
45081
|
+
"sessionAffinity"
|
|
45082
|
+
]);
|
|
45083
|
+
function filterMailboxSendPayload(input) {
|
|
45084
|
+
const payload = {};
|
|
45085
|
+
const stripped = [];
|
|
45086
|
+
for (const key of Object.keys(input)) {
|
|
45087
|
+
if (SEND_ALLOWED_FIELDS.has(key) || SEND_FORBIDDEN_FIELDS.has(key)) {
|
|
45088
|
+
payload[key] = input[key];
|
|
45089
|
+
} else {
|
|
45090
|
+
stripped.push(key);
|
|
45091
|
+
}
|
|
45092
|
+
}
|
|
45093
|
+
return { payload, stripped };
|
|
45094
|
+
}
|
|
44410
45095
|
var ACK_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
44411
45096
|
"messageId",
|
|
44412
45097
|
"read",
|
|
@@ -44644,7 +45329,9 @@ function makeMailSendTool(opts = {}) {
|
|
|
44644
45329
|
required: ["to", "subject", "body"]
|
|
44645
45330
|
},
|
|
44646
45331
|
async execute(input, ctx) {
|
|
44647
|
-
const i
|
|
45332
|
+
const { payload: i, stripped } = filterMailboxSendPayload(
|
|
45333
|
+
input ?? {}
|
|
45334
|
+
);
|
|
44648
45335
|
const rawTo = i.to;
|
|
44649
45336
|
const subject2 = i.subject;
|
|
44650
45337
|
const body = i.body;
|
|
@@ -44667,15 +45354,13 @@ function makeMailSendTool(opts = {}) {
|
|
|
44667
45354
|
recipientAliases: /* @__PURE__ */ new Set([codecIdentity.baseId]),
|
|
44668
45355
|
sessionId: codecIdentity.sessionId
|
|
44669
45356
|
};
|
|
45357
|
+
let parsed;
|
|
44670
45358
|
try {
|
|
44671
|
-
parseMailboxSendInput(i, codecActor);
|
|
45359
|
+
parsed = parseMailboxSendInput(i, codecActor);
|
|
44672
45360
|
} catch (err) {
|
|
44673
45361
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
44674
45362
|
}
|
|
44675
|
-
const audience =
|
|
44676
|
-
if (audience !== void 0 && audience !== "all" && audience !== "leaders") {
|
|
44677
|
-
return { ok: false, error: '"audience" must be "all" or "leaders".' };
|
|
44678
|
-
}
|
|
45363
|
+
const audience = parsed.audience;
|
|
44679
45364
|
const mb = resolveMailbox(ctx);
|
|
44680
45365
|
const identity2 = await register(mb, ctx);
|
|
44681
45366
|
const requestedTo = normalizeRecipient(rawTo, identity2.sessionId);
|
|
@@ -44689,10 +45374,10 @@ function makeMailSendTool(opts = {}) {
|
|
|
44689
45374
|
to: delivery.to,
|
|
44690
45375
|
type: resolvedType,
|
|
44691
45376
|
audience: delivery.audience,
|
|
44692
|
-
subject:
|
|
44693
|
-
body,
|
|
44694
|
-
priority:
|
|
44695
|
-
replyTo:
|
|
45377
|
+
subject: parsed.subject,
|
|
45378
|
+
body: parsed.body,
|
|
45379
|
+
priority: parsed.priority,
|
|
45380
|
+
replyTo: parsed.replyTo,
|
|
44696
45381
|
senderSessionId: identity2.sessionId
|
|
44697
45382
|
});
|
|
44698
45383
|
return {
|
|
@@ -44700,7 +45385,9 @@ function makeMailSendTool(opts = {}) {
|
|
|
44700
45385
|
messageId: msg.id,
|
|
44701
45386
|
from: identity2.callerId,
|
|
44702
45387
|
to: msg.to,
|
|
44703
|
-
|
|
45388
|
+
// Surfacing what was stripped keeps the send auditable without
|
|
45389
|
+
// re-introducing the clutter into the payload itself.
|
|
45390
|
+
...stripped.length > 0 ? { strippedFields: stripped, summary: `Mail sent to ${msg.to === "*" ? "all agents" : msg.to} as ${identity2.callerId}. Ignored ${stripped.length} unrecognized field(s): ${stripped.join(", ")}.` } : { summary: `Mail sent to ${msg.to === "*" ? "all agents" : msg.to} as ${identity2.callerId}.` }
|
|
44704
45391
|
};
|
|
44705
45392
|
}
|
|
44706
45393
|
};
|
|
@@ -48226,7 +48913,7 @@ function createAgentMonitorService(opts) {
|
|
|
48226
48913
|
}
|
|
48227
48914
|
|
|
48228
48915
|
// src/coordination/autonomous-brain.ts
|
|
48229
|
-
import { randomUUID as
|
|
48916
|
+
import { randomUUID as randomUUID25 } from "node:crypto";
|
|
48230
48917
|
var AutonomousBrain = class {
|
|
48231
48918
|
graph;
|
|
48232
48919
|
// Fleet bus for emitting decisions — null-safe, no-op if not provided
|
|
@@ -48332,7 +49019,7 @@ var AutonomousBrain = class {
|
|
|
48332
49019
|
consequence: i === 0 ? `Spawn the most appropriate agent for: ${taskDescription.slice(0, 80)}` : `Spawn an alternative agent for the same task`
|
|
48333
49020
|
}));
|
|
48334
49021
|
return this.decideAuto({
|
|
48335
|
-
id:
|
|
49022
|
+
id: randomUUID25(),
|
|
48336
49023
|
source,
|
|
48337
49024
|
decisionType: "spawn",
|
|
48338
49025
|
question: `Should we spawn a subagent for this task?`,
|
|
@@ -48375,7 +49062,7 @@ var AutonomousBrain = class {
|
|
|
48375
49062
|
}
|
|
48376
49063
|
];
|
|
48377
49064
|
return this.decideAuto({
|
|
48378
|
-
id:
|
|
49065
|
+
id: randomUUID25(),
|
|
48379
49066
|
source,
|
|
48380
49067
|
decisionType: "approve_change",
|
|
48381
49068
|
question: `Should we approve the change "${change.title}"?`,
|
|
@@ -48434,7 +49121,7 @@ var AutonomousBrain = class {
|
|
|
48434
49121
|
consequence: "Break the task into smaller sub-tasks"
|
|
48435
49122
|
});
|
|
48436
49123
|
return this.decideAuto({
|
|
48437
|
-
id:
|
|
49124
|
+
id: randomUUID25(),
|
|
48438
49125
|
source,
|
|
48439
49126
|
decisionType: "escalate_task",
|
|
48440
49127
|
question: `Task failed: ${error2.slice(0, 100)}. How should we proceed?`,
|
|
@@ -48568,12 +49255,12 @@ ${ctx.error}`);
|
|
|
48568
49255
|
};
|
|
48569
49256
|
|
|
48570
49257
|
// src/coordination/autonomous-coordinator.ts
|
|
48571
|
-
import { randomUUID as
|
|
49258
|
+
import { randomUUID as randomUUID28 } from "node:crypto";
|
|
48572
49259
|
|
|
48573
49260
|
// src/coordination/knowledge-graph.ts
|
|
48574
49261
|
init_file_permissions();
|
|
48575
49262
|
init_atomic_write();
|
|
48576
|
-
import { randomUUID as
|
|
49263
|
+
import { randomUUID as randomUUID26 } from "node:crypto";
|
|
48577
49264
|
import * as fsp34 from "node:fs/promises";
|
|
48578
49265
|
import * as path73 from "node:path";
|
|
48579
49266
|
var DEFAULT_MAX_NODES = 2e3;
|
|
@@ -48621,7 +49308,7 @@ var KnowledgeGraph = class _KnowledgeGraph {
|
|
|
48621
49308
|
* Returns the node with its assigned id.
|
|
48622
49309
|
*/
|
|
48623
49310
|
async add(node) {
|
|
48624
|
-
const full = { id:
|
|
49311
|
+
const full = { id: randomUUID26(), ...node };
|
|
48625
49312
|
this.nodes.set(full.id, full);
|
|
48626
49313
|
this._trackSeq(full.id);
|
|
48627
49314
|
this._addToIndex(full, this._indexKeys(full));
|
|
@@ -48750,8 +49437,8 @@ var KnowledgeGraph = class _KnowledgeGraph {
|
|
|
48750
49437
|
if (this.subs.size >= MAX_SUBSCRIPTIONS) {
|
|
48751
49438
|
throw new Error(`Knowledge graph subscription limit reached (${MAX_SUBSCRIPTIONS})`);
|
|
48752
49439
|
}
|
|
48753
|
-
const channel2 =
|
|
48754
|
-
const sub = { id:
|
|
49440
|
+
const channel2 = randomUUID26();
|
|
49441
|
+
const sub = { id: randomUUID26(), agentId, filter, channel: channel2 };
|
|
48755
49442
|
this.subs.set(channel2, sub);
|
|
48756
49443
|
this.pendingDeliveries.set(channel2, []);
|
|
48757
49444
|
return channel2;
|
|
@@ -49232,7 +49919,7 @@ var TaskDAG = class {
|
|
|
49232
49919
|
};
|
|
49233
49920
|
|
|
49234
49921
|
// src/coordination/task-auctioneer.ts
|
|
49235
|
-
import { randomUUID as
|
|
49922
|
+
import { randomUUID as randomUUID27 } from "node:crypto";
|
|
49236
49923
|
function isTerminalGoalStatus(status) {
|
|
49237
49924
|
return status === "done" || status === "failed";
|
|
49238
49925
|
}
|
|
@@ -49355,7 +50042,7 @@ var TaskAuctioneer = class {
|
|
|
49355
50042
|
const score = dispatchResult.confidence * (dispatchResult.role === agent.agentRole ? 1.2 : 1);
|
|
49356
50043
|
if (score < this.minConfidence) return false;
|
|
49357
50044
|
const bid = {
|
|
49358
|
-
id:
|
|
50045
|
+
id: randomUUID27(),
|
|
49359
50046
|
taskId,
|
|
49360
50047
|
agentId: agent.agentId,
|
|
49361
50048
|
agentName: agent.agentName,
|
|
@@ -50292,7 +50979,7 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
|
|
|
50292
50979
|
break;
|
|
50293
50980
|
}
|
|
50294
50981
|
const decision = await this.brain.decideAuto({
|
|
50295
|
-
id:
|
|
50982
|
+
id: randomUUID28(),
|
|
50296
50983
|
source: "system",
|
|
50297
50984
|
decisionType: "prioritize_goals",
|
|
50298
50985
|
question: `What should we work on next? Open goals: ${dispatchable.map((g) => g.title).join(", ")}`,
|
|
@@ -51207,7 +51894,7 @@ var TOKENS = {
|
|
|
51207
51894
|
init_errors();
|
|
51208
51895
|
|
|
51209
51896
|
// src/hq/factory.ts
|
|
51210
|
-
import { createHash as createHash24, randomUUID as
|
|
51897
|
+
import { createHash as createHash24, randomUUID as randomUUID31 } from "node:crypto";
|
|
51211
51898
|
import * as fs30 from "node:fs";
|
|
51212
51899
|
import { hostname as hostname3 } from "node:os";
|
|
51213
51900
|
import { basename as basename15 } from "node:path";
|
|
@@ -51215,13 +51902,13 @@ import { basename as basename15 } from "node:path";
|
|
|
51215
51902
|
// src/hq/auth-store.ts
|
|
51216
51903
|
init_file_permissions();
|
|
51217
51904
|
init_atomic_write();
|
|
51218
|
-
import { createHash as createHash23, randomBytes as randomBytes4, randomUUID as
|
|
51905
|
+
import { createHash as createHash23, randomBytes as randomBytes4, randomUUID as randomUUID29, scrypt, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
51219
51906
|
import * as syncFs from "node:fs";
|
|
51220
51907
|
import * as fs29 from "node:fs/promises";
|
|
51221
51908
|
import * as path75 from "node:path";
|
|
51222
51909
|
|
|
51223
51910
|
// src/hq/auth-audit.ts
|
|
51224
|
-
import { appendFileSync as appendFileSync2, readFileSync as
|
|
51911
|
+
import { appendFileSync as appendFileSync2, readFileSync as readFileSync21, mkdirSync as mkdirSync9 } from "node:fs";
|
|
51225
51912
|
import * as path74 from "node:path";
|
|
51226
51913
|
function hqAuthAuditPath(dataDir) {
|
|
51227
51914
|
return path74.join(dataDir, "auth-audit.jsonl");
|
|
@@ -51230,7 +51917,7 @@ function readHqAuthAuditTail(dataDir, maxEntries = 50) {
|
|
|
51230
51917
|
const filePath = hqAuthAuditPath(dataDir);
|
|
51231
51918
|
let content;
|
|
51232
51919
|
try {
|
|
51233
|
-
content =
|
|
51920
|
+
content = readFileSync21(filePath, "utf8");
|
|
51234
51921
|
} catch {
|
|
51235
51922
|
return [];
|
|
51236
51923
|
}
|
|
@@ -51542,8 +52229,8 @@ function mintHqToken(labelOrOptions) {
|
|
|
51542
52229
|
const at = opts.now ?? Date.now();
|
|
51543
52230
|
const createdAtIso = new Date(at).toISOString();
|
|
51544
52231
|
return {
|
|
51545
|
-
id:
|
|
51546
|
-
token:
|
|
52232
|
+
id: randomUUID29(),
|
|
52233
|
+
token: randomUUID29().replace(/-/g, "") + randomUUID29().replace(/-/g, ""),
|
|
51547
52234
|
createdAt: createdAtIso,
|
|
51548
52235
|
...opts.label ? { label: opts.label } : {},
|
|
51549
52236
|
...opts.ttlMs !== void 0 && Number.isFinite(opts.ttlMs) && opts.ttlMs > 0 ? { expiresAt: new Date(at + opts.ttlMs).toISOString() } : {}
|
|
@@ -51603,7 +52290,7 @@ function watchHqAuthFile(dataDir, onChange, opts = {}) {
|
|
|
51603
52290
|
}
|
|
51604
52291
|
|
|
51605
52292
|
// src/hq/publisher.ts
|
|
51606
|
-
import { randomUUID as
|
|
52293
|
+
import { randomUUID as randomUUID30 } from "node:crypto";
|
|
51607
52294
|
import * as v82 from "node:v8";
|
|
51608
52295
|
|
|
51609
52296
|
// src/hq/protocol/governance.ts
|
|
@@ -52677,7 +53364,7 @@ var HqPublisher = class {
|
|
|
52677
53364
|
this.options = options;
|
|
52678
53365
|
this.socketFactory = options.socketFactory ?? defaultSocketFactory;
|
|
52679
53366
|
this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
52680
|
-
this.idFactory = options.idFactory ??
|
|
53367
|
+
this.idFactory = options.idFactory ?? randomUUID30;
|
|
52681
53368
|
this.capabilities = options.capabilities ?? [
|
|
52682
53369
|
"telemetry.publish",
|
|
52683
53370
|
"mailbox.summary",
|
|
@@ -53261,7 +53948,7 @@ function createHqPublisherFromEnv(options) {
|
|
|
53261
53948
|
const projectAlias = config.projectAlias?.trim() || void 0;
|
|
53262
53949
|
const projectName = projectAlias ?? options.projectName ?? (basename15(options.projectRoot) || "unknown");
|
|
53263
53950
|
const client = {
|
|
53264
|
-
clientId: `${machineId}:${options.clientKind}:${process.pid}:${
|
|
53951
|
+
clientId: `${machineId}:${options.clientKind}:${process.pid}:${randomUUID31().slice(0, 8)}`,
|
|
53265
53952
|
kind: options.clientKind,
|
|
53266
53953
|
machineId,
|
|
53267
53954
|
...host ? { hostname: host } : {},
|
|
@@ -53530,40 +54217,6 @@ async function injectPendingMailboxMessages(checkMailbox2, foldFn, a, deliveryMo
|
|
|
53530
54217
|
return interruptMsg ? { interrupt: true, interruptReason: interruptMsg.body || interruptMsg.subject || "operator interrupt" } : { interrupt: false };
|
|
53531
54218
|
}
|
|
53532
54219
|
|
|
53533
|
-
// src/core/btw.ts
|
|
53534
|
-
var META_KEY2 = "_btwNotes";
|
|
53535
|
-
var MAX_PENDING = 20;
|
|
53536
|
-
function readQueue(ctx) {
|
|
53537
|
-
const raw = ctx.meta[META_KEY2];
|
|
53538
|
-
return Array.isArray(raw) ? raw : [];
|
|
53539
|
-
}
|
|
53540
|
-
function setBtwNote(ctx, text2) {
|
|
53541
|
-
const trimmed = text2.trim();
|
|
53542
|
-
if (!trimmed) return readQueue(ctx).length;
|
|
53543
|
-
const next = [...readQueue(ctx), trimmed].slice(-MAX_PENDING);
|
|
53544
|
-
ctx.meta[META_KEY2] = next;
|
|
53545
|
-
return next.length;
|
|
53546
|
-
}
|
|
53547
|
-
function pendingBtwCount(ctx) {
|
|
53548
|
-
return readQueue(ctx).length;
|
|
53549
|
-
}
|
|
53550
|
-
function consumeBtwNotes(ctx) {
|
|
53551
|
-
const notes = readQueue(ctx);
|
|
53552
|
-
if (notes.length > 0) delete ctx.meta[META_KEY2];
|
|
53553
|
-
return notes;
|
|
53554
|
-
}
|
|
53555
|
-
function buildBtwBlock(notes) {
|
|
53556
|
-
const body = notes.map((n) => `- ${n}`).join("\n");
|
|
53557
|
-
return [
|
|
53558
|
-
"[BY THE WAY \u2014 the user added this while you were working. Fold it into",
|
|
53559
|
-
"your current task; do not restart from scratch unless it contradicts the",
|
|
53560
|
-
"goal:",
|
|
53561
|
-
"",
|
|
53562
|
-
body,
|
|
53563
|
-
"]"
|
|
53564
|
-
].join("\n");
|
|
53565
|
-
}
|
|
53566
|
-
|
|
53567
54220
|
// src/core/fleet-pulse.ts
|
|
53568
54221
|
var DEFAULT_MAX_AGENTS = 15;
|
|
53569
54222
|
var DEFAULT_MAX_CHARS = 900;
|
|
@@ -53571,9 +54224,17 @@ var TASK_SNIPPET_CHARS2 = 60;
|
|
|
53571
54224
|
function fleetPulseSignature(statuses) {
|
|
53572
54225
|
return statuses.map((s) => `${s.agentId}|${s.status}|${s.currentTask ?? ""}`).sort().join("\n");
|
|
53573
54226
|
}
|
|
53574
|
-
function
|
|
54227
|
+
function visibleLineKey(s) {
|
|
54228
|
+
const role = s.role && s.role !== s.name ? s.role : "";
|
|
54229
|
+
const task = s.currentTask && s.currentTask.length > TASK_SNIPPET_CHARS2 ? `${s.currentTask.slice(0, TASK_SNIPPET_CHARS2)}\u2026` : s.currentTask ?? "";
|
|
54230
|
+
const tool = s.currentTool || "";
|
|
54231
|
+
const toolCalls = s.toolCalls > 0 ? String(s.toolCalls) : "";
|
|
54232
|
+
return [s.name, role, s.status, task, tool, toolCalls].join("\0");
|
|
54233
|
+
}
|
|
54234
|
+
function peerLine(s, count = 1) {
|
|
53575
54235
|
const role = s.role && s.role !== s.name ? ` (${s.role})` : "";
|
|
53576
|
-
const
|
|
54236
|
+
const grouped = count > 1 ? ` \xD7${count}` : "";
|
|
54237
|
+
const parts = [`\u2022 ${s.name}${role}${grouped} \u2014 ${s.status}`];
|
|
53577
54238
|
if (s.currentTask) {
|
|
53578
54239
|
const task = s.currentTask.length > TASK_SNIPPET_CHARS2 ? `${s.currentTask.slice(0, TASK_SNIPPET_CHARS2)}\u2026` : s.currentTask;
|
|
53579
54240
|
parts.push(`"${task}"`);
|
|
@@ -53589,13 +54250,20 @@ function buildFleetPulseBlock(statuses, opts) {
|
|
|
53589
54250
|
if (peers.length === 0) return null;
|
|
53590
54251
|
const order = { running: 0, streaming: 0, waiting_user: 1, idle: 2, error: 3, offline: 4 };
|
|
53591
54252
|
const sorted = [...peers].sort(
|
|
53592
|
-
(x, y) => (order[x.status] ?? 5) - (order[y.status] ?? 5) || x.
|
|
54253
|
+
(x, y) => (order[x.status] ?? 5) - (order[y.status] ?? 5) || visibleLineKey(x).localeCompare(visibleLineKey(y))
|
|
53593
54254
|
);
|
|
53594
54255
|
const shown = sorted.slice(0, maxAgents);
|
|
53595
54256
|
const hidden = sorted.length - shown.length;
|
|
53596
54257
|
const parts = [];
|
|
53597
54258
|
parts.push(`[FLEET PULSE] ${peers.length} peer${peers.length === 1 ? "" : "s"} online:`);
|
|
53598
|
-
for (
|
|
54259
|
+
for (let i = 0; i < shown.length; ) {
|
|
54260
|
+
let run = 1;
|
|
54261
|
+
while (i + run < shown.length && visibleLineKey(shown[i]) === visibleLineKey(shown[i + run])) {
|
|
54262
|
+
run++;
|
|
54263
|
+
}
|
|
54264
|
+
parts.push(peerLine(shown[i], run));
|
|
54265
|
+
i += run;
|
|
54266
|
+
}
|
|
53599
54267
|
if (hidden > 0) parts.push(`\u2026 +${hidden} more`);
|
|
53600
54268
|
parts.push(
|
|
53601
54269
|
"[END FLEET PULSE] (FYI \u2014 coordinate via mail_send; avoid duplicating peers' work)"
|
|
@@ -54546,7 +55214,7 @@ async function getPromptJournalEntries(projectRoot, filter = {}) {
|
|
|
54546
55214
|
init_errors();
|
|
54547
55215
|
|
|
54548
55216
|
// src/core/streaming-response-builder.ts
|
|
54549
|
-
import { randomUUID as
|
|
55217
|
+
import { randomUUID as randomUUID33 } from "node:crypto";
|
|
54550
55218
|
var STREAM_DRAIN_TIMEOUT_MS = 500;
|
|
54551
55219
|
function buildResponse(state) {
|
|
54552
55220
|
const content = [];
|
|
@@ -54606,7 +55274,7 @@ function handleContentBlockStart(state, ev) {
|
|
|
54606
55274
|
state.textBuffers.push("");
|
|
54607
55275
|
state.blockOrder.push({ kind: "text", idx: state.currentTextIndex });
|
|
54608
55276
|
} else if (kind === "tool_use") {
|
|
54609
|
-
const id = ev.id ??
|
|
55277
|
+
const id = ev.id ?? randomUUID33();
|
|
54610
55278
|
state.tools.set(id, { name: ev.name ?? "unknown", partial: "" });
|
|
54611
55279
|
state.blockOrder.push({ kind: "tool", id });
|
|
54612
55280
|
state.currentTextIndex = -1;
|
|
@@ -54841,7 +55509,7 @@ async function streamProviderToResponse(provider, req, signal, ctx, events, logg
|
|
|
54841
55509
|
|
|
54842
55510
|
// src/observability/network-telemetry.ts
|
|
54843
55511
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
54844
|
-
import { createHash as createHash25, randomUUID as
|
|
55512
|
+
import { createHash as createHash25, randomUUID as randomUUID34 } from "node:crypto";
|
|
54845
55513
|
import { channel } from "node:diagnostics_channel";
|
|
54846
55514
|
var storage = new AsyncLocalStorage();
|
|
54847
55515
|
var requests = /* @__PURE__ */ new WeakMap();
|
|
@@ -54878,7 +55546,7 @@ function subscribe() {
|
|
|
54878
55546
|
const requestBytes = numberField2(request, "contentLength");
|
|
54879
55547
|
const state = {
|
|
54880
55548
|
...context,
|
|
54881
|
-
requestId:
|
|
55549
|
+
requestId: randomUUID34(),
|
|
54882
55550
|
...target,
|
|
54883
55551
|
...requestBytes !== void 0 ? { requestBytes } : {},
|
|
54884
55552
|
startedAt,
|
|
@@ -55013,7 +55681,7 @@ function hash3(value) {
|
|
|
55013
55681
|
}
|
|
55014
55682
|
|
|
55015
55683
|
// src/core/provider-runner.ts
|
|
55016
|
-
import { randomUUID as
|
|
55684
|
+
import { randomUUID as randomUUID35 } from "node:crypto";
|
|
55017
55685
|
function scrubProviderBody(body) {
|
|
55018
55686
|
if (!body) return void 0;
|
|
55019
55687
|
return {
|
|
@@ -55035,11 +55703,11 @@ function providerLogCtx(p, r) {
|
|
|
55035
55703
|
}
|
|
55036
55704
|
async function runProviderWithRetry(opts) {
|
|
55037
55705
|
const { provider, request, signal, ctx, events, retry, logger, tracer } = opts;
|
|
55038
|
-
const logicalRequestId =
|
|
55706
|
+
const logicalRequestId = randomUUID35();
|
|
55039
55707
|
const promptManifest = createChroniclePromptManifest(request);
|
|
55040
55708
|
let attempt = 0;
|
|
55041
55709
|
for (; ; ) {
|
|
55042
|
-
const attemptId =
|
|
55710
|
+
const attemptId = randomUUID35();
|
|
55043
55711
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
55044
55712
|
const startedNs = process.hrtime.bigint();
|
|
55045
55713
|
const correlation = {
|
|
@@ -59708,7 +60376,7 @@ function _resetDesignRulesCache() {
|
|
|
59708
60376
|
}
|
|
59709
60377
|
|
|
59710
60378
|
// src/execution/design-color.ts
|
|
59711
|
-
function
|
|
60379
|
+
function clamp2(n, lo, hi) {
|
|
59712
60380
|
return n < lo ? lo : n > hi ? hi : n;
|
|
59713
60381
|
}
|
|
59714
60382
|
function parseOklch(value) {
|
|
@@ -59724,9 +60392,9 @@ function parseOklch(value) {
|
|
|
59724
60392
|
let a = 1;
|
|
59725
60393
|
if (alphaPart !== void 0) {
|
|
59726
60394
|
const av = parseComponent(alphaPart.trim(), true);
|
|
59727
|
-
if (av !== null) a =
|
|
60395
|
+
if (av !== null) a = clamp2(av, 0, 1);
|
|
59728
60396
|
}
|
|
59729
|
-
return [
|
|
60397
|
+
return [clamp2(L, 0, 1), Math.max(0, C), H, a];
|
|
59730
60398
|
}
|
|
59731
60399
|
function parseComponent(s, percentIsFraction) {
|
|
59732
60400
|
s = s.trim();
|
|
@@ -59745,7 +60413,7 @@ function parseAngle(s) {
|
|
|
59745
60413
|
}
|
|
59746
60414
|
function linearToSrgb(c) {
|
|
59747
60415
|
const v = c <= 31308e-7 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;
|
|
59748
|
-
return
|
|
60416
|
+
return clamp2(v, 0, 1);
|
|
59749
60417
|
}
|
|
59750
60418
|
function toHex2(n) {
|
|
59751
60419
|
return Math.round(n * 255).toString(16).padStart(2, "0");
|
|
@@ -62492,7 +63160,7 @@ ${summaryText}` : summaryText;
|
|
|
62492
63160
|
|
|
62493
63161
|
// src/execution/parallel-eternal-engine.ts
|
|
62494
63162
|
init_error();
|
|
62495
|
-
import { randomUUID as
|
|
63163
|
+
import { randomUUID as randomUUID36 } from "node:crypto";
|
|
62496
63164
|
var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
62497
63165
|
var ParallelEternalEngine = class {
|
|
62498
63166
|
constructor(opts) {
|
|
@@ -62569,7 +63237,7 @@ var ParallelEternalEngine = class {
|
|
|
62569
63237
|
this.state = "running";
|
|
62570
63238
|
await this.persistState("running");
|
|
62571
63239
|
const config = {
|
|
62572
|
-
coordinatorId: `parallel-${
|
|
63240
|
+
coordinatorId: `parallel-${randomUUID36().slice(0, 8)}`,
|
|
62573
63241
|
maxConcurrent: this.slots,
|
|
62574
63242
|
doneCondition: { type: "all_tasks_done" }
|
|
62575
63243
|
};
|
|
@@ -62623,7 +63291,7 @@ var ParallelEternalEngine = class {
|
|
|
62623
63291
|
}
|
|
62624
63292
|
if (!this.coordinator) {
|
|
62625
63293
|
const config = {
|
|
62626
|
-
coordinatorId: `parallel-${
|
|
63294
|
+
coordinatorId: `parallel-${randomUUID36().slice(0, 8)}`,
|
|
62627
63295
|
maxConcurrent: this.slots,
|
|
62628
63296
|
doneCondition: { type: "all_tasks_done" }
|
|
62629
63297
|
};
|
|
@@ -62709,7 +63377,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
62709
63377
|
const task = expectDefined(tasks[i]);
|
|
62710
63378
|
const route = routes[i] ?? null;
|
|
62711
63379
|
const subagentId = `parallel-${this.iterations}-${i}`;
|
|
62712
|
-
const taskId =
|
|
63380
|
+
const taskId = randomUUID36();
|
|
62713
63381
|
const personaLine = route ? `Acting agent: ${route.definition.config.name} \u2014 ${route.definition.capability.summary}
|
|
62714
63382
|
` : "";
|
|
62715
63383
|
const spec = {
|
|
@@ -64337,7 +65005,7 @@ function readPolicy(ctx) {
|
|
|
64337
65005
|
}
|
|
64338
65006
|
|
|
64339
65007
|
// src/execution/tool-executor.ts
|
|
64340
|
-
import { randomUUID as
|
|
65008
|
+
import { randomUUID as randomUUID39 } from "node:crypto";
|
|
64341
65009
|
import * as fs38 from "node:fs/promises";
|
|
64342
65010
|
import * as path85 from "node:path";
|
|
64343
65011
|
init_errors();
|
|
@@ -64359,7 +65027,7 @@ var ToolErrorCategory = /* @__PURE__ */ ((ToolErrorCategory2) => {
|
|
|
64359
65027
|
})(ToolErrorCategory || {});
|
|
64360
65028
|
|
|
64361
65029
|
// src/execution/tool-executor-support.ts
|
|
64362
|
-
import { createHash as createHash29, randomUUID as
|
|
65030
|
+
import { createHash as createHash29, randomUUID as randomUUID37 } from "node:crypto";
|
|
64363
65031
|
import * as fs37 from "node:fs/promises";
|
|
64364
65032
|
import * as path83 from "node:path";
|
|
64365
65033
|
init_errors();
|
|
@@ -64491,7 +65159,7 @@ async function maybePersistLargeToolOutput(toolName, content, budget) {
|
|
|
64491
65159
|
await fs37.mkdir(dir, { recursive: true });
|
|
64492
65160
|
const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
|
|
64493
65161
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
64494
|
-
const filePath = path83.join(dir, `${stamp}-${safeTool}-${
|
|
65162
|
+
const filePath = path83.join(dir, `${stamp}-${safeTool}-${randomUUID37()}.log`);
|
|
64495
65163
|
await fs37.writeFile(filePath, content, "utf8");
|
|
64496
65164
|
const marker = `[full tool output: ${bytes} bytes at ${filePath}; read/grep that file selectively instead of re-running or requesting more output]`;
|
|
64497
65165
|
const fixedBytes = Buffer.byteLength(marker + TOOL_OUTPUT_ARTIFACT_OMISSION, "utf8");
|
|
@@ -65041,7 +65709,7 @@ ${errorDetails}`,
|
|
|
65041
65709
|
}
|
|
65042
65710
|
|
|
65043
65711
|
// src/execution/tool-executor-runner.ts
|
|
65044
|
-
import { randomUUID as
|
|
65712
|
+
import { randomUUID as randomUUID38 } from "node:crypto";
|
|
65045
65713
|
|
|
65046
65714
|
// src/observability/process-telemetry.ts
|
|
65047
65715
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
@@ -65265,7 +65933,7 @@ async function runToolWithTimeout(tool, input, parentSignal, ctx, opts, config,
|
|
|
65265
65933
|
progressTailChars: config.progressTailChars,
|
|
65266
65934
|
progressHeadChars: config.progressHeadChars
|
|
65267
65935
|
}) : (async () => tool.execute(input, ctx, { signal: combined }))();
|
|
65268
|
-
const telemetryToolCallId = toolUseId ?? `nested-${
|
|
65936
|
+
const telemetryToolCallId = toolUseId ?? `nested-${randomUUID38()}`;
|
|
65269
65937
|
const toolPromise = opts.events ? runWithNetworkTelemetry(
|
|
65270
65938
|
{
|
|
65271
65939
|
events: opts.events,
|
|
@@ -65658,7 +66326,7 @@ ${post.additionalContext}`;
|
|
|
65658
66326
|
const bridge = async (toolName, input) => {
|
|
65659
66327
|
const nestedUse = {
|
|
65660
66328
|
type: "tool_use",
|
|
65661
|
-
id: `nested-${
|
|
66329
|
+
id: `nested-${randomUUID39()}`,
|
|
65662
66330
|
name: toolName,
|
|
65663
66331
|
input
|
|
65664
66332
|
};
|
|
@@ -66263,13 +66931,13 @@ import * as fs39 from "node:fs/promises";
|
|
|
66263
66931
|
import * as path87 from "node:path";
|
|
66264
66932
|
|
|
66265
66933
|
// src/types/mode-prompts.ts
|
|
66266
|
-
import { readFileSync as
|
|
66934
|
+
import { readFileSync as readFileSync24, statSync as statSync9 } from "node:fs";
|
|
66267
66935
|
import * as path86 from "node:path";
|
|
66268
66936
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
66269
66937
|
function modePrompt(id) {
|
|
66270
66938
|
for (const dir of modePromptDirCandidates()) {
|
|
66271
66939
|
try {
|
|
66272
|
-
return
|
|
66940
|
+
return readFileSync24(path86.join(dir, `${id}.md`), "utf8").trimEnd();
|
|
66273
66941
|
} catch {
|
|
66274
66942
|
}
|
|
66275
66943
|
}
|
|
@@ -66950,7 +67618,17 @@ function normalizeModelsDevModel(model) {
|
|
|
66950
67618
|
const reasoningConfig = {
|
|
66951
67619
|
default: disableSupported ? "enabled" : "always_on",
|
|
66952
67620
|
disableSupported,
|
|
66953
|
-
|
|
67621
|
+
// Tri-state (see ReasoningConfig.effortSupported):
|
|
67622
|
+
// options present → documented answer (true when effort values exist;
|
|
67623
|
+
// an explicitly EMPTY array is a documented "no
|
|
67624
|
+
// effort control", not an absent field).
|
|
67625
|
+
// field ABSENT → the model is known to reason but its vocabulary is
|
|
67626
|
+
// undocumented → `undefined`, so the resolver forwards
|
|
67627
|
+
// the request and each wire adapter applies its own
|
|
67628
|
+
// transport gating. Sending `false` here would make
|
|
67629
|
+
// the resolver claim "does not support effort" — an
|
|
67630
|
+
// assertion the catalog never made.
|
|
67631
|
+
...raw === void 0 ? {} : { effortSupported: effortLevels.length > 0 },
|
|
66954
67632
|
effortLevels,
|
|
66955
67633
|
preserveThinking: model.interleaved ? "always_on" : "unsupported"
|
|
66956
67634
|
};
|
|
@@ -67539,9 +68217,9 @@ async function startMetricsServer(opts) {
|
|
|
67539
68217
|
let server;
|
|
67540
68218
|
if (useHttps && tls) {
|
|
67541
68219
|
const { createServer } = await import("node:https");
|
|
67542
|
-
const { readFileSync:
|
|
68220
|
+
const { readFileSync: readFileSync26 } = await import("node:fs");
|
|
67543
68221
|
server = createServer(
|
|
67544
|
-
{ cert:
|
|
68222
|
+
{ cert: readFileSync26(tls.cert), key: readFileSync26(tls.key) },
|
|
67545
68223
|
listener
|
|
67546
68224
|
);
|
|
67547
68225
|
} else {
|
|
@@ -69507,7 +70185,7 @@ function deepFreeze(obj) {
|
|
|
69507
70185
|
init_errors();
|
|
69508
70186
|
init_atomic_write();
|
|
69509
70187
|
init_error();
|
|
69510
|
-
import { randomUUID as
|
|
70188
|
+
import { randomUUID as randomUUID40 } from "node:crypto";
|
|
69511
70189
|
import * as fsp38 from "node:fs/promises";
|
|
69512
70190
|
function assertPlanMutationInvariants(previous, updated) {
|
|
69513
70191
|
const ids = updated.items.map((item) => item.id);
|
|
@@ -69629,7 +70307,7 @@ function emptyPlan(sessionId, title) {
|
|
|
69629
70307
|
function addPlanItem(plan, title, details) {
|
|
69630
70308
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
69631
70309
|
const item = {
|
|
69632
|
-
id: `plan_${Date.now()}_${
|
|
70310
|
+
id: `plan_${Date.now()}_${randomUUID40().slice(0, 6)}`,
|
|
69633
70311
|
title,
|
|
69634
70312
|
details,
|
|
69635
70313
|
status: "open",
|
|
@@ -69701,7 +70379,7 @@ function deriveTodosFromPlanItem(plan, idOrIndex, subtasks) {
|
|
|
69701
70379
|
if (subtasks && subtasks.length > 0) {
|
|
69702
70380
|
for (const st of subtasks) {
|
|
69703
70381
|
todos.push({
|
|
69704
|
-
id: `todo_${Date.now()}_${
|
|
70382
|
+
id: `todo_${Date.now()}_${randomUUID40().slice(0, 6)}`,
|
|
69705
70383
|
content: st,
|
|
69706
70384
|
status: "pending",
|
|
69707
70385
|
promotedFromPlan: item.id
|
|
@@ -73698,7 +74376,7 @@ function resolveReasoningForRequest(settings, rc, warnings) {
|
|
|
73698
74376
|
const cfg = settings.reasoning;
|
|
73699
74377
|
if (!cfg) return void 0;
|
|
73700
74378
|
const capKnown = rc !== void 0;
|
|
73701
|
-
const supportsReasoning = rc ? rc.default !== "disabled" || rc.disableSupported || rc.effortSupported : false;
|
|
74379
|
+
const supportsReasoning = rc ? rc.default !== "disabled" || rc.disableSupported || rc.effortSupported !== false : false;
|
|
73702
74380
|
const out = {};
|
|
73703
74381
|
if (cfg.mode === "off") {
|
|
73704
74382
|
if (capKnown && rc?.disableSupported) {
|
|
@@ -73720,14 +74398,17 @@ function resolveReasoningForRequest(settings, rc, warnings) {
|
|
|
73720
74398
|
}
|
|
73721
74399
|
const effort = cfg.effort;
|
|
73722
74400
|
if (effort !== void 0) {
|
|
73723
|
-
if (capKnown
|
|
73724
|
-
|
|
73725
|
-
|
|
74401
|
+
if (!capKnown) {
|
|
74402
|
+
} else if (rc?.effortSupported === false) {
|
|
74403
|
+
warnings.push(
|
|
74404
|
+
`reasoning effort "${effort}" requested, but this model does not support effort control; the setting was omitted.`
|
|
74405
|
+
);
|
|
74406
|
+
} else if (rc?.effortSupported === true && rc.effortLevels.length > 0 && !rc.effortLevels.includes(effort)) {
|
|
73726
74407
|
warnings.push(
|
|
73727
74408
|
`reasoning effort "${effort}" not supported by this model (supported: ${rc.effortLevels.join(", ")}); the setting was omitted.`
|
|
73728
74409
|
);
|
|
73729
|
-
} else
|
|
73730
|
-
|
|
74410
|
+
} else {
|
|
74411
|
+
out.effort = effort;
|
|
73731
74412
|
}
|
|
73732
74413
|
}
|
|
73733
74414
|
if (cfg.preserve !== void 0) {
|
|
@@ -82152,7 +82833,7 @@ async function snapshotChangedFiles(cwd) {
|
|
|
82152
82833
|
}
|
|
82153
82834
|
|
|
82154
82835
|
// src/plugins/review-claim-registry.ts
|
|
82155
|
-
import { createHash as createHash33, randomUUID as
|
|
82836
|
+
import { createHash as createHash33, randomUUID as randomUUID41 } from "node:crypto";
|
|
82156
82837
|
import * as fsp46 from "node:fs/promises";
|
|
82157
82838
|
import { hostname as hostname5 } from "node:os";
|
|
82158
82839
|
import * as path103 from "node:path";
|
|
@@ -82215,7 +82896,7 @@ async function breakStaleLock(lockPath) {
|
|
|
82215
82896
|
return false;
|
|
82216
82897
|
}
|
|
82217
82898
|
async function breakLockAtomically(lockPath) {
|
|
82218
|
-
const tombstone = `${lockPath}.stale-${
|
|
82899
|
+
const tombstone = `${lockPath}.stale-${randomUUID41()}.tmp`;
|
|
82219
82900
|
try {
|
|
82220
82901
|
await fsp46.rename(lockPath, tombstone);
|
|
82221
82902
|
} catch {
|
|
@@ -82275,7 +82956,7 @@ async function withStoreLock(storeDir, fn, waitMs = LOCK_WAIT_MS) {
|
|
|
82275
82956
|
}
|
|
82276
82957
|
}
|
|
82277
82958
|
var MAX_LEDGER_LINES = 1e4;
|
|
82278
|
-
var HOST_SID =
|
|
82959
|
+
var HOST_SID = randomUUID41();
|
|
82279
82960
|
var claimsByEventBus = /* @__PURE__ */ new WeakMap();
|
|
82280
82961
|
var startedReviews = /* @__PURE__ */ new WeakMap();
|
|
82281
82962
|
var pendingStartedReviews = /* @__PURE__ */ new WeakMap();
|
|
@@ -82356,7 +83037,7 @@ async function compactLedger(storeDir, active) {
|
|
|
82356
83037
|
);
|
|
82357
83038
|
}
|
|
82358
83039
|
}
|
|
82359
|
-
const tmp = `${claimsFilePath(storeDir)}.tmp-${
|
|
83040
|
+
const tmp = `${claimsFilePath(storeDir)}.tmp-${randomUUID41()}`;
|
|
82360
83041
|
await fsp46.writeFile(tmp, lines.length > 0 ? `${lines.join("\n")}
|
|
82361
83042
|
` : "", "utf8");
|
|
82362
83043
|
let replaced = false;
|
|
@@ -83285,7 +83966,7 @@ init_review_finding_store();
|
|
|
83285
83966
|
|
|
83286
83967
|
// src/plugins/review-finding-parser.ts
|
|
83287
83968
|
init_review_finding_types();
|
|
83288
|
-
import { randomUUID as
|
|
83969
|
+
import { randomUUID as randomUUID43 } from "node:crypto";
|
|
83289
83970
|
var SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low"]);
|
|
83290
83971
|
var CATEGORIES = /* @__PURE__ */ new Set([
|
|
83291
83972
|
"bug",
|
|
@@ -83357,7 +84038,7 @@ function parseChimeraReviewReport(reportText, context = {}) {
|
|
|
83357
84038
|
}
|
|
83358
84039
|
const structured = extractStructuredFindingsBlock(reportText);
|
|
83359
84040
|
if (structured) {
|
|
83360
|
-
const reportId2 = context.reportId ??
|
|
84041
|
+
const reportId2 = context.reportId ?? randomUUID43();
|
|
83361
84042
|
const findings2 = structured.findings.map(
|
|
83362
84043
|
(item) => buildFindingFromStructuredItem(item, { ...context, reportId: reportId2 })
|
|
83363
84044
|
);
|
|
@@ -83369,7 +84050,7 @@ function parseChimeraReviewReport(reportText, context = {}) {
|
|
|
83369
84050
|
};
|
|
83370
84051
|
}
|
|
83371
84052
|
const findings = [];
|
|
83372
|
-
const reportId = context.reportId ??
|
|
84053
|
+
const reportId = context.reportId ?? randomUUID43();
|
|
83373
84054
|
let unparseableCount = 0;
|
|
83374
84055
|
let durationSeconds;
|
|
83375
84056
|
let currentSeverity = null;
|
|
@@ -83470,7 +84151,7 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
83470
84151
|
const fullDesc = suggestions.length > 0 ? cleanDesc + "\n" + suggestions.map((s) => " \u2192 " + s).join("\n") : cleanDesc;
|
|
83471
84152
|
const suggestedFix = suggestions.length > 0 ? suggestions.join("\n") : void 0;
|
|
83472
84153
|
return {
|
|
83473
|
-
id:
|
|
84154
|
+
id: randomUUID43(),
|
|
83474
84155
|
fingerprint: computeFindingFingerprint(file ?? "", line ?? null, title),
|
|
83475
84156
|
severity,
|
|
83476
84157
|
source: normalizeFindingSource(context.reviewType),
|
|
@@ -83481,7 +84162,7 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
83481
84162
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83482
84163
|
status: "active",
|
|
83483
84164
|
originReport: {
|
|
83484
|
-
reportId: context.reportId ??
|
|
84165
|
+
reportId: context.reportId ?? randomUUID43(),
|
|
83485
84166
|
sessionId: context.sessionId ?? "",
|
|
83486
84167
|
agentId: context.agentId ?? "",
|
|
83487
84168
|
reviewerModel: context.reviewerModel ?? ""
|
|
@@ -83505,7 +84186,7 @@ function buildFindingFromStructuredItem(item, context) {
|
|
|
83505
84186
|
const title = item.title;
|
|
83506
84187
|
const description = item.description ?? title;
|
|
83507
84188
|
return {
|
|
83508
|
-
id:
|
|
84189
|
+
id: randomUUID43(),
|
|
83509
84190
|
fingerprint: computeFindingFingerprint(file ?? "", line ?? null, title),
|
|
83510
84191
|
severity: item.severity,
|
|
83511
84192
|
source: normalizeFindingSource(context.reviewType),
|
|
@@ -83518,7 +84199,7 @@ function buildFindingFromStructuredItem(item, context) {
|
|
|
83518
84199
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83519
84200
|
status: "active",
|
|
83520
84201
|
originReport: {
|
|
83521
|
-
reportId: context.reportId ??
|
|
84202
|
+
reportId: context.reportId ?? randomUUID43(),
|
|
83522
84203
|
sessionId: context.sessionId ?? "",
|
|
83523
84204
|
agentId: context.agentId ?? "",
|
|
83524
84205
|
reviewerModel: context.reviewerModel ?? ""
|
|
@@ -89169,7 +89850,7 @@ var ReplayProviderRunner = class {
|
|
|
89169
89850
|
};
|
|
89170
89851
|
|
|
89171
89852
|
// src/session-catalog/store.ts
|
|
89172
|
-
import { randomBytes as randomBytes8, randomUUID as
|
|
89853
|
+
import { randomBytes as randomBytes8, randomUUID as randomUUID44 } from "node:crypto";
|
|
89173
89854
|
import * as fs59 from "node:fs";
|
|
89174
89855
|
import * as path119 from "node:path";
|
|
89175
89856
|
init_atomic_write();
|
|
@@ -89520,7 +90201,7 @@ var SessionCatalogStore = class {
|
|
|
89520
90201
|
if (!Number.isSafeInteger(entry.pid) || entry.pid <= 0)
|
|
89521
90202
|
throw new TypeError("Invalid owner pid");
|
|
89522
90203
|
const now = Date.now();
|
|
89523
|
-
const leaseId =
|
|
90204
|
+
const leaseId = randomUUID44();
|
|
89524
90205
|
const leaseSecret = randomBytes8(32).toString("hex");
|
|
89525
90206
|
const expiresAt = now + boundedMs(leaseMs, SESSION_CATALOG_DEFAULT_LEASE_MS, MAX_LEASE_MS);
|
|
89526
90207
|
this.db.prepare(`INSERT INTO session_leases(
|
|
@@ -89592,7 +90273,7 @@ var SessionCatalogStore = class {
|
|
|
89592
90273
|
const catalog = this.db.prepare("SELECT 1 AS yes FROM sessions WHERE session_id=?").get(targetSessionId);
|
|
89593
90274
|
if (!catalog && !fs59.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
|
|
89594
90275
|
throw new Error(`Session not found: ${targetSessionId}`);
|
|
89595
|
-
const reservationId =
|
|
90276
|
+
const reservationId = randomUUID44();
|
|
89596
90277
|
const now = Date.now();
|
|
89597
90278
|
const expiresAt = now + boundedMs(reservationMs, SESSION_CATALOG_DEFAULT_RESERVATION_MS, MAX_RESERVATION_MS);
|
|
89598
90279
|
try {
|
|
@@ -89888,7 +90569,7 @@ var SessionCatalogStore = class {
|
|
|
89888
90569
|
"SELECT 1 AS yes FROM resume_reservations WHERE target_session_id=? AND expires_at>?"
|
|
89889
90570
|
).get(sessionId, Date.now());
|
|
89890
90571
|
if (reservation) throw conflict(`Session ${sessionId} is reserved for resume`);
|
|
89891
|
-
const leaseId =
|
|
90572
|
+
const leaseId = randomUUID44();
|
|
89892
90573
|
const now = Date.now();
|
|
89893
90574
|
const expiresAt = now + boundedMs(leaseMs, 6e4, MAX_MAINTENANCE_MS);
|
|
89894
90575
|
try {
|
|
@@ -90846,7 +91527,7 @@ import * as fs62 from "node:fs/promises";
|
|
|
90846
91527
|
import * as path122 from "node:path";
|
|
90847
91528
|
|
|
90848
91529
|
// src/session-registry-atomic-file.ts
|
|
90849
|
-
import { randomUUID as
|
|
91530
|
+
import { randomUUID as randomUUID45 } from "node:crypto";
|
|
90850
91531
|
import * as fs61 from "node:fs/promises";
|
|
90851
91532
|
import { hostname as hostname6 } from "node:os";
|
|
90852
91533
|
import * as path121 from "node:path";
|
|
@@ -90919,7 +91600,7 @@ async function breakStaleLockVerified2(lockPath, verify) {
|
|
|
90919
91600
|
return await breakLockAtomically2(lockPath) === true;
|
|
90920
91601
|
}
|
|
90921
91602
|
async function breakLockAtomically2(lockPath) {
|
|
90922
|
-
const tombstone = `${lockPath}.stale-${
|
|
91603
|
+
const tombstone = `${lockPath}.stale-${randomUUID45()}.tmp`;
|
|
90923
91604
|
try {
|
|
90924
91605
|
await fs61.rename(lockPath, tombstone);
|
|
90925
91606
|
} catch {
|
|
@@ -90931,7 +91612,7 @@ async function breakLockAtomically2(lockPath) {
|
|
|
90931
91612
|
async function writeAtomicFile(filePath, registry2) {
|
|
90932
91613
|
const tmp = path121.join(
|
|
90933
91614
|
path121.dirname(filePath),
|
|
90934
|
-
`.${path121.basename(filePath)}.${
|
|
91615
|
+
`.${path121.basename(filePath)}.${randomUUID45().slice(0, 8)}.tmp`
|
|
90935
91616
|
);
|
|
90936
91617
|
let tmpPersisted = false;
|
|
90937
91618
|
try {
|
|
@@ -91494,7 +92175,7 @@ var SessionRegistry = class {
|
|
|
91494
92175
|
init_errors();
|
|
91495
92176
|
init_atomic_write();
|
|
91496
92177
|
init_error();
|
|
91497
|
-
import { randomUUID as
|
|
92178
|
+
import { randomUUID as randomUUID46 } from "node:crypto";
|
|
91498
92179
|
import * as fs63 from "node:fs/promises";
|
|
91499
92180
|
var FILE_VERSION = 1;
|
|
91500
92181
|
var MAX_TEXT_LENGTH = 2e3;
|
|
@@ -91592,7 +92273,7 @@ var AnnotationsStore = class {
|
|
|
91592
92273
|
});
|
|
91593
92274
|
}
|
|
91594
92275
|
const annotation = {
|
|
91595
|
-
id:
|
|
92276
|
+
id: randomUUID46(),
|
|
91596
92277
|
sessionId: input.sessionId,
|
|
91597
92278
|
atEventIndex: input.atEventIndex,
|
|
91598
92279
|
authorId: input.authorId,
|
|
@@ -91945,7 +92626,7 @@ var InputHistoryStore = class {
|
|
|
91945
92626
|
|
|
91946
92627
|
// src/storage/memory-backend.ts
|
|
91947
92628
|
init_file_permissions();
|
|
91948
|
-
import { randomUUID as
|
|
92629
|
+
import { randomUUID as randomUUID47 } from "node:crypto";
|
|
91949
92630
|
import * as fs65 from "node:fs/promises";
|
|
91950
92631
|
import * as path124 from "node:path";
|
|
91951
92632
|
|
|
@@ -92173,7 +92854,7 @@ var FileMemoryBackend = class {
|
|
|
92173
92854
|
}
|
|
92174
92855
|
async remember(scope, entry, filePath) {
|
|
92175
92856
|
const file = this.resolveFile(filePath, scope);
|
|
92176
|
-
const id = `mem_${Date.now()}_${
|
|
92857
|
+
const id = `mem_${Date.now()}_${randomUUID47().slice(0, 8)}`;
|
|
92177
92858
|
const meta = formatMetadata(entry);
|
|
92178
92859
|
const line = `- [${entry.ts}] ${id}${meta} ${entry.text.replace(/\n/g, " ")}
|
|
92179
92860
|
`;
|
|
@@ -94187,7 +94868,7 @@ async function mutateTasks(filePath, sessionId, fn, events, traceId) {
|
|
|
94187
94868
|
init_file_permissions();
|
|
94188
94869
|
init_atomic_write();
|
|
94189
94870
|
init_error();
|
|
94190
|
-
import { createHash as createHash39, randomUUID as
|
|
94871
|
+
import { createHash as createHash39, randomUUID as randomUUID48 } from "node:crypto";
|
|
94191
94872
|
import * as fs70 from "node:fs/promises";
|
|
94192
94873
|
var GENESIS_PREV = "0".repeat(64);
|
|
94193
94874
|
var DEFAULT_FSYNC_EVERY = 100;
|
|
@@ -94232,7 +94913,7 @@ var ToolAuditLog = class {
|
|
|
94232
94913
|
const tip = await this._resolveChainTip(input.sessionId, fp);
|
|
94233
94914
|
const prevHash = tip.prevHash;
|
|
94234
94915
|
const index = tip.nextIndex;
|
|
94235
|
-
const id =
|
|
94916
|
+
const id = randomUUID48();
|
|
94236
94917
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
94237
94918
|
const content = {
|
|
94238
94919
|
id,
|
|
@@ -96773,7 +97454,7 @@ var DEFAULT_SPEC_TEMPLATE = {
|
|
|
96773
97454
|
// src/worktree/worktree-manager.ts
|
|
96774
97455
|
init_error();
|
|
96775
97456
|
import { mkdir as mkdir35, readFile as readFile73 } from "node:fs/promises";
|
|
96776
|
-
import { join as
|
|
97457
|
+
import { join as join103, resolve as resolve56, sep as sep9 } from "node:path";
|
|
96777
97458
|
|
|
96778
97459
|
// src/worktree/worktree-git.ts
|
|
96779
97460
|
import { spawn as spawn13 } from "node:child_process";
|
|
@@ -97005,7 +97686,7 @@ var WorktreeManager = class {
|
|
|
97005
97686
|
}
|
|
97006
97687
|
const slug = this.makeSlug(opts.slugHint ?? ownerId);
|
|
97007
97688
|
const branch = `wstack/ap/${slug}`;
|
|
97008
|
-
const dir =
|
|
97689
|
+
const dir = join103(this.worktreesRoot(), slug);
|
|
97009
97690
|
const absDir = resolve56(dir);
|
|
97010
97691
|
const absRoot = resolve56(this.projectRoot);
|
|
97011
97692
|
if (!absDir.startsWith(absRoot + sep9)) {
|
|
@@ -97396,7 +98077,7 @@ ${merged.stderr}`);
|
|
|
97396
98077
|
const startMarker = /^(?:<{7,}(?: |$)|\|{7,}(?: |$))/m;
|
|
97397
98078
|
for (const rel of paths) {
|
|
97398
98079
|
try {
|
|
97399
|
-
const content = (await readFile73(
|
|
98080
|
+
const content = (await readFile73(join103(this.projectRoot, rel), "utf8")).replace(/\r/g, "");
|
|
97400
98081
|
const lines = content.split("\n");
|
|
97401
98082
|
let seenStart = false;
|
|
97402
98083
|
for (const line of lines) {
|
|
@@ -97440,7 +98121,7 @@ ${merged.stderr}`);
|
|
|
97440
98121
|
}
|
|
97441
98122
|
// ── internals ────────────────────────────────────────────────────────────
|
|
97442
98123
|
worktreesRoot() {
|
|
97443
|
-
return
|
|
98124
|
+
return join103(this.projectRoot, ".wrongstack", "worktrees");
|
|
97444
98125
|
}
|
|
97445
98126
|
async detectBaseBranch() {
|
|
97446
98127
|
const head = await this.runGit(["rev-parse", "--abbrev-ref", "HEAD"], this.projectRoot);
|
|
@@ -97858,6 +98539,7 @@ export {
|
|
|
97858
98539
|
QUEUE_MAX_ITEMS,
|
|
97859
98540
|
QUEUE_MAX_ITEM_BYTES,
|
|
97860
98541
|
QueueStore,
|
|
98542
|
+
REASONING_EFFORT_LEVELS,
|
|
97861
98543
|
REFACTOR_PLANNER_AGENT,
|
|
97862
98544
|
REPORT_STORE_FILE,
|
|
97863
98545
|
REVIEW_AGENTS,
|
|
@@ -98321,6 +99003,7 @@ export {
|
|
|
98321
99003
|
isPrivateIPv6,
|
|
98322
99004
|
isProjectId,
|
|
98323
99005
|
isProvenDirective,
|
|
99006
|
+
isReasoningEffort,
|
|
98324
99007
|
isRetryableKind,
|
|
98325
99008
|
isSafePathSegment,
|
|
98326
99009
|
isSddError,
|
|
@@ -98395,6 +99078,7 @@ export {
|
|
|
98395
99078
|
makeMailInboxTool,
|
|
98396
99079
|
makeMailSendTool,
|
|
98397
99080
|
makeMailboxTool,
|
|
99081
|
+
makeMutationTestTool,
|
|
98398
99082
|
makeQualityGateTool,
|
|
98399
99083
|
makeRollUpTool,
|
|
98400
99084
|
makeSpawnTool,
|