@wrongstack/core 0.308.6 → 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/agents/index.js +1 -0
- package/dist/coordination/agents/role-skills.d.ts +1 -0
- 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/explore-companion.d.ts +191 -0
- package/dist/coordination/fleet.d.ts +26 -0
- package/dist/coordination/index.d.ts +2 -1
- package/dist/coordination/index.js +1396 -370
- 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 +731 -52
- package/dist/execution/compaction-core.d.ts +1 -1
- package/dist/execution/compaction-elision.d.ts +0 -10
- package/dist/execution/index.js +269 -16
- package/dist/goal/index.js +54 -27
- package/dist/goal/phase-orchestrator.d.ts +7 -0
- package/dist/goal/types.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1280 -201
- package/dist/kernel/events/agent-events.d.ts +31 -2
- package/dist/models/index.js +11 -1
- package/dist/plugin/discovery.d.ts +73 -0
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/index.js +270 -29
- package/dist/plugin/loader.d.ts +5 -1
- package/dist/plugin/trust.d.ts +78 -0
- package/dist/tools/index.js +1 -0
- package/dist/types/config/mcp-features.d.ts +21 -0
- package/dist/types/config/skills-fleet-brain.d.ts +18 -0
- 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/instructions/agents/explore-companion.md +35 -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 });
|
|
@@ -21958,6 +22107,7 @@ function createProjectAgent(input, projectRoot) {
|
|
|
21958
22107
|
var skillSet = (...names) => names;
|
|
21959
22108
|
var ROLE_SKILL_SETS = {
|
|
21960
22109
|
explore: skillSet("research-web", "node-modern", "typescript-strict"),
|
|
22110
|
+
"explore-companion": skillSet("node-modern", "typescript-strict"),
|
|
21961
22111
|
search: skillSet("bug-hunter", "typescript-strict", "research-web"),
|
|
21962
22112
|
research: skillSet("research-web", "tech-stack", "security-scanner", "api-design"),
|
|
21963
22113
|
analyst: skillSet("sdd", "api-design", "testing", "security-scanner"),
|
|
@@ -29006,7 +29156,7 @@ function attachDepWatcherBridge(opts) {
|
|
|
29006
29156
|
}
|
|
29007
29157
|
|
|
29008
29158
|
// src/coordination/director.ts
|
|
29009
|
-
import { randomUUID as
|
|
29159
|
+
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
29010
29160
|
import * as fsp30 from "node:fs/promises";
|
|
29011
29161
|
|
|
29012
29162
|
// src/storage/director-state.ts
|
|
@@ -30901,7 +31051,7 @@ ${JSON.stringify(result.result, null, 2)}
|
|
|
30901
31051
|
};
|
|
30902
31052
|
|
|
30903
31053
|
// src/coordination/director-tools.ts
|
|
30904
|
-
import { randomUUID as
|
|
31054
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
30905
31055
|
import {
|
|
30906
31056
|
completeKanbanDispatch,
|
|
30907
31057
|
failKanbanDispatch,
|
|
@@ -30996,7 +31146,7 @@ function buildKanbanFleetTaskPrompt(board, task, lease) {
|
|
|
30996
31146
|
const dependencyLines = (task.dependsOn ?? []).map((depId) => board.tasks.find((candidate) => candidate.id === depId)).filter((dep) => Boolean(dep)).map((dep) => `- ${dep.title} [${dep.status}] (${dep.id})`);
|
|
30997
31147
|
const checks = task.successCriteria?.map((check) => `- ${check.description}`).join("\n");
|
|
30998
31148
|
const metrics = task.goalMetrics?.map(
|
|
30999
|
-
(metric) => `- ${metric.name}: ${metric.current ?? "n/a"}${metric.target !== void 0 ? ` / ${metric.target}` : ""}${metric.unit ? ` ${metric.unit}` : ""} [${metric.status}]`
|
|
31149
|
+
(metric) => `- ${metric.name}: ${metric.current ?? "n/a"}${metric.target !== void 0 ? ` / ${metric.direction === "at_most" ? "\u2264" : "\u2265"} ${metric.target}` : ""}${metric.unit ? ` ${metric.unit}` : ""} [${metric.status}]`
|
|
31000
31150
|
).join("\n");
|
|
31001
31151
|
const chain = task.chain ? [
|
|
31002
31152
|
`chainId: ${task.chain.chainId}`,
|
|
@@ -32135,6 +32285,413 @@ function excerpt(text2, max) {
|
|
|
32135
32285
|
...(truncated)`;
|
|
32136
32286
|
}
|
|
32137
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
|
+
|
|
32138
32695
|
// src/coordination/director-tools.ts
|
|
32139
32696
|
function makeSpawnTool(director, roster) {
|
|
32140
32697
|
const dispatchCatalog = () => {
|
|
@@ -32427,7 +32984,7 @@ function makeKanbanQueueTool(director, roster) {
|
|
|
32427
32984
|
try {
|
|
32428
32985
|
const config = buildKanbanSubagentConfig(claim.task, i, roster, instantiateRosterConfig);
|
|
32429
32986
|
subagentId = await director.spawn(config);
|
|
32430
|
-
const dispatchTaskId =
|
|
32987
|
+
const dispatchTaskId = randomUUID15();
|
|
32431
32988
|
const taskSpec = {
|
|
32432
32989
|
id: dispatchTaskId,
|
|
32433
32990
|
subagentId,
|
|
@@ -32703,6 +33260,7 @@ function buildDirectorToolset(director, roster) {
|
|
|
32703
33260
|
makeAskResultTool(director),
|
|
32704
33261
|
makeRollUpTool(director),
|
|
32705
33262
|
makeQualityGateTool(director, roster),
|
|
33263
|
+
makeMutationTestTool(director, roster),
|
|
32706
33264
|
makeTerminateTool(director),
|
|
32707
33265
|
makeTerminateAllTool(director),
|
|
32708
33266
|
makeFleetTool(director),
|
|
@@ -32789,7 +33347,7 @@ import * as fsp29 from "node:fs/promises";
|
|
|
32789
33347
|
import * as path63 from "node:path";
|
|
32790
33348
|
|
|
32791
33349
|
// src/storage/session-store.ts
|
|
32792
|
-
import { randomUUID as
|
|
33350
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
32793
33351
|
import * as fsp28 from "node:fs/promises";
|
|
32794
33352
|
import * as path62 from "node:path";
|
|
32795
33353
|
init_client();
|
|
@@ -33960,7 +34518,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
33960
34518
|
// src/storage/session-checkpoint-cas.ts
|
|
33961
34519
|
init_atomic_write();
|
|
33962
34520
|
import { spawn as spawn5 } from "node:child_process";
|
|
33963
|
-
import { createHash as createHash18, randomUUID as
|
|
34521
|
+
import { createHash as createHash18, randomUUID as randomUUID16 } from "node:crypto";
|
|
33964
34522
|
import * as fsp15 from "node:fs/promises";
|
|
33965
34523
|
import * as path54 from "node:path";
|
|
33966
34524
|
init_error();
|
|
@@ -34198,7 +34756,7 @@ var SessionCheckpointCas = class {
|
|
|
34198
34756
|
}
|
|
34199
34757
|
const temp = path54.join(
|
|
34200
34758
|
path54.dirname(target),
|
|
34201
|
-
`.${path54.basename(target)}.${process.pid}.${
|
|
34759
|
+
`.${path54.basename(target)}.${process.pid}.${randomUUID16()}.tmp`
|
|
34202
34760
|
);
|
|
34203
34761
|
let handle;
|
|
34204
34762
|
try {
|
|
@@ -36006,7 +36564,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
36006
36564
|
onAppend;
|
|
36007
36565
|
onAppendBatch;
|
|
36008
36566
|
catalogClient;
|
|
36009
|
-
maintenanceHolderId =
|
|
36567
|
+
maintenanceHolderId = randomUUID17();
|
|
36010
36568
|
_loadCache = /* @__PURE__ */ new Map();
|
|
36011
36569
|
loadCache = new SessionLoadCache(this._loadCache);
|
|
36012
36570
|
_indexCache = null;
|
|
@@ -36698,7 +37256,7 @@ async function readDirectorSubagentSession(args) {
|
|
|
36698
37256
|
}
|
|
36699
37257
|
|
|
36700
37258
|
// src/core/fallback-model.ts
|
|
36701
|
-
import { randomUUID as
|
|
37259
|
+
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
36702
37260
|
|
|
36703
37261
|
// src/types/provider.ts
|
|
36704
37262
|
init_errors();
|
|
@@ -36708,6 +37266,18 @@ var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not eno
|
|
|
36708
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;
|
|
36709
37267
|
|
|
36710
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
|
+
}
|
|
36711
37281
|
function effectiveInputTokens(usage) {
|
|
36712
37282
|
return usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
|
|
36713
37283
|
}
|
|
@@ -37730,7 +38300,7 @@ function createFallbackModelExtension(deps) {
|
|
|
37730
38300
|
let gateRequestId;
|
|
37731
38301
|
const configuredGateSeconds = cfg.fallbackGateSeconds ?? deps.fallbackGateSeconds;
|
|
37732
38302
|
if (configuredGateSeconds !== 0 && deps.fallbackGate && usableChain.length > 0) {
|
|
37733
|
-
gateRequestId =
|
|
38303
|
+
gateRequestId = randomUUID18();
|
|
37734
38304
|
const autoSwitchSeconds = Math.max(1, configuredGateSeconds ?? 7);
|
|
37735
38305
|
const gateCandidates = usableChain.map((e) => ({
|
|
37736
38306
|
providerId: e.providerId,
|
|
@@ -38702,7 +39272,7 @@ function hashStr(s) {
|
|
|
38702
39272
|
}
|
|
38703
39273
|
|
|
38704
39274
|
// src/coordination/multi-agent-coordinator.ts
|
|
38705
|
-
import { randomUUID as
|
|
39275
|
+
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
38706
39276
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
38707
39277
|
|
|
38708
39278
|
// src/coordination/coordinator/error-classifier.ts
|
|
@@ -38805,6 +39375,42 @@ var SHADOW_AGENT = {
|
|
|
38805
39375
|
...defineAgent("shadow-agent", "Shadow"),
|
|
38806
39376
|
skillNames: [...SHADOW_AGENT_SKILLS]
|
|
38807
39377
|
};
|
|
39378
|
+
var EXPLORE_COMPANION_AGENT = {
|
|
39379
|
+
...defineAgent("explore-companion", "Explore Companion"),
|
|
39380
|
+
tools: [...TOOLS.read, ...TOOLS.index],
|
|
39381
|
+
// Read-only, triple-enforced: allowlist has no write/bash, and the
|
|
39382
|
+
// disabled list blocks the escape hatches explicitly.
|
|
39383
|
+
disabledTools: [
|
|
39384
|
+
"write",
|
|
39385
|
+
"edit",
|
|
39386
|
+
"replace",
|
|
39387
|
+
"patch",
|
|
39388
|
+
"bash",
|
|
39389
|
+
"exec",
|
|
39390
|
+
"delegate",
|
|
39391
|
+
"spawn_subagent",
|
|
39392
|
+
"assign_task"
|
|
39393
|
+
],
|
|
39394
|
+
skillNames: [...ROLE_SKILL_SETS["explore-companion"]],
|
|
39395
|
+
spawnBudgetExempt: true,
|
|
39396
|
+
// Findings travel via mailbox + submit_result, not the leader's stream.
|
|
39397
|
+
textStream: "silent",
|
|
39398
|
+
toolStream: "silent"
|
|
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
|
+
};
|
|
38808
39414
|
var CRITIC_AGENT = defineAgent("critic", "Critic");
|
|
38809
39415
|
var GENERIC_AGENT = defineAgent("generic", "Generic Project Agent");
|
|
38810
39416
|
function withDispatchMetadata(definition) {
|
|
@@ -38823,6 +39429,8 @@ var FLEET_ROSTER = {
|
|
|
38823
39429
|
critic: CRITIC_AGENT,
|
|
38824
39430
|
generic: GENERIC_AGENT,
|
|
38825
39431
|
"shadow-agent": SHADOW_AGENT,
|
|
39432
|
+
"explore-companion": EXPLORE_COMPANION_AGENT,
|
|
39433
|
+
"chaos-monkey": CHAOS_MONKEY_AGENT,
|
|
38826
39434
|
...Object.fromEntries(
|
|
38827
39435
|
ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, withDispatchMetadata(d)])
|
|
38828
39436
|
)
|
|
@@ -38846,6 +39454,23 @@ var FLEET_ROSTER_BUDGETS = {
|
|
|
38846
39454
|
maxTokens: 96e3,
|
|
38847
39455
|
maxCostUsd: 0.5
|
|
38848
39456
|
},
|
|
39457
|
+
"explore-companion": {
|
|
39458
|
+
idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
|
|
39459
|
+
maxIterations: 3e3,
|
|
39460
|
+
maxToolCalls: 8e3,
|
|
39461
|
+
maxTokens: 96e3,
|
|
39462
|
+
maxCostUsd: 0.5
|
|
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
|
+
},
|
|
38849
39474
|
...Object.fromEntries(
|
|
38850
39475
|
ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.budget])
|
|
38851
39476
|
)
|
|
@@ -38908,7 +39533,8 @@ async function executeSubagentWithTimeout({
|
|
|
38908
39533
|
budget,
|
|
38909
39534
|
preemptFraction = TIMEOUT_PREEMPT_FRACTION,
|
|
38910
39535
|
abortSubagent,
|
|
38911
|
-
currentSessionId
|
|
39536
|
+
currentSessionId,
|
|
39537
|
+
gracefulFinish
|
|
38912
39538
|
}) {
|
|
38913
39539
|
const initialTimeoutMs = budget.limits.timeoutMs;
|
|
38914
39540
|
const idleLimitMs = budget.limits.idleTimeoutMs;
|
|
@@ -38939,9 +39565,17 @@ async function executeSubagentWithTimeout({
|
|
|
38939
39565
|
const scheduleNext = () => {
|
|
38940
39566
|
const wallLimit = budget.limits.timeoutMs ?? initialTimeoutMs;
|
|
38941
39567
|
const wallRemaining = initialTimeoutMs === void 0 ? Number.POSITIVE_INFINITY : wallLimit - (Date.now() - start);
|
|
38942
|
-
const idleRemaining = idleLimitMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();
|
|
38943
|
-
const preemptRemaining = initialTimeoutMs === void 0 || preemptedCeiling === wallLimit ? Number.POSITIVE_INFINITY : wallLimit * preemptFraction - (Date.now() - start);
|
|
38944
|
-
|
|
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));
|
|
38945
39579
|
};
|
|
38946
39580
|
const negotiateTimeout = async (used, limit) => {
|
|
38947
39581
|
const handler = budget.onThreshold;
|
|
@@ -38990,6 +39624,10 @@ async function executeSubagentWithTimeout({
|
|
|
38990
39624
|
const wallExceeded = wallLimit !== void 0 && elapsed2 >= wallLimit;
|
|
38991
39625
|
const idleExceeded = idleLimit !== void 0 && budget.idleMs() >= idleLimit;
|
|
38992
39626
|
if (idleExceeded && !wallExceeded) {
|
|
39627
|
+
if (gracefulFinish !== void 0 && initialTimeoutMs !== void 0) {
|
|
39628
|
+
scheduleNext();
|
|
39629
|
+
return;
|
|
39630
|
+
}
|
|
38993
39631
|
const sessionId = currentSessionId();
|
|
38994
39632
|
budget._events?.emit("budget.threshold_reached", {
|
|
38995
39633
|
...sessionId ? { sessionId } : {},
|
|
@@ -39006,7 +39644,7 @@ async function executeSubagentWithTimeout({
|
|
|
39006
39644
|
reject(new BudgetExceededError("idle_timeout", idleLimit ?? 0, budget.idleMs()));
|
|
39007
39645
|
return;
|
|
39008
39646
|
}
|
|
39009
|
-
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) {
|
|
39010
39648
|
const activityTs = Date.now() - budget.idleMs();
|
|
39011
39649
|
if (activityTs <= lastGrantActivityTs) {
|
|
39012
39650
|
preemptState = "locked" /* LOCKED */;
|
|
@@ -39040,6 +39678,22 @@ async function executeSubagentWithTimeout({
|
|
|
39040
39678
|
return;
|
|
39041
39679
|
}
|
|
39042
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
|
+
}
|
|
39043
39697
|
if (!budget.onThreshold) {
|
|
39044
39698
|
abortSubagent(ctx.subagentId);
|
|
39045
39699
|
reject(new BudgetExceededError("timeout", limit, elapsed2));
|
|
@@ -39187,7 +39841,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39187
39841
|
return { ...subagent, name: display };
|
|
39188
39842
|
}
|
|
39189
39843
|
async spawn(subagent) {
|
|
39190
|
-
const id = subagent.id ||
|
|
39844
|
+
const id = subagent.id || randomUUID19();
|
|
39191
39845
|
const cfg = this.withNickname(subagent, id);
|
|
39192
39846
|
if (this.subagents.has(id)) {
|
|
39193
39847
|
throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
|
|
@@ -39424,6 +40078,32 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39424
40078
|
completeTask(result) {
|
|
39425
40079
|
this.recordCompletion(result);
|
|
39426
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
|
+
}
|
|
39427
40107
|
// --- internal dispatching ---------------------------------------------
|
|
39428
40108
|
tryDispatchNext() {
|
|
39429
40109
|
while (this.canDispatch()) {
|
|
@@ -39597,7 +40277,14 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39597
40277
|
idleTimeoutMs: rawIdleTimeoutMs ?? this.config.defaultBudget?.idleTimeoutMs ?? configWithRosterDefaults.idleTimeoutMs
|
|
39598
40278
|
},
|
|
39599
40279
|
"auto",
|
|
39600
|
-
{
|
|
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
|
+
}
|
|
39601
40288
|
);
|
|
39602
40289
|
subagent.activeBudget = budget;
|
|
39603
40290
|
if (!this.runner) {
|
|
@@ -39630,7 +40317,8 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39630
40317
|
task,
|
|
39631
40318
|
runCtx,
|
|
39632
40319
|
budget,
|
|
39633
|
-
subagent.config.preemptFraction
|
|
40320
|
+
subagent.config.preemptFraction,
|
|
40321
|
+
resolveGracefulFinish(subagent.config)
|
|
39634
40322
|
);
|
|
39635
40323
|
result = {
|
|
39636
40324
|
subagentId,
|
|
@@ -39660,13 +40348,14 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
39660
40348
|
}
|
|
39661
40349
|
this.recordCompletion(result);
|
|
39662
40350
|
}
|
|
39663
|
-
async executeWithTimeout(runner, task, ctx, budget, preemptFraction) {
|
|
40351
|
+
async executeWithTimeout(runner, task, ctx, budget, preemptFraction, gracefulFinish) {
|
|
39664
40352
|
return executeSubagentWithTimeout({
|
|
39665
40353
|
runner,
|
|
39666
40354
|
task,
|
|
39667
40355
|
ctx,
|
|
39668
40356
|
budget,
|
|
39669
40357
|
preemptFraction,
|
|
40358
|
+
gracefulFinish,
|
|
39670
40359
|
abortSubagent: (subagentId) => this.subagents.get(subagentId)?.abortController.abort(),
|
|
39671
40360
|
currentSessionId: () => this.currentSessionId()
|
|
39672
40361
|
});
|
|
@@ -40073,7 +40762,7 @@ var Director = class _Director {
|
|
|
40073
40762
|
sessionProvider;
|
|
40074
40763
|
sessionModel;
|
|
40075
40764
|
constructor(opts) {
|
|
40076
|
-
this.id = opts.config.coordinatorId ||
|
|
40765
|
+
this.id = opts.config.coordinatorId || randomUUID20();
|
|
40077
40766
|
this.manifestPath = opts.manifestPath;
|
|
40078
40767
|
this.roster = opts.roster;
|
|
40079
40768
|
this.directorPreamble = opts.directorPreamble ?? DEFAULT_DIRECTOR_PREAMBLE;
|
|
@@ -40280,6 +40969,17 @@ var Director = class _Director {
|
|
|
40280
40969
|
isWorkComplete() {
|
|
40281
40970
|
return this.workCompleteFlag;
|
|
40282
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
|
+
}
|
|
40283
40983
|
setLeaderBtwNote(note) {
|
|
40284
40984
|
return this.btwNotes.add(note);
|
|
40285
40985
|
}
|
|
@@ -40356,7 +41056,7 @@ var Director = class _Director {
|
|
|
40356
41056
|
);
|
|
40357
41057
|
}
|
|
40358
41058
|
const msg = {
|
|
40359
|
-
id:
|
|
41059
|
+
id: randomUUID20(),
|
|
40360
41060
|
type: "task",
|
|
40361
41061
|
from: this.id,
|
|
40362
41062
|
to: subagentId,
|
|
@@ -40610,7 +41310,7 @@ var Director = class _Director {
|
|
|
40610
41310
|
};
|
|
40611
41311
|
|
|
40612
41312
|
// src/coordination/fleet-manager.ts
|
|
40613
|
-
import { randomUUID as
|
|
41313
|
+
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
40614
41314
|
import * as fsp31 from "node:fs/promises";
|
|
40615
41315
|
import * as path64 from "node:path";
|
|
40616
41316
|
init_atomic_write();
|
|
@@ -40678,7 +41378,7 @@ var FleetManager = class {
|
|
|
40678
41378
|
maxContext;
|
|
40679
41379
|
constructor(opts = {}) {
|
|
40680
41380
|
this.manifestPath = opts.manifestPath;
|
|
40681
|
-
this.directorRunId = opts.directorRunId ??
|
|
41381
|
+
this.directorRunId = opts.directorRunId ?? randomUUID21();
|
|
40682
41382
|
this.maxSpawns = opts.maxSpawns ?? Number.POSITIVE_INFINITY;
|
|
40683
41383
|
this.maxSpawnDepth = resolveMaxSpawnDepth(opts.maxSpawnDepth);
|
|
40684
41384
|
this.spawnDepth = opts.spawnDepth ?? 0;
|
|
@@ -42730,7 +43430,7 @@ function makeFleetStatusTool(opts = {}) {
|
|
|
42730
43430
|
}
|
|
42731
43431
|
|
|
42732
43432
|
// src/coordination/fleet-supervisor.ts
|
|
42733
|
-
import { randomUUID as
|
|
43433
|
+
import { randomUUID as randomUUID22 } from "node:crypto";
|
|
42734
43434
|
var COLLAB_ID_PREFIXES2 = ["bug-hunter-", "refactor-planner-", "critic-"];
|
|
42735
43435
|
var DEFAULTS = {
|
|
42736
43436
|
intervalMs: 2e4,
|
|
@@ -43008,7 +43708,7 @@ var FleetSupervisor = class {
|
|
|
43008
43708
|
*/
|
|
43009
43709
|
async decide(question, context, options, risk) {
|
|
43010
43710
|
const request = {
|
|
43011
|
-
id: `fleetsup-${
|
|
43711
|
+
id: `fleetsup-${randomUUID22()}`,
|
|
43012
43712
|
sessionId: this.opts.sessionId?.(),
|
|
43013
43713
|
source: "system",
|
|
43014
43714
|
question,
|
|
@@ -43404,7 +44104,7 @@ function attachAutoExtend(events, policy = {}) {
|
|
|
43404
44104
|
}
|
|
43405
44105
|
|
|
43406
44106
|
// src/coordination/delegate-tool.ts
|
|
43407
|
-
import { randomUUID as
|
|
44107
|
+
import { randomUUID as randomUUID23 } from "node:crypto";
|
|
43408
44108
|
import * as fsp32 from "node:fs/promises";
|
|
43409
44109
|
import * as path69 from "node:path";
|
|
43410
44110
|
init_error();
|
|
@@ -43611,7 +44311,7 @@ function createDelegateTool(opts) {
|
|
|
43611
44311
|
}
|
|
43612
44312
|
const description = delegatedTask;
|
|
43613
44313
|
const taskId = await dir.assign({
|
|
43614
|
-
id:
|
|
44314
|
+
id: randomUUID23(),
|
|
43615
44315
|
description,
|
|
43616
44316
|
subagentId
|
|
43617
44317
|
});
|
|
@@ -43832,7 +44532,7 @@ async function awaitDelegateAttempt(director, subagentId, taskId, timeoutMs, abo
|
|
|
43832
44532
|
function freshHandoffConfig(cfg, role, handoffCount) {
|
|
43833
44533
|
return {
|
|
43834
44534
|
...cfg,
|
|
43835
|
-
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)}`
|
|
43836
44536
|
};
|
|
43837
44537
|
}
|
|
43838
44538
|
function continuationFor(result, partial, config) {
|
|
@@ -43892,7 +44592,7 @@ function instantiateRosterConfig2(role, base, requestedTimeoutMs, defaultTimeout
|
|
|
43892
44592
|
timeoutMs: requestedTimeoutMs === void 0 ? rosterTimeoutMs ?? defaultTimeoutMs : void 0,
|
|
43893
44593
|
// Give each spawn a fresh id so parallel or repeated delegates
|
|
43894
44594
|
// can use the same role safely.
|
|
43895
|
-
id: `${role}-${
|
|
44595
|
+
id: `${role}-${randomUUID23().slice(0, 8)}`
|
|
43896
44596
|
};
|
|
43897
44597
|
}
|
|
43898
44598
|
function hintForKind(kind, retryable, backoffMs, partial) {
|
|
@@ -44017,6 +44717,334 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
44017
44717
|
return void 0;
|
|
44018
44718
|
}
|
|
44019
44719
|
|
|
44720
|
+
// src/coordination/explore-companion.ts
|
|
44721
|
+
import { randomUUID as randomUUID24 } from "node:crypto";
|
|
44722
|
+
var DEFAULT_EXPLORE_COMPANION_AGENT_ID = "explore-companion";
|
|
44723
|
+
var DEFAULT_PROBE_COOLDOWN_MS = 12e4;
|
|
44724
|
+
var DEFAULT_MAX_PENDING_PROBES = 8;
|
|
44725
|
+
var DEFAULT_MAILBOX_POLL_INTERVAL_MS = 5e3;
|
|
44726
|
+
var DEFAULT_EXPLORE_EDIT_TOOLS = [
|
|
44727
|
+
"edit",
|
|
44728
|
+
"write",
|
|
44729
|
+
"patch",
|
|
44730
|
+
"multi_edit",
|
|
44731
|
+
"multiedit",
|
|
44732
|
+
"str_replace"
|
|
44733
|
+
];
|
|
44734
|
+
var DEFAULT_EXPLORE_SEARCH_TOOLS = [
|
|
44735
|
+
"search",
|
|
44736
|
+
"grep",
|
|
44737
|
+
"codebase-search"
|
|
44738
|
+
];
|
|
44739
|
+
function buildProbeTaskText(probe2) {
|
|
44740
|
+
const payload = { probe: probe2.probe };
|
|
44741
|
+
if (probe2.hint) payload.hint = probe2.hint;
|
|
44742
|
+
if (probe2.context) payload.context = probe2.context;
|
|
44743
|
+
return JSON.stringify(payload, null, 2);
|
|
44744
|
+
}
|
|
44745
|
+
function extractedPath(input) {
|
|
44746
|
+
if (!input || typeof input !== "object") return void 0;
|
|
44747
|
+
const rec = input;
|
|
44748
|
+
const candidate = typeof rec["path"] === "string" ? rec["path"] : typeof rec["file"] === "string" ? rec["file"] : void 0;
|
|
44749
|
+
return candidate && candidate.length > 0 ? candidate : void 0;
|
|
44750
|
+
}
|
|
44751
|
+
function looksEmpty(e) {
|
|
44752
|
+
if (typeof e.outputLines === "number" && e.outputLines === 0) return true;
|
|
44753
|
+
const out = e.output ?? "";
|
|
44754
|
+
return /(?:^|\n)(?:no |0 )(?:matches|results|files? found|occurrences)/i.test(out) || /total\s*:\s*0\b/i.test(out);
|
|
44755
|
+
}
|
|
44756
|
+
function extractSubjectTokens(text2) {
|
|
44757
|
+
const out = [];
|
|
44758
|
+
const fileRe = /([\w@./-]+\.(?:[cm]?[jt]sx?|json|md|py|go|rs|ya?ml))\b/g;
|
|
44759
|
+
for (const m of text2.matchAll(fileRe)) {
|
|
44760
|
+
const value = m[1];
|
|
44761
|
+
if (value) out.push({ kind: "file", value });
|
|
44762
|
+
}
|
|
44763
|
+
const symRe = /\b[A-Z][A-Za-z0-9_]{2,}\b/g;
|
|
44764
|
+
for (const m of text2.matchAll(symRe)) {
|
|
44765
|
+
out.push({ kind: "symbol", value: m[0] });
|
|
44766
|
+
}
|
|
44767
|
+
return out;
|
|
44768
|
+
}
|
|
44769
|
+
var ExploreCompanion = class {
|
|
44770
|
+
constructor(opts) {
|
|
44771
|
+
this.opts = opts;
|
|
44772
|
+
this.cfg = this.resolveConfig(opts);
|
|
44773
|
+
}
|
|
44774
|
+
opts;
|
|
44775
|
+
unsubscribers = [];
|
|
44776
|
+
/** Paths the leader has read (readSet) — feeds edit-unread + unfamiliar-read. */
|
|
44777
|
+
readSet = /* @__PURE__ */ new Set();
|
|
44778
|
+
/** subject → last probe time; cooldown gate. Survives detach/reconfigure. */
|
|
44779
|
+
probedAt = /* @__PURE__ */ new Map();
|
|
44780
|
+
/** todo id → last observed status, per leader agent. */
|
|
44781
|
+
todoSeen = /* @__PURE__ */ new Map();
|
|
44782
|
+
pending = [];
|
|
44783
|
+
inFlight = false;
|
|
44784
|
+
pollTimer;
|
|
44785
|
+
running = false;
|
|
44786
|
+
hostStarted = false;
|
|
44787
|
+
cfg;
|
|
44788
|
+
resolveConfig(opts) {
|
|
44789
|
+
const signals = opts.signals ?? {};
|
|
44790
|
+
return {
|
|
44791
|
+
enabled: opts.enabled ?? true,
|
|
44792
|
+
cooldownMs: opts.cooldownMs ?? DEFAULT_PROBE_COOLDOWN_MS,
|
|
44793
|
+
maxPending: opts.maxPending ?? DEFAULT_MAX_PENDING_PROBES,
|
|
44794
|
+
pollIntervalMs: opts.pollIntervalMs ?? DEFAULT_MAILBOX_POLL_INTERVAL_MS,
|
|
44795
|
+
companionAgentId: opts.companionAgentId ?? DEFAULT_EXPLORE_COMPANION_AGENT_ID,
|
|
44796
|
+
signals: {
|
|
44797
|
+
editUnreadFile: signals.editUnreadFile ?? true,
|
|
44798
|
+
searchZeroHits: signals.searchZeroHits ?? true,
|
|
44799
|
+
unfamiliarRead: signals.unfamiliarRead ?? true,
|
|
44800
|
+
todoInProgress: signals.todoInProgress ?? true,
|
|
44801
|
+
errorSymbol: signals.errorSymbol ?? true,
|
|
44802
|
+
mailboxAsk: signals.mailboxAsk ?? true
|
|
44803
|
+
},
|
|
44804
|
+
fileEditTools: new Set(
|
|
44805
|
+
(opts.fileEditTools ?? DEFAULT_EXPLORE_EDIT_TOOLS).map((t2) => t2.toLowerCase())
|
|
44806
|
+
),
|
|
44807
|
+
searchTools: new Set(
|
|
44808
|
+
(opts.searchTools ?? DEFAULT_EXPLORE_SEARCH_TOOLS).map((t2) => t2.toLowerCase())
|
|
44809
|
+
)
|
|
44810
|
+
};
|
|
44811
|
+
}
|
|
44812
|
+
/** Resolve the leader's own session id for event filtering. */
|
|
44813
|
+
resolveLeaderSessionId() {
|
|
44814
|
+
const sid = this.opts.leaderSessionId;
|
|
44815
|
+
return typeof sid === "function" ? sid() : sid;
|
|
44816
|
+
}
|
|
44817
|
+
/** Resolve the leader's agent id for todo diffing (optional signal). */
|
|
44818
|
+
resolveLeaderAgentId() {
|
|
44819
|
+
const aid = this.opts.leaderAgentId;
|
|
44820
|
+
if (!aid) return void 0;
|
|
44821
|
+
return typeof aid === "function" ? aid() : aid;
|
|
44822
|
+
}
|
|
44823
|
+
/** Re-apply tunables to a (possibly running) companion. */
|
|
44824
|
+
reconfigure(next) {
|
|
44825
|
+
const merged = { ...this.opts, ...next };
|
|
44826
|
+
const nextCfg = this.resolveConfig(merged);
|
|
44827
|
+
const changed = nextCfg.enabled !== this.cfg.enabled || nextCfg.cooldownMs !== this.cfg.cooldownMs || nextCfg.maxPending !== this.cfg.maxPending || nextCfg.pollIntervalMs !== this.cfg.pollIntervalMs || nextCfg.companionAgentId !== this.cfg.companionAgentId || Object.keys(nextCfg.signals).some(
|
|
44828
|
+
(k) => nextCfg.signals[k] !== this.cfg.signals[k]
|
|
44829
|
+
);
|
|
44830
|
+
this.cfg = nextCfg;
|
|
44831
|
+
if (!changed) return false;
|
|
44832
|
+
if (this.hostStarted) {
|
|
44833
|
+
this.detach();
|
|
44834
|
+
this.attach();
|
|
44835
|
+
}
|
|
44836
|
+
return true;
|
|
44837
|
+
}
|
|
44838
|
+
/** Begin watching. Idempotent; a disabled companion records intent only. */
|
|
44839
|
+
start() {
|
|
44840
|
+
this.hostStarted = true;
|
|
44841
|
+
this.attach();
|
|
44842
|
+
}
|
|
44843
|
+
/** Stop watching and drop the host's intent to watch. */
|
|
44844
|
+
stop() {
|
|
44845
|
+
this.hostStarted = false;
|
|
44846
|
+
this.detach();
|
|
44847
|
+
}
|
|
44848
|
+
/** True while the watchers are attached. */
|
|
44849
|
+
isRunning() {
|
|
44850
|
+
return this.running;
|
|
44851
|
+
}
|
|
44852
|
+
/** Number of probes queued but not yet dispatched (for status surfaces). */
|
|
44853
|
+
pendingCount() {
|
|
44854
|
+
return this.pending.length;
|
|
44855
|
+
}
|
|
44856
|
+
attach() {
|
|
44857
|
+
if (!this.cfg.enabled || this.running) return;
|
|
44858
|
+
this.running = true;
|
|
44859
|
+
this.unsubscribers.push(
|
|
44860
|
+
this.opts.events.on("tool.executed", (e) => {
|
|
44861
|
+
const lsid = this.resolveLeaderSessionId();
|
|
44862
|
+
if (lsid && e.sessionId && e.sessionId !== lsid) return;
|
|
44863
|
+
this.trackToolExecuted(e);
|
|
44864
|
+
})
|
|
44865
|
+
);
|
|
44866
|
+
if (this.cfg.signals.todoInProgress && this.resolveLeaderAgentId()) {
|
|
44867
|
+
this.unsubscribers.push(
|
|
44868
|
+
this.opts.events.on("session.agents_updated", (e) => {
|
|
44869
|
+
const lsid = this.resolveLeaderSessionId();
|
|
44870
|
+
if (lsid && e.sessionId && e.sessionId !== lsid) return;
|
|
44871
|
+
this.trackAgentTodos(e.agents);
|
|
44872
|
+
})
|
|
44873
|
+
);
|
|
44874
|
+
}
|
|
44875
|
+
if (this.cfg.signals.errorSymbol) {
|
|
44876
|
+
this.unsubscribers.push(
|
|
44877
|
+
this.opts.events.on("error", (e) => {
|
|
44878
|
+
const lsid = this.resolveLeaderSessionId();
|
|
44879
|
+
if (lsid && e.sessionId && e.sessionId !== lsid) return;
|
|
44880
|
+
this.trackError(e.err);
|
|
44881
|
+
})
|
|
44882
|
+
);
|
|
44883
|
+
}
|
|
44884
|
+
if (this.cfg.signals.mailboxAsk) {
|
|
44885
|
+
this.pollTimer = setInterval(() => {
|
|
44886
|
+
void this.pollMailbox();
|
|
44887
|
+
}, this.cfg.pollIntervalMs);
|
|
44888
|
+
this.pollTimer.unref?.();
|
|
44889
|
+
}
|
|
44890
|
+
}
|
|
44891
|
+
/** Tear down watchers without touching host intent. Cooldowns survive. */
|
|
44892
|
+
detach() {
|
|
44893
|
+
for (const unsub of this.unsubscribers.splice(0)) unsub();
|
|
44894
|
+
if (this.pollTimer) {
|
|
44895
|
+
clearInterval(this.pollTimer);
|
|
44896
|
+
this.pollTimer = void 0;
|
|
44897
|
+
}
|
|
44898
|
+
this.running = false;
|
|
44899
|
+
}
|
|
44900
|
+
// ── signal handlers ──────────────────────────────────────────────────────
|
|
44901
|
+
trackToolExecuted(e) {
|
|
44902
|
+
const tool = e.name.toLowerCase();
|
|
44903
|
+
const path131 = extractedPath(e.input);
|
|
44904
|
+
if (e.ok && this.cfg.signals.editUnreadFile && this.cfg.fileEditTools.has(tool) && path131) {
|
|
44905
|
+
if (!this.readSet.has(path131)) {
|
|
44906
|
+
this.engage({
|
|
44907
|
+
id: randomUUID24(),
|
|
44908
|
+
probe: `Map file ${path131}: role, exports, dependencies, and callers \u2014 the leader is about to edit it.`,
|
|
44909
|
+
hint: { file: path131 },
|
|
44910
|
+
context: `Leader edited ${path131} without reading it first.`,
|
|
44911
|
+
source: "edit_unread_file",
|
|
44912
|
+
subject: `file:${path131}`,
|
|
44913
|
+
createdAt: this.now()
|
|
44914
|
+
});
|
|
44915
|
+
}
|
|
44916
|
+
return;
|
|
44917
|
+
}
|
|
44918
|
+
if (e.ok && this.cfg.signals.unfamiliarRead && tool === "read" && path131) {
|
|
44919
|
+
if (!this.readSet.has(path131)) {
|
|
44920
|
+
this.readSet.add(path131);
|
|
44921
|
+
this.engage({
|
|
44922
|
+
id: randomUUID24(),
|
|
44923
|
+
probe: `Skeleton + callers + dependents of ${path131}: what it exports, who imports it, and how it fits the feature flow.`,
|
|
44924
|
+
hint: { file: path131 },
|
|
44925
|
+
context: `Leader read unfamiliar file ${path131}.`,
|
|
44926
|
+
source: "unfamiliar_read",
|
|
44927
|
+
subject: `file:${path131}`,
|
|
44928
|
+
createdAt: this.now()
|
|
44929
|
+
});
|
|
44930
|
+
}
|
|
44931
|
+
return;
|
|
44932
|
+
}
|
|
44933
|
+
if (e.ok && this.cfg.signals.searchZeroHits && this.cfg.searchTools.has(tool) && looksEmpty(e)) {
|
|
44934
|
+
const input = e.input ?? {};
|
|
44935
|
+
const query = typeof input["query"] === "string" ? input["query"] : typeof input["pattern"] === "string" ? input["pattern"] : "";
|
|
44936
|
+
this.engage({
|
|
44937
|
+
id: randomUUID24(),
|
|
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.`,
|
|
44939
|
+
hint: query ? { symbol: query } : void 0,
|
|
44940
|
+
context: `${e.name} for "${query}" returned zero results.`,
|
|
44941
|
+
source: "search_zero_hits",
|
|
44942
|
+
subject: `search:${query}`,
|
|
44943
|
+
createdAt: this.now()
|
|
44944
|
+
});
|
|
44945
|
+
}
|
|
44946
|
+
}
|
|
44947
|
+
trackAgentTodos(agents) {
|
|
44948
|
+
const leaderId = this.resolveLeaderAgentId();
|
|
44949
|
+
if (!leaderId) return;
|
|
44950
|
+
const leader = agents.find((a) => a.id === leaderId);
|
|
44951
|
+
if (!leader?.todos) return;
|
|
44952
|
+
for (const todo of leader.todos) {
|
|
44953
|
+
const prev = this.todoSeen.get(todo.id);
|
|
44954
|
+
if (prev !== "in_progress" && todo.status === "in_progress") {
|
|
44955
|
+
const mentions = extractSubjectTokens(todo.content);
|
|
44956
|
+
const first = mentions[0];
|
|
44957
|
+
this.engage({
|
|
44958
|
+
id: randomUUID24(),
|
|
44959
|
+
probe: `Pre-map the files/symbols behind this in-progress todo: "${todo.content.slice(0, 160)}".`,
|
|
44960
|
+
hint: first ? { [first.kind]: first.value } : void 0,
|
|
44961
|
+
context: `Todo "${todo.content.slice(0, 120)}" flipped to in_progress.`,
|
|
44962
|
+
source: "todo_in_progress",
|
|
44963
|
+
subject: `todo:${todo.id}`,
|
|
44964
|
+
createdAt: this.now()
|
|
44965
|
+
});
|
|
44966
|
+
}
|
|
44967
|
+
this.todoSeen.set(todo.id, todo.status);
|
|
44968
|
+
}
|
|
44969
|
+
}
|
|
44970
|
+
trackError(err) {
|
|
44971
|
+
const tokens = extractSubjectTokens(err.message);
|
|
44972
|
+
for (const token of tokens.slice(0, 2)) {
|
|
44973
|
+
this.engage({
|
|
44974
|
+
id: randomUUID24(),
|
|
44975
|
+
probe: `What is ${token.value}, where does it live, and who uses it? The leader hit an error naming it.`,
|
|
44976
|
+
hint: { [token.kind]: token.value },
|
|
44977
|
+
context: `Error: ${err.message.slice(0, 300)}`,
|
|
44978
|
+
source: "error_symbol",
|
|
44979
|
+
subject: `token:${token.value}`,
|
|
44980
|
+
createdAt: this.now()
|
|
44981
|
+
});
|
|
44982
|
+
}
|
|
44983
|
+
}
|
|
44984
|
+
async pollMailbox() {
|
|
44985
|
+
if (!this.cfg.enabled || !this.cfg.signals.mailboxAsk) return;
|
|
44986
|
+
try {
|
|
44987
|
+
const messages = await this.opts.mailbox.query({
|
|
44988
|
+
unreadBy: this.cfg.companionAgentId,
|
|
44989
|
+
limit: 20
|
|
44990
|
+
});
|
|
44991
|
+
const lsid = this.resolveLeaderSessionId();
|
|
44992
|
+
for (const msg of messages) {
|
|
44993
|
+
if (msg.type !== "ask" && msg.type !== "assign") continue;
|
|
44994
|
+
const fromLeader = isMailboxLeader(msg.from) || lsid != null && msg.senderSessionId === lsid;
|
|
44995
|
+
if (!fromLeader) continue;
|
|
44996
|
+
this.engage({
|
|
44997
|
+
id: randomUUID24(),
|
|
44998
|
+
probe: msg.body.trim().slice(0, 2e3) || msg.subject,
|
|
44999
|
+
context: `Direct ask from ${msg.from}: ${msg.subject}`,
|
|
45000
|
+
source: "mailbox_ask",
|
|
45001
|
+
subject: `mail:${msg.id}`,
|
|
45002
|
+
createdAt: this.now()
|
|
45003
|
+
});
|
|
45004
|
+
await this.opts.mailbox.ack({
|
|
45005
|
+
messageId: msg.id,
|
|
45006
|
+
readerId: this.cfg.companionAgentId,
|
|
45007
|
+
read: true,
|
|
45008
|
+
completed: true
|
|
45009
|
+
}).catch(() => {
|
|
45010
|
+
});
|
|
45011
|
+
}
|
|
45012
|
+
} catch {
|
|
45013
|
+
}
|
|
45014
|
+
}
|
|
45015
|
+
// ── engagement ───────────────────────────────────────────────────────────
|
|
45016
|
+
cooldownOk(subject2) {
|
|
45017
|
+
const last = this.probedAt.get(subject2);
|
|
45018
|
+
return last === void 0 || this.now() - last >= this.cfg.cooldownMs;
|
|
45019
|
+
}
|
|
45020
|
+
now() {
|
|
45021
|
+
return this.opts.now ? this.opts.now() : Date.now();
|
|
45022
|
+
}
|
|
45023
|
+
engage(probe2) {
|
|
45024
|
+
if (!this.cfg.enabled) return;
|
|
45025
|
+
if (!this.cooldownOk(probe2.subject)) return;
|
|
45026
|
+
this.probedAt.set(probe2.subject, this.now());
|
|
45027
|
+
if (this.pending.length >= this.cfg.maxPending) {
|
|
45028
|
+
this.pending.shift();
|
|
45029
|
+
}
|
|
45030
|
+
this.pending.push(probe2);
|
|
45031
|
+
void this.drain();
|
|
45032
|
+
}
|
|
45033
|
+
async drain() {
|
|
45034
|
+
if (this.inFlight) return;
|
|
45035
|
+
const probe2 = this.pending.shift();
|
|
45036
|
+
if (!probe2) return;
|
|
45037
|
+
this.inFlight = true;
|
|
45038
|
+
try {
|
|
45039
|
+
await this.opts.onProbe(probe2);
|
|
45040
|
+
} catch {
|
|
45041
|
+
} finally {
|
|
45042
|
+
this.inFlight = false;
|
|
45043
|
+
if (this.pending.length > 0) void this.drain();
|
|
45044
|
+
}
|
|
45045
|
+
}
|
|
45046
|
+
};
|
|
45047
|
+
|
|
44020
45048
|
// src/coordination/mailbox-codecs.ts
|
|
44021
45049
|
var MailboxValidationError = class extends Error {
|
|
44022
45050
|
code;
|
|
@@ -44048,6 +45076,22 @@ var SEND_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
44048
45076
|
// receiver trusts the sender-asserted `sessionId`; the boundary must
|
|
44049
45077
|
// refuse the field entirely.
|
|
44050
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
|
+
}
|
|
44051
45095
|
var ACK_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
44052
45096
|
"messageId",
|
|
44053
45097
|
"read",
|
|
@@ -44285,7 +45329,9 @@ function makeMailSendTool(opts = {}) {
|
|
|
44285
45329
|
required: ["to", "subject", "body"]
|
|
44286
45330
|
},
|
|
44287
45331
|
async execute(input, ctx) {
|
|
44288
|
-
const i
|
|
45332
|
+
const { payload: i, stripped } = filterMailboxSendPayload(
|
|
45333
|
+
input ?? {}
|
|
45334
|
+
);
|
|
44289
45335
|
const rawTo = i.to;
|
|
44290
45336
|
const subject2 = i.subject;
|
|
44291
45337
|
const body = i.body;
|
|
@@ -44308,15 +45354,13 @@ function makeMailSendTool(opts = {}) {
|
|
|
44308
45354
|
recipientAliases: /* @__PURE__ */ new Set([codecIdentity.baseId]),
|
|
44309
45355
|
sessionId: codecIdentity.sessionId
|
|
44310
45356
|
};
|
|
45357
|
+
let parsed;
|
|
44311
45358
|
try {
|
|
44312
|
-
parseMailboxSendInput(i, codecActor);
|
|
45359
|
+
parsed = parseMailboxSendInput(i, codecActor);
|
|
44313
45360
|
} catch (err) {
|
|
44314
45361
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
44315
45362
|
}
|
|
44316
|
-
const audience =
|
|
44317
|
-
if (audience !== void 0 && audience !== "all" && audience !== "leaders") {
|
|
44318
|
-
return { ok: false, error: '"audience" must be "all" or "leaders".' };
|
|
44319
|
-
}
|
|
45363
|
+
const audience = parsed.audience;
|
|
44320
45364
|
const mb = resolveMailbox(ctx);
|
|
44321
45365
|
const identity2 = await register(mb, ctx);
|
|
44322
45366
|
const requestedTo = normalizeRecipient(rawTo, identity2.sessionId);
|
|
@@ -44330,10 +45374,10 @@ function makeMailSendTool(opts = {}) {
|
|
|
44330
45374
|
to: delivery.to,
|
|
44331
45375
|
type: resolvedType,
|
|
44332
45376
|
audience: delivery.audience,
|
|
44333
|
-
subject:
|
|
44334
|
-
body,
|
|
44335
|
-
priority:
|
|
44336
|
-
replyTo:
|
|
45377
|
+
subject: parsed.subject,
|
|
45378
|
+
body: parsed.body,
|
|
45379
|
+
priority: parsed.priority,
|
|
45380
|
+
replyTo: parsed.replyTo,
|
|
44337
45381
|
senderSessionId: identity2.sessionId
|
|
44338
45382
|
});
|
|
44339
45383
|
return {
|
|
@@ -44341,7 +45385,9 @@ function makeMailSendTool(opts = {}) {
|
|
|
44341
45385
|
messageId: msg.id,
|
|
44342
45386
|
from: identity2.callerId,
|
|
44343
45387
|
to: msg.to,
|
|
44344
|
-
|
|
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}.` }
|
|
44345
45391
|
};
|
|
44346
45392
|
}
|
|
44347
45393
|
};
|
|
@@ -47867,7 +48913,7 @@ function createAgentMonitorService(opts) {
|
|
|
47867
48913
|
}
|
|
47868
48914
|
|
|
47869
48915
|
// src/coordination/autonomous-brain.ts
|
|
47870
|
-
import { randomUUID as
|
|
48916
|
+
import { randomUUID as randomUUID25 } from "node:crypto";
|
|
47871
48917
|
var AutonomousBrain = class {
|
|
47872
48918
|
graph;
|
|
47873
48919
|
// Fleet bus for emitting decisions — null-safe, no-op if not provided
|
|
@@ -47973,7 +49019,7 @@ var AutonomousBrain = class {
|
|
|
47973
49019
|
consequence: i === 0 ? `Spawn the most appropriate agent for: ${taskDescription.slice(0, 80)}` : `Spawn an alternative agent for the same task`
|
|
47974
49020
|
}));
|
|
47975
49021
|
return this.decideAuto({
|
|
47976
|
-
id:
|
|
49022
|
+
id: randomUUID25(),
|
|
47977
49023
|
source,
|
|
47978
49024
|
decisionType: "spawn",
|
|
47979
49025
|
question: `Should we spawn a subagent for this task?`,
|
|
@@ -48016,7 +49062,7 @@ var AutonomousBrain = class {
|
|
|
48016
49062
|
}
|
|
48017
49063
|
];
|
|
48018
49064
|
return this.decideAuto({
|
|
48019
|
-
id:
|
|
49065
|
+
id: randomUUID25(),
|
|
48020
49066
|
source,
|
|
48021
49067
|
decisionType: "approve_change",
|
|
48022
49068
|
question: `Should we approve the change "${change.title}"?`,
|
|
@@ -48075,7 +49121,7 @@ var AutonomousBrain = class {
|
|
|
48075
49121
|
consequence: "Break the task into smaller sub-tasks"
|
|
48076
49122
|
});
|
|
48077
49123
|
return this.decideAuto({
|
|
48078
|
-
id:
|
|
49124
|
+
id: randomUUID25(),
|
|
48079
49125
|
source,
|
|
48080
49126
|
decisionType: "escalate_task",
|
|
48081
49127
|
question: `Task failed: ${error2.slice(0, 100)}. How should we proceed?`,
|
|
@@ -48209,12 +49255,12 @@ ${ctx.error}`);
|
|
|
48209
49255
|
};
|
|
48210
49256
|
|
|
48211
49257
|
// src/coordination/autonomous-coordinator.ts
|
|
48212
|
-
import { randomUUID as
|
|
49258
|
+
import { randomUUID as randomUUID28 } from "node:crypto";
|
|
48213
49259
|
|
|
48214
49260
|
// src/coordination/knowledge-graph.ts
|
|
48215
49261
|
init_file_permissions();
|
|
48216
49262
|
init_atomic_write();
|
|
48217
|
-
import { randomUUID as
|
|
49263
|
+
import { randomUUID as randomUUID26 } from "node:crypto";
|
|
48218
49264
|
import * as fsp34 from "node:fs/promises";
|
|
48219
49265
|
import * as path73 from "node:path";
|
|
48220
49266
|
var DEFAULT_MAX_NODES = 2e3;
|
|
@@ -48262,7 +49308,7 @@ var KnowledgeGraph = class _KnowledgeGraph {
|
|
|
48262
49308
|
* Returns the node with its assigned id.
|
|
48263
49309
|
*/
|
|
48264
49310
|
async add(node) {
|
|
48265
|
-
const full = { id:
|
|
49311
|
+
const full = { id: randomUUID26(), ...node };
|
|
48266
49312
|
this.nodes.set(full.id, full);
|
|
48267
49313
|
this._trackSeq(full.id);
|
|
48268
49314
|
this._addToIndex(full, this._indexKeys(full));
|
|
@@ -48391,8 +49437,8 @@ var KnowledgeGraph = class _KnowledgeGraph {
|
|
|
48391
49437
|
if (this.subs.size >= MAX_SUBSCRIPTIONS) {
|
|
48392
49438
|
throw new Error(`Knowledge graph subscription limit reached (${MAX_SUBSCRIPTIONS})`);
|
|
48393
49439
|
}
|
|
48394
|
-
const channel2 =
|
|
48395
|
-
const sub = { id:
|
|
49440
|
+
const channel2 = randomUUID26();
|
|
49441
|
+
const sub = { id: randomUUID26(), agentId, filter, channel: channel2 };
|
|
48396
49442
|
this.subs.set(channel2, sub);
|
|
48397
49443
|
this.pendingDeliveries.set(channel2, []);
|
|
48398
49444
|
return channel2;
|
|
@@ -48873,7 +49919,7 @@ var TaskDAG = class {
|
|
|
48873
49919
|
};
|
|
48874
49920
|
|
|
48875
49921
|
// src/coordination/task-auctioneer.ts
|
|
48876
|
-
import { randomUUID as
|
|
49922
|
+
import { randomUUID as randomUUID27 } from "node:crypto";
|
|
48877
49923
|
function isTerminalGoalStatus(status) {
|
|
48878
49924
|
return status === "done" || status === "failed";
|
|
48879
49925
|
}
|
|
@@ -48996,7 +50042,7 @@ var TaskAuctioneer = class {
|
|
|
48996
50042
|
const score = dispatchResult.confidence * (dispatchResult.role === agent.agentRole ? 1.2 : 1);
|
|
48997
50043
|
if (score < this.minConfidence) return false;
|
|
48998
50044
|
const bid = {
|
|
48999
|
-
id:
|
|
50045
|
+
id: randomUUID27(),
|
|
49000
50046
|
taskId,
|
|
49001
50047
|
agentId: agent.agentId,
|
|
49002
50048
|
agentName: agent.agentName,
|
|
@@ -49933,7 +50979,7 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
|
|
|
49933
50979
|
break;
|
|
49934
50980
|
}
|
|
49935
50981
|
const decision = await this.brain.decideAuto({
|
|
49936
|
-
id:
|
|
50982
|
+
id: randomUUID28(),
|
|
49937
50983
|
source: "system",
|
|
49938
50984
|
decisionType: "prioritize_goals",
|
|
49939
50985
|
question: `What should we work on next? Open goals: ${dispatchable.map((g) => g.title).join(", ")}`,
|
|
@@ -50848,7 +51894,7 @@ var TOKENS = {
|
|
|
50848
51894
|
init_errors();
|
|
50849
51895
|
|
|
50850
51896
|
// src/hq/factory.ts
|
|
50851
|
-
import { createHash as createHash24, randomUUID as
|
|
51897
|
+
import { createHash as createHash24, randomUUID as randomUUID31 } from "node:crypto";
|
|
50852
51898
|
import * as fs30 from "node:fs";
|
|
50853
51899
|
import { hostname as hostname3 } from "node:os";
|
|
50854
51900
|
import { basename as basename15 } from "node:path";
|
|
@@ -50856,13 +51902,13 @@ import { basename as basename15 } from "node:path";
|
|
|
50856
51902
|
// src/hq/auth-store.ts
|
|
50857
51903
|
init_file_permissions();
|
|
50858
51904
|
init_atomic_write();
|
|
50859
|
-
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";
|
|
50860
51906
|
import * as syncFs from "node:fs";
|
|
50861
51907
|
import * as fs29 from "node:fs/promises";
|
|
50862
51908
|
import * as path75 from "node:path";
|
|
50863
51909
|
|
|
50864
51910
|
// src/hq/auth-audit.ts
|
|
50865
|
-
import { appendFileSync as appendFileSync2, readFileSync as
|
|
51911
|
+
import { appendFileSync as appendFileSync2, readFileSync as readFileSync21, mkdirSync as mkdirSync9 } from "node:fs";
|
|
50866
51912
|
import * as path74 from "node:path";
|
|
50867
51913
|
function hqAuthAuditPath(dataDir) {
|
|
50868
51914
|
return path74.join(dataDir, "auth-audit.jsonl");
|
|
@@ -50871,7 +51917,7 @@ function readHqAuthAuditTail(dataDir, maxEntries = 50) {
|
|
|
50871
51917
|
const filePath = hqAuthAuditPath(dataDir);
|
|
50872
51918
|
let content;
|
|
50873
51919
|
try {
|
|
50874
|
-
content =
|
|
51920
|
+
content = readFileSync21(filePath, "utf8");
|
|
50875
51921
|
} catch {
|
|
50876
51922
|
return [];
|
|
50877
51923
|
}
|
|
@@ -51183,8 +52229,8 @@ function mintHqToken(labelOrOptions) {
|
|
|
51183
52229
|
const at = opts.now ?? Date.now();
|
|
51184
52230
|
const createdAtIso = new Date(at).toISOString();
|
|
51185
52231
|
return {
|
|
51186
|
-
id:
|
|
51187
|
-
token:
|
|
52232
|
+
id: randomUUID29(),
|
|
52233
|
+
token: randomUUID29().replace(/-/g, "") + randomUUID29().replace(/-/g, ""),
|
|
51188
52234
|
createdAt: createdAtIso,
|
|
51189
52235
|
...opts.label ? { label: opts.label } : {},
|
|
51190
52236
|
...opts.ttlMs !== void 0 && Number.isFinite(opts.ttlMs) && opts.ttlMs > 0 ? { expiresAt: new Date(at + opts.ttlMs).toISOString() } : {}
|
|
@@ -51244,7 +52290,7 @@ function watchHqAuthFile(dataDir, onChange, opts = {}) {
|
|
|
51244
52290
|
}
|
|
51245
52291
|
|
|
51246
52292
|
// src/hq/publisher.ts
|
|
51247
|
-
import { randomUUID as
|
|
52293
|
+
import { randomUUID as randomUUID30 } from "node:crypto";
|
|
51248
52294
|
import * as v82 from "node:v8";
|
|
51249
52295
|
|
|
51250
52296
|
// src/hq/protocol/governance.ts
|
|
@@ -52318,7 +53364,7 @@ var HqPublisher = class {
|
|
|
52318
53364
|
this.options = options;
|
|
52319
53365
|
this.socketFactory = options.socketFactory ?? defaultSocketFactory;
|
|
52320
53366
|
this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
52321
|
-
this.idFactory = options.idFactory ??
|
|
53367
|
+
this.idFactory = options.idFactory ?? randomUUID30;
|
|
52322
53368
|
this.capabilities = options.capabilities ?? [
|
|
52323
53369
|
"telemetry.publish",
|
|
52324
53370
|
"mailbox.summary",
|
|
@@ -52902,7 +53948,7 @@ function createHqPublisherFromEnv(options) {
|
|
|
52902
53948
|
const projectAlias = config.projectAlias?.trim() || void 0;
|
|
52903
53949
|
const projectName = projectAlias ?? options.projectName ?? (basename15(options.projectRoot) || "unknown");
|
|
52904
53950
|
const client = {
|
|
52905
|
-
clientId: `${machineId}:${options.clientKind}:${process.pid}:${
|
|
53951
|
+
clientId: `${machineId}:${options.clientKind}:${process.pid}:${randomUUID31().slice(0, 8)}`,
|
|
52906
53952
|
kind: options.clientKind,
|
|
52907
53953
|
machineId,
|
|
52908
53954
|
...host ? { hostname: host } : {},
|
|
@@ -53171,40 +54217,6 @@ async function injectPendingMailboxMessages(checkMailbox2, foldFn, a, deliveryMo
|
|
|
53171
54217
|
return interruptMsg ? { interrupt: true, interruptReason: interruptMsg.body || interruptMsg.subject || "operator interrupt" } : { interrupt: false };
|
|
53172
54218
|
}
|
|
53173
54219
|
|
|
53174
|
-
// src/core/btw.ts
|
|
53175
|
-
var META_KEY2 = "_btwNotes";
|
|
53176
|
-
var MAX_PENDING = 20;
|
|
53177
|
-
function readQueue(ctx) {
|
|
53178
|
-
const raw = ctx.meta[META_KEY2];
|
|
53179
|
-
return Array.isArray(raw) ? raw : [];
|
|
53180
|
-
}
|
|
53181
|
-
function setBtwNote(ctx, text2) {
|
|
53182
|
-
const trimmed = text2.trim();
|
|
53183
|
-
if (!trimmed) return readQueue(ctx).length;
|
|
53184
|
-
const next = [...readQueue(ctx), trimmed].slice(-MAX_PENDING);
|
|
53185
|
-
ctx.meta[META_KEY2] = next;
|
|
53186
|
-
return next.length;
|
|
53187
|
-
}
|
|
53188
|
-
function pendingBtwCount(ctx) {
|
|
53189
|
-
return readQueue(ctx).length;
|
|
53190
|
-
}
|
|
53191
|
-
function consumeBtwNotes(ctx) {
|
|
53192
|
-
const notes = readQueue(ctx);
|
|
53193
|
-
if (notes.length > 0) delete ctx.meta[META_KEY2];
|
|
53194
|
-
return notes;
|
|
53195
|
-
}
|
|
53196
|
-
function buildBtwBlock(notes) {
|
|
53197
|
-
const body = notes.map((n) => `- ${n}`).join("\n");
|
|
53198
|
-
return [
|
|
53199
|
-
"[BY THE WAY \u2014 the user added this while you were working. Fold it into",
|
|
53200
|
-
"your current task; do not restart from scratch unless it contradicts the",
|
|
53201
|
-
"goal:",
|
|
53202
|
-
"",
|
|
53203
|
-
body,
|
|
53204
|
-
"]"
|
|
53205
|
-
].join("\n");
|
|
53206
|
-
}
|
|
53207
|
-
|
|
53208
54220
|
// src/core/fleet-pulse.ts
|
|
53209
54221
|
var DEFAULT_MAX_AGENTS = 15;
|
|
53210
54222
|
var DEFAULT_MAX_CHARS = 900;
|
|
@@ -53212,9 +54224,17 @@ var TASK_SNIPPET_CHARS2 = 60;
|
|
|
53212
54224
|
function fleetPulseSignature(statuses) {
|
|
53213
54225
|
return statuses.map((s) => `${s.agentId}|${s.status}|${s.currentTask ?? ""}`).sort().join("\n");
|
|
53214
54226
|
}
|
|
53215
|
-
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) {
|
|
53216
54235
|
const role = s.role && s.role !== s.name ? ` (${s.role})` : "";
|
|
53217
|
-
const
|
|
54236
|
+
const grouped = count > 1 ? ` \xD7${count}` : "";
|
|
54237
|
+
const parts = [`\u2022 ${s.name}${role}${grouped} \u2014 ${s.status}`];
|
|
53218
54238
|
if (s.currentTask) {
|
|
53219
54239
|
const task = s.currentTask.length > TASK_SNIPPET_CHARS2 ? `${s.currentTask.slice(0, TASK_SNIPPET_CHARS2)}\u2026` : s.currentTask;
|
|
53220
54240
|
parts.push(`"${task}"`);
|
|
@@ -53230,13 +54250,20 @@ function buildFleetPulseBlock(statuses, opts) {
|
|
|
53230
54250
|
if (peers.length === 0) return null;
|
|
53231
54251
|
const order = { running: 0, streaming: 0, waiting_user: 1, idle: 2, error: 3, offline: 4 };
|
|
53232
54252
|
const sorted = [...peers].sort(
|
|
53233
|
-
(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))
|
|
53234
54254
|
);
|
|
53235
54255
|
const shown = sorted.slice(0, maxAgents);
|
|
53236
54256
|
const hidden = sorted.length - shown.length;
|
|
53237
54257
|
const parts = [];
|
|
53238
54258
|
parts.push(`[FLEET PULSE] ${peers.length} peer${peers.length === 1 ? "" : "s"} online:`);
|
|
53239
|
-
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
|
+
}
|
|
53240
54267
|
if (hidden > 0) parts.push(`\u2026 +${hidden} more`);
|
|
53241
54268
|
parts.push(
|
|
53242
54269
|
"[END FLEET PULSE] (FYI \u2014 coordinate via mail_send; avoid duplicating peers' work)"
|
|
@@ -54187,7 +55214,7 @@ async function getPromptJournalEntries(projectRoot, filter = {}) {
|
|
|
54187
55214
|
init_errors();
|
|
54188
55215
|
|
|
54189
55216
|
// src/core/streaming-response-builder.ts
|
|
54190
|
-
import { randomUUID as
|
|
55217
|
+
import { randomUUID as randomUUID33 } from "node:crypto";
|
|
54191
55218
|
var STREAM_DRAIN_TIMEOUT_MS = 500;
|
|
54192
55219
|
function buildResponse(state) {
|
|
54193
55220
|
const content = [];
|
|
@@ -54247,7 +55274,7 @@ function handleContentBlockStart(state, ev) {
|
|
|
54247
55274
|
state.textBuffers.push("");
|
|
54248
55275
|
state.blockOrder.push({ kind: "text", idx: state.currentTextIndex });
|
|
54249
55276
|
} else if (kind === "tool_use") {
|
|
54250
|
-
const id = ev.id ??
|
|
55277
|
+
const id = ev.id ?? randomUUID33();
|
|
54251
55278
|
state.tools.set(id, { name: ev.name ?? "unknown", partial: "" });
|
|
54252
55279
|
state.blockOrder.push({ kind: "tool", id });
|
|
54253
55280
|
state.currentTextIndex = -1;
|
|
@@ -54482,7 +55509,7 @@ async function streamProviderToResponse(provider, req, signal, ctx, events, logg
|
|
|
54482
55509
|
|
|
54483
55510
|
// src/observability/network-telemetry.ts
|
|
54484
55511
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
54485
|
-
import { createHash as createHash25, randomUUID as
|
|
55512
|
+
import { createHash as createHash25, randomUUID as randomUUID34 } from "node:crypto";
|
|
54486
55513
|
import { channel } from "node:diagnostics_channel";
|
|
54487
55514
|
var storage = new AsyncLocalStorage();
|
|
54488
55515
|
var requests = /* @__PURE__ */ new WeakMap();
|
|
@@ -54519,7 +55546,7 @@ function subscribe() {
|
|
|
54519
55546
|
const requestBytes = numberField2(request, "contentLength");
|
|
54520
55547
|
const state = {
|
|
54521
55548
|
...context,
|
|
54522
|
-
requestId:
|
|
55549
|
+
requestId: randomUUID34(),
|
|
54523
55550
|
...target,
|
|
54524
55551
|
...requestBytes !== void 0 ? { requestBytes } : {},
|
|
54525
55552
|
startedAt,
|
|
@@ -54654,7 +55681,7 @@ function hash3(value) {
|
|
|
54654
55681
|
}
|
|
54655
55682
|
|
|
54656
55683
|
// src/core/provider-runner.ts
|
|
54657
|
-
import { randomUUID as
|
|
55684
|
+
import { randomUUID as randomUUID35 } from "node:crypto";
|
|
54658
55685
|
function scrubProviderBody(body) {
|
|
54659
55686
|
if (!body) return void 0;
|
|
54660
55687
|
return {
|
|
@@ -54676,11 +55703,11 @@ function providerLogCtx(p, r) {
|
|
|
54676
55703
|
}
|
|
54677
55704
|
async function runProviderWithRetry(opts) {
|
|
54678
55705
|
const { provider, request, signal, ctx, events, retry, logger, tracer } = opts;
|
|
54679
|
-
const logicalRequestId =
|
|
55706
|
+
const logicalRequestId = randomUUID35();
|
|
54680
55707
|
const promptManifest = createChroniclePromptManifest(request);
|
|
54681
55708
|
let attempt = 0;
|
|
54682
55709
|
for (; ; ) {
|
|
54683
|
-
const attemptId =
|
|
55710
|
+
const attemptId = randomUUID35();
|
|
54684
55711
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
54685
55712
|
const startedNs = process.hrtime.bigint();
|
|
54686
55713
|
const correlation = {
|
|
@@ -59349,7 +60376,7 @@ function _resetDesignRulesCache() {
|
|
|
59349
60376
|
}
|
|
59350
60377
|
|
|
59351
60378
|
// src/execution/design-color.ts
|
|
59352
|
-
function
|
|
60379
|
+
function clamp2(n, lo, hi) {
|
|
59353
60380
|
return n < lo ? lo : n > hi ? hi : n;
|
|
59354
60381
|
}
|
|
59355
60382
|
function parseOklch(value) {
|
|
@@ -59365,9 +60392,9 @@ function parseOklch(value) {
|
|
|
59365
60392
|
let a = 1;
|
|
59366
60393
|
if (alphaPart !== void 0) {
|
|
59367
60394
|
const av = parseComponent(alphaPart.trim(), true);
|
|
59368
|
-
if (av !== null) a =
|
|
60395
|
+
if (av !== null) a = clamp2(av, 0, 1);
|
|
59369
60396
|
}
|
|
59370
|
-
return [
|
|
60397
|
+
return [clamp2(L, 0, 1), Math.max(0, C), H, a];
|
|
59371
60398
|
}
|
|
59372
60399
|
function parseComponent(s, percentIsFraction) {
|
|
59373
60400
|
s = s.trim();
|
|
@@ -59386,7 +60413,7 @@ function parseAngle(s) {
|
|
|
59386
60413
|
}
|
|
59387
60414
|
function linearToSrgb(c) {
|
|
59388
60415
|
const v = c <= 31308e-7 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;
|
|
59389
|
-
return
|
|
60416
|
+
return clamp2(v, 0, 1);
|
|
59390
60417
|
}
|
|
59391
60418
|
function toHex2(n) {
|
|
59392
60419
|
return Math.round(n * 255).toString(16).padStart(2, "0");
|
|
@@ -62133,7 +63160,7 @@ ${summaryText}` : summaryText;
|
|
|
62133
63160
|
|
|
62134
63161
|
// src/execution/parallel-eternal-engine.ts
|
|
62135
63162
|
init_error();
|
|
62136
|
-
import { randomUUID as
|
|
63163
|
+
import { randomUUID as randomUUID36 } from "node:crypto";
|
|
62137
63164
|
var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
62138
63165
|
var ParallelEternalEngine = class {
|
|
62139
63166
|
constructor(opts) {
|
|
@@ -62210,7 +63237,7 @@ var ParallelEternalEngine = class {
|
|
|
62210
63237
|
this.state = "running";
|
|
62211
63238
|
await this.persistState("running");
|
|
62212
63239
|
const config = {
|
|
62213
|
-
coordinatorId: `parallel-${
|
|
63240
|
+
coordinatorId: `parallel-${randomUUID36().slice(0, 8)}`,
|
|
62214
63241
|
maxConcurrent: this.slots,
|
|
62215
63242
|
doneCondition: { type: "all_tasks_done" }
|
|
62216
63243
|
};
|
|
@@ -62264,7 +63291,7 @@ var ParallelEternalEngine = class {
|
|
|
62264
63291
|
}
|
|
62265
63292
|
if (!this.coordinator) {
|
|
62266
63293
|
const config = {
|
|
62267
|
-
coordinatorId: `parallel-${
|
|
63294
|
+
coordinatorId: `parallel-${randomUUID36().slice(0, 8)}`,
|
|
62268
63295
|
maxConcurrent: this.slots,
|
|
62269
63296
|
doneCondition: { type: "all_tasks_done" }
|
|
62270
63297
|
};
|
|
@@ -62350,7 +63377,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
62350
63377
|
const task = expectDefined(tasks[i]);
|
|
62351
63378
|
const route = routes[i] ?? null;
|
|
62352
63379
|
const subagentId = `parallel-${this.iterations}-${i}`;
|
|
62353
|
-
const taskId =
|
|
63380
|
+
const taskId = randomUUID36();
|
|
62354
63381
|
const personaLine = route ? `Acting agent: ${route.definition.config.name} \u2014 ${route.definition.capability.summary}
|
|
62355
63382
|
` : "";
|
|
62356
63383
|
const spec = {
|
|
@@ -63978,7 +65005,7 @@ function readPolicy(ctx) {
|
|
|
63978
65005
|
}
|
|
63979
65006
|
|
|
63980
65007
|
// src/execution/tool-executor.ts
|
|
63981
|
-
import { randomUUID as
|
|
65008
|
+
import { randomUUID as randomUUID39 } from "node:crypto";
|
|
63982
65009
|
import * as fs38 from "node:fs/promises";
|
|
63983
65010
|
import * as path85 from "node:path";
|
|
63984
65011
|
init_errors();
|
|
@@ -64000,7 +65027,7 @@ var ToolErrorCategory = /* @__PURE__ */ ((ToolErrorCategory2) => {
|
|
|
64000
65027
|
})(ToolErrorCategory || {});
|
|
64001
65028
|
|
|
64002
65029
|
// src/execution/tool-executor-support.ts
|
|
64003
|
-
import { createHash as createHash29, randomUUID as
|
|
65030
|
+
import { createHash as createHash29, randomUUID as randomUUID37 } from "node:crypto";
|
|
64004
65031
|
import * as fs37 from "node:fs/promises";
|
|
64005
65032
|
import * as path83 from "node:path";
|
|
64006
65033
|
init_errors();
|
|
@@ -64132,7 +65159,7 @@ async function maybePersistLargeToolOutput(toolName, content, budget) {
|
|
|
64132
65159
|
await fs37.mkdir(dir, { recursive: true });
|
|
64133
65160
|
const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
|
|
64134
65161
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
64135
|
-
const filePath = path83.join(dir, `${stamp}-${safeTool}-${
|
|
65162
|
+
const filePath = path83.join(dir, `${stamp}-${safeTool}-${randomUUID37()}.log`);
|
|
64136
65163
|
await fs37.writeFile(filePath, content, "utf8");
|
|
64137
65164
|
const marker = `[full tool output: ${bytes} bytes at ${filePath}; read/grep that file selectively instead of re-running or requesting more output]`;
|
|
64138
65165
|
const fixedBytes = Buffer.byteLength(marker + TOOL_OUTPUT_ARTIFACT_OMISSION, "utf8");
|
|
@@ -64682,7 +65709,7 @@ ${errorDetails}`,
|
|
|
64682
65709
|
}
|
|
64683
65710
|
|
|
64684
65711
|
// src/execution/tool-executor-runner.ts
|
|
64685
|
-
import { randomUUID as
|
|
65712
|
+
import { randomUUID as randomUUID38 } from "node:crypto";
|
|
64686
65713
|
|
|
64687
65714
|
// src/observability/process-telemetry.ts
|
|
64688
65715
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
@@ -64906,7 +65933,7 @@ async function runToolWithTimeout(tool, input, parentSignal, ctx, opts, config,
|
|
|
64906
65933
|
progressTailChars: config.progressTailChars,
|
|
64907
65934
|
progressHeadChars: config.progressHeadChars
|
|
64908
65935
|
}) : (async () => tool.execute(input, ctx, { signal: combined }))();
|
|
64909
|
-
const telemetryToolCallId = toolUseId ?? `nested-${
|
|
65936
|
+
const telemetryToolCallId = toolUseId ?? `nested-${randomUUID38()}`;
|
|
64910
65937
|
const toolPromise = opts.events ? runWithNetworkTelemetry(
|
|
64911
65938
|
{
|
|
64912
65939
|
events: opts.events,
|
|
@@ -65299,7 +66326,7 @@ ${post.additionalContext}`;
|
|
|
65299
66326
|
const bridge = async (toolName, input) => {
|
|
65300
66327
|
const nestedUse = {
|
|
65301
66328
|
type: "tool_use",
|
|
65302
|
-
id: `nested-${
|
|
66329
|
+
id: `nested-${randomUUID39()}`,
|
|
65303
66330
|
name: toolName,
|
|
65304
66331
|
input
|
|
65305
66332
|
};
|
|
@@ -65904,13 +66931,13 @@ import * as fs39 from "node:fs/promises";
|
|
|
65904
66931
|
import * as path87 from "node:path";
|
|
65905
66932
|
|
|
65906
66933
|
// src/types/mode-prompts.ts
|
|
65907
|
-
import { readFileSync as
|
|
66934
|
+
import { readFileSync as readFileSync24, statSync as statSync9 } from "node:fs";
|
|
65908
66935
|
import * as path86 from "node:path";
|
|
65909
66936
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
65910
66937
|
function modePrompt(id) {
|
|
65911
66938
|
for (const dir of modePromptDirCandidates()) {
|
|
65912
66939
|
try {
|
|
65913
|
-
return
|
|
66940
|
+
return readFileSync24(path86.join(dir, `${id}.md`), "utf8").trimEnd();
|
|
65914
66941
|
} catch {
|
|
65915
66942
|
}
|
|
65916
66943
|
}
|
|
@@ -66591,7 +67618,17 @@ function normalizeModelsDevModel(model) {
|
|
|
66591
67618
|
const reasoningConfig = {
|
|
66592
67619
|
default: disableSupported ? "enabled" : "always_on",
|
|
66593
67620
|
disableSupported,
|
|
66594
|
-
|
|
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 },
|
|
66595
67632
|
effortLevels,
|
|
66596
67633
|
preserveThinking: model.interleaved ? "always_on" : "unsupported"
|
|
66597
67634
|
};
|
|
@@ -67180,9 +68217,9 @@ async function startMetricsServer(opts) {
|
|
|
67180
68217
|
let server;
|
|
67181
68218
|
if (useHttps && tls) {
|
|
67182
68219
|
const { createServer } = await import("node:https");
|
|
67183
|
-
const { readFileSync:
|
|
68220
|
+
const { readFileSync: readFileSync26 } = await import("node:fs");
|
|
67184
68221
|
server = createServer(
|
|
67185
|
-
{ cert:
|
|
68222
|
+
{ cert: readFileSync26(tls.cert), key: readFileSync26(tls.key) },
|
|
67186
68223
|
listener
|
|
67187
68224
|
);
|
|
67188
68225
|
} else {
|
|
@@ -69148,7 +70185,7 @@ function deepFreeze(obj) {
|
|
|
69148
70185
|
init_errors();
|
|
69149
70186
|
init_atomic_write();
|
|
69150
70187
|
init_error();
|
|
69151
|
-
import { randomUUID as
|
|
70188
|
+
import { randomUUID as randomUUID40 } from "node:crypto";
|
|
69152
70189
|
import * as fsp38 from "node:fs/promises";
|
|
69153
70190
|
function assertPlanMutationInvariants(previous, updated) {
|
|
69154
70191
|
const ids = updated.items.map((item) => item.id);
|
|
@@ -69270,7 +70307,7 @@ function emptyPlan(sessionId, title) {
|
|
|
69270
70307
|
function addPlanItem(plan, title, details) {
|
|
69271
70308
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
69272
70309
|
const item = {
|
|
69273
|
-
id: `plan_${Date.now()}_${
|
|
70310
|
+
id: `plan_${Date.now()}_${randomUUID40().slice(0, 6)}`,
|
|
69274
70311
|
title,
|
|
69275
70312
|
details,
|
|
69276
70313
|
status: "open",
|
|
@@ -69342,7 +70379,7 @@ function deriveTodosFromPlanItem(plan, idOrIndex, subtasks) {
|
|
|
69342
70379
|
if (subtasks && subtasks.length > 0) {
|
|
69343
70380
|
for (const st of subtasks) {
|
|
69344
70381
|
todos.push({
|
|
69345
|
-
id: `todo_${Date.now()}_${
|
|
70382
|
+
id: `todo_${Date.now()}_${randomUUID40().slice(0, 6)}`,
|
|
69346
70383
|
content: st,
|
|
69347
70384
|
status: "pending",
|
|
69348
70385
|
promotedFromPlan: item.id
|
|
@@ -73339,7 +74376,7 @@ function resolveReasoningForRequest(settings, rc, warnings) {
|
|
|
73339
74376
|
const cfg = settings.reasoning;
|
|
73340
74377
|
if (!cfg) return void 0;
|
|
73341
74378
|
const capKnown = rc !== void 0;
|
|
73342
|
-
const supportsReasoning = rc ? rc.default !== "disabled" || rc.disableSupported || rc.effortSupported : false;
|
|
74379
|
+
const supportsReasoning = rc ? rc.default !== "disabled" || rc.disableSupported || rc.effortSupported !== false : false;
|
|
73343
74380
|
const out = {};
|
|
73344
74381
|
if (cfg.mode === "off") {
|
|
73345
74382
|
if (capKnown && rc?.disableSupported) {
|
|
@@ -73361,14 +74398,17 @@ function resolveReasoningForRequest(settings, rc, warnings) {
|
|
|
73361
74398
|
}
|
|
73362
74399
|
const effort = cfg.effort;
|
|
73363
74400
|
if (effort !== void 0) {
|
|
73364
|
-
if (capKnown
|
|
73365
|
-
|
|
73366
|
-
|
|
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)) {
|
|
73367
74407
|
warnings.push(
|
|
73368
74408
|
`reasoning effort "${effort}" not supported by this model (supported: ${rc.effortLevels.join(", ")}); the setting was omitted.`
|
|
73369
74409
|
);
|
|
73370
|
-
} else
|
|
73371
|
-
|
|
74410
|
+
} else {
|
|
74411
|
+
out.effort = effort;
|
|
73372
74412
|
}
|
|
73373
74413
|
}
|
|
73374
74414
|
if (cfg.preserve !== void 0) {
|
|
@@ -75244,6 +76284,13 @@ var PhaseOrchestrator = class {
|
|
|
75244
76284
|
events;
|
|
75245
76285
|
stopped = false;
|
|
75246
76286
|
paused = false;
|
|
76287
|
+
/**
|
|
76288
|
+
* Run-wide abort source. stop() aborts it; every in-flight
|
|
76289
|
+
* ctx.executeTask call observes the abort through its per-task signal
|
|
76290
|
+
* (composed from this controller and the task's own timeout controller).
|
|
76291
|
+
* Recreated by start() so a stopped orchestrator can be reused.
|
|
76292
|
+
*/
|
|
76293
|
+
stopController = new AbortController();
|
|
75247
76294
|
runningPhases = /* @__PURE__ */ new Set();
|
|
75248
76295
|
tickInterval = null;
|
|
75249
76296
|
trackerCache = /* @__PURE__ */ new Map();
|
|
@@ -75286,6 +76333,7 @@ var PhaseOrchestrator = class {
|
|
|
75286
76333
|
async start() {
|
|
75287
76334
|
this.stopped = false;
|
|
75288
76335
|
this.paused = false;
|
|
76336
|
+
this.stopController = new AbortController();
|
|
75289
76337
|
this.normalizeForResume();
|
|
75290
76338
|
this.graph.startedAt = Date.now();
|
|
75291
76339
|
this.graph.updatedAt = Date.now();
|
|
@@ -75345,6 +76393,7 @@ var PhaseOrchestrator = class {
|
|
|
75345
76393
|
/** Stop completely, including active phases. */
|
|
75346
76394
|
stop() {
|
|
75347
76395
|
this.stopped = true;
|
|
76396
|
+
this.stopController.abort();
|
|
75348
76397
|
if (this.tickInterval) {
|
|
75349
76398
|
clearInterval(this.tickInterval);
|
|
75350
76399
|
this.tickInterval = null;
|
|
@@ -75421,6 +76470,7 @@ var PhaseOrchestrator = class {
|
|
|
75421
76470
|
return;
|
|
75422
76471
|
}
|
|
75423
76472
|
await this.executePhaseTasks(phase);
|
|
76473
|
+
if (this.stopped) return;
|
|
75424
76474
|
const failedTasks = this.getFailedTaskCount(phase);
|
|
75425
76475
|
const completedTasks = this.getCompletedTaskCount(phase);
|
|
75426
76476
|
this.emit("phase.allTasksDone", {
|
|
@@ -75580,34 +76630,47 @@ var PhaseOrchestrator = class {
|
|
|
75580
76630
|
agentName: task.assignee
|
|
75581
76631
|
});
|
|
75582
76632
|
const handle = this.phaseWorktrees.get(phase.id);
|
|
75583
|
-
const
|
|
75584
|
-
|
|
75585
|
-
|
|
75586
|
-
|
|
75587
|
-
|
|
75588
|
-
|
|
75589
|
-
|
|
75590
|
-
|
|
75591
|
-
|
|
75592
|
-
|
|
75593
|
-
|
|
75594
|
-
|
|
75595
|
-
|
|
75596
|
-
|
|
75597
|
-
|
|
75598
|
-
|
|
75599
|
-
|
|
75600
|
-
|
|
75601
|
-
|
|
75602
|
-
|
|
75603
|
-
|
|
75604
|
-
|
|
75605
|
-
|
|
75606
|
-
|
|
75607
|
-
|
|
75608
|
-
|
|
75609
|
-
|
|
75610
|
-
|
|
76633
|
+
const timeoutController = this.opts.taskTimeoutMs > 0 ? new AbortController() : void 0;
|
|
76634
|
+
const signal = timeoutController ? AbortSignal.any([this.stopController.signal, timeoutController.signal]) : this.stopController.signal;
|
|
76635
|
+
const taskPromise = this.ctx.executeTask(
|
|
76636
|
+
task,
|
|
76637
|
+
phase.id,
|
|
76638
|
+
{ cwd: handle?.dir, branch: handle?.branch },
|
|
76639
|
+
signal
|
|
76640
|
+
);
|
|
76641
|
+
if (!timeoutController) return taskPromise;
|
|
76642
|
+
const timeoutMs = this.opts.taskTimeoutMs;
|
|
76643
|
+
const timedOut = /* @__PURE__ */ Symbol("timed_out");
|
|
76644
|
+
const result = await Promise.race([
|
|
76645
|
+
taskPromise,
|
|
76646
|
+
new Promise((resolve57) => {
|
|
76647
|
+
const timer = setTimeout(() => {
|
|
76648
|
+
timeoutController.abort();
|
|
76649
|
+
resolve57(timedOut);
|
|
76650
|
+
}, timeoutMs);
|
|
76651
|
+
taskPromise.then(() => clearTimeout(timer)).catch(() => clearTimeout(timer));
|
|
76652
|
+
})
|
|
76653
|
+
]);
|
|
76654
|
+
if (result !== timedOut) return result;
|
|
76655
|
+
this.emit("phase.taskTimedOut", {
|
|
76656
|
+
phaseId: phase.id,
|
|
76657
|
+
taskId: task.id,
|
|
76658
|
+
taskTitle: task.title,
|
|
76659
|
+
timeoutMs
|
|
76660
|
+
});
|
|
76661
|
+
const settled = taskPromise.then(
|
|
76662
|
+
() => void 0,
|
|
76663
|
+
() => void 0
|
|
76664
|
+
);
|
|
76665
|
+
const grace = new Promise((resolve57) => {
|
|
76666
|
+
const timer = setTimeout(resolve57, 5e3);
|
|
76667
|
+
timer.unref?.();
|
|
76668
|
+
void settled.then(() => clearTimeout(timer));
|
|
76669
|
+
});
|
|
76670
|
+
await Promise.race([settled, grace]);
|
|
76671
|
+
throw new Error(
|
|
76672
|
+
`Task "${task.title}" (${task.id}) exceeded timeout of ${timeoutMs} ms`
|
|
76673
|
+
);
|
|
75611
76674
|
}
|
|
75612
76675
|
markTaskCompleted(phase, task) {
|
|
75613
76676
|
const tracker = this.getTrackerForPhase(phase);
|
|
@@ -75622,6 +76685,10 @@ var PhaseOrchestrator = class {
|
|
|
75622
76685
|
const tracker = this.getTrackerForPhase(phase);
|
|
75623
76686
|
const taskKey = `${phase.id}:${task.id}`;
|
|
75624
76687
|
const currentRetries = this.taskRetryCounts.get(taskKey) ?? 0;
|
|
76688
|
+
if (this.stopped) {
|
|
76689
|
+
tracker.updateNodeStatus(task.id, "pending", "Stopped before completion");
|
|
76690
|
+
return;
|
|
76691
|
+
}
|
|
75625
76692
|
if (currentRetries < this.opts.maxRetries) {
|
|
75626
76693
|
this.taskRetryCounts.set(taskKey, currentRetries + 1);
|
|
75627
76694
|
tracker.updateNodeStatus(
|
|
@@ -80934,7 +82001,8 @@ async function loadPlugins(plugins, opts) {
|
|
|
80934
82001
|
plugin,
|
|
80935
82002
|
resolution.options
|
|
80936
82003
|
);
|
|
80937
|
-
const
|
|
82004
|
+
const enforceForPlugin = typeof opts.enforceCapabilities === "function" ? opts.enforceCapabilities(plugin) : opts.enforceCapabilities ?? false;
|
|
82005
|
+
const api = plugin.capabilities ? wrapApiForCapabilityCheck(plugin, rawApi, opts.log, enforceForPlugin) : rawApi;
|
|
80938
82006
|
registration = {
|
|
80939
82007
|
plugin,
|
|
80940
82008
|
api,
|
|
@@ -81765,7 +82833,7 @@ async function snapshotChangedFiles(cwd) {
|
|
|
81765
82833
|
}
|
|
81766
82834
|
|
|
81767
82835
|
// src/plugins/review-claim-registry.ts
|
|
81768
|
-
import { createHash as createHash33, randomUUID as
|
|
82836
|
+
import { createHash as createHash33, randomUUID as randomUUID41 } from "node:crypto";
|
|
81769
82837
|
import * as fsp46 from "node:fs/promises";
|
|
81770
82838
|
import { hostname as hostname5 } from "node:os";
|
|
81771
82839
|
import * as path103 from "node:path";
|
|
@@ -81828,7 +82896,7 @@ async function breakStaleLock(lockPath) {
|
|
|
81828
82896
|
return false;
|
|
81829
82897
|
}
|
|
81830
82898
|
async function breakLockAtomically(lockPath) {
|
|
81831
|
-
const tombstone = `${lockPath}.stale-${
|
|
82899
|
+
const tombstone = `${lockPath}.stale-${randomUUID41()}.tmp`;
|
|
81832
82900
|
try {
|
|
81833
82901
|
await fsp46.rename(lockPath, tombstone);
|
|
81834
82902
|
} catch {
|
|
@@ -81888,7 +82956,7 @@ async function withStoreLock(storeDir, fn, waitMs = LOCK_WAIT_MS) {
|
|
|
81888
82956
|
}
|
|
81889
82957
|
}
|
|
81890
82958
|
var MAX_LEDGER_LINES = 1e4;
|
|
81891
|
-
var HOST_SID =
|
|
82959
|
+
var HOST_SID = randomUUID41();
|
|
81892
82960
|
var claimsByEventBus = /* @__PURE__ */ new WeakMap();
|
|
81893
82961
|
var startedReviews = /* @__PURE__ */ new WeakMap();
|
|
81894
82962
|
var pendingStartedReviews = /* @__PURE__ */ new WeakMap();
|
|
@@ -81969,7 +83037,7 @@ async function compactLedger(storeDir, active) {
|
|
|
81969
83037
|
);
|
|
81970
83038
|
}
|
|
81971
83039
|
}
|
|
81972
|
-
const tmp = `${claimsFilePath(storeDir)}.tmp-${
|
|
83040
|
+
const tmp = `${claimsFilePath(storeDir)}.tmp-${randomUUID41()}`;
|
|
81973
83041
|
await fsp46.writeFile(tmp, lines.length > 0 ? `${lines.join("\n")}
|
|
81974
83042
|
` : "", "utf8");
|
|
81975
83043
|
let replaced = false;
|
|
@@ -82898,7 +83966,7 @@ init_review_finding_store();
|
|
|
82898
83966
|
|
|
82899
83967
|
// src/plugins/review-finding-parser.ts
|
|
82900
83968
|
init_review_finding_types();
|
|
82901
|
-
import { randomUUID as
|
|
83969
|
+
import { randomUUID as randomUUID43 } from "node:crypto";
|
|
82902
83970
|
var SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low"]);
|
|
82903
83971
|
var CATEGORIES = /* @__PURE__ */ new Set([
|
|
82904
83972
|
"bug",
|
|
@@ -82970,7 +84038,7 @@ function parseChimeraReviewReport(reportText, context = {}) {
|
|
|
82970
84038
|
}
|
|
82971
84039
|
const structured = extractStructuredFindingsBlock(reportText);
|
|
82972
84040
|
if (structured) {
|
|
82973
|
-
const reportId2 = context.reportId ??
|
|
84041
|
+
const reportId2 = context.reportId ?? randomUUID43();
|
|
82974
84042
|
const findings2 = structured.findings.map(
|
|
82975
84043
|
(item) => buildFindingFromStructuredItem(item, { ...context, reportId: reportId2 })
|
|
82976
84044
|
);
|
|
@@ -82982,7 +84050,7 @@ function parseChimeraReviewReport(reportText, context = {}) {
|
|
|
82982
84050
|
};
|
|
82983
84051
|
}
|
|
82984
84052
|
const findings = [];
|
|
82985
|
-
const reportId = context.reportId ??
|
|
84053
|
+
const reportId = context.reportId ?? randomUUID43();
|
|
82986
84054
|
let unparseableCount = 0;
|
|
82987
84055
|
let durationSeconds;
|
|
82988
84056
|
let currentSeverity = null;
|
|
@@ -83083,7 +84151,7 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
83083
84151
|
const fullDesc = suggestions.length > 0 ? cleanDesc + "\n" + suggestions.map((s) => " \u2192 " + s).join("\n") : cleanDesc;
|
|
83084
84152
|
const suggestedFix = suggestions.length > 0 ? suggestions.join("\n") : void 0;
|
|
83085
84153
|
return {
|
|
83086
|
-
id:
|
|
84154
|
+
id: randomUUID43(),
|
|
83087
84155
|
fingerprint: computeFindingFingerprint(file ?? "", line ?? null, title),
|
|
83088
84156
|
severity,
|
|
83089
84157
|
source: normalizeFindingSource(context.reviewType),
|
|
@@ -83094,7 +84162,7 @@ function parseFindingSegment(segment, severity, context) {
|
|
|
83094
84162
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83095
84163
|
status: "active",
|
|
83096
84164
|
originReport: {
|
|
83097
|
-
reportId: context.reportId ??
|
|
84165
|
+
reportId: context.reportId ?? randomUUID43(),
|
|
83098
84166
|
sessionId: context.sessionId ?? "",
|
|
83099
84167
|
agentId: context.agentId ?? "",
|
|
83100
84168
|
reviewerModel: context.reviewerModel ?? ""
|
|
@@ -83118,7 +84186,7 @@ function buildFindingFromStructuredItem(item, context) {
|
|
|
83118
84186
|
const title = item.title;
|
|
83119
84187
|
const description = item.description ?? title;
|
|
83120
84188
|
return {
|
|
83121
|
-
id:
|
|
84189
|
+
id: randomUUID43(),
|
|
83122
84190
|
fingerprint: computeFindingFingerprint(file ?? "", line ?? null, title),
|
|
83123
84191
|
severity: item.severity,
|
|
83124
84192
|
source: normalizeFindingSource(context.reviewType),
|
|
@@ -83131,7 +84199,7 @@ function buildFindingFromStructuredItem(item, context) {
|
|
|
83131
84199
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83132
84200
|
status: "active",
|
|
83133
84201
|
originReport: {
|
|
83134
|
-
reportId: context.reportId ??
|
|
84202
|
+
reportId: context.reportId ?? randomUUID43(),
|
|
83135
84203
|
sessionId: context.sessionId ?? "",
|
|
83136
84204
|
agentId: context.agentId ?? "",
|
|
83137
84205
|
reviewerModel: context.reviewerModel ?? ""
|
|
@@ -88782,7 +89850,7 @@ var ReplayProviderRunner = class {
|
|
|
88782
89850
|
};
|
|
88783
89851
|
|
|
88784
89852
|
// src/session-catalog/store.ts
|
|
88785
|
-
import { randomBytes as randomBytes8, randomUUID as
|
|
89853
|
+
import { randomBytes as randomBytes8, randomUUID as randomUUID44 } from "node:crypto";
|
|
88786
89854
|
import * as fs59 from "node:fs";
|
|
88787
89855
|
import * as path119 from "node:path";
|
|
88788
89856
|
init_atomic_write();
|
|
@@ -89133,7 +90201,7 @@ var SessionCatalogStore = class {
|
|
|
89133
90201
|
if (!Number.isSafeInteger(entry.pid) || entry.pid <= 0)
|
|
89134
90202
|
throw new TypeError("Invalid owner pid");
|
|
89135
90203
|
const now = Date.now();
|
|
89136
|
-
const leaseId =
|
|
90204
|
+
const leaseId = randomUUID44();
|
|
89137
90205
|
const leaseSecret = randomBytes8(32).toString("hex");
|
|
89138
90206
|
const expiresAt = now + boundedMs(leaseMs, SESSION_CATALOG_DEFAULT_LEASE_MS, MAX_LEASE_MS);
|
|
89139
90207
|
this.db.prepare(`INSERT INTO session_leases(
|
|
@@ -89205,7 +90273,7 @@ var SessionCatalogStore = class {
|
|
|
89205
90273
|
const catalog = this.db.prepare("SELECT 1 AS yes FROM sessions WHERE session_id=?").get(targetSessionId);
|
|
89206
90274
|
if (!catalog && !fs59.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
|
|
89207
90275
|
throw new Error(`Session not found: ${targetSessionId}`);
|
|
89208
|
-
const reservationId =
|
|
90276
|
+
const reservationId = randomUUID44();
|
|
89209
90277
|
const now = Date.now();
|
|
89210
90278
|
const expiresAt = now + boundedMs(reservationMs, SESSION_CATALOG_DEFAULT_RESERVATION_MS, MAX_RESERVATION_MS);
|
|
89211
90279
|
try {
|
|
@@ -89501,7 +90569,7 @@ var SessionCatalogStore = class {
|
|
|
89501
90569
|
"SELECT 1 AS yes FROM resume_reservations WHERE target_session_id=? AND expires_at>?"
|
|
89502
90570
|
).get(sessionId, Date.now());
|
|
89503
90571
|
if (reservation) throw conflict(`Session ${sessionId} is reserved for resume`);
|
|
89504
|
-
const leaseId =
|
|
90572
|
+
const leaseId = randomUUID44();
|
|
89505
90573
|
const now = Date.now();
|
|
89506
90574
|
const expiresAt = now + boundedMs(leaseMs, 6e4, MAX_MAINTENANCE_MS);
|
|
89507
90575
|
try {
|
|
@@ -90459,7 +91527,7 @@ import * as fs62 from "node:fs/promises";
|
|
|
90459
91527
|
import * as path122 from "node:path";
|
|
90460
91528
|
|
|
90461
91529
|
// src/session-registry-atomic-file.ts
|
|
90462
|
-
import { randomUUID as
|
|
91530
|
+
import { randomUUID as randomUUID45 } from "node:crypto";
|
|
90463
91531
|
import * as fs61 from "node:fs/promises";
|
|
90464
91532
|
import { hostname as hostname6 } from "node:os";
|
|
90465
91533
|
import * as path121 from "node:path";
|
|
@@ -90532,7 +91600,7 @@ async function breakStaleLockVerified2(lockPath, verify) {
|
|
|
90532
91600
|
return await breakLockAtomically2(lockPath) === true;
|
|
90533
91601
|
}
|
|
90534
91602
|
async function breakLockAtomically2(lockPath) {
|
|
90535
|
-
const tombstone = `${lockPath}.stale-${
|
|
91603
|
+
const tombstone = `${lockPath}.stale-${randomUUID45()}.tmp`;
|
|
90536
91604
|
try {
|
|
90537
91605
|
await fs61.rename(lockPath, tombstone);
|
|
90538
91606
|
} catch {
|
|
@@ -90544,7 +91612,7 @@ async function breakLockAtomically2(lockPath) {
|
|
|
90544
91612
|
async function writeAtomicFile(filePath, registry2) {
|
|
90545
91613
|
const tmp = path121.join(
|
|
90546
91614
|
path121.dirname(filePath),
|
|
90547
|
-
`.${path121.basename(filePath)}.${
|
|
91615
|
+
`.${path121.basename(filePath)}.${randomUUID45().slice(0, 8)}.tmp`
|
|
90548
91616
|
);
|
|
90549
91617
|
let tmpPersisted = false;
|
|
90550
91618
|
try {
|
|
@@ -91107,7 +92175,7 @@ var SessionRegistry = class {
|
|
|
91107
92175
|
init_errors();
|
|
91108
92176
|
init_atomic_write();
|
|
91109
92177
|
init_error();
|
|
91110
|
-
import { randomUUID as
|
|
92178
|
+
import { randomUUID as randomUUID46 } from "node:crypto";
|
|
91111
92179
|
import * as fs63 from "node:fs/promises";
|
|
91112
92180
|
var FILE_VERSION = 1;
|
|
91113
92181
|
var MAX_TEXT_LENGTH = 2e3;
|
|
@@ -91205,7 +92273,7 @@ var AnnotationsStore = class {
|
|
|
91205
92273
|
});
|
|
91206
92274
|
}
|
|
91207
92275
|
const annotation = {
|
|
91208
|
-
id:
|
|
92276
|
+
id: randomUUID46(),
|
|
91209
92277
|
sessionId: input.sessionId,
|
|
91210
92278
|
atEventIndex: input.atEventIndex,
|
|
91211
92279
|
authorId: input.authorId,
|
|
@@ -91558,7 +92626,7 @@ var InputHistoryStore = class {
|
|
|
91558
92626
|
|
|
91559
92627
|
// src/storage/memory-backend.ts
|
|
91560
92628
|
init_file_permissions();
|
|
91561
|
-
import { randomUUID as
|
|
92629
|
+
import { randomUUID as randomUUID47 } from "node:crypto";
|
|
91562
92630
|
import * as fs65 from "node:fs/promises";
|
|
91563
92631
|
import * as path124 from "node:path";
|
|
91564
92632
|
|
|
@@ -91786,7 +92854,7 @@ var FileMemoryBackend = class {
|
|
|
91786
92854
|
}
|
|
91787
92855
|
async remember(scope, entry, filePath) {
|
|
91788
92856
|
const file = this.resolveFile(filePath, scope);
|
|
91789
|
-
const id = `mem_${Date.now()}_${
|
|
92857
|
+
const id = `mem_${Date.now()}_${randomUUID47().slice(0, 8)}`;
|
|
91790
92858
|
const meta = formatMetadata(entry);
|
|
91791
92859
|
const line = `- [${entry.ts}] ${id}${meta} ${entry.text.replace(/\n/g, " ")}
|
|
91792
92860
|
`;
|
|
@@ -93800,7 +94868,7 @@ async function mutateTasks(filePath, sessionId, fn, events, traceId) {
|
|
|
93800
94868
|
init_file_permissions();
|
|
93801
94869
|
init_atomic_write();
|
|
93802
94870
|
init_error();
|
|
93803
|
-
import { createHash as createHash39, randomUUID as
|
|
94871
|
+
import { createHash as createHash39, randomUUID as randomUUID48 } from "node:crypto";
|
|
93804
94872
|
import * as fs70 from "node:fs/promises";
|
|
93805
94873
|
var GENESIS_PREV = "0".repeat(64);
|
|
93806
94874
|
var DEFAULT_FSYNC_EVERY = 100;
|
|
@@ -93845,7 +94913,7 @@ var ToolAuditLog = class {
|
|
|
93845
94913
|
const tip = await this._resolveChainTip(input.sessionId, fp);
|
|
93846
94914
|
const prevHash = tip.prevHash;
|
|
93847
94915
|
const index = tip.nextIndex;
|
|
93848
|
-
const id =
|
|
94916
|
+
const id = randomUUID48();
|
|
93849
94917
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
93850
94918
|
const content = {
|
|
93851
94919
|
id,
|
|
@@ -96386,7 +97454,7 @@ var DEFAULT_SPEC_TEMPLATE = {
|
|
|
96386
97454
|
// src/worktree/worktree-manager.ts
|
|
96387
97455
|
init_error();
|
|
96388
97456
|
import { mkdir as mkdir35, readFile as readFile73 } from "node:fs/promises";
|
|
96389
|
-
import { join as
|
|
97457
|
+
import { join as join103, resolve as resolve56, sep as sep9 } from "node:path";
|
|
96390
97458
|
|
|
96391
97459
|
// src/worktree/worktree-git.ts
|
|
96392
97460
|
import { spawn as spawn13 } from "node:child_process";
|
|
@@ -96618,7 +97686,7 @@ var WorktreeManager = class {
|
|
|
96618
97686
|
}
|
|
96619
97687
|
const slug = this.makeSlug(opts.slugHint ?? ownerId);
|
|
96620
97688
|
const branch = `wstack/ap/${slug}`;
|
|
96621
|
-
const dir =
|
|
97689
|
+
const dir = join103(this.worktreesRoot(), slug);
|
|
96622
97690
|
const absDir = resolve56(dir);
|
|
96623
97691
|
const absRoot = resolve56(this.projectRoot);
|
|
96624
97692
|
if (!absDir.startsWith(absRoot + sep9)) {
|
|
@@ -97009,7 +98077,7 @@ ${merged.stderr}`);
|
|
|
97009
98077
|
const startMarker = /^(?:<{7,}(?: |$)|\|{7,}(?: |$))/m;
|
|
97010
98078
|
for (const rel of paths) {
|
|
97011
98079
|
try {
|
|
97012
|
-
const content = (await readFile73(
|
|
98080
|
+
const content = (await readFile73(join103(this.projectRoot, rel), "utf8")).replace(/\r/g, "");
|
|
97013
98081
|
const lines = content.split("\n");
|
|
97014
98082
|
let seenStart = false;
|
|
97015
98083
|
for (const line of lines) {
|
|
@@ -97053,7 +98121,7 @@ ${merged.stderr}`);
|
|
|
97053
98121
|
}
|
|
97054
98122
|
// ── internals ────────────────────────────────────────────────────────────
|
|
97055
98123
|
worktreesRoot() {
|
|
97056
|
-
return
|
|
98124
|
+
return join103(this.projectRoot, ".wrongstack", "worktrees");
|
|
97057
98125
|
}
|
|
97058
98126
|
async detectBaseBranch() {
|
|
97059
98127
|
const head = await this.runGit(["rev-parse", "--abbrev-ref", "HEAD"], this.projectRoot);
|
|
@@ -97240,11 +98308,17 @@ export {
|
|
|
97240
98308
|
DEFAULT_DIRECTOR_PREAMBLE,
|
|
97241
98309
|
DEFAULT_DISPATCH_ROLE,
|
|
97242
98310
|
DEFAULT_EAGER_SKILL_LIMIT,
|
|
98311
|
+
DEFAULT_EXPLORE_COMPANION_AGENT_ID,
|
|
98312
|
+
DEFAULT_EXPLORE_EDIT_TOOLS,
|
|
98313
|
+
DEFAULT_EXPLORE_SEARCH_TOOLS,
|
|
97243
98314
|
DEFAULT_FILE_EDIT_TOOLS,
|
|
97244
98315
|
DEFAULT_HQ_REDACTION_POLICY,
|
|
98316
|
+
DEFAULT_MAILBOX_POLL_INTERVAL_MS,
|
|
97245
98317
|
DEFAULT_MAX_FLEET_SPAWNS,
|
|
97246
98318
|
DEFAULT_MAX_ITERATIONS,
|
|
98319
|
+
DEFAULT_MAX_PENDING_PROBES,
|
|
97247
98320
|
DEFAULT_MODES,
|
|
98321
|
+
DEFAULT_PROBE_COOLDOWN_MS,
|
|
97248
98322
|
DEFAULT_QUALITY_CHECKS,
|
|
97249
98323
|
DEFAULT_REFINER_RETRY_FEEDBACK,
|
|
97250
98324
|
DEFAULT_SESSION_LOGGING_CONFIG,
|
|
@@ -97304,6 +98378,7 @@ export {
|
|
|
97304
98378
|
EscalationRoutingBrainArbiter,
|
|
97305
98379
|
EternalAutonomyEngine,
|
|
97306
98380
|
EventBus,
|
|
98381
|
+
ExploreCompanion,
|
|
97307
98382
|
ExtensionRegistry,
|
|
97308
98383
|
FALLBACK_CHAIN_MANAGE_TOOL_NAME,
|
|
97309
98384
|
FALLBACK_PROFILE_MANAGE_TOOL_NAME,
|
|
@@ -97464,6 +98539,7 @@ export {
|
|
|
97464
98539
|
QUEUE_MAX_ITEMS,
|
|
97465
98540
|
QUEUE_MAX_ITEM_BYTES,
|
|
97466
98541
|
QueueStore,
|
|
98542
|
+
REASONING_EFFORT_LEVELS,
|
|
97467
98543
|
REFACTOR_PLANNER_AGENT,
|
|
97468
98544
|
REPORT_STORE_FILE,
|
|
97469
98545
|
REVIEW_AGENTS,
|
|
@@ -97604,6 +98680,7 @@ export {
|
|
|
97604
98680
|
buildNamespacePayloads,
|
|
97605
98681
|
buildOtlpMetricsRequest,
|
|
97606
98682
|
buildOtlpTracesRequest,
|
|
98683
|
+
buildProbeTaskText,
|
|
97607
98684
|
buildProjectContextualizedPrompt,
|
|
97608
98685
|
buildQueuedMessagesBlock,
|
|
97609
98686
|
buildRecoveryAlert,
|
|
@@ -97926,6 +99003,7 @@ export {
|
|
|
97926
99003
|
isPrivateIPv6,
|
|
97927
99004
|
isProjectId,
|
|
97928
99005
|
isProvenDirective,
|
|
99006
|
+
isReasoningEffort,
|
|
97929
99007
|
isRetryableKind,
|
|
97930
99008
|
isSafePathSegment,
|
|
97931
99009
|
isSddError,
|
|
@@ -98000,6 +99078,7 @@ export {
|
|
|
98000
99078
|
makeMailInboxTool,
|
|
98001
99079
|
makeMailSendTool,
|
|
98002
99080
|
makeMailboxTool,
|
|
99081
|
+
makeMutationTestTool,
|
|
98003
99082
|
makeQualityGateTool,
|
|
98004
99083
|
makeRollUpTool,
|
|
98005
99084
|
makeSpawnTool,
|