@wrongstack/core 0.270.0 → 0.272.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-bridge-PcHQl_UQ.d.ts → agent-bridge-DFQYEeXf.d.ts} +1 -1
- package/dist/{agent-subagent-runner-SHJW7t8q.d.ts → agent-subagent-runner-BZa_IEcd.d.ts} +7 -7
- package/dist/{brain-BYcK__Ym.d.ts → brain-etbcbRwV.d.ts} +95 -2
- package/dist/{compactor-C2RKEBtC.d.ts → compactor-72ug-ZRB.d.ts} +1 -1
- package/dist/{config-C_ae2k86.d.ts → config-rRS8yorV.d.ts} +71 -2
- package/dist/{context-Dp87Bcaq.d.ts → context-Dw55zZ_Q.d.ts} +110 -1
- package/dist/coordination/index.d.ts +181 -17
- package/dist/coordination/index.js +1018 -166
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +25 -25
- package/dist/defaults/index.js +804 -222
- package/dist/defaults/index.js.map +1 -1
- package/dist/execution/index.d.ts +23 -18
- package/dist/execution/index.js +136 -41
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +36 -6
- package/dist/execution/prompt-enhancer.js +35 -9
- package/dist/execution/prompt-enhancer.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/{global-mailbox-Bvrz1P3f.d.ts → global-mailbox-DJ4EoRr0.d.ts} +145 -5
- package/dist/{goal-preamble-CA_4yiGQ.d.ts → goal-preamble-hM8BH7TK.d.ts} +9 -9
- package/dist/{goal-store-DhuJoUNG.d.ts → goal-store-CWlbT0TO.d.ts} +1 -1
- package/dist/hq/index.d.ts +95 -6
- package/dist/hq/index.js +628 -50
- package/dist/hq/index.js.map +1 -1
- package/dist/{index-whDfTANu.d.ts → index-2Lhk5v0o.d.ts} +2 -2
- package/dist/{index-W4VJCzHa.d.ts → index-DWm_PE9L.d.ts} +5 -5
- package/dist/{index-CZQ6Pwbs.d.ts → index-DqW4o62H.d.ts} +8 -8
- package/dist/index.d.ts +96 -56
- package/dist/index.js +2464 -519
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +5 -3
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +9 -9
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-DJdZiRcv.d.ts → mcp-servers-BpWHTKlE.d.ts} +3 -3
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +28 -5
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-C3a-2-Yd.d.ts → models-registry-CXQFUn5t.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-CJSpTe5O.d.ts → multi-agent-coordinator-jyimfo7D.d.ts} +1 -1
- package/dist/{null-fleet-bus-QVshIsDx.d.ts → null-fleet-bus-DOGQcvrY.d.ts} +6 -6
- package/dist/observability/index.d.ts +2 -2
- package/dist/{parallel-eternal-engine-D9y5Pkcc.d.ts → parallel-eternal-engine-rItJBYp9.d.ts} +9 -9
- package/dist/{path-resolver-CnQ8SIfh.d.ts → path-resolver-DrpF5MGK.d.ts} +3 -3
- package/dist/{permission-CvYQNUqZ.d.ts → permission-CC7XFYWG.d.ts} +1 -1
- package/dist/{permission-policy-D5Ss8j4B.d.ts → permission-policy-cYR4RJmw.d.ts} +2 -2
- package/dist/{pipeline-l_zzFRh3.d.ts → pipeline-Ckkn3AOA.d.ts} +2 -2
- package/dist/{plan-templates-NtPgyeJA.d.ts → plan-templates-BvHw5Znw.d.ts} +33 -9
- package/dist/{provider-model-resolve-d5poT5y0.d.ts → provider-model-resolve-nZqnCeaR.d.ts} +3 -3
- package/dist/{provider-runner-gkctlQV_.d.ts → provider-runner-zVOn1p67.d.ts} +3 -3
- package/dist/{retry-policy-CtFhfwa8.d.ts → retry-policy-BV7nzeAd.d.ts} +1 -1
- package/dist/sdd/index.d.ts +8 -8
- package/dist/sdd/index.js +2 -0
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-vault-BLsVmTIK.d.ts → secret-vault-eMBKfheR.d.ts} +9 -1
- package/dist/security/index.d.ts +5 -5
- package/dist/security/index.js +137 -10
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-CXl2_y9W.d.ts → selector-C4ORTOid.d.ts} +1 -1
- package/dist/{session-event-bridge-Ccud20CC.d.ts → session-event-bridge-CeNpUL9w.d.ts} +1 -1
- package/dist/{session-reader-ZeXQmsmE.d.ts → session-reader-BepLSnGL.d.ts} +1 -1
- package/dist/storage/index.d.ts +50 -13
- package/dist/storage/index.js +620 -220
- package/dist/storage/index.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js +9 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +19 -19
- package/dist/types/index.js +202 -41
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +17 -4
- package/dist/utils/index.js +48 -9
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,8 @@ import { isAbsolute, resolve } from 'path';
|
|
|
5
5
|
import * as os from 'os';
|
|
6
6
|
import { hostname } from 'os';
|
|
7
7
|
import { EventEmitter } from 'events';
|
|
8
|
+
import { createReadStream } from 'fs';
|
|
9
|
+
import { createInterface } from 'readline';
|
|
8
10
|
|
|
9
11
|
// src/coordination/brain.ts
|
|
10
12
|
var ObservableBrainArbiter = class {
|
|
@@ -5877,6 +5879,68 @@ Working rules:
|
|
|
5877
5879
|
- When in doubt, flag as medium rather than ignoring potential issues`
|
|
5878
5880
|
// Budgets are set by the orchestrator per task — see fleet.ts header.
|
|
5879
5881
|
};
|
|
5882
|
+
var SHADOW_AGENT = {
|
|
5883
|
+
id: "shadow-agent",
|
|
5884
|
+
name: "Shadow",
|
|
5885
|
+
role: "shadow-agent",
|
|
5886
|
+
prompt: `You are the Shadow Agent \u2014 a silent background monitor for the WrongStack fleet.
|
|
5887
|
+
|
|
5888
|
+
Your job is to observe, detect anomalies, and be ready to intervene \u2014 but only when commanded.
|
|
5889
|
+
|
|
5890
|
+
## Core Responsibilities
|
|
5891
|
+
|
|
5892
|
+
1. **Fleet Monitoring** (every 30s)
|
|
5893
|
+
- Call \`fleet_status\` + \`fleet_health\` on each heartbeat
|
|
5894
|
+
- Track what each agent is doing (task descriptions)
|
|
5895
|
+
- Detect stuck agents (>5min no events), idle agents, crashed agents
|
|
5896
|
+
|
|
5897
|
+
2. **FleetBus Subscription**
|
|
5898
|
+
- Subscribe to \`subagent.*\` events to track lifecycle
|
|
5899
|
+
- Subscribe to \`tool.executed\` to monitor activity
|
|
5900
|
+
- Track agent joins (subagent.started) and leaves (subagent.stopped)
|
|
5901
|
+
|
|
5902
|
+
3. **Mailbox Surveillance**
|
|
5903
|
+
- Monitor for \`control\` type messages starting with "hoop"
|
|
5904
|
+
- Detect orphan assigns (assign without result within 5min)
|
|
5905
|
+
- Cross-session awareness via shared project mailbox
|
|
5906
|
+
|
|
5907
|
+
4. **Spike Detection**
|
|
5908
|
+
- Track task duration per agent
|
|
5909
|
+
- Flag agents that spawn and die within <5 seconds
|
|
5910
|
+
- Log spike events with reason (completed/error/killed/timeout)
|
|
5911
|
+
|
|
5912
|
+
5. **Intervention Commands**
|
|
5913
|
+
Parse these from mailbox control messages:
|
|
5914
|
+
- \`hoop <agentId>\` \u2014 terminate specific agent
|
|
5915
|
+
- \`hoop all\` \u2014 terminate all running agents
|
|
5916
|
+
- \`shadow status\` \u2014 report current fleet snapshot
|
|
5917
|
+
- \`shadow mute\` \u2014 pause heartbeat monitoring
|
|
5918
|
+
- \`shadow resume\` \u2014 resume heartbeat monitoring
|
|
5919
|
+
- \`shadow interval <ms>\` \u2014 change heartbeat interval
|
|
5920
|
+
- \`shadow model <model-id>\` \u2014 change analysis model
|
|
5921
|
+
|
|
5922
|
+
## Operating Rules
|
|
5923
|
+
|
|
5924
|
+
- **Silent by default**: Use DEBUG level logging unless anomaly detected
|
|
5925
|
+
- **Deterministic**: Same state always produces same actions \u2014 no randomness
|
|
5926
|
+
- **Report on anomaly**: When anomaly detected, use \`mail_send\` to broadcast warning
|
|
5927
|
+
- **Never auto-intervene**: Always report unless explicitly commanded
|
|
5928
|
+
- **Minimal footprint**: Small state, efficient snapshots
|
|
5929
|
+
|
|
5930
|
+
## Startup Sequence
|
|
5931
|
+
|
|
5932
|
+
1. Send broadcast: \`shadow:started { intervalMs, model, startTime }\`
|
|
5933
|
+
2. Subscribe to FleetBus for all relevant events
|
|
5934
|
+
3. Schedule heartbeat cron job at configured interval
|
|
5935
|
+
4. Wait for commands or anomalies
|
|
5936
|
+
|
|
5937
|
+
## Shutdown Sequence
|
|
5938
|
+
|
|
5939
|
+
1. Cancel all cron jobs (\`cron_cancel\`)
|
|
5940
|
+
2. Send broadcast: \`shadow:stopped { reason, finalState }\`
|
|
5941
|
+
3. Clean up FleetBus subscriptions`
|
|
5942
|
+
// Budgets are set by the orchestrator per task — see fleet.ts header.
|
|
5943
|
+
};
|
|
5880
5944
|
var CRITIC_AGENT = {
|
|
5881
5945
|
id: "critic",
|
|
5882
5946
|
name: "Critic",
|
|
@@ -5917,6 +5981,7 @@ var FLEET_ROSTER = {
|
|
|
5917
5981
|
"refactor-planner": REFACTOR_PLANNER_AGENT,
|
|
5918
5982
|
"security-scanner": SECURITY_SCANNER_AGENT,
|
|
5919
5983
|
"critic": CRITIC_AGENT,
|
|
5984
|
+
"shadow-agent": SHADOW_AGENT,
|
|
5920
5985
|
...Object.fromEntries(
|
|
5921
5986
|
ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.config])
|
|
5922
5987
|
)
|
|
@@ -5928,6 +5993,8 @@ var FLEET_ROSTER_BUDGETS = {
|
|
|
5928
5993
|
"refactor-planner": { timeoutMs: 7.5 * 60 * 60 * 1e3, maxIterations: 6e3, maxToolCalls: 18e3 },
|
|
5929
5994
|
"security-scanner": { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 },
|
|
5930
5995
|
"critic": { timeoutMs: 5 * 60 * 60 * 1e3, maxIterations: 4e3, maxToolCalls: 12e3 },
|
|
5996
|
+
"shadow-agent": { timeoutMs: 24 * 60 * 60 * 1e3, maxIterations: 1e4, maxToolCalls: 5e3 },
|
|
5997
|
+
// Long-running background monitor
|
|
5931
5998
|
...Object.fromEntries(
|
|
5932
5999
|
ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.budget])
|
|
5933
6000
|
)
|
|
@@ -8748,6 +8815,8 @@ function generateSessionId(startedAt, model) {
|
|
|
8748
8815
|
const modelPart = model ? `_${sanitizeModel(model)}` : "";
|
|
8749
8816
|
return `${date}/${time}Z${modelPart}_${suffix}`;
|
|
8750
8817
|
}
|
|
8818
|
+
|
|
8819
|
+
// src/storage/session-store.ts
|
|
8751
8820
|
var DefaultSessionStore = class _DefaultSessionStore {
|
|
8752
8821
|
dir;
|
|
8753
8822
|
events;
|
|
@@ -8765,6 +8834,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
8765
8834
|
_loadCache = /* @__PURE__ */ new Map();
|
|
8766
8835
|
_indexCache = null;
|
|
8767
8836
|
static LOAD_CACHE_MAX_ENTRIES = 50;
|
|
8837
|
+
static LIST_SCAN_CONCURRENCY = 32;
|
|
8768
8838
|
constructor(opts) {
|
|
8769
8839
|
this.dir = opts.dir;
|
|
8770
8840
|
this.events = opts.events;
|
|
@@ -8781,7 +8851,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
8781
8851
|
this._loadCache.clear();
|
|
8782
8852
|
}
|
|
8783
8853
|
}
|
|
8784
|
-
//
|
|
8854
|
+
// ── Storage event helpers ───────────────────────────────────────────────────
|
|
8785
8855
|
emitRead(sessionId, filePath, operation, outcome, durationMs, error) {
|
|
8786
8856
|
this.events?.emit("storage.read", {
|
|
8787
8857
|
sessionId,
|
|
@@ -8896,7 +8966,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
8896
8966
|
this.events,
|
|
8897
8967
|
{
|
|
8898
8968
|
resumed: true,
|
|
8899
|
-
// Shard directory (sessions/<date>/)
|
|
8969
|
+
// Shard directory (sessions/<date>/) — must match create() so the
|
|
8900
8970
|
// .summary.json sidecar lands next to the JSONL instead of the
|
|
8901
8971
|
// sessions root (where summaryFor() would never find it).
|
|
8902
8972
|
dir: path5.dirname(file),
|
|
@@ -8937,19 +9007,93 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
8937
9007
|
const raw = await fsp6.readFile(file, "utf8");
|
|
8938
9008
|
const lines = raw.split("\n").filter((l) => l.trim());
|
|
8939
9009
|
const events = [];
|
|
9010
|
+
let sessionStartEvent;
|
|
9011
|
+
let sessionEndEvent;
|
|
9012
|
+
let sessionModel;
|
|
9013
|
+
let sessionProvider;
|
|
9014
|
+
let sessionPendingToolUses;
|
|
9015
|
+
const messages = [];
|
|
9016
|
+
const openToolUses = /* @__PURE__ */ new Set();
|
|
9017
|
+
let usage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
8940
9018
|
for (const line of lines) {
|
|
8941
9019
|
try {
|
|
8942
9020
|
const parsed = JSON.parse(line);
|
|
8943
9021
|
if (parsed !== null && typeof parsed === "object" && typeof parsed.type === "string" && typeof parsed.ts === "string") {
|
|
8944
|
-
|
|
9022
|
+
const ev = parsed;
|
|
9023
|
+
events.push(ev);
|
|
9024
|
+
if (ev.type === "session_start" && !sessionStartEvent) {
|
|
9025
|
+
sessionStartEvent = ev;
|
|
9026
|
+
sessionModel = ev.model;
|
|
9027
|
+
sessionProvider = ev.provider;
|
|
9028
|
+
}
|
|
9029
|
+
if (ev.type === "session_end") {
|
|
9030
|
+
sessionEndEvent = ev;
|
|
9031
|
+
sessionPendingToolUses = ev.pendingToolUses;
|
|
9032
|
+
}
|
|
9033
|
+
if (ev.type === "user_input") {
|
|
9034
|
+
openToolUses.clear();
|
|
9035
|
+
messages.push({ role: "user", content: ev.content, ts: ev.ts });
|
|
9036
|
+
} else if (ev.type === "llm_response") {
|
|
9037
|
+
messages.push({ role: "assistant", content: ev.content, ts: ev.ts });
|
|
9038
|
+
for (const b of ev.content) {
|
|
9039
|
+
if (b.type === "tool_use") openToolUses.add(b.id);
|
|
9040
|
+
}
|
|
9041
|
+
usage = {
|
|
9042
|
+
input: usage.input + (ev.usage.input ?? 0),
|
|
9043
|
+
output: usage.output + (ev.usage.output ?? 0),
|
|
9044
|
+
cacheRead: (usage.cacheRead ?? 0) + (ev.usage.cacheRead ?? 0),
|
|
9045
|
+
cacheWrite: (usage.cacheWrite ?? 0) + (ev.usage.cacheWrite ?? 0)
|
|
9046
|
+
};
|
|
9047
|
+
} else if (ev.type === "tool_result") {
|
|
9048
|
+
if (!openToolUses.has(ev.id)) {
|
|
9049
|
+
this.events?.emit("session.damaged", {
|
|
9050
|
+
sessionId: id,
|
|
9051
|
+
detail: `Orphan tool_result "${ev.id}" has no matching tool_use`
|
|
9052
|
+
});
|
|
9053
|
+
continue;
|
|
9054
|
+
}
|
|
9055
|
+
openToolUses.delete(ev.id);
|
|
9056
|
+
const resultBlock = {
|
|
9057
|
+
type: "tool_result",
|
|
9058
|
+
tool_use_id: ev.id,
|
|
9059
|
+
content: typeof ev.content === "string" ? ev.content : JSON.stringify(ev.content),
|
|
9060
|
+
is_error: ev.isError
|
|
9061
|
+
};
|
|
9062
|
+
const last = messages[messages.length - 1];
|
|
9063
|
+
const lastIsToolResultUser = last?.role === "user" && Array.isArray(last.content) && last.content.every((b) => b.type === "tool_result");
|
|
9064
|
+
if (lastIsToolResultUser && Array.isArray(last.content)) {
|
|
9065
|
+
last.content.push(resultBlock);
|
|
9066
|
+
} else {
|
|
9067
|
+
messages.push({ role: "user", content: [resultBlock], ts: ev.ts });
|
|
9068
|
+
}
|
|
9069
|
+
}
|
|
8945
9070
|
}
|
|
8946
9071
|
} catch {
|
|
8947
9072
|
}
|
|
8948
9073
|
}
|
|
8949
|
-
|
|
8950
|
-
|
|
9074
|
+
if (openToolUses.size > 0) {
|
|
9075
|
+
this.events?.emit("session.damaged", {
|
|
9076
|
+
sessionId: id,
|
|
9077
|
+
detail: `${openToolUses.size} tool_use blocks without matching results - replay repaired`
|
|
9078
|
+
});
|
|
9079
|
+
}
|
|
9080
|
+
const repaired = repairToolUseAdjacency(messages);
|
|
9081
|
+
if (repaired.report.changed) {
|
|
9082
|
+
this.events?.emit("session.damaged", {
|
|
9083
|
+
sessionId: id,
|
|
9084
|
+
detail: `Repaired replay adjacency: removed ${repaired.report.removedToolUses.length} tool_use, ${repaired.report.removedToolResults.length} tool_result, ${repaired.report.removedMessages} empty messages`
|
|
9085
|
+
});
|
|
9086
|
+
}
|
|
9087
|
+
const meta = {
|
|
9088
|
+
id,
|
|
9089
|
+
startedAt: sessionStartEvent?.ts ?? (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
9090
|
+
endedAt: sessionEndEvent?.ts,
|
|
9091
|
+
model: sessionModel,
|
|
9092
|
+
provider: sessionProvider,
|
|
9093
|
+
pendingToolUses: sessionPendingToolUses
|
|
9094
|
+
};
|
|
8951
9095
|
const toolCallEnds = extractToolCallEnds(events);
|
|
8952
|
-
const data = { metadata: meta, events, messages, usage, toolCallEnds };
|
|
9096
|
+
const data = { metadata: meta, events, messages: repaired.messages, usage, toolCallEnds };
|
|
8953
9097
|
if (this._loadCache.size >= _DefaultSessionStore.LOAD_CACHE_MAX_ENTRIES) {
|
|
8954
9098
|
const oldest = this._loadCache.keys().next().value;
|
|
8955
9099
|
if (oldest !== void 0) {
|
|
@@ -8987,20 +9131,12 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
8987
9131
|
});
|
|
8988
9132
|
return indexed.slice(0, limit);
|
|
8989
9133
|
}
|
|
8990
|
-
|
|
8991
|
-
const sessions = await Promise.all(ids.map((id) => this.summaryFor(id).catch(() => null)));
|
|
8992
|
-
const out = sessions.filter((s) => s !== null);
|
|
8993
|
-
out.sort((a, b) => {
|
|
8994
|
-
if (a.startedAt < b.startedAt) return 1;
|
|
8995
|
-
if (a.startedAt > b.startedAt) return -1;
|
|
8996
|
-
return a.id.localeCompare(b.id);
|
|
8997
|
-
});
|
|
8998
|
-
return out.slice(0, limit);
|
|
9134
|
+
return await this.listFromDirectoryScan(limit);
|
|
8999
9135
|
} catch {
|
|
9000
9136
|
return [];
|
|
9001
9137
|
}
|
|
9002
9138
|
}
|
|
9003
|
-
//
|
|
9139
|
+
// ── Session index (_index.jsonl) ─────────────────────────────────────────
|
|
9004
9140
|
//
|
|
9005
9141
|
// One JSON line per closed session, appended atomically on close().
|
|
9006
9142
|
// When a session is deleted, a tombstone {action:"delete",id:"..."} is
|
|
@@ -9120,43 +9256,102 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
9120
9256
|
this._indexCache = null;
|
|
9121
9257
|
return valid.length;
|
|
9122
9258
|
}
|
|
9259
|
+
async listFromDirectoryScan(limit) {
|
|
9260
|
+
const refs = await this.collectSessionFiles(this.dir);
|
|
9261
|
+
const candidates = await mapWithConcurrency(
|
|
9262
|
+
refs,
|
|
9263
|
+
_DefaultSessionStore.LIST_SCAN_CONCURRENCY,
|
|
9264
|
+
async (ref) => {
|
|
9265
|
+
const manifest = await this.readSummaryManifest(ref.id);
|
|
9266
|
+
if (manifest) return { summary: manifest, needsBackfill: false };
|
|
9267
|
+
const summary = await this.summaryHeaderFor(ref);
|
|
9268
|
+
return summary ? { summary, needsBackfill: true } : null;
|
|
9269
|
+
}
|
|
9270
|
+
);
|
|
9271
|
+
const out = candidates.filter((s) => s !== null);
|
|
9272
|
+
out.sort((a, b) => compareSessionSummaries(a.summary, b.summary));
|
|
9273
|
+
const selected = out.slice(0, limit);
|
|
9274
|
+
const summaries = await mapWithConcurrency(
|
|
9275
|
+
selected,
|
|
9276
|
+
Math.min(_DefaultSessionStore.LIST_SCAN_CONCURRENCY, Math.max(1, limit)),
|
|
9277
|
+
async (candidate) => {
|
|
9278
|
+
if (!candidate.needsBackfill) return candidate.summary;
|
|
9279
|
+
return await this.summaryFor(candidate.summary.id).catch(() => candidate.summary);
|
|
9280
|
+
}
|
|
9281
|
+
);
|
|
9282
|
+
return summaries.filter((s) => s !== null);
|
|
9283
|
+
}
|
|
9284
|
+
async collectSessionFiles(dir, prefix = "", depth = 0) {
|
|
9285
|
+
let entries;
|
|
9286
|
+
try {
|
|
9287
|
+
entries = await fsp6.readdir(dir, { withFileTypes: true });
|
|
9288
|
+
} catch {
|
|
9289
|
+
return [];
|
|
9290
|
+
}
|
|
9291
|
+
const dirEntries = [];
|
|
9292
|
+
const files = [];
|
|
9293
|
+
for (const entry of entries) {
|
|
9294
|
+
if (entry.name.startsWith(".") && entry.name !== ".wrongstack") continue;
|
|
9295
|
+
if (entry.name === "shared" || entry.name === "subagents" || entry.name === "attachments")
|
|
9296
|
+
continue;
|
|
9297
|
+
if (entry.isDirectory()) {
|
|
9298
|
+
dirEntries.push(entry);
|
|
9299
|
+
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
9300
|
+
if (entry.name === "_index.jsonl") continue;
|
|
9301
|
+
const base = entry.name.replace(/\.jsonl$/, "");
|
|
9302
|
+
const id = prefix ? `${prefix}/${base}` : base;
|
|
9303
|
+
files.push({ id, filePath: path5.join(dir, entry.name) });
|
|
9304
|
+
}
|
|
9305
|
+
}
|
|
9306
|
+
const childFileArrays = await Promise.all(
|
|
9307
|
+
dirEntries.map((entry) => {
|
|
9308
|
+
const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
|
|
9309
|
+
return this.collectSessionFiles(path5.join(dir, entry.name), childPrefix, depth + 1);
|
|
9310
|
+
})
|
|
9311
|
+
);
|
|
9312
|
+
return [...childFileArrays.flat(), ...files];
|
|
9313
|
+
}
|
|
9123
9314
|
/** Recursively collect session IDs from date-shard subdirectories.
|
|
9124
|
-
* IDs include the date-prefix path (e.g. "2026-06-06/17-46-57Z_
|
|
9315
|
+
* IDs include the date-prefix path (e.g. "2026-06-06/17-46-57Z_…").
|
|
9125
9316
|
* Skips `.jsonl`/`.summary.json` root files, dot-files, and
|
|
9126
9317
|
* sub-directories that belong to fleet/subagent sessions. */
|
|
9127
9318
|
async collectSessionIds(dir, prefix = "", depth = 0) {
|
|
9128
|
-
const ids = [];
|
|
9129
9319
|
let entries;
|
|
9130
9320
|
try {
|
|
9131
9321
|
entries = await fsp6.readdir(dir, { withFileTypes: true });
|
|
9132
9322
|
} catch {
|
|
9133
|
-
return
|
|
9323
|
+
return [];
|
|
9134
9324
|
}
|
|
9325
|
+
const dirEntries = [];
|
|
9326
|
+
const fileIds = [];
|
|
9135
9327
|
for (const entry of entries) {
|
|
9136
9328
|
if (entry.name.startsWith(".") && entry.name !== ".wrongstack") continue;
|
|
9137
9329
|
if (entry.name === "shared" || entry.name === "subagents" || entry.name === "attachments")
|
|
9138
9330
|
continue;
|
|
9139
9331
|
if (entry.isDirectory()) {
|
|
9140
|
-
|
|
9141
|
-
ids.push(...await this.collectSessionIds(path5.join(dir, entry.name), childPrefix, depth + 1));
|
|
9332
|
+
dirEntries.push(entry);
|
|
9142
9333
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
9143
9334
|
if (entry.name === "_index.jsonl") continue;
|
|
9144
9335
|
const base = entry.name.replace(/\.jsonl$/, "");
|
|
9145
|
-
|
|
9336
|
+
fileIds.push(prefix ? `${prefix}/${base}` : base);
|
|
9146
9337
|
}
|
|
9147
9338
|
}
|
|
9148
|
-
|
|
9339
|
+
const childIdArrays = await Promise.all(
|
|
9340
|
+
dirEntries.map((entry) => {
|
|
9341
|
+
const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
|
|
9342
|
+
return this.collectSessionIds(path5.join(dir, entry.name), childPrefix, depth + 1);
|
|
9343
|
+
})
|
|
9344
|
+
);
|
|
9345
|
+
return [...childIdArrays.flat(), ...fileIds];
|
|
9149
9346
|
}
|
|
9150
9347
|
async summaryFor(id) {
|
|
9151
9348
|
const manifest = this.sessionPath(id, ".summary.json");
|
|
9152
9349
|
const t0 = Date.now();
|
|
9153
9350
|
let outcome = "success";
|
|
9154
9351
|
let errorMsg;
|
|
9352
|
+
const fromManifest = await this.readSummaryManifest(id, t0);
|
|
9353
|
+
if (fromManifest) return fromManifest;
|
|
9155
9354
|
try {
|
|
9156
|
-
const raw = await fsp6.readFile(manifest, "utf8");
|
|
9157
|
-
this.emitRead(id, manifest, "summary", "success", Date.now() - t0);
|
|
9158
|
-
return JSON.parse(raw);
|
|
9159
|
-
} catch {
|
|
9160
9355
|
const full = this.sessionPath(id, ".jsonl");
|
|
9161
9356
|
const stat7 = await fsp6.stat(full);
|
|
9162
9357
|
const summary = await this.summarize(id, stat7.mtime.toISOString());
|
|
@@ -9172,9 +9367,81 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
9172
9367
|
}));
|
|
9173
9368
|
});
|
|
9174
9369
|
outcome = "failure";
|
|
9175
|
-
errorMsg = "summary fallback \
|
|
9370
|
+
errorMsg = "summary fallback \xE2\u20AC\u201D manifest rebuilt";
|
|
9176
9371
|
this.emitRead(id, manifest, "summary", outcome, Date.now() - t0, errorMsg);
|
|
9177
9372
|
return summary;
|
|
9373
|
+
} catch (err) {
|
|
9374
|
+
outcome = "failure";
|
|
9375
|
+
errorMsg = toErrorMessage(err);
|
|
9376
|
+
this.emitRead(id, manifest, "summary", outcome, Date.now() - t0, errorMsg);
|
|
9377
|
+
return {
|
|
9378
|
+
id,
|
|
9379
|
+
title: "(damaged)",
|
|
9380
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9381
|
+
model: "unknown",
|
|
9382
|
+
provider: "unknown",
|
|
9383
|
+
tokenTotal: 0
|
|
9384
|
+
};
|
|
9385
|
+
}
|
|
9386
|
+
}
|
|
9387
|
+
async readSummaryManifest(id, startTime = Date.now()) {
|
|
9388
|
+
const manifest = this.sessionPath(id, ".summary.json");
|
|
9389
|
+
try {
|
|
9390
|
+
const raw = await fsp6.readFile(manifest, "utf8");
|
|
9391
|
+
this.emitRead(id, manifest, "summary", "success", Date.now() - startTime);
|
|
9392
|
+
return JSON.parse(raw);
|
|
9393
|
+
} catch {
|
|
9394
|
+
return null;
|
|
9395
|
+
}
|
|
9396
|
+
}
|
|
9397
|
+
async summaryHeaderFor(ref) {
|
|
9398
|
+
let mtime = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
9399
|
+
try {
|
|
9400
|
+
const stat7 = await fsp6.stat(ref.filePath);
|
|
9401
|
+
if (!stat7.isFile()) {
|
|
9402
|
+
return {
|
|
9403
|
+
id: ref.id,
|
|
9404
|
+
title: "(damaged)",
|
|
9405
|
+
startedAt: stat7.mtime.toISOString(),
|
|
9406
|
+
model: "unknown",
|
|
9407
|
+
provider: "unknown",
|
|
9408
|
+
tokenTotal: 0
|
|
9409
|
+
};
|
|
9410
|
+
}
|
|
9411
|
+
mtime = stat7.mtime.toISOString();
|
|
9412
|
+
} catch {
|
|
9413
|
+
return null;
|
|
9414
|
+
}
|
|
9415
|
+
try {
|
|
9416
|
+
for await (const event of this.iterSessionEvents(ref.filePath)) {
|
|
9417
|
+
if (event.type === "session_start") {
|
|
9418
|
+
return {
|
|
9419
|
+
id: ref.id,
|
|
9420
|
+
title: "(empty session)",
|
|
9421
|
+
startedAt: event.ts,
|
|
9422
|
+
model: event.model ?? "unknown",
|
|
9423
|
+
provider: event.provider ?? "unknown",
|
|
9424
|
+
tokenTotal: 0
|
|
9425
|
+
};
|
|
9426
|
+
}
|
|
9427
|
+
}
|
|
9428
|
+
return {
|
|
9429
|
+
id: ref.id,
|
|
9430
|
+
title: "(empty session)",
|
|
9431
|
+
startedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
9432
|
+
model: "unknown",
|
|
9433
|
+
provider: "unknown",
|
|
9434
|
+
tokenTotal: 0
|
|
9435
|
+
};
|
|
9436
|
+
} catch {
|
|
9437
|
+
return {
|
|
9438
|
+
id: ref.id,
|
|
9439
|
+
title: "(damaged)",
|
|
9440
|
+
startedAt: mtime,
|
|
9441
|
+
model: "unknown",
|
|
9442
|
+
provider: "unknown",
|
|
9443
|
+
tokenTotal: 0
|
|
9444
|
+
};
|
|
9178
9445
|
}
|
|
9179
9446
|
}
|
|
9180
9447
|
/**
|
|
@@ -9299,39 +9566,62 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
9299
9566
|
}
|
|
9300
9567
|
async summarize(id, mtime) {
|
|
9301
9568
|
try {
|
|
9302
|
-
const
|
|
9303
|
-
|
|
9304
|
-
|
|
9569
|
+
const file = this.sessionPath(id, ".jsonl");
|
|
9570
|
+
let title = "(empty session)";
|
|
9571
|
+
let startedAt = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
9572
|
+
let endedAt;
|
|
9573
|
+
let model = "unknown";
|
|
9574
|
+
let provider = "unknown";
|
|
9575
|
+
let tokenIn = 0;
|
|
9576
|
+
let tokenOut = 0;
|
|
9305
9577
|
let iterationCount = 0;
|
|
9306
9578
|
let toolCallCount = 0;
|
|
9307
9579
|
let toolErrorCount = 0;
|
|
9308
9580
|
let fileChangeCount = 0;
|
|
9309
9581
|
const toolBreakdown = {};
|
|
9310
9582
|
let outcome;
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9583
|
+
let lastEventType;
|
|
9584
|
+
let hasError = false;
|
|
9585
|
+
let sawStart = false;
|
|
9586
|
+
for await (const e of this.iterSessionEvents(file)) {
|
|
9587
|
+
lastEventType = e.type;
|
|
9588
|
+
if (e.type === "session_start") {
|
|
9589
|
+
if (!sawStart) {
|
|
9590
|
+
sawStart = true;
|
|
9591
|
+
startedAt = e.ts;
|
|
9592
|
+
model = e.model ?? "unknown";
|
|
9593
|
+
provider = e.provider ?? "unknown";
|
|
9594
|
+
}
|
|
9595
|
+
} else if (e.type === "session_end") {
|
|
9596
|
+
endedAt = e.ts;
|
|
9597
|
+
} else if (e.type === "user_input") {
|
|
9598
|
+
if (title === "(empty session)") title = userInputTitle(e.content);
|
|
9599
|
+
} else if (e.type === "llm_response") {
|
|
9600
|
+
tokenIn += e.usage.input ?? 0;
|
|
9601
|
+
tokenOut += e.usage.output ?? 0;
|
|
9602
|
+
} else if (e.type === "in_flight_start") iterationCount++;
|
|
9314
9603
|
else if (e.type === "tool_call_start") {
|
|
9315
9604
|
toolCallCount++;
|
|
9316
9605
|
toolBreakdown[e.name] = (toolBreakdown[e.name] ?? 0) + 1;
|
|
9317
9606
|
} else if (e.type === "tool_result" && e.isError) toolErrorCount++;
|
|
9318
9607
|
else if (e.type === "file_snapshot") fileChangeCount += e.files.length;
|
|
9608
|
+
else if (e.type === "error" || e.type === "provider_error") hasError = true;
|
|
9319
9609
|
}
|
|
9320
|
-
if (
|
|
9610
|
+
if (lastEventType === "session_end") {
|
|
9321
9611
|
outcome = "completed";
|
|
9322
|
-
} else if (
|
|
9612
|
+
} else if (lastEventType === "in_flight_start") {
|
|
9323
9613
|
outcome = "aborted";
|
|
9324
|
-
} else if (
|
|
9614
|
+
} else if (hasError) {
|
|
9325
9615
|
outcome = "error";
|
|
9326
9616
|
}
|
|
9327
9617
|
return {
|
|
9328
9618
|
id,
|
|
9329
9619
|
title,
|
|
9330
|
-
startedAt
|
|
9331
|
-
endedAt
|
|
9332
|
-
model
|
|
9333
|
-
provider
|
|
9334
|
-
tokenTotal:
|
|
9620
|
+
startedAt,
|
|
9621
|
+
endedAt,
|
|
9622
|
+
model,
|
|
9623
|
+
provider,
|
|
9624
|
+
tokenTotal: tokenIn + tokenOut,
|
|
9335
9625
|
iterationCount: iterationCount > 0 ? iterationCount : void 0,
|
|
9336
9626
|
toolCallCount: toolCallCount > 0 ? toolCallCount : void 0,
|
|
9337
9627
|
toolErrorCount: toolErrorCount > 0 ? toolErrorCount : void 0,
|
|
@@ -9350,75 +9640,24 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
9350
9640
|
};
|
|
9351
9641
|
}
|
|
9352
9642
|
}
|
|
9353
|
-
|
|
9354
|
-
const
|
|
9355
|
-
const
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
replay(events, sessionId = "unknown") {
|
|
9366
|
-
const messages = [];
|
|
9367
|
-
let usage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
9368
|
-
const openToolUses = /* @__PURE__ */ new Set();
|
|
9369
|
-
for (const e of events) {
|
|
9370
|
-
if (e.type === "user_input") {
|
|
9371
|
-
openToolUses.clear();
|
|
9372
|
-
messages.push({ role: "user", content: e.content, ts: e.ts });
|
|
9373
|
-
} else if (e.type === "llm_response") {
|
|
9374
|
-
messages.push({ role: "assistant", content: e.content, ts: e.ts });
|
|
9375
|
-
for (const b of e.content) {
|
|
9376
|
-
if (b.type === "tool_use") openToolUses.add(b.id);
|
|
9377
|
-
}
|
|
9378
|
-
usage = {
|
|
9379
|
-
input: usage.input + (e.usage.input ?? 0),
|
|
9380
|
-
output: usage.output + (e.usage.output ?? 0),
|
|
9381
|
-
cacheRead: (usage.cacheRead ?? 0) + (e.usage.cacheRead ?? 0),
|
|
9382
|
-
cacheWrite: (usage.cacheWrite ?? 0) + (e.usage.cacheWrite ?? 0)
|
|
9383
|
-
};
|
|
9384
|
-
} else if (e.type === "tool_result") {
|
|
9385
|
-
if (!openToolUses.has(e.id)) {
|
|
9386
|
-
this.events?.emit("session.damaged", {
|
|
9387
|
-
sessionId,
|
|
9388
|
-
detail: `Orphan tool_result "${e.id}" has no matching tool_use`
|
|
9389
|
-
});
|
|
9390
|
-
continue;
|
|
9391
|
-
}
|
|
9392
|
-
openToolUses.delete(e.id);
|
|
9393
|
-
const resultBlock = {
|
|
9394
|
-
type: "tool_result",
|
|
9395
|
-
tool_use_id: e.id,
|
|
9396
|
-
content: typeof e.content === "string" ? e.content : JSON.stringify(e.content),
|
|
9397
|
-
is_error: e.isError
|
|
9398
|
-
};
|
|
9399
|
-
const last = messages[messages.length - 1];
|
|
9400
|
-
const lastIsToolResultUser = last?.role === "user" && Array.isArray(last.content) && last.content.every((b) => b.type === "tool_result");
|
|
9401
|
-
if (lastIsToolResultUser && Array.isArray(last.content)) {
|
|
9402
|
-
last.content.push(resultBlock);
|
|
9403
|
-
} else {
|
|
9404
|
-
messages.push({ role: "user", content: [resultBlock], ts: e.ts });
|
|
9643
|
+
async *iterSessionEvents(file) {
|
|
9644
|
+
const stream = createReadStream(file, { encoding: "utf8" });
|
|
9645
|
+
const lines = createInterface({ input: stream, crlfDelay: Infinity });
|
|
9646
|
+
try {
|
|
9647
|
+
for await (const line of lines) {
|
|
9648
|
+
if (!line.trim()) continue;
|
|
9649
|
+
try {
|
|
9650
|
+
const parsed = JSON.parse(line);
|
|
9651
|
+
if (parsed !== null && typeof parsed === "object" && typeof parsed.type === "string" && typeof parsed.ts === "string") {
|
|
9652
|
+
yield parsed;
|
|
9653
|
+
}
|
|
9654
|
+
} catch {
|
|
9405
9655
|
}
|
|
9406
9656
|
}
|
|
9657
|
+
} finally {
|
|
9658
|
+
lines.close();
|
|
9659
|
+
stream.destroy();
|
|
9407
9660
|
}
|
|
9408
|
-
if (openToolUses.size > 0) {
|
|
9409
|
-
this.events?.emit("session.damaged", {
|
|
9410
|
-
sessionId,
|
|
9411
|
-
detail: `${openToolUses.size} tool_use blocks without matching results - replay repaired`
|
|
9412
|
-
});
|
|
9413
|
-
}
|
|
9414
|
-
const repaired = repairToolUseAdjacency(messages);
|
|
9415
|
-
if (repaired.report.changed) {
|
|
9416
|
-
this.events?.emit("session.damaged", {
|
|
9417
|
-
sessionId,
|
|
9418
|
-
detail: `Repaired replay adjacency: removed ${repaired.report.removedToolUses.length} tool_use, ${repaired.report.removedToolResults.length} tool_result, ${repaired.report.removedMessages} empty messages`
|
|
9419
|
-
});
|
|
9420
|
-
}
|
|
9421
|
-
return { messages: repaired.messages, usage };
|
|
9422
9661
|
}
|
|
9423
9662
|
};
|
|
9424
9663
|
function extractToolCallEnds(events) {
|
|
@@ -9478,7 +9717,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9478
9717
|
/**
|
|
9479
9718
|
* Lazy session_start/session_resumed init, shared by all appenders.
|
|
9480
9719
|
* A single promise (not a boolean) so a second append racing the first
|
|
9481
|
-
* can't push its event into the buffer BEFORE the first append's event
|
|
9720
|
+
* can't push its event into the buffer BEFORE the first append's event —
|
|
9482
9721
|
* every appender awaits the same init and resumes in FIFO call order.
|
|
9483
9722
|
*/
|
|
9484
9723
|
initPromise = null;
|
|
@@ -9491,24 +9730,24 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9491
9730
|
lastAppendWarnAt = 0;
|
|
9492
9731
|
secretScrubber;
|
|
9493
9732
|
onCloseCb;
|
|
9494
|
-
/** Implements SessionWriter.traceId
|
|
9733
|
+
/** Implements SessionWriter.traceId — propagated from ContextInit.traceId. */
|
|
9495
9734
|
traceId;
|
|
9496
|
-
//
|
|
9735
|
+
// ── Write buffer — batches events to reduce per-event disk I/O ─────────
|
|
9497
9736
|
//
|
|
9498
9737
|
// Every append() pushes the scrubbed event into an in-memory buffer instead
|
|
9499
9738
|
// of calling handle.appendFile() synchronously. The buffer flushes to disk
|
|
9500
9739
|
// when it reaches FLUSH_SIZE events OR after FLUSH_INTERVAL_MS of inactivity.
|
|
9501
9740
|
// This cuts the number of disk writes by ~95% without changing the on-disk
|
|
9502
|
-
// format
|
|
9741
|
+
// format — the JSONL is still one JSON object per line.
|
|
9503
9742
|
writeBuffer = [];
|
|
9504
9743
|
flushTimer = null;
|
|
9505
9744
|
static FLUSH_INTERVAL_MS = 500;
|
|
9506
9745
|
static FLUSH_SIZE = 50;
|
|
9507
|
-
//
|
|
9746
|
+
// ── Write serialization ─────────────────────────────────────────────────
|
|
9508
9747
|
//
|
|
9509
9748
|
// All disk writes are funneled through a FIFO promise chain. Without it,
|
|
9510
9749
|
// a timer-driven flush racing an explicit flush()/close() issues two
|
|
9511
|
-
// concurrent appendFile() calls on the shared O_APPEND handle
|
|
9750
|
+
// concurrent appendFile() calls on the shared O_APPEND handle — the kernel
|
|
9512
9751
|
// may complete them out of order (chronology breaks) or, for large
|
|
9513
9752
|
// batches, interleave partial writes (torn JSONL lines). The chain keeps
|
|
9514
9753
|
// exactly one write in flight; failures don't break the chain.
|
|
@@ -9522,7 +9761,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9522
9761
|
);
|
|
9523
9762
|
return write;
|
|
9524
9763
|
}
|
|
9525
|
-
//
|
|
9764
|
+
// ── Enriched summary tracking ──────────────────────────────────────────
|
|
9526
9765
|
iterationCount = 0;
|
|
9527
9766
|
toolCallCount = 0;
|
|
9528
9767
|
toolErrorCount = 0;
|
|
@@ -9614,7 +9853,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9614
9853
|
* (user_input, llm_response) call this so they survive SIGKILL/crash
|
|
9615
9854
|
* instead of sitting in the in-memory buffer for up to 500ms.
|
|
9616
9855
|
*
|
|
9617
|
-
* Idempotent
|
|
9856
|
+
* Idempotent — cancels any pending timer and writes whatever has
|
|
9618
9857
|
* accumulated in the buffer. Safe to call even when the buffer
|
|
9619
9858
|
* is empty (no-op).
|
|
9620
9859
|
*/
|
|
@@ -9637,7 +9876,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9637
9876
|
/**
|
|
9638
9877
|
* Flush all buffered events to disk as a single appendFile call.
|
|
9639
9878
|
* Errors use the same throttled-warning pattern the old per-event
|
|
9640
|
-
* append path used
|
|
9879
|
+
* append path used — one warning every 5s with a suppressed count.
|
|
9641
9880
|
* On failure the buffer is cleared (events are best-effort, same as
|
|
9642
9881
|
* the old per-event path where a failed write was silently dropped).
|
|
9643
9882
|
*/
|
|
@@ -9820,7 +10059,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9820
10059
|
/**
|
|
9821
10060
|
* Truncate the session file to the checkpoint with the given promptIndex,
|
|
9822
10061
|
* removing all events that follow it. Uses a single-pass byte-offset scan
|
|
9823
|
-
* so post-checkpoint content is never read or parsed
|
|
10062
|
+
* so post-checkpoint content is never read or parsed — O(1) memory instead
|
|
9824
10063
|
* of O(N) JSON.parse calls over the full file.
|
|
9825
10064
|
*/
|
|
9826
10065
|
async truncateToCheckpoint(targetPromptIndex) {
|
|
@@ -9977,7 +10216,7 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9977
10216
|
await fsp6.writeFile(this.filePath, record, "utf8");
|
|
9978
10217
|
}
|
|
9979
10218
|
/**
|
|
9980
|
-
* Idea #1
|
|
10219
|
+
* Idea #1 — write an in-flight marker. The agent loop should call
|
|
9981
10220
|
* this at the start of each long-running operation; a matching
|
|
9982
10221
|
* `clearInFlightMarker` follows on clean exit. A stale marker
|
|
9983
10222
|
* (no end) is what `SessionRecovery.detectStale` looks for.
|
|
@@ -9994,9 +10233,9 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
9994
10233
|
this.events?.emit("in_flight.started", { context, ts: (/* @__PURE__ */ new Date()).toISOString() });
|
|
9995
10234
|
}
|
|
9996
10235
|
/**
|
|
9997
|
-
* Idea #1
|
|
10236
|
+
* Idea #1 — close the in-flight marker. Idempotent in spirit
|
|
9998
10237
|
* (you can call it after a successful iteration even if you
|
|
9999
|
-
* didn't open one this round)
|
|
10238
|
+
* didn't open one this round) — but the session log records
|
|
10000
10239
|
* every call so postmortem tooling can see "the agent finished
|
|
10001
10240
|
* cleanly X times, then died without finishing Y".
|
|
10002
10241
|
*/
|
|
@@ -10013,6 +10252,27 @@ function userInputTitle(content) {
|
|
|
10013
10252
|
const text = typeof content === "string" ? content : content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
|
|
10014
10253
|
return (text || "(non-text input)").slice(0, 60);
|
|
10015
10254
|
}
|
|
10255
|
+
function compareSessionSummaries(a, b) {
|
|
10256
|
+
if (a.startedAt < b.startedAt) return 1;
|
|
10257
|
+
if (a.startedAt > b.startedAt) return -1;
|
|
10258
|
+
return a.id.localeCompare(b.id);
|
|
10259
|
+
}
|
|
10260
|
+
async function mapWithConcurrency(items, concurrency, fn) {
|
|
10261
|
+
if (items.length === 0) return [];
|
|
10262
|
+
const out = new Array(items.length);
|
|
10263
|
+
let next = 0;
|
|
10264
|
+
const workerCount = Math.min(Math.max(1, concurrency), items.length);
|
|
10265
|
+
const workers = Array.from({ length: workerCount }, async () => {
|
|
10266
|
+
for (; ; ) {
|
|
10267
|
+
const idx = next++;
|
|
10268
|
+
if (idx >= items.length) return;
|
|
10269
|
+
const item = items[idx];
|
|
10270
|
+
if (item !== void 0) out[idx] = await fn(item);
|
|
10271
|
+
}
|
|
10272
|
+
});
|
|
10273
|
+
await Promise.all(workers);
|
|
10274
|
+
return out;
|
|
10275
|
+
}
|
|
10016
10276
|
|
|
10017
10277
|
// src/coordination/director-session.ts
|
|
10018
10278
|
function makeDirectorSessionFactory(opts) {
|
|
@@ -10487,6 +10747,10 @@ var DefaultMailbox = class {
|
|
|
10487
10747
|
_messageCache = null;
|
|
10488
10748
|
_messageCacheMtime = -1;
|
|
10489
10749
|
_messageCacheSize = -1;
|
|
10750
|
+
/** Primary index: recipient → Set of messages (points into _messageCache). */
|
|
10751
|
+
_byTo = /* @__PURE__ */ new Map();
|
|
10752
|
+
/** Secondary index: sender → Set of messages (points into _messageCache). */
|
|
10753
|
+
_byFrom = /* @__PURE__ */ new Map();
|
|
10490
10754
|
constructor(sessionDir) {
|
|
10491
10755
|
this.filePath = path5.join(sessionDir, MAILBOX_FILE);
|
|
10492
10756
|
}
|
|
@@ -10522,12 +10786,30 @@ var DefaultMailbox = class {
|
|
|
10522
10786
|
}
|
|
10523
10787
|
// ── Query ─────────────────────────────────────────────────────────────
|
|
10524
10788
|
async query(q) {
|
|
10525
|
-
const
|
|
10789
|
+
const needFullScan = q.unreadBy !== void 0 || q.since !== void 0;
|
|
10790
|
+
let candidates;
|
|
10791
|
+
if (needFullScan) {
|
|
10792
|
+
candidates = await this._readAllCached();
|
|
10793
|
+
} else {
|
|
10794
|
+
await this._readAllCached();
|
|
10795
|
+
if (q.to !== void 0) {
|
|
10796
|
+
const direct = this._byTo.get(q.to);
|
|
10797
|
+
const broadcast = this._byTo.get("*");
|
|
10798
|
+
const combined = /* @__PURE__ */ new Map();
|
|
10799
|
+
if (direct) for (const m of direct) combined.set(m.id, m);
|
|
10800
|
+
if (broadcast) for (const m of broadcast) combined.set(m.id, m);
|
|
10801
|
+
candidates = Array.from(combined.values());
|
|
10802
|
+
} else if (q.from !== void 0) {
|
|
10803
|
+
candidates = Array.from(this._byFrom.get(q.from) ?? []);
|
|
10804
|
+
} else {
|
|
10805
|
+
candidates = await this._readAllCached();
|
|
10806
|
+
}
|
|
10807
|
+
}
|
|
10526
10808
|
const limit = q.limit ?? 50;
|
|
10527
10809
|
const order = q.minPriority !== void 0 ? { low: 0, normal: 1, high: 2 } : null;
|
|
10528
10810
|
const minPriorityRank = order && q.minPriority !== void 0 ? order[q.minPriority] : 0;
|
|
10529
10811
|
const filtered = [];
|
|
10530
|
-
for (const msg of
|
|
10812
|
+
for (const msg of candidates) {
|
|
10531
10813
|
if (q.to !== void 0 && msg.to !== q.to && msg.to !== "*") continue;
|
|
10532
10814
|
if (q.from !== void 0 && msg.from !== q.from) continue;
|
|
10533
10815
|
if (q.unreadBy !== void 0 && q.unreadBy in msg.readBy) continue;
|
|
@@ -10628,6 +10910,8 @@ var DefaultMailbox = class {
|
|
|
10628
10910
|
this._messageCache = null;
|
|
10629
10911
|
this._messageCacheMtime = -1;
|
|
10630
10912
|
this._messageCacheSize = -1;
|
|
10913
|
+
this._byTo.clear();
|
|
10914
|
+
this._byFrom.clear();
|
|
10631
10915
|
}
|
|
10632
10916
|
async clearAll() {
|
|
10633
10917
|
await withFileLock(this.filePath, async () => {
|
|
@@ -10686,36 +10970,81 @@ var DefaultMailbox = class {
|
|
|
10686
10970
|
async _readAll() {
|
|
10687
10971
|
try {
|
|
10688
10972
|
const raw = await fsp6.readFile(this.filePath, "utf8");
|
|
10689
|
-
|
|
10690
|
-
const messages = [];
|
|
10691
|
-
for (const line of lines) {
|
|
10692
|
-
try {
|
|
10693
|
-
const parsed = JSON.parse(line);
|
|
10694
|
-
if (!parsed["readBy"]) {
|
|
10695
|
-
const readBy = {};
|
|
10696
|
-
if (parsed["read"] && parsed["readAt"]) {
|
|
10697
|
-
readBy[parsed["to"] ?? "unknown"] = parsed["readAt"];
|
|
10698
|
-
}
|
|
10699
|
-
parsed["readBy"] = readBy;
|
|
10700
|
-
delete parsed["read"];
|
|
10701
|
-
delete parsed["readAt"];
|
|
10702
|
-
}
|
|
10703
|
-
messages.push(parsed);
|
|
10704
|
-
} catch {
|
|
10705
|
-
}
|
|
10706
|
-
}
|
|
10707
|
-
return messages;
|
|
10973
|
+
return this._parseLines(raw);
|
|
10708
10974
|
} catch (err) {
|
|
10709
10975
|
if (err.code === "ENOENT") return [];
|
|
10710
10976
|
throw err;
|
|
10711
10977
|
}
|
|
10712
10978
|
}
|
|
10979
|
+
/**
|
|
10980
|
+
* Read only newly-appended bytes from the file and append them to the
|
|
10981
|
+
* in-memory cache, avoiding a full re-read when the file only grew.
|
|
10982
|
+
*/
|
|
10983
|
+
async _readNewMessagesOnly(fd, oldSize, newSize) {
|
|
10984
|
+
const tailLen = newSize - oldSize;
|
|
10985
|
+
const buf = Buffer.alloc(tailLen);
|
|
10986
|
+
await fd.read(buf, 0, tailLen, oldSize);
|
|
10987
|
+
const tail = buf.toString("utf8");
|
|
10988
|
+
for (const line of tail.split(LINE_SEPARATOR)) {
|
|
10989
|
+
if (!line.trim()) continue;
|
|
10990
|
+
try {
|
|
10991
|
+
const parsed = JSON.parse(line);
|
|
10992
|
+
if (!parsed["readBy"]) {
|
|
10993
|
+
const readBy = {};
|
|
10994
|
+
if (parsed["read"] && parsed["readAt"]) {
|
|
10995
|
+
readBy[parsed["to"] ?? "unknown"] = parsed["readAt"];
|
|
10996
|
+
}
|
|
10997
|
+
parsed["readBy"] = readBy;
|
|
10998
|
+
delete parsed["read"];
|
|
10999
|
+
delete parsed["readAt"];
|
|
11000
|
+
}
|
|
11001
|
+
const msg = parsed;
|
|
11002
|
+
this._messageCache.push(msg);
|
|
11003
|
+
this._indexMsg(msg);
|
|
11004
|
+
} catch {
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
11007
|
+
return this._messageCache;
|
|
11008
|
+
}
|
|
11009
|
+
/** Parse a JSONL string into MailboxMessage[], including migration. */
|
|
11010
|
+
_parseLines(raw) {
|
|
11011
|
+
const lines = raw.split(LINE_SEPARATOR).filter((l) => l.trim().length > 0);
|
|
11012
|
+
const messages = [];
|
|
11013
|
+
for (const line of lines) {
|
|
11014
|
+
try {
|
|
11015
|
+
const parsed = JSON.parse(line);
|
|
11016
|
+
if (!parsed["readBy"]) {
|
|
11017
|
+
const readBy = {};
|
|
11018
|
+
if (parsed["read"] && parsed["readAt"]) {
|
|
11019
|
+
readBy[parsed["to"] ?? "unknown"] = parsed["readAt"];
|
|
11020
|
+
}
|
|
11021
|
+
parsed["readBy"] = readBy;
|
|
11022
|
+
delete parsed["read"];
|
|
11023
|
+
delete parsed["readAt"];
|
|
11024
|
+
}
|
|
11025
|
+
messages.push(parsed);
|
|
11026
|
+
} catch {
|
|
11027
|
+
}
|
|
11028
|
+
}
|
|
11029
|
+
return messages;
|
|
11030
|
+
}
|
|
10713
11031
|
async _readAllCached() {
|
|
10714
11032
|
try {
|
|
10715
11033
|
const st = await fsp6.stat(this.filePath);
|
|
10716
11034
|
if (this._messageCache !== null && this._messageCacheMtime === st.mtimeMs && this._messageCacheSize === st.size) {
|
|
10717
11035
|
return this._messageCache;
|
|
10718
11036
|
}
|
|
11037
|
+
if (this._messageCache !== null && this._messageCacheSize >= 0 && st.size > this._messageCacheSize) {
|
|
11038
|
+
const fd = await fsp6.open(this.filePath, "r");
|
|
11039
|
+
try {
|
|
11040
|
+
const updated = await this._readNewMessagesOnly(fd, this._messageCacheSize, st.size);
|
|
11041
|
+
this._messageCacheMtime = st.mtimeMs;
|
|
11042
|
+
this._messageCacheSize = st.size;
|
|
11043
|
+
return updated;
|
|
11044
|
+
} finally {
|
|
11045
|
+
await fd.close();
|
|
11046
|
+
}
|
|
11047
|
+
}
|
|
10719
11048
|
const all = await this._readAll();
|
|
10720
11049
|
this._setMessageCache(all, st.mtimeMs, st.size);
|
|
10721
11050
|
return all;
|
|
@@ -10732,9 +11061,12 @@ var DefaultMailbox = class {
|
|
|
10732
11061
|
this._messageCache = null;
|
|
10733
11062
|
this._messageCacheMtime = -1;
|
|
10734
11063
|
this._messageCacheSize = -1;
|
|
11064
|
+
this._byTo.clear();
|
|
11065
|
+
this._byFrom.clear();
|
|
10735
11066
|
return;
|
|
10736
11067
|
}
|
|
10737
11068
|
this._messageCache = messages;
|
|
11069
|
+
this._buildIndexes(messages);
|
|
10738
11070
|
if (mtime !== void 0 && size !== void 0) {
|
|
10739
11071
|
this._messageCacheMtime = mtime;
|
|
10740
11072
|
this._messageCacheSize = size;
|
|
@@ -10752,9 +11084,35 @@ var DefaultMailbox = class {
|
|
|
10752
11084
|
this._messageCache = null;
|
|
10753
11085
|
this._messageCacheMtime = -1;
|
|
10754
11086
|
this._messageCacheSize = -1;
|
|
11087
|
+
this._byTo.clear();
|
|
11088
|
+
this._byFrom.clear();
|
|
10755
11089
|
return;
|
|
10756
11090
|
}
|
|
10757
11091
|
this._messageCache.push(msg);
|
|
11092
|
+
this._indexMsg(msg);
|
|
11093
|
+
}
|
|
11094
|
+
/** Rebuild both indexes from a full message list. */
|
|
11095
|
+
_buildIndexes(messages) {
|
|
11096
|
+
this._byTo.clear();
|
|
11097
|
+
this._byFrom.clear();
|
|
11098
|
+
for (const msg of messages) {
|
|
11099
|
+
this._indexMsg(msg);
|
|
11100
|
+
}
|
|
11101
|
+
}
|
|
11102
|
+
/** Add a single message to both indexes. */
|
|
11103
|
+
_indexMsg(msg) {
|
|
11104
|
+
const toSet = this._byTo.get(msg.to);
|
|
11105
|
+
if (toSet) {
|
|
11106
|
+
toSet.add(msg);
|
|
11107
|
+
} else {
|
|
11108
|
+
this._byTo.set(msg.to, /* @__PURE__ */ new Set([msg]));
|
|
11109
|
+
}
|
|
11110
|
+
const fromSet = this._byFrom.get(msg.from);
|
|
11111
|
+
if (fromSet) {
|
|
11112
|
+
fromSet.add(msg);
|
|
11113
|
+
} else {
|
|
11114
|
+
this._byFrom.set(msg.from, /* @__PURE__ */ new Set([msg]));
|
|
11115
|
+
}
|
|
10758
11116
|
}
|
|
10759
11117
|
};
|
|
10760
11118
|
var BrainMonitor = class {
|
|
@@ -10948,7 +11306,7 @@ var GlobalMailbox = class {
|
|
|
10948
11306
|
/**
|
|
10949
11307
|
* @param projectDir — `~/.wrongstack/projects/<slug>/`
|
|
10950
11308
|
* @param events — optional EventBus for real-time TUI/WebUI notifications
|
|
10951
|
-
* @param hqPublisher — optional HQ publisher for cross-project telemetry
|
|
11309
|
+
* @param hqPublisher — optional HQ publisher, or getter, for cross-project telemetry
|
|
10952
11310
|
*/
|
|
10953
11311
|
constructor(projectDir, events, hqPublisher) {
|
|
10954
11312
|
this.messagePath = path5.join(projectDir, MAILBOX_FILE2);
|
|
@@ -10960,15 +11318,19 @@ var GlobalMailbox = class {
|
|
|
10960
11318
|
get hqMailboxId() {
|
|
10961
11319
|
return `${path5.basename(path5.dirname(this.messagePath))}:mailbox`;
|
|
10962
11320
|
}
|
|
11321
|
+
get hqPublisher() {
|
|
11322
|
+
return typeof this._hqPublisher === "function" ? this._hqPublisher() : this._hqPublisher;
|
|
11323
|
+
}
|
|
10963
11324
|
publishHqMailboxEvent(input) {
|
|
10964
11325
|
try {
|
|
10965
|
-
this.
|
|
11326
|
+
this.hqPublisher?.publishMailboxEvent(input);
|
|
10966
11327
|
} catch {
|
|
10967
11328
|
}
|
|
10968
11329
|
}
|
|
10969
11330
|
publishHqMailboxSnapshot() {
|
|
10970
|
-
|
|
10971
|
-
|
|
11331
|
+
const publisher = this.hqPublisher;
|
|
11332
|
+
if (publisher === void 0) return;
|
|
11333
|
+
void publisher.publishMailboxSnapshot(this, { mailboxId: this.hqMailboxId }).catch(() => {
|
|
10972
11334
|
});
|
|
10973
11335
|
}
|
|
10974
11336
|
// ── Messages ────────────────────────────────────────────────────────────
|
|
@@ -11330,30 +11692,69 @@ var GlobalMailbox = class {
|
|
|
11330
11692
|
async _readMessages() {
|
|
11331
11693
|
try {
|
|
11332
11694
|
const raw = await fsp6.readFile(this.messagePath, "utf8");
|
|
11333
|
-
|
|
11334
|
-
const messages = [];
|
|
11335
|
-
for (const line of lines) {
|
|
11336
|
-
try {
|
|
11337
|
-
const parsed = JSON.parse(line);
|
|
11338
|
-
if (!parsed["readBy"]) {
|
|
11339
|
-
const readBy = {};
|
|
11340
|
-
if (parsed["read"] && parsed["readAt"]) {
|
|
11341
|
-
readBy[parsed["to"]] = parsed["readAt"];
|
|
11342
|
-
}
|
|
11343
|
-
parsed["readBy"] = readBy;
|
|
11344
|
-
delete parsed["read"];
|
|
11345
|
-
delete parsed["readAt"];
|
|
11346
|
-
}
|
|
11347
|
-
messages.push(parsed);
|
|
11348
|
-
} catch {
|
|
11349
|
-
}
|
|
11350
|
-
}
|
|
11351
|
-
return messages;
|
|
11695
|
+
return this._parseLines(raw);
|
|
11352
11696
|
} catch (err) {
|
|
11353
11697
|
if (err.code === "ENOENT") return [];
|
|
11354
11698
|
throw err;
|
|
11355
11699
|
}
|
|
11356
11700
|
}
|
|
11701
|
+
/**
|
|
11702
|
+
* Read only newly-appended bytes from the file and append them to the
|
|
11703
|
+
* in-memory cache. This avoids re-reading and re-parsing the entire file
|
|
11704
|
+
* when another process appended messages since our last read.
|
|
11705
|
+
*
|
|
11706
|
+
* Only safe when the file grew in size (messages are append-only). When
|
|
11707
|
+
* the file was rewritten (ack/purge changed existing content), callers
|
|
11708
|
+
* must fall back to {@link _readMessages}.
|
|
11709
|
+
*
|
|
11710
|
+
* @returns The (now up-to-date) message cache.
|
|
11711
|
+
*/
|
|
11712
|
+
async _readNewMessagesOnly(fd, oldSize, newSize) {
|
|
11713
|
+
const tailLen = newSize - oldSize;
|
|
11714
|
+
const buf = Buffer.alloc(tailLen);
|
|
11715
|
+
await fd.read(buf, 0, tailLen, oldSize);
|
|
11716
|
+
const tail = buf.toString("utf8");
|
|
11717
|
+
for (const line of tail.split(LINE_SEPARATOR2)) {
|
|
11718
|
+
if (!line.trim()) continue;
|
|
11719
|
+
try {
|
|
11720
|
+
const parsed = JSON.parse(line);
|
|
11721
|
+
if (!parsed["readBy"]) {
|
|
11722
|
+
const readBy = {};
|
|
11723
|
+
if (parsed["read"] && parsed["readAt"]) {
|
|
11724
|
+
readBy[parsed["to"]] = parsed["readAt"];
|
|
11725
|
+
}
|
|
11726
|
+
parsed["readBy"] = readBy;
|
|
11727
|
+
delete parsed["read"];
|
|
11728
|
+
delete parsed["readAt"];
|
|
11729
|
+
}
|
|
11730
|
+
this._messageCache.push(parsed);
|
|
11731
|
+
} catch {
|
|
11732
|
+
}
|
|
11733
|
+
}
|
|
11734
|
+
return this._messageCache;
|
|
11735
|
+
}
|
|
11736
|
+
/** Parse a JSONL string into MailboxMessage[], including migration. */
|
|
11737
|
+
_parseLines(raw) {
|
|
11738
|
+
const lines = raw.split(LINE_SEPARATOR2).filter((l) => l.trim().length > 0);
|
|
11739
|
+
const messages = [];
|
|
11740
|
+
for (const line of lines) {
|
|
11741
|
+
try {
|
|
11742
|
+
const parsed = JSON.parse(line);
|
|
11743
|
+
if (!parsed["readBy"]) {
|
|
11744
|
+
const readBy = {};
|
|
11745
|
+
if (parsed["read"] && parsed["readAt"]) {
|
|
11746
|
+
readBy[parsed["to"]] = parsed["readAt"];
|
|
11747
|
+
}
|
|
11748
|
+
parsed["readBy"] = readBy;
|
|
11749
|
+
delete parsed["read"];
|
|
11750
|
+
delete parsed["readAt"];
|
|
11751
|
+
}
|
|
11752
|
+
messages.push(parsed);
|
|
11753
|
+
} catch {
|
|
11754
|
+
}
|
|
11755
|
+
}
|
|
11756
|
+
return messages;
|
|
11757
|
+
}
|
|
11357
11758
|
/**
|
|
11358
11759
|
* Read messages, then adopt the result as the in-memory cache. Use this
|
|
11359
11760
|
* from writers that just took the file lock — the read reflects the
|
|
@@ -11373,6 +11774,10 @@ var GlobalMailbox = class {
|
|
|
11373
11774
|
* stat matches the cached mtime+size we return the cached array — no
|
|
11374
11775
|
* file read and no JSON.parse — collapsing the per-iteration query
|
|
11375
11776
|
* cost on the mailbox-loop hot path.
|
|
11777
|
+
*
|
|
11778
|
+
* When the file only grew (new messages appended by another process),
|
|
11779
|
+
* we read and parse just the tail bytes instead of the entire file.
|
|
11780
|
+
* This avoids re-parsing the full 10K-message history on every check.
|
|
11376
11781
|
*/
|
|
11377
11782
|
async _readMessagesCached() {
|
|
11378
11783
|
try {
|
|
@@ -11380,6 +11785,17 @@ var GlobalMailbox = class {
|
|
|
11380
11785
|
if (this._messageCache !== null && this._messageCacheMtime === st.mtimeMs && this._messageCacheSize === st.size) {
|
|
11381
11786
|
return this._messageCache;
|
|
11382
11787
|
}
|
|
11788
|
+
if (this._messageCache !== null && this._messageCacheSize >= 0 && st.size > this._messageCacheSize) {
|
|
11789
|
+
const fd = await fsp6.open(this.messagePath, "r");
|
|
11790
|
+
try {
|
|
11791
|
+
const updated = await this._readNewMessagesOnly(fd, this._messageCacheSize, st.size);
|
|
11792
|
+
this._messageCacheMtime = st.mtimeMs;
|
|
11793
|
+
this._messageCacheSize = st.size;
|
|
11794
|
+
return updated;
|
|
11795
|
+
} finally {
|
|
11796
|
+
await fd.close();
|
|
11797
|
+
}
|
|
11798
|
+
}
|
|
11383
11799
|
const all = await this._readMessages();
|
|
11384
11800
|
this._setMessageCache(all, st.mtimeMs, st.size);
|
|
11385
11801
|
return all;
|
|
@@ -14814,7 +15230,443 @@ ${input.detail}`
|
|
|
14814
15230
|
this.onCoordinatorEvent?.(event);
|
|
14815
15231
|
}
|
|
14816
15232
|
};
|
|
15233
|
+
var AgentMonitorService = class {
|
|
15234
|
+
_fleetBus;
|
|
15235
|
+
_events;
|
|
15236
|
+
_transcriptsDir;
|
|
15237
|
+
_maxEntries;
|
|
15238
|
+
_streamEnabled;
|
|
15239
|
+
_onEntry;
|
|
15240
|
+
/** Per-subagent virtual sessions. */
|
|
15241
|
+
_sessions = /* @__PURE__ */ new Map();
|
|
15242
|
+
/** Disposers for FleetBus subscriptions, keyed by subagentId. */
|
|
15243
|
+
_subscriptions = /* @__PURE__ */ new Map();
|
|
15244
|
+
/** Generic fleet-wide subscription disposer. */
|
|
15245
|
+
_fleetDisposer;
|
|
15246
|
+
/** Track whether service is running. */
|
|
15247
|
+
_started = false;
|
|
15248
|
+
constructor(opts) {
|
|
15249
|
+
this._fleetBus = opts.fleetBus;
|
|
15250
|
+
this._events = opts.events;
|
|
15251
|
+
this._transcriptsDir = opts.transcriptsDir;
|
|
15252
|
+
this._maxEntries = opts.maxEntriesPerAgent ?? 500;
|
|
15253
|
+
this._streamEnabled = opts.streamEnabled ?? false;
|
|
15254
|
+
this._onEntry = opts.onEntry;
|
|
15255
|
+
}
|
|
15256
|
+
// ── Public API ────────────────────────────────────────────────────
|
|
15257
|
+
/** Set the FleetBus to listen on. Must be called before `start()`. */
|
|
15258
|
+
setFleetBus(bus) {
|
|
15259
|
+
this._fleetBus = bus;
|
|
15260
|
+
}
|
|
15261
|
+
get streamEnabled() {
|
|
15262
|
+
return this._streamEnabled;
|
|
15263
|
+
}
|
|
15264
|
+
/** Enable/disable streaming agent conversations to the main chat timeline. */
|
|
15265
|
+
setStreamEnabled(enabled) {
|
|
15266
|
+
this._streamEnabled = enabled;
|
|
15267
|
+
}
|
|
15268
|
+
/** Get a snapshot of all known agent sessions. */
|
|
15269
|
+
getAllSessions() {
|
|
15270
|
+
return Array.from(this._sessions.values());
|
|
15271
|
+
}
|
|
15272
|
+
/** Get a specific agent's virtual session, or undefined. */
|
|
15273
|
+
getSession(subagentId) {
|
|
15274
|
+
return this._sessions.get(subagentId);
|
|
15275
|
+
}
|
|
15276
|
+
/** Get transcript entries for a specific agent, newest first. */
|
|
15277
|
+
getTranscript(subagentId, limit = 50) {
|
|
15278
|
+
const session = this._sessions.get(subagentId);
|
|
15279
|
+
if (!session) return [];
|
|
15280
|
+
return session.transcript.slice(-limit).reverse();
|
|
15281
|
+
}
|
|
15282
|
+
/** Set a callback for each new timeline entry (HQ bridge). */
|
|
15283
|
+
setOnEntry(handler) {
|
|
15284
|
+
this._onEntry = handler;
|
|
15285
|
+
}
|
|
15286
|
+
// ── Lifecycle ──────────────────────────────────────────────────────
|
|
15287
|
+
/** Start listening to FleetBus events. */
|
|
15288
|
+
start() {
|
|
15289
|
+
if (this._started) return;
|
|
15290
|
+
if (!this._fleetBus) {
|
|
15291
|
+
this._started = true;
|
|
15292
|
+
return;
|
|
15293
|
+
}
|
|
15294
|
+
this._started = true;
|
|
15295
|
+
this._fleetDisposer = this._fleetBus.onAny((event) => {
|
|
15296
|
+
this._routeEvent(event.subagentId, event.type, event.payload);
|
|
15297
|
+
});
|
|
15298
|
+
}
|
|
15299
|
+
/** Stop listening and clean up all subscriptions. */
|
|
15300
|
+
stop() {
|
|
15301
|
+
if (!this._started) return;
|
|
15302
|
+
this._started = false;
|
|
15303
|
+
if (this._fleetDisposer) {
|
|
15304
|
+
this._fleetDisposer();
|
|
15305
|
+
this._fleetDisposer = void 0;
|
|
15306
|
+
}
|
|
15307
|
+
for (const disposer of this._subscriptions.values()) {
|
|
15308
|
+
disposer();
|
|
15309
|
+
}
|
|
15310
|
+
this._subscriptions.clear();
|
|
15311
|
+
}
|
|
15312
|
+
/** Ensure a subagent is being tracked. Called when a subagent spawns. */
|
|
15313
|
+
trackSubagent(subagentId, agentName, task) {
|
|
15314
|
+
if (this._sessions.has(subagentId)) return;
|
|
15315
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15316
|
+
const session = {
|
|
15317
|
+
subagentId,
|
|
15318
|
+
agentName,
|
|
15319
|
+
createdAt: now,
|
|
15320
|
+
status: "spawned",
|
|
15321
|
+
task,
|
|
15322
|
+
transcript: []
|
|
15323
|
+
};
|
|
15324
|
+
this._sessions.set(subagentId, session);
|
|
15325
|
+
this._addEntry(subagentId, {
|
|
15326
|
+
id: this._uid(),
|
|
15327
|
+
subagentId,
|
|
15328
|
+
agentName,
|
|
15329
|
+
ts: now,
|
|
15330
|
+
kind: "system",
|
|
15331
|
+
content: task ? `\u{1F3AF} Spawned: ${task}` : "\u{1F916} Agent spawned",
|
|
15332
|
+
iteration: 0
|
|
15333
|
+
});
|
|
15334
|
+
this._events.emit("agent.status_changed", {
|
|
15335
|
+
subagentId,
|
|
15336
|
+
agentName,
|
|
15337
|
+
status: "spawned",
|
|
15338
|
+
ts: now,
|
|
15339
|
+
summary: task,
|
|
15340
|
+
task
|
|
15341
|
+
});
|
|
15342
|
+
}
|
|
15343
|
+
/** Mark a subagent as completed/failed/etc. Called on subagent finish. */
|
|
15344
|
+
completeSubagent(subagentId, status, summary) {
|
|
15345
|
+
const session = this._sessions.get(subagentId);
|
|
15346
|
+
if (!session) return;
|
|
15347
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15348
|
+
session.status = status;
|
|
15349
|
+
this._addEntry(subagentId, {
|
|
15350
|
+
id: this._uid(),
|
|
15351
|
+
subagentId,
|
|
15352
|
+
agentName: session.agentName,
|
|
15353
|
+
ts: now,
|
|
15354
|
+
kind: "status",
|
|
15355
|
+
content: summary ?? `Agent ${status}`,
|
|
15356
|
+
iteration: 999
|
|
15357
|
+
});
|
|
15358
|
+
this._events.emit("agent.status_changed", {
|
|
15359
|
+
subagentId,
|
|
15360
|
+
agentName: session.agentName,
|
|
15361
|
+
status,
|
|
15362
|
+
ts: now,
|
|
15363
|
+
summary,
|
|
15364
|
+
task: session.task
|
|
15365
|
+
});
|
|
15366
|
+
}
|
|
15367
|
+
// ── Internal ───────────────────────────────────────────────────────
|
|
15368
|
+
_routeEvent(subagentId, type, payload) {
|
|
15369
|
+
const session = this._sessions.get(subagentId);
|
|
15370
|
+
if (!session) return;
|
|
15371
|
+
switch (type) {
|
|
15372
|
+
case "provider.text_delta": {
|
|
15373
|
+
const text = payload.text;
|
|
15374
|
+
if (!text || text.length === 0) return;
|
|
15375
|
+
const iteration = payload.iteration ?? 0;
|
|
15376
|
+
this._addEntry(subagentId, {
|
|
15377
|
+
id: this._uid(),
|
|
15378
|
+
subagentId,
|
|
15379
|
+
agentName: session.agentName,
|
|
15380
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15381
|
+
kind: "text",
|
|
15382
|
+
content: text,
|
|
15383
|
+
iteration
|
|
15384
|
+
});
|
|
15385
|
+
break;
|
|
15386
|
+
}
|
|
15387
|
+
case "provider.thinking_delta": {
|
|
15388
|
+
const text = payload.text;
|
|
15389
|
+
if (!text || text.length === 0) return;
|
|
15390
|
+
const iteration = payload.iteration ?? 0;
|
|
15391
|
+
this._addEntry(subagentId, {
|
|
15392
|
+
id: this._uid(),
|
|
15393
|
+
subagentId,
|
|
15394
|
+
agentName: session.agentName,
|
|
15395
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15396
|
+
kind: "text",
|
|
15397
|
+
content: `\u{1F9E0} ${text}`,
|
|
15398
|
+
iteration
|
|
15399
|
+
});
|
|
15400
|
+
break;
|
|
15401
|
+
}
|
|
15402
|
+
case "tool.started": {
|
|
15403
|
+
const name = payload.name;
|
|
15404
|
+
if (!name) return;
|
|
15405
|
+
this._addEntry(subagentId, {
|
|
15406
|
+
id: this._uid(),
|
|
15407
|
+
subagentId,
|
|
15408
|
+
agentName: session.agentName,
|
|
15409
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15410
|
+
kind: "tool_use",
|
|
15411
|
+
content: `\u{1F527} ${name}()`,
|
|
15412
|
+
iteration: payload.iteration ?? 0,
|
|
15413
|
+
toolName: name
|
|
15414
|
+
});
|
|
15415
|
+
break;
|
|
15416
|
+
}
|
|
15417
|
+
case "tool.executed": {
|
|
15418
|
+
const name = payload.name;
|
|
15419
|
+
const ok = payload.ok;
|
|
15420
|
+
const durationMs = payload.durationMs;
|
|
15421
|
+
if (!name) return;
|
|
15422
|
+
const statusIcon = ok ? "\u2705" : "\u274C";
|
|
15423
|
+
const duration = durationMs !== void 0 ? ` (${durationMs}ms)` : "";
|
|
15424
|
+
this._addEntry(subagentId, {
|
|
15425
|
+
id: this._uid(),
|
|
15426
|
+
subagentId,
|
|
15427
|
+
agentName: session.agentName,
|
|
15428
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15429
|
+
kind: "tool_result",
|
|
15430
|
+
content: `${statusIcon} ${name}${duration}`,
|
|
15431
|
+
iteration: payload.iteration ?? 0,
|
|
15432
|
+
toolName: name,
|
|
15433
|
+
toolOk: ok
|
|
15434
|
+
});
|
|
15435
|
+
break;
|
|
15436
|
+
}
|
|
15437
|
+
case "iteration.completed": {
|
|
15438
|
+
const index = payload.index ?? 0;
|
|
15439
|
+
if (index > 0 && index % 5 === 0) {
|
|
15440
|
+
this._addEntry(subagentId, {
|
|
15441
|
+
id: this._uid(),
|
|
15442
|
+
subagentId,
|
|
15443
|
+
agentName: session.agentName,
|
|
15444
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15445
|
+
kind: "status",
|
|
15446
|
+
content: `\u{1F504} Iteration ${index}`,
|
|
15447
|
+
iteration: index
|
|
15448
|
+
});
|
|
15449
|
+
}
|
|
15450
|
+
break;
|
|
15451
|
+
}
|
|
15452
|
+
}
|
|
15453
|
+
}
|
|
15454
|
+
_addEntry(subagentId, entry) {
|
|
15455
|
+
const session = this._sessions.get(subagentId);
|
|
15456
|
+
if (!session) return;
|
|
15457
|
+
session.transcript.push(entry);
|
|
15458
|
+
if (session.transcript.length > this._maxEntries) {
|
|
15459
|
+
session.transcript.splice(0, session.transcript.length - this._maxEntries);
|
|
15460
|
+
}
|
|
15461
|
+
this._appendToFile(subagentId, entry).catch(() => {
|
|
15462
|
+
});
|
|
15463
|
+
this._events.emit("agent.timeline.message", {
|
|
15464
|
+
subagentId: entry.subagentId,
|
|
15465
|
+
agentName: entry.agentName,
|
|
15466
|
+
content: entry.content,
|
|
15467
|
+
kind: entry.kind === "tool_result" ? "tool_use" : entry.kind === "system" ? "status" : entry.kind,
|
|
15468
|
+
iteration: entry.iteration,
|
|
15469
|
+
ts: entry.ts,
|
|
15470
|
+
toolName: entry.toolName,
|
|
15471
|
+
costUsd: entry.costUsd
|
|
15472
|
+
});
|
|
15473
|
+
this._onEntry?.(entry);
|
|
15474
|
+
}
|
|
15475
|
+
async _appendToFile(subagentId, entry) {
|
|
15476
|
+
const dir = path5.join(this._transcriptsDir, subagentId);
|
|
15477
|
+
await fsp6.mkdir(dir, { recursive: true });
|
|
15478
|
+
const filePath = path5.join(dir, "transcript.jsonl");
|
|
15479
|
+
const line = JSON.stringify(entry) + "\n";
|
|
15480
|
+
await fsp6.appendFile(filePath, line, { encoding: "utf8" });
|
|
15481
|
+
}
|
|
15482
|
+
_uid() {
|
|
15483
|
+
return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
15484
|
+
}
|
|
15485
|
+
};
|
|
15486
|
+
function createAgentMonitorService(opts) {
|
|
15487
|
+
return new AgentMonitorService(opts);
|
|
15488
|
+
}
|
|
15489
|
+
|
|
15490
|
+
// src/coordination/adaptive-concurrency.ts
|
|
15491
|
+
var DEFAULT_CONFIG = Object.freeze({
|
|
15492
|
+
enabled: false,
|
|
15493
|
+
minConcurrent: 1,
|
|
15494
|
+
maxConcurrent: 16,
|
|
15495
|
+
decreaseFactor: 0.5,
|
|
15496
|
+
successThreshold: 10,
|
|
15497
|
+
recoveryIntervalMs: 3e4
|
|
15498
|
+
});
|
|
15499
|
+
var AdaptiveConcurrencyController = class {
|
|
15500
|
+
config;
|
|
15501
|
+
state;
|
|
15502
|
+
disposers = [];
|
|
15503
|
+
stateChangeHandlers = [];
|
|
15504
|
+
constructor(fleetBus, setMaxConcurrent, config = {}, onStateChange) {
|
|
15505
|
+
this.config = {
|
|
15506
|
+
enabled: config.enabled ?? DEFAULT_CONFIG.enabled,
|
|
15507
|
+
minConcurrent: config.minConcurrent ?? DEFAULT_CONFIG.minConcurrent,
|
|
15508
|
+
maxConcurrent: config.maxConcurrent ?? DEFAULT_CONFIG.maxConcurrent,
|
|
15509
|
+
decreaseFactor: config.decreaseFactor ?? DEFAULT_CONFIG.decreaseFactor,
|
|
15510
|
+
successThreshold: config.successThreshold ?? DEFAULT_CONFIG.successThreshold,
|
|
15511
|
+
recoveryIntervalMs: config.recoveryIntervalMs ?? DEFAULT_CONFIG.recoveryIntervalMs
|
|
15512
|
+
};
|
|
15513
|
+
this.state = {
|
|
15514
|
+
current: this.config.maxConcurrent,
|
|
15515
|
+
min: this.config.minConcurrent,
|
|
15516
|
+
max: this.config.maxConcurrent,
|
|
15517
|
+
consecutiveSuccesses: 0,
|
|
15518
|
+
consecutiveFailures: 0,
|
|
15519
|
+
totalDecreases: 0,
|
|
15520
|
+
totalIncreases: 0,
|
|
15521
|
+
enabled: this.config.enabled
|
|
15522
|
+
};
|
|
15523
|
+
if (onStateChange) {
|
|
15524
|
+
this.stateChangeHandlers.push(onStateChange);
|
|
15525
|
+
}
|
|
15526
|
+
if (this.config.enabled) {
|
|
15527
|
+
setMaxConcurrent(this.state.current);
|
|
15528
|
+
}
|
|
15529
|
+
this.setupEventHandlers(fleetBus, setMaxConcurrent);
|
|
15530
|
+
}
|
|
15531
|
+
setupEventHandlers(fleetBus, setMaxConcurrent) {
|
|
15532
|
+
if (!this.config.enabled) return;
|
|
15533
|
+
const off = fleetBus.onAny((event) => {
|
|
15534
|
+
if (!this.config.enabled) return;
|
|
15535
|
+
if (event.type === "error" || event.type === "provider_error") {
|
|
15536
|
+
const payload = event.payload;
|
|
15537
|
+
if (payload?.status === 429 || payload?.code === "rate_limit_error" || payload?.kind === "rate_limit") {
|
|
15538
|
+
this.handleRateLimit(setMaxConcurrent);
|
|
15539
|
+
}
|
|
15540
|
+
}
|
|
15541
|
+
});
|
|
15542
|
+
this.disposers.push(off);
|
|
15543
|
+
}
|
|
15544
|
+
/**
|
|
15545
|
+
* Handle a rate limit (429) error - decrease concurrency
|
|
15546
|
+
*/
|
|
15547
|
+
handleRateLimit(setMaxConcurrent) {
|
|
15548
|
+
if (this.state.current <= this.config.minConcurrent) {
|
|
15549
|
+
this.state.consecutiveFailures++;
|
|
15550
|
+
this.state.consecutiveSuccesses = 0;
|
|
15551
|
+
this.notifyStateChange();
|
|
15552
|
+
return;
|
|
15553
|
+
}
|
|
15554
|
+
const newConcurrent = Math.max(
|
|
15555
|
+
this.config.minConcurrent,
|
|
15556
|
+
Math.floor(this.state.current * this.config.decreaseFactor)
|
|
15557
|
+
);
|
|
15558
|
+
if (newConcurrent < this.state.current) {
|
|
15559
|
+
const previousConcurrent = this.state.current;
|
|
15560
|
+
this.state.current = newConcurrent;
|
|
15561
|
+
this.state.consecutiveFailures++;
|
|
15562
|
+
this.state.consecutiveSuccesses = 0;
|
|
15563
|
+
this.state.totalDecreases++;
|
|
15564
|
+
setMaxConcurrent(this.state.current);
|
|
15565
|
+
this.notifyStateChange();
|
|
15566
|
+
console.log(
|
|
15567
|
+
JSON.stringify({
|
|
15568
|
+
level: "warn",
|
|
15569
|
+
event: "adaptive_concurrency.decreased",
|
|
15570
|
+
reason: "rate_limit",
|
|
15571
|
+
previousConcurrent,
|
|
15572
|
+
newConcurrent: this.state.current,
|
|
15573
|
+
decreaseFactor: this.config.decreaseFactor,
|
|
15574
|
+
totalDecreases: this.state.totalDecreases
|
|
15575
|
+
})
|
|
15576
|
+
);
|
|
15577
|
+
}
|
|
15578
|
+
}
|
|
15579
|
+
/**
|
|
15580
|
+
* Force a decrease (e.g., manual trigger or other error types)
|
|
15581
|
+
*/
|
|
15582
|
+
decrease(target) {
|
|
15583
|
+
if (!this.config.enabled) return;
|
|
15584
|
+
const newConcurrent = target ?? Math.max(
|
|
15585
|
+
this.config.minConcurrent,
|
|
15586
|
+
Math.floor(this.state.current * this.config.decreaseFactor)
|
|
15587
|
+
);
|
|
15588
|
+
if (newConcurrent < this.state.current) {
|
|
15589
|
+
const previousConcurrent = this.state.current;
|
|
15590
|
+
this.state.current = newConcurrent;
|
|
15591
|
+
this.state.consecutiveSuccesses = 0;
|
|
15592
|
+
this.state.totalDecreases++;
|
|
15593
|
+
this.notifyStateChange();
|
|
15594
|
+
console.log(
|
|
15595
|
+
JSON.stringify({
|
|
15596
|
+
level: "warn",
|
|
15597
|
+
event: "adaptive_concurrency.decreased",
|
|
15598
|
+
reason: "manual",
|
|
15599
|
+
previousConcurrent,
|
|
15600
|
+
newConcurrent: this.state.current,
|
|
15601
|
+
totalDecreases: this.state.totalDecreases
|
|
15602
|
+
})
|
|
15603
|
+
);
|
|
15604
|
+
}
|
|
15605
|
+
}
|
|
15606
|
+
/**
|
|
15607
|
+
* Get the current state
|
|
15608
|
+
*/
|
|
15609
|
+
getState() {
|
|
15610
|
+
return { ...this.state };
|
|
15611
|
+
}
|
|
15612
|
+
/**
|
|
15613
|
+
* Update configuration at runtime
|
|
15614
|
+
*/
|
|
15615
|
+
updateConfig(config) {
|
|
15616
|
+
if (config.enabled !== void 0) {
|
|
15617
|
+
this.config.enabled = config.enabled;
|
|
15618
|
+
}
|
|
15619
|
+
if (config.minConcurrent !== void 0) {
|
|
15620
|
+
this.config.minConcurrent = config.minConcurrent;
|
|
15621
|
+
}
|
|
15622
|
+
if (config.maxConcurrent !== void 0) {
|
|
15623
|
+
this.config.maxConcurrent = config.maxConcurrent;
|
|
15624
|
+
}
|
|
15625
|
+
if (config.decreaseFactor !== void 0) {
|
|
15626
|
+
this.config.decreaseFactor = config.decreaseFactor;
|
|
15627
|
+
}
|
|
15628
|
+
if (config.successThreshold !== void 0) {
|
|
15629
|
+
this.config.successThreshold = config.successThreshold;
|
|
15630
|
+
}
|
|
15631
|
+
if (config.recoveryIntervalMs !== void 0) {
|
|
15632
|
+
this.config.recoveryIntervalMs = config.recoveryIntervalMs;
|
|
15633
|
+
}
|
|
15634
|
+
this.state.current = Math.max(this.config.minConcurrent, Math.min(this.state.current, this.config.maxConcurrent));
|
|
15635
|
+
this.state.enabled = this.config.enabled;
|
|
15636
|
+
this.state.min = this.config.minConcurrent;
|
|
15637
|
+
this.state.max = this.config.maxConcurrent;
|
|
15638
|
+
this.notifyStateChange();
|
|
15639
|
+
}
|
|
15640
|
+
/**
|
|
15641
|
+
* Dispose of the controller and clean up event listeners
|
|
15642
|
+
*/
|
|
15643
|
+
dispose() {
|
|
15644
|
+
for (const dispose of this.disposers) {
|
|
15645
|
+
dispose();
|
|
15646
|
+
}
|
|
15647
|
+
this.disposers.length = 0;
|
|
15648
|
+
this.stateChangeHandlers = [];
|
|
15649
|
+
}
|
|
15650
|
+
notifyStateChange() {
|
|
15651
|
+
const state = this.getState();
|
|
15652
|
+
for (const handler of this.stateChangeHandlers) {
|
|
15653
|
+
handler(state);
|
|
15654
|
+
}
|
|
15655
|
+
}
|
|
15656
|
+
/**
|
|
15657
|
+
* Register a state change handler
|
|
15658
|
+
*/
|
|
15659
|
+
onStateChange(handler) {
|
|
15660
|
+
this.stateChangeHandlers.push(handler);
|
|
15661
|
+
return () => {
|
|
15662
|
+
const index = this.stateChangeHandlers.indexOf(handler);
|
|
15663
|
+
if (index !== -1) {
|
|
15664
|
+
this.stateChangeHandlers.splice(index, 1);
|
|
15665
|
+
}
|
|
15666
|
+
};
|
|
15667
|
+
}
|
|
15668
|
+
};
|
|
14817
15669
|
|
|
14818
|
-
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutonomousBrain, AutonomousCoordinator, BUG_HUNTER_AGENT, BUILD_AGENTS, BrainDecisionQueue, BrainMonitor, BudgetExceededError, BudgetThresholdSignal, ChangeManager, CollabSession, ConsensusProtocol, DECISION_TIMEOUT_MS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_QUALITY_CHECKS, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultBrainArbiter, DefaultMailbox, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, GlobalMailbox, HEAVY_BUDGET, HumanEscalatingBrainArbiter, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, KnowledgeGraph, LIGHT_BUDGET, LargeAnswerStore, MEDIUM_BUDGET, META_AGENTS, NULL_FLEET_BUS, ObservableBrainArbiter, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, TIMEOUT_PREEMPT_FRACTION, TaskAuctioneer, TaskDAG, VERIFY_AGENTS, applyRosterBudget, attachAutoExtend, attachDepWatcherBridge, composeDirectorPrompt, composeSubagentPrompt, createDelegateTool, createMailboxHooks, createMessage, detectEcosystem, dispatchAgent, formatHumanPrompt, getAgentDefinition, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, mailboxSessionTag, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeRollUpTool, makeSpawnTool, makeTerminateTool, makeWorkCompleteTool, normalizeRecipient, recordPackageAction, resolveMailboxIdentity, resolveProjectDir, rosterSummaryFromConfigs, scoreAgents, startPackageOutdatedWatcher, updatePackageOutdatedStatus, withDisabledToolFiltering };
|
|
15670
|
+
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AdaptiveConcurrencyController, AgentMonitorService, AutonomousBrain, AutonomousCoordinator, BUG_HUNTER_AGENT, BUILD_AGENTS, BrainDecisionQueue, BrainMonitor, BudgetExceededError, BudgetThresholdSignal, ChangeManager, CollabSession, ConsensusProtocol, DECISION_TIMEOUT_MS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_QUALITY_CHECKS, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultBrainArbiter, DefaultMailbox, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, GlobalMailbox, HEAVY_BUDGET, HumanEscalatingBrainArbiter, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, KnowledgeGraph, LIGHT_BUDGET, LargeAnswerStore, MEDIUM_BUDGET, META_AGENTS, NULL_FLEET_BUS, ObservableBrainArbiter, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, TIMEOUT_PREEMPT_FRACTION, TaskAuctioneer, TaskDAG, VERIFY_AGENTS, applyRosterBudget, attachAutoExtend, attachDepWatcherBridge, composeDirectorPrompt, composeSubagentPrompt, createAgentMonitorService, createDelegateTool, createMailboxHooks, createMessage, detectEcosystem, dispatchAgent, formatHumanPrompt, getAgentDefinition, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, mailboxSessionTag, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeRollUpTool, makeSpawnTool, makeTerminateTool, makeWorkCompleteTool, normalizeRecipient, recordPackageAction, resolveMailboxIdentity, resolveProjectDir, rosterSummaryFromConfigs, scoreAgents, startPackageOutdatedWatcher, updatePackageOutdatedStatus, withDisabledToolFiltering };
|
|
14819
15671
|
//# sourceMappingURL=index.js.map
|
|
14820
15672
|
//# sourceMappingURL=index.js.map
|