@wrongstack/core 0.277.1 → 0.280.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-bridge-BFJ2ODzI.d.ts → agent-bridge-DXC6QDJ4.d.ts} +1 -1
- package/dist/{agent-subagent-runner-BimKihiC.d.ts → agent-subagent-runner-PoqNKiR4.d.ts} +563 -471
- package/dist/{compactor-D3BGw26y.d.ts → compactor-U3agvUIG.d.ts} +1 -1
- package/dist/{config-DAOjriz9.d.ts → config-Cr3312zc.d.ts} +102 -4
- package/dist/coordination/index.d.ts +1087 -998
- package/dist/coordination/index.js +12235 -12052
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +31 -30
- package/dist/defaults/index.js +403 -189
- package/dist/defaults/index.js.map +1 -1
- package/dist/{brain-CCfuEOdp.d.ts → events-Bs2fmldo.d.ts} +117 -112
- package/dist/execution/index.d.ts +27 -19
- package/dist/execution/index.js +216 -63
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +1 -1
- package/dist/execution/prompt-enhancer.js.map +1 -1
- package/dist/extension/index.d.ts +8 -7
- package/dist/{global-mailbox-Dr4cTKqL.d.ts → global-mailbox-Ct7IorLJ.d.ts} +84 -6
- package/dist/{goal-store-C1uH4srH.d.ts → goal-store-C4F6DjC0.d.ts} +1 -1
- package/dist/hq/index.d.ts +504 -7
- package/dist/hq/index.js +1069 -20
- package/dist/hq/index.js.map +1 -1
- package/dist/{index-DJXj-dcr.d.ts → index-kidebiDh.d.ts} +8 -5
- package/dist/{index-cMEmzCVN.d.ts → index-nP09-oP2.d.ts} +2 -2
- package/dist/index.d.ts +153 -76
- package/dist/index.js +5791 -3163
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +7 -6
- package/dist/kernel/index.d.ts +14 -13
- package/dist/kernel/index.js +31 -15
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mailbox-types-DTl7bRH3.d.ts → mailbox-types-BGZWrYTJ.d.ts} +38 -0
- package/dist/{mcp-servers-CFb60-pH.d.ts → mcp-servers-D910X5_r.d.ts} +3 -3
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-5Ufn7f2m.d.ts → models-registry-CLkoOcHk.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-CcrcncvG.d.ts → multi-agent-coordinator-CieyUoEL.d.ts} +1 -1
- package/dist/{null-fleet-bus-C9KsYyrI.d.ts → null-fleet-bus-DkdmZJ_W.d.ts} +464 -464
- package/dist/observability/index.d.ts +3 -2
- package/dist/{path-resolver-CEeX9I7O.d.ts → path-resolver-XfZ9eLxG.d.ts} +3 -3
- package/dist/{permission-DbsGOA1C.d.ts → permission-Dx6dIqS2.d.ts} +2 -7
- package/dist/{permission-policy-BpEea3r7.d.ts → permission-policy-C8vJcnX5.d.ts} +2 -2
- package/dist/{pipeline-CEjBjzVA.d.ts → pipeline-BwAP21_4.d.ts} +9 -4
- package/dist/{provider-model-resolve-BpfXp3Jj.d.ts → provider-model-resolve-CwQNZWt_.d.ts} +3 -3
- package/dist/{provider-runner-CnOSr5BN.d.ts → provider-runner-CYHFImzV.d.ts} +3 -3
- package/dist/{retry-policy-Git9WF6d.d.ts → retry-policy-D4feSLk3.d.ts} +1 -1
- package/dist/sdd/index.d.ts +11 -10
- package/dist/sdd/index.js +2 -2
- package/dist/sdd/index.js.map +1 -1
- package/dist/secret-scrubber-3MHDDAtm.d.ts +6 -0
- package/dist/{secret-vault-DDSMHqIm.d.ts → secret-vault-CImt2XrR.d.ts} +1 -1
- package/dist/security/index.d.ts +6 -5
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-Cq72C0Oy.d.ts → selector-Dy-MzKp1.d.ts} +1 -1
- package/dist/{session-event-bridge-DG94B3Bk.d.ts → session-event-bridge-CqdiGnfU.d.ts} +1 -1
- package/dist/{session-reader-BzT-iMQT.d.ts → session-reader-Hk0WbNm9.d.ts} +1 -1
- package/dist/{skill-DGIXCtdv.d.ts → skill-DHniprNl.d.ts} +15 -1
- package/dist/skills/index.d.ts +472 -26
- package/dist/skills/index.js +872 -129
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +27 -14
- package/dist/storage/index.js +264 -85
- package/dist/storage/index.js.map +1 -1
- package/dist/{strategy-compactor-Bt_ZH6R0.d.ts → strategy-compactor-CQwhbErd.d.ts} +32 -17
- package/dist/{todos-checkpoint-CH1pcua9.d.ts → todos-checkpoint-Bk2uP7Ex.d.ts} +6 -6
- package/dist/{context-DPlA6kid.d.ts → tool-BkOgs_KL.d.ts} +306 -286
- package/dist/{tool-executor-SVFq7IOR.d.ts → tool-executor-SiE1wlZo.d.ts} +9 -9
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +22 -21
- package/dist/types/index.js +7 -9
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +30 -4
- package/dist/utils/index.js +50 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/{worktree-manager-C4YIf1Fa.d.ts → worktree-manager-BjOFF6bt.d.ts} +1 -1
- package/dist/{wstack-paths-_NrRovdr.d.ts → wstack-paths-CMl_cYgq.d.ts} +8 -0
- package/package.json +1 -1
- package/skills/mailbox-bridge/SKILL.md +1 -0
- package/skills/plugin-author/SKILL.md +350 -0
- package/skills/sdd/SKILL.md +134 -134
- package/skills/skill-creator/SKILL.md +45 -7
- package/skills/wrongstack-mailbox/SKILL.md +40 -21
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export {
|
|
10
|
-
import { b as
|
|
11
|
-
export {
|
|
12
|
-
import { G as GlobalMailbox } from '../global-mailbox-
|
|
13
|
-
export {
|
|
14
|
-
import { C as Context, T as Tool } from '../
|
|
15
|
-
import { A as AdaptiveConcurrencyConfig } from '../config-
|
|
1
|
+
export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-DXC6QDJ4.js';
|
|
2
|
+
import { F as FleetBus } from '../agent-subagent-runner-PoqNKiR4.js';
|
|
3
|
+
export { i as AgentFactory, x as AgentFactoryResult, y as AgentRunnerOptions, z as BudgetExceededError, E as BudgetKind, G as BudgetLimits, H as BudgetNegotiationMode, I as BudgetThresholdDecision, J as BudgetThresholdHandler, K as BudgetThresholdSignal, L as BudgetUsage, O as DECISION_TIMEOUT_MS, Q as FleetEvent, R as FleetHandler, j as FleetUsage, k as FleetUsageAggregator, W as SubagentBudget, a0 as SubagentUsageSnapshot, a1 as TIMEOUT_PREEMPT_FRACTION, a3 as makeAgentSubagentRunner, a4 as withDisabledToolFiltering } from '../agent-subagent-runner-PoqNKiR4.js';
|
|
4
|
+
import { H as FleetManager, s as Director } from '../null-fleet-bus-DkdmZJ_W.js';
|
|
5
|
+
export { A as ACP_AGENTS, a as AGENTS_BY_PHASE, b as AGENT_CATALOG, c as ALL_AGENT_DEFINITIONS, d as ALL_FLEET_AGENTS, e as AUDIT_LOG_AGENT, f as AutoExtendCeiling, g as AutoExtendPolicy, B as BUG_HUNTER_AGENT, h as BugFinding, C as CollabBudgetConfig, i as CollabBudgetOverrides, j as CollabBudgetWarningPayload, k as CollabDebugReport, l as CollabSession, m as CollabSessionOptions, n as CreateDelegateToolOptions, o as CriticConcern, p as CriticEvaluation, D as DEFAULT_DIRECTOR_PREAMBLE, q as DEFAULT_SUBAGENT_BASELINE, r as DelegateHost, t as DirectorAlert, u as DirectorAlertLevel, v as DirectorCancelCollabPayload, w as DirectorPromptParts, x as DirectorSessionFactory, y as DirectorSessionFactoryOptions, F as FLEET_ROSTER, z as FLEET_ROSTER_BUDGETS, E as FLEET_ROSTER_WITHACP, G as FleetCostCapError, I as FleetManagerOptions, J as FleetRosterBudget, K as FleetSpawnBudgetError, L as ICoordinator, M as IFleetManager, N as LargeAnswerStore, O as NULL_FLEET_BUS, R as REFACTOR_PLANNER_AGENT, P as RefactorPhase, Q as RefactorPlan, S as SECURITY_SCANNER_AGENT, T as SharedFileEntry, U as SharedFileSnapshot, V as SubagentPromptParts, W as applyRosterBudget, X as attachAutoExtend, Y as composeDirectorPrompt, Z as composeSubagentPrompt, _ as createDelegateTool, $ as getAgentDefinition, a0 as makeAskResultTool, a1 as makeAskTool, a2 as makeAssignTool, a3 as makeAwaitTasksTool, a4 as makeCollabDebugTool, a5 as makeDirectorSessionFactory, a6 as makeFleetEmitTool, a7 as makeFleetHealthTool, a7 as makeFleetSessionTool, a7 as makeFleetStatusTool, a7 as makeFleetTool, a7 as makeFleetUsageTool, a8 as makeRollUpTool, a9 as makeSpawnTool, aa as makeTerminateAllTool, ab as makeTerminateTool, ac as makeWorkCompleteTool, ad as rosterSummaryFromConfigs } from '../null-fleet-bus-DkdmZJ_W.js';
|
|
6
|
+
import { E as EventBus, B as BrainArbiter, f as BrainDecisionOption, k as BrainRisk, h as BrainDecisionRequest, e as BrainDecision, i as BrainDecisionSource } from '../events-Bs2fmldo.js';
|
|
7
|
+
export { g as BrainDecisionQueue, j as BrainFallback, D as DefaultBrainArbiter, l as DefaultBrainArbiterOptions, H as HumanEscalatingBrainArbiter, O as ObservableBrainArbiter, w as formatHumanPrompt } from '../events-Bs2fmldo.js';
|
|
8
|
+
import { b as Mailbox, c as MailboxSendInput, M as MailboxMessage, d as MailboxQuery, e as MailboxAckInput, f as MailboxAckBatchInput, a as MailboxAgentStatus, A as AgentRegistrationInput, g as AgentHeartbeatInput, P as PurgeOptions, j as PurgeResult, C as ClientRegistrationInput, h as ClientHeartbeatInput, i as ClientStatus } from '../mailbox-types-BGZWrYTJ.js';
|
|
9
|
+
export { k as ClientSource, l as MailboxMessageType, m as MailboxTaskContext, R as ReadReceipts, n as RegisteredAgent, o as normalizeRecipient } from '../mailbox-types-BGZWrYTJ.js';
|
|
10
|
+
import { b as AgentDefinition } from '../multi-agent-coordinator-CieyUoEL.js';
|
|
11
|
+
export { T as AGENT_TOOL_PRESETS, c as AgentBudgetTier, d as AgentCapability, A as AgentPhase, e as DEFAULT_DISPATCH_ROLE, a as DefaultMultiAgentCoordinator, f as DispatchCandidate, D as DispatchClassifier, g as DispatchMethod, h as DispatchOptions, i as DispatchResult, H as HEAVY_BUDGET, L as LIGHT_BUDGET, M as MEDIUM_BUDGET, j as MultiAgentCoordinatorOptions, k as dispatchAgent, m as makeLLMClassifier, s as scoreAgents } from '../multi-agent-coordinator-CieyUoEL.js';
|
|
12
|
+
import { G as GlobalMailbox } from '../global-mailbox-Ct7IorLJ.js';
|
|
13
|
+
export { aA as resolveProjectDir } from '../global-mailbox-Ct7IorLJ.js';
|
|
14
|
+
import { C as Context, T as Tool } from '../tool-BkOgs_KL.js';
|
|
15
|
+
import { A as AdaptiveConcurrencyConfig } from '../config-Cr3312zc.js';
|
|
16
|
+
import { L as Logger } from '../logger-B63L5bTg.js';
|
|
17
|
+
import '../index-kidebiDh.js';
|
|
18
|
+
import '../pipeline-BwAP21_4.js';
|
|
19
|
+
import '../permission-Dx6dIqS2.js';
|
|
20
|
+
import '../observability-D-HZN_mF.js';
|
|
21
|
+
import '../secret-scrubber-3MHDDAtm.js';
|
|
22
|
+
import '../retry-policy-D4feSLk3.js';
|
|
16
23
|
import 'node:events';
|
|
17
|
-
import '../logger-B63L5bTg.js';
|
|
18
24
|
import '../director-state-BfeCUbmk.js';
|
|
19
|
-
import '../index-DJXj-dcr.js';
|
|
20
|
-
import '../pipeline-CEjBjzVA.js';
|
|
21
|
-
import '../observability-D-HZN_mF.js';
|
|
22
|
-
import '../permission-DbsGOA1C.js';
|
|
23
|
-
import '../retry-policy-Git9WF6d.js';
|
|
24
25
|
|
|
25
26
|
/** Phase 1 · Discovery — map the territory before any work begins. */
|
|
26
27
|
declare const DISCOVERY_AGENTS: AgentDefinition[];
|
|
@@ -49,72 +50,6 @@ declare const DELIVERY_AGENTS: AgentDefinition[];
|
|
|
49
50
|
/** Phase 9 · Meta — agents that improve the agent system itself. */
|
|
50
51
|
declare const META_AGENTS: AgentDefinition[];
|
|
51
52
|
|
|
52
|
-
/**
|
|
53
|
-
* DefaultMailbox — append-only JSONL inter-agent mailbox (per-session).
|
|
54
|
-
*
|
|
55
|
-
* Stores messages under `<sessionDir>/_mailbox.jsonl`. Every send appends
|
|
56
|
-
* one line. Query reads and filters all lines. Ack rewrites changed
|
|
57
|
-
* messages in-place via atomic write.
|
|
58
|
-
*
|
|
59
|
-
* For cross-session communication, use GlobalMailbox instead.
|
|
60
|
-
*
|
|
61
|
-
* @module DefaultMailbox
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
|
-
declare class DefaultMailbox implements Mailbox {
|
|
65
|
-
private readonly filePath;
|
|
66
|
-
private _messageCache;
|
|
67
|
-
private _messageCacheMtime;
|
|
68
|
-
private _messageCacheSize;
|
|
69
|
-
/** Primary index: recipient → Set of messages (points into _messageCache). */
|
|
70
|
-
private _byTo;
|
|
71
|
-
/** Secondary index: sender → Set of messages (points into _messageCache). */
|
|
72
|
-
private _byFrom;
|
|
73
|
-
/** Counts malformed JSONL lines skipped during parsing for observability. */
|
|
74
|
-
private _corruptionCount;
|
|
75
|
-
constructor(sessionDir: string);
|
|
76
|
-
get mailboxPath(): string;
|
|
77
|
-
/** Returns the count of malformed JSONL lines encountered during reads. */
|
|
78
|
-
get corruptionCount(): number;
|
|
79
|
-
send(input: MailboxSendInput): Promise<MailboxMessage>;
|
|
80
|
-
query(q: MailboxQuery): Promise<MailboxMessage[]>;
|
|
81
|
-
ack(input: MailboxAckInput): Promise<MailboxMessage | null>;
|
|
82
|
-
ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]>;
|
|
83
|
-
getAgentStatuses(): Promise<MailboxAgentStatus[]>;
|
|
84
|
-
getOnlineAgents(): Promise<MailboxAgentStatus[]>;
|
|
85
|
-
registerAgent(_input: AgentRegistrationInput): Promise<void>;
|
|
86
|
-
heartbeat(_input: AgentHeartbeatInput): Promise<void>;
|
|
87
|
-
unreadCount(forAgentId: string): Promise<number>;
|
|
88
|
-
close(): Promise<void>;
|
|
89
|
-
clearAll(): Promise<void>;
|
|
90
|
-
purgeStale(opts?: PurgeOptions): Promise<PurgeResult>;
|
|
91
|
-
registerClient(_input: ClientRegistrationInput): Promise<void>;
|
|
92
|
-
clientHeartbeat(_input: ClientHeartbeatInput): Promise<void>;
|
|
93
|
-
getClientStatuses(): Promise<ClientStatus[]>;
|
|
94
|
-
private _readAll;
|
|
95
|
-
/**
|
|
96
|
-
* Read only newly-appended bytes from the file and append them to the
|
|
97
|
-
* in-memory cache, avoiding a full re-read when the file only grew.
|
|
98
|
-
*/
|
|
99
|
-
private _readNewMessagesOnly;
|
|
100
|
-
/** Parse a JSONL string into MailboxMessage[], including migration. */
|
|
101
|
-
private _parseLines;
|
|
102
|
-
/**
|
|
103
|
-
* Stat the mailbox file under the assumption that we are holding the
|
|
104
|
-
* file lock, and that a write to the file has just completed. Returns
|
|
105
|
-
* the (mtimeMs, size) pair, or (-1, -1) if the file does not exist
|
|
106
|
-
* (e.g. ackMany/purgeStale on a session that has never sent a message).
|
|
107
|
-
*/
|
|
108
|
-
private _statUnderLockOrAbsent;
|
|
109
|
-
private _readAllCached;
|
|
110
|
-
private _setMessageCache;
|
|
111
|
-
private _pushToCache;
|
|
112
|
-
/** Rebuild both indexes from a full message list. */
|
|
113
|
-
private _buildIndexes;
|
|
114
|
-
/** Add a single message to both indexes. */
|
|
115
|
-
private _indexMsg;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
53
|
/**
|
|
119
54
|
* BrainMonitor — the Brain's SELF-ACTIVATION layer.
|
|
120
55
|
*
|
|
@@ -189,276 +124,124 @@ declare class BrainMonitor {
|
|
|
189
124
|
}
|
|
190
125
|
|
|
191
126
|
/**
|
|
192
|
-
*
|
|
127
|
+
* dep-watcher — File-change → Mailbox bridge for dependency monitoring.
|
|
193
128
|
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* and (with default port 0) different OS-assigned ports.
|
|
129
|
+
* Watches dependency manifest files (package.json, go.mod, Cargo.toml, etc.)
|
|
130
|
+
* and when they change (create/update), posts a message to the inter-agent
|
|
131
|
+
* mailbox. A tech-stack analysis agent can then pick up the message and
|
|
132
|
+
* run a full tech-stack validation, feeding results back to the coding LLM.
|
|
199
133
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* - url convenience copy for callers
|
|
204
|
-
* - token the bearer token (so external agents don't have to
|
|
205
|
-
* re-read it from .mailbox.token separately)
|
|
206
|
-
* - generation monotonically increasing counter; bumped on every
|
|
207
|
-
* acquire. Lets a release() call identify whether the
|
|
208
|
-
* current lock file still belongs to *this* process
|
|
209
|
-
* (e.g. after a stale cleanup raced with us).
|
|
210
|
-
* - spawnedAt ISO timestamp — for observability, not load-bearing.
|
|
134
|
+
* This module is a *config factory*, not a watcher itself. It produces
|
|
135
|
+
* configuration that the file-watcher plugin (`watch_start`) can consume,
|
|
136
|
+
* plus a callback that posts to a Mailbox instance.
|
|
211
137
|
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
* fine (someone else already took over). A generation mismatch means
|
|
221
|
-
* we lost the race and another instance owns it now — also fine.
|
|
138
|
+
* Usage:
|
|
139
|
+
* const cfg = makeDependencyWatcherConfig({
|
|
140
|
+
* projectRoot: '/path/to/project',
|
|
141
|
+
* mailbox,
|
|
142
|
+
* targetAgent: 'tech-stack-agent',
|
|
143
|
+
* });
|
|
144
|
+
* // cfg.watchPaths → pass to watch_start
|
|
145
|
+
* // cfg.onChange → call on file-watcher:changed events
|
|
222
146
|
*
|
|
223
|
-
*
|
|
224
|
-
* `.mailbox.token`, so an external agent that reads either file gets the
|
|
225
|
-
* same value. While an instance stays alive, every joining caller
|
|
226
|
-
* (`kind: 'joined'`) reuses that one token. A cold (re)start — no lock,
|
|
227
|
-
* or a lock whose owner PID is dead/unhealthy — mints a FRESH token and
|
|
228
|
-
* rewrites both files atomically. External agents must therefore re-read
|
|
229
|
-
* `.mailbox.token` after a bridge restart (a stale token returns 401).
|
|
147
|
+
* @module dep-watcher
|
|
230
148
|
*/
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Files that declare project dependencies. When any of these change
|
|
152
|
+
* (create/update), a mailbox message triggers a tech-stack audit.
|
|
153
|
+
*/
|
|
154
|
+
declare const DEPENDENCY_FILE_PATTERNS: ReadonlyArray<string>;
|
|
155
|
+
interface DepWatchEntry {
|
|
156
|
+
/** Relative path from project root that changed. */
|
|
157
|
+
path: string;
|
|
158
|
+
/** Event type from the file watcher: 'change', 'add', 'delete' (rare). */
|
|
159
|
+
event: string;
|
|
160
|
+
/** ISO8601 timestamp of when the change was detected. */
|
|
161
|
+
timestamp: string;
|
|
241
162
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
interface
|
|
255
|
-
/**
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
|
|
163
|
+
interface DependencyWatcherConfig {
|
|
164
|
+
/** Paths to pass to `watch_start` — the project-root-relative dependency files. */
|
|
165
|
+
watchPaths: string[];
|
|
166
|
+
/** Callback to invoke when a dependency file changes. Posts to mailbox. */
|
|
167
|
+
onChange: (entry: DepWatchEntry) => Promise<void>;
|
|
168
|
+
/** Debounce window in ms — multiple changes to the same file within this window are collapsed. */
|
|
169
|
+
debounceMs: number;
|
|
170
|
+
/** Cancel all in-flight debounce timers. Call when the file watcher is
|
|
171
|
+
* stopped (session end / project switch) so pending setTimeouts — each
|
|
172
|
+
* holding a closure over the mailbox + entry — don't leak. */
|
|
173
|
+
dispose: () => void;
|
|
174
|
+
}
|
|
175
|
+
interface DependencyWatcherOptions {
|
|
176
|
+
/** Absolute path to the project root. */
|
|
177
|
+
projectRoot: string;
|
|
178
|
+
/** The mailbox instance where messages will be posted. */
|
|
179
|
+
mailbox: Mailbox;
|
|
180
|
+
/** Agent id that should receive the tech-stack audit task. */
|
|
181
|
+
targetAgent?: string | undefined;
|
|
182
|
+
/** Agent id of the watcher (sender). */
|
|
183
|
+
watcherAgentId?: string | undefined;
|
|
184
|
+
/** Debounce window in ms. Default: 3000 (3 seconds). */
|
|
185
|
+
debounceMs?: number | undefined;
|
|
186
|
+
/** Only watch these specific patterns. Defaults to DEPENDENCY_FILE_PATTERNS. */
|
|
187
|
+
patterns?: string[] | undefined;
|
|
263
188
|
}
|
|
264
189
|
/**
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
* the
|
|
268
|
-
*
|
|
269
|
-
* Two-phase contract:
|
|
270
|
-
* 1. Caller invokes `acquireOrJoin(...)` BEFORE calling
|
|
271
|
-
* `server.listen()`. The returned lock either:
|
|
272
|
-
* - `kind: 'joined'` → another instance is alive, the caller
|
|
273
|
-
* should NOT bind; just print the URL/token
|
|
274
|
-
* and exit cleanly (return 0).
|
|
275
|
-
* - `kind: 'acquired'` → caller is the owner, proceeds to bind.
|
|
276
|
-
* - `kind: 'port-conflict'` → caller asked for an explicit port
|
|
277
|
-
* that's already taken by an unrelated
|
|
278
|
-
* process; we return the existing owner
|
|
279
|
-
* but the caller decides what to do
|
|
280
|
-
* (loud-fail).
|
|
281
|
-
* 2. After `server.listen()` resolves with a real port, the caller
|
|
282
|
-
* invokes `finalize(lock, boundPort)` to atomically write the
|
|
283
|
-
* final lock + token file with the OS-assigned port.
|
|
190
|
+
* Build a dependency watcher configuration. The returned `watchPaths` can be
|
|
191
|
+
* passed directly to the `watch_start` tool, and `onChange` should be wired
|
|
192
|
+
* to the `file-watcher:changed` custom event.
|
|
284
193
|
*
|
|
285
|
-
*
|
|
286
|
-
* the
|
|
287
|
-
* the
|
|
194
|
+
* When a dependency file changes, `onChange` posts a high-priority `assign`
|
|
195
|
+
* message to the mailbox targeting the tech-stack agent, with the changed
|
|
196
|
+
* file path and event type in the body.
|
|
288
197
|
*/
|
|
289
|
-
declare function
|
|
198
|
+
declare function makeDependencyWatcherConfig(opts: DependencyWatcherOptions): DependencyWatcherConfig;
|
|
199
|
+
|
|
290
200
|
/**
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
* .mailbox.token file with mode 0600 so external agents can read it.
|
|
201
|
+
* dep-watcher-bridge — Bridges the file-watcher plugin's custom events
|
|
202
|
+
* to the dependency watcher → mailbox pipeline.
|
|
294
203
|
*
|
|
295
|
-
*
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
* Phase 3 — best-effort cleanup on shutdown. Removes the lock + token
|
|
300
|
-
* files IF this process is still the recorded owner (generation match).
|
|
204
|
+
* The file-watcher plugin emits `file-watcher:changed` custom events
|
|
205
|
+
* when files change. This module subscribes to those events, filters
|
|
206
|
+
* for dependency manifests (package.json, go.mod, etc.), and posts
|
|
207
|
+
* assign messages to the inter-agent mailbox for tech-stack audit.
|
|
301
208
|
*
|
|
302
|
-
*
|
|
303
|
-
* superseded us — we must NOT delete their lock.
|
|
304
|
-
*/
|
|
305
|
-
declare function release(projectDir: string, generation: number): Promise<void>;
|
|
306
|
-
/**
|
|
307
|
-
* Read the lock file and return it, with enough information for the
|
|
308
|
-
* caller to distinguish:
|
|
309
|
-
* - 'live' — PID alive, /healthz reachable; safe to use.
|
|
310
|
-
* - 'probe-failed' — PID alive (or recently was) but /healthz
|
|
311
|
-
* unreachable. Caller can still return the URL
|
|
312
|
-
* + token to the host so its request layer can
|
|
313
|
-
* retry; the host's fetch timeout will surface
|
|
314
|
-
* the real error if the bridge is truly dead.
|
|
315
|
-
* - 'absent' — no lock file existed, or it was malformed
|
|
316
|
-
* (cleaned up best-effort).
|
|
209
|
+
* Returns a dispose function that unsubscribes from the event bus.
|
|
317
210
|
*
|
|
318
|
-
*
|
|
319
|
-
* "joined vs spawned" decision in tryAcquireMailboxBridge — we
|
|
320
|
-
* don't want to spawn a second bridge just because /healthz flaked.
|
|
211
|
+
* @module dep-watcher-bridge
|
|
321
212
|
*/
|
|
322
|
-
type LiveLockResult = {
|
|
323
|
-
kind: 'live';
|
|
324
|
-
lock: MailboxBridgeLock;
|
|
325
|
-
} | {
|
|
326
|
-
kind: 'probe-failed';
|
|
327
|
-
lock: MailboxBridgeLock;
|
|
328
|
-
} | {
|
|
329
|
-
kind: 'absent';
|
|
330
|
-
};
|
|
331
|
-
declare function readLiveLock(projectDir: string): Promise<LiveLockResult>;
|
|
332
213
|
|
|
214
|
+
interface DepWatcherBridgeOptions {
|
|
215
|
+
/** The event bus to subscribe to (same bus the file-watcher plugin emits on). */
|
|
216
|
+
events: EventBus;
|
|
217
|
+
/** The mailbox instance where dep-change notifications will be posted. */
|
|
218
|
+
mailbox: Mailbox;
|
|
219
|
+
/** Absolute project root — used to build watch paths and match file patterns. */
|
|
220
|
+
projectRoot: string;
|
|
221
|
+
/** Agent id the tech-stack audit tasks should target. Default: 'tech-stack'. */
|
|
222
|
+
targetAgent?: string | undefined;
|
|
223
|
+
/** Agent id of the watcher/sender. Default: 'dep-watcher'. */
|
|
224
|
+
watcherAgentId?: string | undefined;
|
|
225
|
+
/** Debounce window in ms. Default: 3000 (3 seconds). */
|
|
226
|
+
debounceMs?: number | undefined;
|
|
227
|
+
}
|
|
333
228
|
/**
|
|
334
|
-
*
|
|
335
|
-
*
|
|
229
|
+
* Wire the file-watcher's `file-watcher:changed` events into the
|
|
230
|
+
* dependency watcher → mailbox pipeline.
|
|
336
231
|
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
* coordination channel, so the cheapest reliable signal is "ask the
|
|
340
|
-
* bridge if it's alive, and if it's not, tell the rest of the team
|
|
341
|
-
* via the same channel the bridge exposes."
|
|
232
|
+
* Returns a dispose function. Call it to unsubscribe when the
|
|
233
|
+
* session ends or the watcher is no longer needed.
|
|
342
234
|
*
|
|
343
235
|
* Usage:
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
* url: 'http://127.0.0.1:7788',
|
|
349
|
-
* probeIntervalMs: 15_000,
|
|
350
|
-
* onAlert: (event) => console.warn('mailbox bridge', event.kind),
|
|
236
|
+
* const dispose = attachDepWatcherBridge({
|
|
237
|
+
* events: ctx.events,
|
|
238
|
+
* mailbox: new DefaultMailbox(sessionDir),
|
|
239
|
+
* projectRoot: ctx.projectRoot,
|
|
351
240
|
* });
|
|
352
|
-
*
|
|
353
|
-
* //
|
|
354
|
-
* await watchdog.stop();
|
|
355
|
-
*
|
|
356
|
-
* The watchdog is a passive observer: it does NOT start the bridge.
|
|
357
|
-
* Starting the bridge is the user's job (`wstack mailbox serve` or
|
|
358
|
-
* `/mailbox-serve`). The watchdog then reports on what the user did.
|
|
359
|
-
*/
|
|
360
|
-
|
|
361
|
-
interface MailboxHealthWatchdogOptions {
|
|
362
|
-
/** Project mailbox to probe-and-report on. Required. */
|
|
363
|
-
mailbox: GlobalMailbox;
|
|
364
|
-
/** URL of the mailbox bridge (no trailing slash). Required. */
|
|
365
|
-
url: string;
|
|
366
|
-
/** Probe interval in milliseconds. Default: 15_000. */
|
|
367
|
-
probeIntervalMs?: number;
|
|
368
|
-
/** Per-probe timeout in milliseconds. Default: 3_000. */
|
|
369
|
-
probeTimeoutMs?: number;
|
|
370
|
-
/**
|
|
371
|
-
* After this many consecutive failures the watchdog posts an alert.
|
|
372
|
-
* Default: 2 (so a single transient timeout doesn't trigger spam).
|
|
373
|
-
*/
|
|
374
|
-
failureThreshold?: number;
|
|
375
|
-
/**
|
|
376
|
-
* Optional callback for local observability — fired on every state
|
|
377
|
-
* transition. The mailbox post is independent of this callback.
|
|
378
|
-
*/
|
|
379
|
-
onAlert?: ((event: MailboxHealthEvent) => void) | undefined;
|
|
380
|
-
/**
|
|
381
|
-
* Agent id used to post the alert message. Default: 'mailbox-bridge-watchdog'.
|
|
382
|
-
*/
|
|
383
|
-
from?: string;
|
|
384
|
-
}
|
|
385
|
-
type MailboxHealthEvent = {
|
|
386
|
-
kind: 'probe-failed';
|
|
387
|
-
status?: number;
|
|
388
|
-
error?: string;
|
|
389
|
-
} | {
|
|
390
|
-
kind: 'alert-posted';
|
|
391
|
-
consecutiveFailures: number;
|
|
392
|
-
} | {
|
|
393
|
-
kind: 'recovery-posted';
|
|
394
|
-
downtimeMs: number;
|
|
395
|
-
} | {
|
|
396
|
-
kind: 'started';
|
|
397
|
-
intervalMs: number;
|
|
398
|
-
} | {
|
|
399
|
-
kind: 'stopped';
|
|
400
|
-
};
|
|
401
|
-
declare const MAILBOX_HEALTH_DEFAULT_INTERVAL_MS = 15000;
|
|
402
|
-
declare const MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS = 3000;
|
|
403
|
-
declare const MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD = 2;
|
|
404
|
-
declare const MAILBOX_HEALTH_DEFAULT_FROM = "mailbox-bridge-watchdog";
|
|
405
|
-
declare class MailboxHealthWatchdog {
|
|
406
|
-
private readonly mailbox;
|
|
407
|
-
private readonly url;
|
|
408
|
-
private readonly intervalMs;
|
|
409
|
-
private readonly timeoutMs;
|
|
410
|
-
private readonly failureThreshold;
|
|
411
|
-
private readonly from;
|
|
412
|
-
private readonly onAlert?;
|
|
413
|
-
private timer;
|
|
414
|
-
private consecutiveFailures;
|
|
415
|
-
private downSince;
|
|
416
|
-
private alerting;
|
|
417
|
-
private inFlight;
|
|
418
|
-
private aborted;
|
|
419
|
-
constructor(opts: MailboxHealthWatchdogOptions);
|
|
420
|
-
/** Start probing on `intervalMs`. Idempotent — second call is a no-op. */
|
|
421
|
-
start(): Promise<void>;
|
|
422
|
-
/** Stop probing. Safe to call multiple times. */
|
|
423
|
-
stop(): Promise<void>;
|
|
424
|
-
/** True between start() and stop(). */
|
|
425
|
-
isRunning(): boolean;
|
|
426
|
-
/** Number of consecutive failed probes since the last successful probe. */
|
|
427
|
-
get currentFailureStreak(): number;
|
|
428
|
-
/** True iff the watchdog currently considers the bridge down. */
|
|
429
|
-
isBridgeDown(): boolean;
|
|
430
|
-
private emit;
|
|
431
|
-
private tick;
|
|
432
|
-
private probe;
|
|
433
|
-
private recordSuccess;
|
|
434
|
-
private recordFailure;
|
|
435
|
-
private postDown;
|
|
436
|
-
private postRecovery;
|
|
437
|
-
}
|
|
438
|
-
interface DownAlertInput {
|
|
439
|
-
from: string;
|
|
440
|
-
url: string;
|
|
441
|
-
consecutiveFailures: number;
|
|
442
|
-
}
|
|
443
|
-
declare function buildDownAlert(input: DownAlertInput): MailboxSendInput;
|
|
444
|
-
interface RecoveryAlertInput {
|
|
445
|
-
from: string;
|
|
446
|
-
url: string;
|
|
447
|
-
downtimeMs: number;
|
|
448
|
-
consecutiveFailures: number;
|
|
449
|
-
}
|
|
450
|
-
declare function buildRecoveryAlert(input: RecoveryAlertInput): MailboxSendInput;
|
|
451
|
-
interface WatchdogConfig {
|
|
452
|
-
probeIntervalMs: number;
|
|
453
|
-
probeTimeoutMs: number;
|
|
454
|
-
failureThreshold: number;
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Throws if the watchdog config is invalid. Called from the
|
|
458
|
-
* MailboxHealthWatchdog constructor so misconfiguration fails fast
|
|
459
|
-
* (at startup), not silently after the first probe.
|
|
241
|
+
* // ... session runs ...
|
|
242
|
+
* dispose(); // clean up on exit
|
|
460
243
|
*/
|
|
461
|
-
declare function
|
|
244
|
+
declare function attachDepWatcherBridge(opts: DepWatcherBridgeOptions): () => void;
|
|
462
245
|
|
|
463
246
|
/**
|
|
464
247
|
* mailbox-tool — Tool that exposes the inter-agent mailbox to agents.
|
|
@@ -564,124 +347,271 @@ declare function makeMailSendTool(opts?: MailToolsOptions): Tool;
|
|
|
564
347
|
declare function makeMailInboxTool(opts?: MailToolsOptions): Tool;
|
|
565
348
|
|
|
566
349
|
/**
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
* Watches dependency manifest files (package.json, go.mod, Cargo.toml, etc.)
|
|
570
|
-
* and when they change (create/update), posts a message to the inter-agent
|
|
571
|
-
* mailbox. A tech-stack analysis agent can then pick up the message and
|
|
572
|
-
* run a full tech-stack validation, feeding results back to the coding LLM.
|
|
350
|
+
* DefaultMailbox — append-only JSONL inter-agent mailbox (per-session).
|
|
573
351
|
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
*
|
|
352
|
+
* Stores messages under `<sessionDir>/_mailbox.jsonl`. Every send appends
|
|
353
|
+
* one line. Query reads and filters all lines. Ack rewrites changed
|
|
354
|
+
* messages in-place via atomic write.
|
|
577
355
|
*
|
|
578
|
-
*
|
|
579
|
-
* const cfg = makeDependencyWatcherConfig({
|
|
580
|
-
* projectRoot: '/path/to/project',
|
|
581
|
-
* mailbox,
|
|
582
|
-
* targetAgent: 'tech-stack-agent',
|
|
583
|
-
* });
|
|
584
|
-
* // cfg.watchPaths → pass to watch_start
|
|
585
|
-
* // cfg.onChange → call on file-watcher:changed events
|
|
356
|
+
* For cross-session communication, use GlobalMailbox instead.
|
|
586
357
|
*
|
|
587
|
-
* @module
|
|
358
|
+
* @module DefaultMailbox
|
|
588
359
|
*/
|
|
589
360
|
|
|
361
|
+
declare class DefaultMailbox implements Mailbox {
|
|
362
|
+
private readonly filePath;
|
|
363
|
+
private _messageCache;
|
|
364
|
+
private _messageCacheMtime;
|
|
365
|
+
private _messageCacheSize;
|
|
366
|
+
/** Primary index: recipient → Set of messages (points into _messageCache). */
|
|
367
|
+
private _byTo;
|
|
368
|
+
/** Secondary index: sender → Set of messages (points into _messageCache). */
|
|
369
|
+
private _byFrom;
|
|
370
|
+
/** Counts malformed JSONL lines skipped during parsing for observability. */
|
|
371
|
+
private _corruptionCount;
|
|
372
|
+
constructor(sessionDir: string);
|
|
373
|
+
get mailboxPath(): string;
|
|
374
|
+
/** Returns the count of malformed JSONL lines encountered during reads. */
|
|
375
|
+
get corruptionCount(): number;
|
|
376
|
+
send(input: MailboxSendInput): Promise<MailboxMessage>;
|
|
377
|
+
query(q: MailboxQuery): Promise<MailboxMessage[]>;
|
|
378
|
+
ack(input: MailboxAckInput): Promise<MailboxMessage | null>;
|
|
379
|
+
softDelete(_mailId: string, _by: string): Promise<MailboxMessage | null>;
|
|
380
|
+
restore(_mailId: string): Promise<MailboxMessage | null>;
|
|
381
|
+
ackMany(input: MailboxAckBatchInput): Promise<MailboxMessage[]>;
|
|
382
|
+
getAgentStatuses(): Promise<MailboxAgentStatus[]>;
|
|
383
|
+
getOnlineAgents(): Promise<MailboxAgentStatus[]>;
|
|
384
|
+
registerAgent(_input: AgentRegistrationInput): Promise<void>;
|
|
385
|
+
deregisterAgent(_agentId: string): Promise<void>;
|
|
386
|
+
heartbeat(_input: AgentHeartbeatInput): Promise<void>;
|
|
387
|
+
unreadCount(forAgentId: string): Promise<number>;
|
|
388
|
+
close(): Promise<void>;
|
|
389
|
+
clearAll(): Promise<void>;
|
|
390
|
+
purgeStale(opts?: PurgeOptions): Promise<PurgeResult>;
|
|
391
|
+
registerClient(_input: ClientRegistrationInput): Promise<void>;
|
|
392
|
+
clientHeartbeat(_input: ClientHeartbeatInput): Promise<void>;
|
|
393
|
+
getClientStatuses(): Promise<ClientStatus[]>;
|
|
394
|
+
private _readAll;
|
|
395
|
+
/**
|
|
396
|
+
* Read only newly-appended bytes from the file and append them to the
|
|
397
|
+
* in-memory cache, avoiding a full re-read when the file only grew.
|
|
398
|
+
*/
|
|
399
|
+
private _readNewMessagesOnly;
|
|
400
|
+
/** Parse a JSONL string into MailboxMessage[], including migration. */
|
|
401
|
+
private _parseLines;
|
|
402
|
+
/**
|
|
403
|
+
* Stat the mailbox file under the assumption that we are holding the
|
|
404
|
+
* file lock, and that a write to the file has just completed. Returns
|
|
405
|
+
* the (mtimeMs, size) pair, or (-1, -1) if the file does not exist
|
|
406
|
+
* (e.g. ackMany/purgeStale on a session that has never sent a message).
|
|
407
|
+
*/
|
|
408
|
+
private _statUnderLockOrAbsent;
|
|
409
|
+
private _readAllCached;
|
|
410
|
+
private _setMessageCache;
|
|
411
|
+
private _pushToCache;
|
|
412
|
+
/** Rebuild both indexes from a full message list. */
|
|
413
|
+
private _buildIndexes;
|
|
414
|
+
/** Add a single message to both indexes. */
|
|
415
|
+
private _indexMsg;
|
|
416
|
+
}
|
|
417
|
+
|
|
590
418
|
/**
|
|
591
|
-
*
|
|
592
|
-
*
|
|
419
|
+
* Mailbox message action helpers (skeleton).
|
|
420
|
+
*
|
|
421
|
+
* Phase 1 skeleton: declares the {@link MailboxMessageAction} union
|
|
422
|
+
* (the verb that a user or agent issues against a single message) and
|
|
423
|
+
* the per-action input shapes. The actual implementations
|
|
424
|
+
* ({@link GlobalMailbox.markRead}, {@link GlobalMailbox.acknowledge},
|
|
425
|
+
* {@link GlobalMailbox.softDelete}, {@link GlobalMailbox.restore}) are
|
|
426
|
+
* added in Phase 2 alongside the corresponding `GlobalMailbox`
|
|
427
|
+
* methods.
|
|
428
|
+
*
|
|
429
|
+
* Keeping the verb+input types in their own file means the WebUI
|
|
430
|
+
* client (Phase 3) and the server route handlers (Phase 4) can
|
|
431
|
+
* import them independently of the `GlobalMailbox` implementation,
|
|
432
|
+
* and a future "message actions" CLI subcommand only has to add
|
|
433
|
+
* one verb to a single place.
|
|
593
434
|
*/
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
/**
|
|
627
|
-
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* High-level verbs the WebUI/server route handlers expose. The
|
|
438
|
+
* mapping to underlying `MailboxAckInput` is straightforward:
|
|
439
|
+
* - `mark-read` → `ack({ read: true, completed: false })`
|
|
440
|
+
* - `acknowledge`→ `ack({ read: true, completed: true })`
|
|
441
|
+
* - `reopen` → `ack({ read: false, completed: false })`
|
|
442
|
+
* - `soft-delete`→ not an `ack` — a separate `Mailbox.softDelete()`
|
|
443
|
+
* that flips `deletedAt` to "now" (recoverable) and is filtered
|
|
444
|
+
* out of the default `query()`.
|
|
445
|
+
* - `restore` → the inverse of `soft-delete`. Undoes a
|
|
446
|
+
* `softDelete` by clearing `deletedAt`.
|
|
447
|
+
*/
|
|
448
|
+
type MailboxMessageAction = 'mark-read' | 'acknowledge' | 'reopen' | 'soft-delete' | 'restore';
|
|
449
|
+
/** Per-action request body sent from the WebUI → server route. */
|
|
450
|
+
interface MailboxActionInput {
|
|
451
|
+
action: MailboxMessageAction;
|
|
452
|
+
mailId: string;
|
|
453
|
+
/** Acting agent / user. Required by the server to stamp
|
|
454
|
+
* `readBy` / `completedBy`. */
|
|
455
|
+
readerId: string;
|
|
456
|
+
/** Optional human note (e.g. "triaged — will follow up"). */
|
|
457
|
+
note?: string | undefined;
|
|
458
|
+
/** Optional idempotency key so retried requests don't double-apply
|
|
459
|
+
* the action. Phase 4 wires this through to the CLI. */
|
|
460
|
+
requestId?: string | undefined;
|
|
461
|
+
}
|
|
462
|
+
/** Per-action response. Echoes the action + the resulting message
|
|
463
|
+
* state so the UI can reconcile optimistic updates. */
|
|
464
|
+
interface MailboxActionResult {
|
|
465
|
+
action: MailboxMessageAction;
|
|
466
|
+
mailId: string;
|
|
467
|
+
/** Updated message snapshot. `null` if the message was already in
|
|
468
|
+
* the target state (e.g. `mark-read` on a message the user has
|
|
469
|
+
* already read) — the WebUI can ignore the result in that case. */
|
|
470
|
+
message: MailboxMessage | null;
|
|
471
|
+
/** True if the action actually mutated state; false if it was a
|
|
472
|
+
* no-op. Lets the WebUI decide whether to update its local copy. */
|
|
473
|
+
changed: boolean;
|
|
628
474
|
}
|
|
629
475
|
/**
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
476
|
+
* Convert a high-level action into the underlying
|
|
477
|
+
* {@link MailboxAckInput} the existing `GlobalMailbox.ack` already
|
|
478
|
+
* supports. `soft-delete` and `restore` do NOT go through `ack` —
|
|
479
|
+
* the caller must dispatch them to `GlobalMailbox.softDelete` /
|
|
480
|
+
* `GlobalMailbox.restore` instead. This helper returns `null` for
|
|
481
|
+
* those two so the type signature forces the caller to handle them
|
|
482
|
+
* separately.
|
|
637
483
|
*/
|
|
638
|
-
declare function
|
|
484
|
+
declare function actionToAckInput(action: Exclude<MailboxMessageAction, 'soft-delete' | 'restore'>, input: MailboxActionInput): MailboxAckInput;
|
|
639
485
|
|
|
640
486
|
/**
|
|
641
|
-
*
|
|
642
|
-
*
|
|
487
|
+
* MailboxHealthWatchdog — probes the mailbox HTTP bridge and posts a
|
|
488
|
+
* status message when it goes down.
|
|
643
489
|
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
*
|
|
490
|
+
* Designed to be embedded inside the WrongStack REPL/TUI/WebUI process —
|
|
491
|
+
* NOT a standalone agent. WrongStack has its own cross-agent
|
|
492
|
+
* coordination channel, so the cheapest reliable signal is "ask the
|
|
493
|
+
* bridge if it's alive, and if it's not, tell the rest of the team
|
|
494
|
+
* via the same channel the bridge exposes."
|
|
648
495
|
*
|
|
649
|
-
*
|
|
496
|
+
* Usage:
|
|
650
497
|
*
|
|
651
|
-
*
|
|
498
|
+
* const mailbox = new GlobalMailbox(projectDir);
|
|
499
|
+
* const watchdog = new MailboxHealthWatchdog({
|
|
500
|
+
* mailbox,
|
|
501
|
+
* url: 'http://127.0.0.1:7788',
|
|
502
|
+
* probeIntervalMs: 15_000,
|
|
503
|
+
* onAlert: (event) => console.warn('mailbox bridge', event.kind),
|
|
504
|
+
* });
|
|
505
|
+
* await watchdog.start();
|
|
506
|
+
* // ...later...
|
|
507
|
+
* await watchdog.stop();
|
|
508
|
+
*
|
|
509
|
+
* The watchdog is a passive observer: it does NOT start the bridge.
|
|
510
|
+
* Starting the bridge is the user's job (`wstack mailbox serve` or
|
|
511
|
+
* `/mailbox-serve`). The watchdog then reports on what the user did.
|
|
652
512
|
*/
|
|
653
513
|
|
|
654
|
-
interface
|
|
655
|
-
/**
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
|
|
659
|
-
/**
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
514
|
+
interface MailboxHealthWatchdogOptions {
|
|
515
|
+
/** Project mailbox to probe-and-report on. Required. */
|
|
516
|
+
mailbox: GlobalMailbox;
|
|
517
|
+
/** URL of the mailbox bridge (no trailing slash). Required. */
|
|
518
|
+
url: string;
|
|
519
|
+
/** Probe interval in milliseconds. Default: 15_000. */
|
|
520
|
+
probeIntervalMs?: number;
|
|
521
|
+
/** Per-probe timeout in milliseconds. Default: 3_000. */
|
|
522
|
+
probeTimeoutMs?: number;
|
|
523
|
+
/**
|
|
524
|
+
* After this many consecutive failures the watchdog posts an alert.
|
|
525
|
+
* Default: 2 (so a single transient timeout doesn't trigger spam).
|
|
526
|
+
*/
|
|
527
|
+
failureThreshold?: number;
|
|
528
|
+
/**
|
|
529
|
+
* Optional callback for local observability — fired on every state
|
|
530
|
+
* transition. The mailbox post is independent of this callback.
|
|
531
|
+
*/
|
|
532
|
+
onAlert?: ((event: MailboxHealthEvent) => void) | undefined;
|
|
533
|
+
/**
|
|
534
|
+
* Agent id used to post the alert message. Default: 'mailbox-bridge-watchdog'.
|
|
535
|
+
*/
|
|
536
|
+
from?: string;
|
|
667
537
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
538
|
+
type MailboxHealthEvent = {
|
|
539
|
+
kind: 'probe-failed';
|
|
540
|
+
status?: number;
|
|
541
|
+
error?: string;
|
|
542
|
+
} | {
|
|
543
|
+
kind: 'alert-posted';
|
|
544
|
+
consecutiveFailures: number;
|
|
545
|
+
} | {
|
|
546
|
+
kind: 'recovery-posted';
|
|
547
|
+
downtimeMs: number;
|
|
548
|
+
} | {
|
|
549
|
+
kind: 'started';
|
|
550
|
+
intervalMs: number;
|
|
551
|
+
} | {
|
|
552
|
+
kind: 'stopped';
|
|
553
|
+
};
|
|
554
|
+
declare const MAILBOX_HEALTH_DEFAULT_INTERVAL_MS = 15000;
|
|
555
|
+
declare const MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS = 3000;
|
|
556
|
+
declare const MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD = 2;
|
|
557
|
+
declare const MAILBOX_HEALTH_DEFAULT_FROM = "mailbox-bridge-watchdog";
|
|
558
|
+
declare class MailboxHealthWatchdog {
|
|
559
|
+
private readonly mailbox;
|
|
560
|
+
private readonly url;
|
|
561
|
+
private readonly intervalMs;
|
|
562
|
+
private readonly timeoutMs;
|
|
563
|
+
private readonly failureThreshold;
|
|
564
|
+
private readonly from;
|
|
565
|
+
private readonly onAlert?;
|
|
566
|
+
private timer;
|
|
567
|
+
private consecutiveFailures;
|
|
568
|
+
private downSince;
|
|
569
|
+
private alerting;
|
|
570
|
+
private inFlight;
|
|
571
|
+
private aborted;
|
|
572
|
+
constructor(opts: MailboxHealthWatchdogOptions);
|
|
573
|
+
/** Start probing on `intervalMs`. Idempotent — second call is a no-op. */
|
|
574
|
+
start(): Promise<void>;
|
|
575
|
+
/** Stop probing. Safe to call multiple times. */
|
|
576
|
+
stop(): Promise<void>;
|
|
577
|
+
/** True between start() and stop(). */
|
|
578
|
+
isRunning(): boolean;
|
|
579
|
+
/** Number of consecutive failed probes since the last successful probe. */
|
|
580
|
+
get currentFailureStreak(): number;
|
|
581
|
+
/** True iff the watchdog currently considers the bridge down. */
|
|
582
|
+
isBridgeDown(): boolean;
|
|
583
|
+
private emit;
|
|
584
|
+
private tick;
|
|
585
|
+
private probe;
|
|
586
|
+
private recordSuccess;
|
|
587
|
+
private recordFailure;
|
|
588
|
+
private postDown;
|
|
589
|
+
private postRecovery;
|
|
590
|
+
}
|
|
591
|
+
interface DownAlertInput {
|
|
592
|
+
from: string;
|
|
593
|
+
url: string;
|
|
594
|
+
consecutiveFailures: number;
|
|
595
|
+
}
|
|
596
|
+
declare function buildDownAlert(input: DownAlertInput): MailboxSendInput;
|
|
597
|
+
interface RecoveryAlertInput {
|
|
598
|
+
from: string;
|
|
599
|
+
url: string;
|
|
600
|
+
downtimeMs: number;
|
|
601
|
+
consecutiveFailures: number;
|
|
602
|
+
}
|
|
603
|
+
declare function buildRecoveryAlert(input: RecoveryAlertInput): MailboxSendInput;
|
|
604
|
+
interface WatchdogConfig {
|
|
605
|
+
probeIntervalMs: number;
|
|
606
|
+
probeTimeoutMs: number;
|
|
607
|
+
failureThreshold: number;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Throws if the watchdog config is invalid. Called from the
|
|
611
|
+
* MailboxHealthWatchdog constructor so misconfiguration fails fast
|
|
612
|
+
* (at startup), not silently after the first probe.
|
|
683
613
|
*/
|
|
684
|
-
declare function
|
|
614
|
+
declare function validateWatchdogOptions(cfg: WatchdogConfig): void;
|
|
685
615
|
|
|
686
616
|
/**
|
|
687
617
|
* mailbox-hooks — Tool-execution hooks for mailbox integration.
|
|
@@ -893,19 +823,330 @@ interface PackageOutdatedWatcherOptions {
|
|
|
893
823
|
/** Called on errors. */
|
|
894
824
|
onError?: ((err: unknown) => void) | undefined;
|
|
895
825
|
}
|
|
896
|
-
interface OutdatedNotifyMessage {
|
|
897
|
-
from: string;
|
|
898
|
-
to: string;
|
|
899
|
-
subject: string;
|
|
900
|
-
body: string;
|
|
901
|
-
priority: 'high' | 'normal' | 'low';
|
|
826
|
+
interface OutdatedNotifyMessage {
|
|
827
|
+
from: string;
|
|
828
|
+
to: string;
|
|
829
|
+
subject: string;
|
|
830
|
+
body: string;
|
|
831
|
+
priority: 'high' | 'normal' | 'low';
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Start the package outdated watcher.
|
|
835
|
+
*
|
|
836
|
+
* Returns a dispose function that stops polling and cleans up.
|
|
837
|
+
*/
|
|
838
|
+
declare function startPackageOutdatedWatcher(opts: PackageOutdatedWatcherOptions): () => void;
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Single-instance mailbox-bridge lock.
|
|
842
|
+
*
|
|
843
|
+
* Per-project isolation: each project (resolved via
|
|
844
|
+
* `resolveProjectDir`) gets its own lock file under
|
|
845
|
+
* `<projectDir>/.mailbox-bridge.lock`. Two projects on the same
|
|
846
|
+
* machine never collide — different slugs, different lock files,
|
|
847
|
+
* and (with default port 0) different OS-assigned ports.
|
|
848
|
+
*
|
|
849
|
+
* The lock holds:
|
|
850
|
+
* - pid process id of the owning `wstack mailbox serve`
|
|
851
|
+
* - host, port what the owner actually bound (port may be OS-assigned)
|
|
852
|
+
* - url convenience copy for callers
|
|
853
|
+
* - token the bearer token (so external agents don't have to
|
|
854
|
+
* re-read it from .mailbox.token separately)
|
|
855
|
+
* - generation monotonically increasing counter; bumped on every
|
|
856
|
+
* acquire. Lets a release() call identify whether the
|
|
857
|
+
* current lock file still belongs to *this* process
|
|
858
|
+
* (e.g. after a stale cleanup raced with us).
|
|
859
|
+
* - spawnedAt ISO timestamp — for observability, not load-bearing.
|
|
860
|
+
*
|
|
861
|
+
* Concurrency model:
|
|
862
|
+
* - `acquireOrJoin` is atomic via rename(2). Two concurrent spawns
|
|
863
|
+
* race to write a tmpfile then rename; one wins, the other reads
|
|
864
|
+
* the winner's lock and joins.
|
|
865
|
+
* - PID liveness is checked via `process.kill(pid, 0)` (POSIX) or
|
|
866
|
+
* `tasklist` (Windows). A live PID means another instance owns
|
|
867
|
+
* this project; a dead PID means the lock is stale and gets cleaned.
|
|
868
|
+
* - `release` is best-effort: a missing lock file at shutdown is
|
|
869
|
+
* fine (someone else already took over). A generation mismatch means
|
|
870
|
+
* we lost the race and another instance owns it now — also fine.
|
|
871
|
+
*
|
|
872
|
+
* Token persistence: the token in the lock always matches the token in
|
|
873
|
+
* `.mailbox.token`, so an external agent that reads either file gets the
|
|
874
|
+
* same value. While an instance stays alive, every joining caller
|
|
875
|
+
* (`kind: 'joined'`) reuses that one token. A cold (re)start — no lock,
|
|
876
|
+
* or a lock whose owner PID is dead/unhealthy — mints a FRESH token and
|
|
877
|
+
* rewrites both files atomically. External agents must therefore re-read
|
|
878
|
+
* `.mailbox.token` after a bridge restart (a stale token returns 401).
|
|
879
|
+
*/
|
|
880
|
+
declare const MAILBOX_BRIDGE_LOCK_FILENAME = ".mailbox-bridge.lock";
|
|
881
|
+
declare const MAILBOX_BRIDGE_TOKEN_FILENAME = ".mailbox.token";
|
|
882
|
+
interface MailboxBridgeLock {
|
|
883
|
+
pid: number;
|
|
884
|
+
host: string;
|
|
885
|
+
port: number;
|
|
886
|
+
url: string;
|
|
887
|
+
token: string;
|
|
888
|
+
generation: number;
|
|
889
|
+
spawnedAt: string;
|
|
890
|
+
}
|
|
891
|
+
type AcquireResult = {
|
|
892
|
+
kind: 'acquired';
|
|
893
|
+
lock: MailboxBridgeLock;
|
|
894
|
+
tokenPath: string;
|
|
895
|
+
} | {
|
|
896
|
+
kind: 'joined';
|
|
897
|
+
lock: MailboxBridgeLock;
|
|
898
|
+
tokenPath: string;
|
|
899
|
+
} | {
|
|
900
|
+
kind: 'port-conflict';
|
|
901
|
+
existing: MailboxBridgeLock;
|
|
902
|
+
};
|
|
903
|
+
interface AcquireOptions {
|
|
904
|
+
/** Project dir (already resolved by caller via resolveProjectDir). */
|
|
905
|
+
projectDir: string;
|
|
906
|
+
/** Bind host. Required when acquiring. */
|
|
907
|
+
host: string;
|
|
908
|
+
/** Explicit port. Pass null/undefined to mean "OS-assigned" (read it after listen). */
|
|
909
|
+
requestedPort: number | null;
|
|
910
|
+
/** When true, fail loud on EADDRINUSE. When false, fall back to OS-assigned. */
|
|
911
|
+
strictPort: boolean;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Try to acquire the mailbox-bridge lock for `projectDir`. If another
|
|
915
|
+
* instance is already alive and healthy, join it. Otherwise claim
|
|
916
|
+
* the slot for ourselves.
|
|
917
|
+
*
|
|
918
|
+
* Two-phase contract:
|
|
919
|
+
* 1. Caller invokes `acquireOrJoin(...)` BEFORE calling
|
|
920
|
+
* `server.listen()`. The returned lock either:
|
|
921
|
+
* - `kind: 'joined'` → another instance is alive, the caller
|
|
922
|
+
* should NOT bind; just print the URL/token
|
|
923
|
+
* and exit cleanly (return 0).
|
|
924
|
+
* - `kind: 'acquired'` → caller is the owner, proceeds to bind.
|
|
925
|
+
* - `kind: 'port-conflict'` → caller asked for an explicit port
|
|
926
|
+
* that's already taken by an unrelated
|
|
927
|
+
* process; we return the existing owner
|
|
928
|
+
* but the caller decides what to do
|
|
929
|
+
* (loud-fail).
|
|
930
|
+
* 2. After `server.listen()` resolves with a real port, the caller
|
|
931
|
+
* invokes `finalize(lock, boundPort)` to atomically write the
|
|
932
|
+
* final lock + token file with the OS-assigned port.
|
|
933
|
+
*
|
|
934
|
+
* The two-phase split keeps the listen() call out of the lock module —
|
|
935
|
+
* the caller owns the HTTP server instance; the lock module owns
|
|
936
|
+
* the on-disk contract.
|
|
937
|
+
*/
|
|
938
|
+
declare function acquireOrJoin(opts: AcquireOptions): Promise<AcquireResult>;
|
|
939
|
+
/**
|
|
940
|
+
* Phase 2 — after server.listen() resolves, write the final lock
|
|
941
|
+
* with the actually-bound port and the same token. Also writes the
|
|
942
|
+
* .mailbox.token file with mode 0600 so external agents can read it.
|
|
943
|
+
*
|
|
944
|
+
* Returns the finalized lock so the caller can use the resolved URL.
|
|
945
|
+
*/
|
|
946
|
+
declare function finalize(projectDir: string, tentative: MailboxBridgeLock, boundPort: number): Promise<MailboxBridgeLock>;
|
|
947
|
+
/**
|
|
948
|
+
* Phase 3 — best-effort cleanup on shutdown. Removes the lock + token
|
|
949
|
+
* files IF this process is still the recorded owner (generation match).
|
|
950
|
+
*
|
|
951
|
+
* If the generation doesn't match, another acquire() has already
|
|
952
|
+
* superseded us — we must NOT delete their lock.
|
|
953
|
+
*/
|
|
954
|
+
declare function release(projectDir: string, generation: number): Promise<void>;
|
|
955
|
+
/**
|
|
956
|
+
* Read the lock file and return it, with enough information for the
|
|
957
|
+
* caller to distinguish:
|
|
958
|
+
* - 'live' — PID alive, /healthz reachable; safe to use.
|
|
959
|
+
* - 'probe-failed' — PID alive (or recently was) but /healthz
|
|
960
|
+
* unreachable. Caller can still return the URL
|
|
961
|
+
* + token to the host so its request layer can
|
|
962
|
+
* retry; the host's fetch timeout will surface
|
|
963
|
+
* the real error if the bridge is truly dead.
|
|
964
|
+
* - 'absent' — no lock file existed, or it was malformed
|
|
965
|
+
* (cleaned up best-effort).
|
|
966
|
+
*
|
|
967
|
+
* Distinguishing 'probe-failed' from 'absent' matters for the
|
|
968
|
+
* "joined vs spawned" decision in tryAcquireMailboxBridge — we
|
|
969
|
+
* don't want to spawn a second bridge just because /healthz flaked.
|
|
970
|
+
*/
|
|
971
|
+
type LiveLockResult = {
|
|
972
|
+
kind: 'live';
|
|
973
|
+
lock: MailboxBridgeLock;
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* The lock exists but isn't usable. `pidAlive` tells the caller
|
|
977
|
+
* which recovery to pick:
|
|
978
|
+
* - `pidAlive: false` — the owning process is dead (stale lock).
|
|
979
|
+
* Callers should treat this like `absent` and spawn a fresh
|
|
980
|
+
* bridge rather than surfacing a dead URL.
|
|
981
|
+
* - `pidAlive: true` — the process is alive but /healthz didn't
|
|
982
|
+
* respond (booting/wedged/PID-reuse). Callers may return the
|
|
983
|
+
* recorded URL/token and let a real request confirm liveness.
|
|
984
|
+
*/
|
|
985
|
+
| {
|
|
986
|
+
kind: 'probe-failed';
|
|
987
|
+
lock: MailboxBridgeLock;
|
|
988
|
+
pidAlive: boolean;
|
|
989
|
+
} | {
|
|
990
|
+
kind: 'absent';
|
|
991
|
+
};
|
|
992
|
+
declare function readLiveLock(projectDir: string): Promise<LiveLockResult>;
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Adaptive Concurrency Controller
|
|
996
|
+
*
|
|
997
|
+
* Automatically adjusts `maxConcurrent` based on:
|
|
998
|
+
* - Rate limit (429) errors → decrease concurrency
|
|
999
|
+
* - Sustained successful requests → increase concurrency
|
|
1000
|
+
*
|
|
1001
|
+
* This provides automatic backpressure without manual tuning.
|
|
1002
|
+
*/
|
|
1003
|
+
|
|
1004
|
+
interface AdaptiveConcurrencyState {
|
|
1005
|
+
current: number;
|
|
1006
|
+
min: number;
|
|
1007
|
+
max: number;
|
|
1008
|
+
consecutiveSuccesses: number;
|
|
1009
|
+
consecutiveFailures: number;
|
|
1010
|
+
totalDecreases: number;
|
|
1011
|
+
totalIncreases: number;
|
|
1012
|
+
enabled: boolean;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Adaptive Concurrency Controller
|
|
1016
|
+
*
|
|
1017
|
+
* Monitors fleet events for rate-limit (429) errors and adjusts concurrency
|
|
1018
|
+
* automatically to prevent overwhelming the API provider.
|
|
1019
|
+
*/
|
|
1020
|
+
declare class AdaptiveConcurrencyController {
|
|
1021
|
+
private readonly config;
|
|
1022
|
+
private state;
|
|
1023
|
+
private readonly disposers;
|
|
1024
|
+
private stateChangeHandlers;
|
|
1025
|
+
private readonly logger;
|
|
1026
|
+
constructor(fleetBus: FleetBus, setMaxConcurrent: (n: number) => void, config?: Partial<AdaptiveConcurrencyConfig>, onStateChange?: (state: AdaptiveConcurrencyState) => void, logger?: Pick<Logger, 'warn'>);
|
|
1027
|
+
private setupEventHandlers;
|
|
1028
|
+
/**
|
|
1029
|
+
* Handle a rate limit (429) error - decrease concurrency
|
|
1030
|
+
*/
|
|
1031
|
+
private handleRateLimit;
|
|
1032
|
+
/**
|
|
1033
|
+
* Force a decrease (e.g., manual trigger or other error types)
|
|
1034
|
+
*/
|
|
1035
|
+
decrease(target?: number): void;
|
|
1036
|
+
/**
|
|
1037
|
+
* Get the current state
|
|
1038
|
+
*/
|
|
1039
|
+
getState(): AdaptiveConcurrencyState;
|
|
1040
|
+
/**
|
|
1041
|
+
* Update configuration at runtime
|
|
1042
|
+
*/
|
|
1043
|
+
updateConfig(config: Partial<AdaptiveConcurrencyConfig>): void;
|
|
1044
|
+
/**
|
|
1045
|
+
* Dispose of the controller and clean up event listeners
|
|
1046
|
+
*/
|
|
1047
|
+
dispose(): void;
|
|
1048
|
+
private notifyStateChange;
|
|
1049
|
+
/**
|
|
1050
|
+
* Register a state change handler
|
|
1051
|
+
*/
|
|
1052
|
+
onStateChange(handler: (state: AdaptiveConcurrencyState) => void): () => void;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
interface AgentTimelineEntry {
|
|
1056
|
+
/** Unique entry id (ULID or timestamp-based). */
|
|
1057
|
+
id: string;
|
|
1058
|
+
/** Subagent id this entry belongs to. */
|
|
1059
|
+
subagentId: string;
|
|
1060
|
+
/** Human-readable agent name/role. */
|
|
1061
|
+
agentName: string;
|
|
1062
|
+
/** ISO 8601 timestamp. */
|
|
1063
|
+
ts: string;
|
|
1064
|
+
/** Content type. */
|
|
1065
|
+
kind: 'text' | 'thinking' | 'tool_use' | 'tool_result' | 'error' | 'status' | 'system';
|
|
1066
|
+
/** The message content (text, tool summary, error message, status text). */
|
|
1067
|
+
content: string;
|
|
1068
|
+
/** Iteration index within the subagent's run. */
|
|
1069
|
+
iteration: number;
|
|
1070
|
+
/** For tool entries: tool name. */
|
|
1071
|
+
toolName?: string | undefined;
|
|
1072
|
+
/** For tool entries: whether the tool succeeded. */
|
|
1073
|
+
toolOk?: boolean | undefined;
|
|
1074
|
+
/** Running cost estimate. */
|
|
1075
|
+
costUsd?: number | undefined;
|
|
1076
|
+
}
|
|
1077
|
+
interface AgentVirtualSession {
|
|
1078
|
+
subagentId: string;
|
|
1079
|
+
agentName: string;
|
|
1080
|
+
createdAt: string;
|
|
1081
|
+
status: string;
|
|
1082
|
+
task?: string | undefined;
|
|
1083
|
+
/** Ordered transcript entries (newest last). */
|
|
1084
|
+
transcript: AgentTimelineEntry[];
|
|
1085
|
+
}
|
|
1086
|
+
interface AgentMonitorOptions {
|
|
1087
|
+
/** Parent/host session id for emitted agent timeline/status events. */
|
|
1088
|
+
sessionId?: string | undefined;
|
|
1089
|
+
/** The FleetBus to listen on for subagent events. Optional — set via `setFleetBus()` before `start()`. */
|
|
1090
|
+
fleetBus?: FleetBus | undefined;
|
|
1091
|
+
/** Local EventBus for emitting agent.timeline.* and agent.status_changed events. */
|
|
1092
|
+
events: EventBus;
|
|
1093
|
+
/** Directory where per-subagent JSONL transcripts will be written. */
|
|
1094
|
+
transcriptsDir: string;
|
|
1095
|
+
/** Maximum in-memory entries per subagent (ring buffer). Default 500. */
|
|
1096
|
+
maxEntriesPerAgent?: number;
|
|
1097
|
+
/** Whether agent stream is initially enabled. Default false. */
|
|
1098
|
+
streamEnabled?: boolean;
|
|
1099
|
+
/** Called for each new timeline entry — used by HQ publisher bridge. */
|
|
1100
|
+
onEntry?: ((entry: AgentTimelineEntry) => void) | undefined;
|
|
902
1101
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1102
|
+
declare class AgentMonitorService {
|
|
1103
|
+
private _fleetBus;
|
|
1104
|
+
private readonly _events;
|
|
1105
|
+
private readonly _sessionId;
|
|
1106
|
+
private readonly _transcriptsDir;
|
|
1107
|
+
private readonly _maxEntries;
|
|
1108
|
+
private _streamEnabled;
|
|
1109
|
+
private _onEntry;
|
|
1110
|
+
/** Per-subagent virtual sessions. */
|
|
1111
|
+
private readonly _sessions;
|
|
1112
|
+
/** Disposers for FleetBus subscriptions, keyed by subagentId. */
|
|
1113
|
+
private readonly _subscriptions;
|
|
1114
|
+
/** Generic fleet-wide subscription disposer. */
|
|
1115
|
+
private _fleetDisposer;
|
|
1116
|
+
/** Track whether service is running. */
|
|
1117
|
+
private _started;
|
|
1118
|
+
constructor(opts: AgentMonitorOptions);
|
|
1119
|
+
/** Set the FleetBus to listen on. Must be called before `start()`. */
|
|
1120
|
+
setFleetBus(bus: FleetBus): void;
|
|
1121
|
+
get streamEnabled(): boolean;
|
|
1122
|
+
/** Enable/disable streaming agent conversations to the main chat timeline. */
|
|
1123
|
+
setStreamEnabled(enabled: boolean): void;
|
|
1124
|
+
/** Get a snapshot of all known agent sessions. */
|
|
1125
|
+
getAllSessions(): AgentVirtualSession[];
|
|
1126
|
+
/** Get a specific agent's virtual session, or undefined. */
|
|
1127
|
+
getSession(subagentId: string): AgentVirtualSession | undefined;
|
|
1128
|
+
/** Get transcript entries for a specific agent, newest first. */
|
|
1129
|
+
getTranscript(subagentId: string, limit?: number): AgentTimelineEntry[];
|
|
1130
|
+
/** Set a callback for each new timeline entry (HQ bridge). */
|
|
1131
|
+
setOnEntry(handler: ((entry: AgentTimelineEntry) => void) | undefined): void;
|
|
1132
|
+
/** Start listening to FleetBus events. */
|
|
1133
|
+
start(): void;
|
|
1134
|
+
/** Stop listening and clean up all subscriptions. */
|
|
1135
|
+
stop(): void;
|
|
1136
|
+
/** Ensure a subagent is being tracked. Called when a subagent spawns. */
|
|
1137
|
+
trackSubagent(subagentId: string, agentName: string, task?: string): void;
|
|
1138
|
+
/** Mark a subagent as completed/failed/etc. Called on subagent finish. */
|
|
1139
|
+
completeSubagent(subagentId: string, status: 'completed' | 'failed' | 'timeout' | 'stopped' | 'budget_exhausted', summary?: string): void;
|
|
1140
|
+
private _routeEvent;
|
|
1141
|
+
private _addEntry;
|
|
1142
|
+
private _appendToFile;
|
|
1143
|
+
private _uid;
|
|
1144
|
+
private _formatToolUse;
|
|
1145
|
+
private _formatToolResult;
|
|
1146
|
+
private _stringifyForTimeline;
|
|
1147
|
+
private _capTimelineText;
|
|
1148
|
+
}
|
|
1149
|
+
declare function createAgentMonitorService(opts: AgentMonitorOptions): AgentMonitorService;
|
|
909
1150
|
|
|
910
1151
|
type NodeType = 'fact' | 'goal' | 'decision' | 'change' | 'vote';
|
|
911
1152
|
type FactCategory = 'bug' | 'refactor' | 'security' | 'test' | 'perf' | 'deps' | 'architecture' | 'quality';
|
|
@@ -1035,93 +1276,242 @@ interface NodeFilter {
|
|
|
1035
1276
|
/** Only nodes added after this timestamp */
|
|
1036
1277
|
since?: string;
|
|
1037
1278
|
}
|
|
1038
|
-
declare class KnowledgeGraph {
|
|
1039
|
-
private readonly nodes;
|
|
1040
|
-
private readonly index;
|
|
1041
|
-
private readonly subs;
|
|
1042
|
-
private readonly pendingDeliveries;
|
|
1043
|
-
private readonly filePath;
|
|
1044
|
-
private readonly graphFilePath;
|
|
1279
|
+
declare class KnowledgeGraph {
|
|
1280
|
+
private readonly nodes;
|
|
1281
|
+
private readonly index;
|
|
1282
|
+
private readonly subs;
|
|
1283
|
+
private readonly pendingDeliveries;
|
|
1284
|
+
private readonly filePath;
|
|
1285
|
+
private readonly graphFilePath;
|
|
1286
|
+
/**
|
|
1287
|
+
* Stable per-node insertion sequence. `nodes` (a Map) preserves insertion
|
|
1288
|
+
* order even across `update()` (Map.set on an existing key keeps its slot),
|
|
1289
|
+
* but the type index's `Set<string>` does NOT — `update()` removes then
|
|
1290
|
+
* re-adds a node's id, moving it to the set's tail. Index-routed queries sort
|
|
1291
|
+
* by this sequence so they return nodes in creation order, matching the old
|
|
1292
|
+
* `nodes.values()` scan that callers like decision-history `slice(-10)` rely on.
|
|
1293
|
+
*/
|
|
1294
|
+
private readonly seq;
|
|
1295
|
+
private seqCounter;
|
|
1296
|
+
/** Assign a stable insertion sequence the first time a node id is seen. */
|
|
1297
|
+
private _trackSeq;
|
|
1298
|
+
/** Exposed for unit-testing only: read current index contents. */
|
|
1299
|
+
getIndex(): ReadonlyMap<string, ReadonlySet<string>>;
|
|
1300
|
+
constructor(sessionDir: string);
|
|
1301
|
+
/**
|
|
1302
|
+
* Add a node. Fires to all matching subscriptions synchronously.
|
|
1303
|
+
* Returns the node with its assigned id.
|
|
1304
|
+
*/
|
|
1305
|
+
add(node: Omit<GraphNode, 'id'>): Promise<GraphNode>;
|
|
1306
|
+
/** Update an existing node by id. Returns updated node or null if not found. */
|
|
1307
|
+
update(id: string, patch: Partial<GraphNode>): Promise<GraphNode | null>;
|
|
1308
|
+
get(id: string): GraphNode | undefined;
|
|
1309
|
+
getAll(filter?: NodeFilter): GraphNode[];
|
|
1310
|
+
getGoals(filter?: Partial<{
|
|
1311
|
+
status: GoalStatus;
|
|
1312
|
+
assignee: string;
|
|
1313
|
+
priority: GoalPriority;
|
|
1314
|
+
}>): GoalNode[];
|
|
1315
|
+
getFacts(filter?: Partial<{
|
|
1316
|
+
category: FactCategory;
|
|
1317
|
+
severity: string;
|
|
1318
|
+
}>): FactNode[];
|
|
1319
|
+
getChanges(filter?: Partial<{
|
|
1320
|
+
status: ChangeStatus;
|
|
1321
|
+
}>): ChangeNode[];
|
|
1322
|
+
getOpenGoals(): GoalNode[];
|
|
1323
|
+
getTopLevelGoals(): GoalNode[];
|
|
1324
|
+
getBlockedGoals(): GoalNode[];
|
|
1325
|
+
getPendingChanges(): ChangeNode[];
|
|
1326
|
+
getDecisions(since?: string): DecisionNode[];
|
|
1327
|
+
searchFacts(query: string): FactNode[];
|
|
1328
|
+
getRelatedFacts(factId: string): FactNode[];
|
|
1329
|
+
/**
|
|
1330
|
+
* Subscribe to nodes matching a filter. Returns a channel id that can be
|
|
1331
|
+
* used to poll for new nodes since the last check.
|
|
1332
|
+
*/
|
|
1333
|
+
subscribe(agentId: string, filter: NodeFilter): string;
|
|
1334
|
+
/**
|
|
1335
|
+
* Poll for new nodes delivered to a channel since last check.
|
|
1336
|
+
* Clears the delivery buffer after reading.
|
|
1337
|
+
*/
|
|
1338
|
+
poll(channel: string): GraphNode[];
|
|
1339
|
+
unsubscribe(channel: string): void;
|
|
1340
|
+
/**
|
|
1341
|
+
* Create a quality gate result. Call this when a change is being proposed
|
|
1342
|
+
* so the change node carries the gate result.
|
|
1343
|
+
*/
|
|
1344
|
+
static makeQualityGate(checks: {
|
|
1345
|
+
name: string;
|
|
1346
|
+
passed: boolean;
|
|
1347
|
+
detail?: string;
|
|
1348
|
+
}[]): QualityGateResult;
|
|
1349
|
+
/** Pure: compute the set of index keys a node would belong to. */
|
|
1350
|
+
private _indexKeys;
|
|
1351
|
+
/** Mutate the index: add a node's id to every set for the given keys. */
|
|
1352
|
+
private _addToIndex;
|
|
1353
|
+
/** Remove a node's id from all index sets for the given keys. */
|
|
1354
|
+
private _removeFromIndex;
|
|
1355
|
+
private _matches;
|
|
1356
|
+
private _deliver;
|
|
1357
|
+
private _persist;
|
|
1358
|
+
private _append;
|
|
1359
|
+
/** Rebuild in-memory state from the log file. Call on startup. */
|
|
1360
|
+
load(): Promise<void>;
|
|
1361
|
+
/** Snapshot for serialization. */
|
|
1362
|
+
snapshot(): {
|
|
1363
|
+
nodes: GraphNode[];
|
|
1364
|
+
subs: number;
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
type AutonomousDecisionType = 'spawn' | 'approve_change' | 'reject_change' | 'prioritize_goals' | 'escalate_task' | 'rollback_change' | 'retry_task' | 'merge_results' | 'decompose_goal' | 'assign_task';
|
|
1369
|
+
interface AutonomousDecisionRequest {
|
|
1370
|
+
id: string;
|
|
1371
|
+
source: BrainDecisionSource;
|
|
1372
|
+
decisionType: AutonomousDecisionType;
|
|
1373
|
+
question: string;
|
|
1374
|
+
context: {
|
|
1375
|
+
/** Relevant facts from the knowledge graph */
|
|
1376
|
+
facts?: FactNode[];
|
|
1377
|
+
/** Goals relevant to this decision */
|
|
1378
|
+
goals?: GoalNode[];
|
|
1379
|
+
/** Change being reviewed (for approval decisions) */
|
|
1380
|
+
change?: ChangeNode;
|
|
1381
|
+
/** Current fleet status */
|
|
1382
|
+
fleetStatus?: {
|
|
1383
|
+
running: number;
|
|
1384
|
+
idle: number;
|
|
1385
|
+
total: number;
|
|
1386
|
+
costSoFar: number;
|
|
1387
|
+
};
|
|
1388
|
+
/** Task that triggered this decision */
|
|
1389
|
+
taskDescription?: string;
|
|
1390
|
+
/** Error that triggered escalation, if any */
|
|
1391
|
+
error?: string;
|
|
1392
|
+
/** Number of times this task has been attempted */
|
|
1393
|
+
attempts?: number;
|
|
1394
|
+
};
|
|
1395
|
+
options: BrainDecisionOption[];
|
|
1396
|
+
risk: BrainRisk;
|
|
1397
|
+
/** Whether this decision requires consensus */
|
|
1398
|
+
requiresConsensus: boolean;
|
|
1399
|
+
}
|
|
1400
|
+
interface SpawnDecision {
|
|
1401
|
+
role: string;
|
|
1402
|
+
budget: {
|
|
1403
|
+
timeoutMs?: number;
|
|
1404
|
+
maxIterations?: number;
|
|
1405
|
+
maxToolCalls?: number;
|
|
1406
|
+
maxCostUsd?: number;
|
|
1407
|
+
};
|
|
1408
|
+
rationale: string;
|
|
1409
|
+
}
|
|
1410
|
+
interface ApprovalDecision {
|
|
1411
|
+
approved: boolean;
|
|
1412
|
+
rationale: string;
|
|
1413
|
+
waivers?: string[];
|
|
1414
|
+
conditions?: string[];
|
|
1415
|
+
}
|
|
1416
|
+
interface PrioritizationDecision {
|
|
1417
|
+
orderedGoals: string[];
|
|
1418
|
+
rationale: string;
|
|
1419
|
+
}
|
|
1420
|
+
interface EscalationDecision {
|
|
1421
|
+
action: 'retry' | 'delegate' | 'mark_failed' | 'ask_for_help';
|
|
1422
|
+
rationale: string;
|
|
1423
|
+
budgetAdjustment?: {
|
|
1424
|
+
increaseFactor?: number;
|
|
1425
|
+
newTimeoutMs?: number;
|
|
1426
|
+
addModel?: string;
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
interface AutonomousBrainOptions {
|
|
1430
|
+
/** The LLM provider for making decisions */
|
|
1431
|
+
llmProvider: LLMProvider;
|
|
1432
|
+
graph: KnowledgeGraph;
|
|
1433
|
+
fleet?: FleetBus | undefined;
|
|
1434
|
+
/** Maximum retries before a task is marked failed. Default: 3. */
|
|
1435
|
+
maxRetries?: number | undefined;
|
|
1436
|
+
/** Risk threshold above which consensus is required. Default: 'high'. */
|
|
1437
|
+
consensusRiskThreshold?: BrainRisk | undefined;
|
|
1438
|
+
/** Self-improve: track decision history for learning. Default: true. */
|
|
1439
|
+
selfImprove?: boolean | undefined;
|
|
1440
|
+
}
|
|
1441
|
+
interface LLMProvider {
|
|
1442
|
+
/**
|
|
1443
|
+
* Generate a decision. Receives the full context as a structured prompt.
|
|
1444
|
+
* Returns the chosen option id and rationale.
|
|
1445
|
+
*/
|
|
1446
|
+
decide(prompt: DecisionPrompt): Promise<{
|
|
1447
|
+
optionId: string;
|
|
1448
|
+
rationale: string;
|
|
1449
|
+
}>;
|
|
1450
|
+
}
|
|
1451
|
+
interface DecisionPrompt {
|
|
1452
|
+
decisionType: AutonomousDecisionType;
|
|
1453
|
+
question: string;
|
|
1454
|
+
context: string;
|
|
1455
|
+
options: BrainDecisionOption[];
|
|
1456
|
+
risk: BrainRisk;
|
|
1457
|
+
decisionHistory: DecisionNode[];
|
|
1458
|
+
/** Hints derived from self-improvement data */
|
|
1459
|
+
selfImproveHints?: string[];
|
|
1460
|
+
}
|
|
1461
|
+
declare class AutonomousBrain implements BrainArbiter {
|
|
1462
|
+
private readonly graph;
|
|
1463
|
+
private readonly fleetBus?;
|
|
1464
|
+
private readonly llmProvider;
|
|
1465
|
+
private readonly maxRetries;
|
|
1466
|
+
private readonly consensusRiskThreshold;
|
|
1467
|
+
private readonly selfImprove;
|
|
1468
|
+
/** Decision history for self-improvement and audit. */
|
|
1469
|
+
private decisionHistory;
|
|
1470
|
+
/** Tracks failure patterns for self-improvement. */
|
|
1471
|
+
private failurePatterns;
|
|
1472
|
+
private readonly RISK_ORDER;
|
|
1473
|
+
private _emit;
|
|
1474
|
+
constructor(opts: AutonomousBrainOptions);
|
|
1475
|
+
/** Implements BrainArbiter — bridges standard brain.ts interface to autonomous engine. */
|
|
1476
|
+
decide(request: BrainDecisionRequest): Promise<BrainDecision>;
|
|
1045
1477
|
/**
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1050
|
-
*
|
|
1051
|
-
* `nodes.values()` scan that callers like decision-history `slice(-10)` rely on.
|
|
1478
|
+
* Primary autonomous decision engine — receives AutonomousDecisionRequest,
|
|
1479
|
+
* queries the LLM, records the decision, and returns a BrainDecision.
|
|
1480
|
+
*
|
|
1481
|
+
* Specialized methods (decideSpawn, decideApproval, etc.) should call this
|
|
1482
|
+
* directly with a pre-built AutonomousDecisionRequest.
|
|
1052
1483
|
*/
|
|
1053
|
-
|
|
1054
|
-
private seqCounter;
|
|
1055
|
-
/** Assign a stable insertion sequence the first time a node id is seen. */
|
|
1056
|
-
private _trackSeq;
|
|
1057
|
-
/** Exposed for unit-testing only: read current index contents. */
|
|
1058
|
-
getIndex(): ReadonlyMap<string, ReadonlySet<string>>;
|
|
1059
|
-
constructor(sessionDir: string);
|
|
1484
|
+
decideAuto(request: AutonomousDecisionRequest): Promise<BrainDecision>;
|
|
1060
1485
|
/**
|
|
1061
|
-
*
|
|
1062
|
-
* Returns the node with its assigned id.
|
|
1486
|
+
* Decide whether to spawn a subagent, which role to use, and what budget.
|
|
1063
1487
|
*/
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
status: GoalStatus;
|
|
1071
|
-
assignee: string;
|
|
1072
|
-
priority: GoalPriority;
|
|
1073
|
-
}>): GoalNode[];
|
|
1074
|
-
getFacts(filter?: Partial<{
|
|
1075
|
-
category: FactCategory;
|
|
1076
|
-
severity: string;
|
|
1077
|
-
}>): FactNode[];
|
|
1078
|
-
getChanges(filter?: Partial<{
|
|
1079
|
-
status: ChangeStatus;
|
|
1080
|
-
}>): ChangeNode[];
|
|
1081
|
-
getOpenGoals(): GoalNode[];
|
|
1082
|
-
getTopLevelGoals(): GoalNode[];
|
|
1083
|
-
getBlockedGoals(): GoalNode[];
|
|
1084
|
-
getPendingChanges(): ChangeNode[];
|
|
1085
|
-
getDecisions(since?: string): DecisionNode[];
|
|
1086
|
-
searchFacts(query: string): FactNode[];
|
|
1087
|
-
getRelatedFacts(factId: string): FactNode[];
|
|
1488
|
+
decideSpawn(source: BrainDecisionSource, taskDescription: string, availableFacts: FactNode[], fleetStatus: {
|
|
1489
|
+
running: number;
|
|
1490
|
+
idle: number;
|
|
1491
|
+
total: number;
|
|
1492
|
+
costSoFar: number;
|
|
1493
|
+
}): Promise<BrainDecision>;
|
|
1088
1494
|
/**
|
|
1089
|
-
*
|
|
1090
|
-
* used to poll for new nodes since the last check.
|
|
1495
|
+
* Decide whether to approve a proposed change.
|
|
1091
1496
|
*/
|
|
1092
|
-
|
|
1497
|
+
decideApproval(source: BrainDecisionSource, change: ChangeNode, relevantFacts: FactNode[]): Promise<BrainDecision>;
|
|
1093
1498
|
/**
|
|
1094
|
-
*
|
|
1095
|
-
* Clears the delivery buffer after reading.
|
|
1499
|
+
* Decide how to handle a failed task.
|
|
1096
1500
|
*/
|
|
1097
|
-
|
|
1098
|
-
unsubscribe(channel: string): void;
|
|
1501
|
+
decideEscalation(source: BrainDecisionSource, taskId: string, error: string, attempts: number): Promise<BrainDecision>;
|
|
1099
1502
|
/**
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1503
|
+
* Record the outcome of a decision for self-improvement.
|
|
1504
|
+
* Call this after a spawned agent completes or a change is applied.
|
|
1102
1505
|
*/
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
private
|
|
1110
|
-
|
|
1111
|
-
private
|
|
1112
|
-
/** Remove a node's id from all index sets for the given keys. */
|
|
1113
|
-
private _removeFromIndex;
|
|
1114
|
-
private _matches;
|
|
1115
|
-
private _deliver;
|
|
1116
|
-
private _persist;
|
|
1117
|
-
private _append;
|
|
1118
|
-
/** Rebuild in-memory state from the log file. Call on startup. */
|
|
1119
|
-
load(): Promise<void>;
|
|
1120
|
-
/** Snapshot for serialization. */
|
|
1121
|
-
snapshot(): {
|
|
1122
|
-
nodes: GraphNode[];
|
|
1123
|
-
subs: number;
|
|
1124
|
-
};
|
|
1506
|
+
recordOutcome(decisionId: string, outcome: 'success' | 'failure', _detail?: string): void;
|
|
1507
|
+
private _getSelfImproveHints;
|
|
1508
|
+
private _toAutonomous;
|
|
1509
|
+
private _inferDecisionType;
|
|
1510
|
+
private _serializeContext;
|
|
1511
|
+
private _loadHistory;
|
|
1512
|
+
private _recordDecision;
|
|
1513
|
+
private _inferRoles;
|
|
1514
|
+
private _changeRisk;
|
|
1125
1515
|
}
|
|
1126
1516
|
|
|
1127
1517
|
/**
|
|
@@ -1271,6 +1661,144 @@ declare class TaskDAG {
|
|
|
1271
1661
|
private _wouldCycle;
|
|
1272
1662
|
}
|
|
1273
1663
|
|
|
1664
|
+
interface TaskBid {
|
|
1665
|
+
id: string;
|
|
1666
|
+
taskId: string;
|
|
1667
|
+
agentId: string;
|
|
1668
|
+
agentName: string;
|
|
1669
|
+
agentRole: string;
|
|
1670
|
+
/** Dispatcher score for this task */
|
|
1671
|
+
score: number;
|
|
1672
|
+
/** Why this agent is a good fit */
|
|
1673
|
+
rationale: string;
|
|
1674
|
+
submittedAt: string;
|
|
1675
|
+
}
|
|
1676
|
+
interface TaskAuctionOptions {
|
|
1677
|
+
graph: KnowledgeGraph;
|
|
1678
|
+
fleet?: FleetBus | undefined;
|
|
1679
|
+
mailbox?: Mailbox | undefined;
|
|
1680
|
+
selfAgentId?: string | undefined;
|
|
1681
|
+
/** How long a bid window stays open before auto-awarding. Default: 30s */
|
|
1682
|
+
bidWindowMs?: number | undefined;
|
|
1683
|
+
/** Maximum concurrent tasks per agent. Default: 3 */
|
|
1684
|
+
maxTasksPerAgent?: number | undefined;
|
|
1685
|
+
/** Minimum confidence threshold for dispatcher scoring. Default: 0.3 */
|
|
1686
|
+
minConfidence?: number | undefined;
|
|
1687
|
+
/**
|
|
1688
|
+
* Maximum times a task can be republished when no bids are received.
|
|
1689
|
+
* After this, the task is marked as 'failed' with reason 'no_bids'.
|
|
1690
|
+
* Default: 3.
|
|
1691
|
+
*/
|
|
1692
|
+
maxBidRetries?: number | undefined;
|
|
1693
|
+
}
|
|
1694
|
+
declare class TaskAuctioneer {
|
|
1695
|
+
private readonly graph;
|
|
1696
|
+
private readonly fleet?;
|
|
1697
|
+
private readonly mailbox?;
|
|
1698
|
+
private readonly selfAgentId;
|
|
1699
|
+
private readonly bidWindowMs;
|
|
1700
|
+
private readonly maxTasksPerAgent;
|
|
1701
|
+
private readonly minConfidence;
|
|
1702
|
+
private readonly maxBidRetries;
|
|
1703
|
+
/** Pending bids keyed by taskId. */
|
|
1704
|
+
private readonly pendingBids;
|
|
1705
|
+
/** Active bid windows keyed by taskId. */
|
|
1706
|
+
private readonly bidTimers;
|
|
1707
|
+
/** FleetBus subscription disposers, detached in dispose(). */
|
|
1708
|
+
private readonly unsubs;
|
|
1709
|
+
/** How many times a task has been republished with no bids received. */
|
|
1710
|
+
private readonly bidRetryCounts;
|
|
1711
|
+
/** Agent → current task count (from graph + in-flight). */
|
|
1712
|
+
private readonly agentTaskCounts;
|
|
1713
|
+
constructor(opts: TaskAuctionOptions);
|
|
1714
|
+
/**
|
|
1715
|
+
* Detach all FleetBus subscriptions and cancel any open bid-window timers.
|
|
1716
|
+
* Call when the owning coordinator stops/restarts so handlers and timers
|
|
1717
|
+
* don't accumulate across cycles.
|
|
1718
|
+
*/
|
|
1719
|
+
dispose(): void;
|
|
1720
|
+
/**
|
|
1721
|
+
* Publish a new task to the auction. Creates a GoalNode and broadcasts
|
|
1722
|
+
* it to all online agents. Returns the goal id.
|
|
1723
|
+
*
|
|
1724
|
+
* If `targetAgent` is specified, the task is assigned directly without auction.
|
|
1725
|
+
*/
|
|
1726
|
+
publishTask(input: {
|
|
1727
|
+
title: string;
|
|
1728
|
+
description: string;
|
|
1729
|
+
priority?: GoalPriority;
|
|
1730
|
+
tags?: string[];
|
|
1731
|
+
targetAgent?: string;
|
|
1732
|
+
parentGoal?: string;
|
|
1733
|
+
satisfiesGoals?: string[];
|
|
1734
|
+
/** Goal ids that must reach 'done' before this goal becomes workable. */
|
|
1735
|
+
blockedBy?: string[];
|
|
1736
|
+
deadline?: string;
|
|
1737
|
+
reward?: string;
|
|
1738
|
+
}): Promise<string>;
|
|
1739
|
+
/**
|
|
1740
|
+
* Submit a bid for a task. Called by agents who want to work on it.
|
|
1741
|
+
* Returns true if the bid was accepted, false if the task was already claimed.
|
|
1742
|
+
*/
|
|
1743
|
+
bid(taskId: string, agent: {
|
|
1744
|
+
agentId: string;
|
|
1745
|
+
agentName: string;
|
|
1746
|
+
agentRole: string;
|
|
1747
|
+
}, rationale: string): Promise<boolean>;
|
|
1748
|
+
/**
|
|
1749
|
+
* Award a task to a specific agent. Called internally by the bid window
|
|
1750
|
+
* expiry, or can be called directly to force an award.
|
|
1751
|
+
*/
|
|
1752
|
+
claim(taskId: string, agentId: string, agentName: string): Promise<boolean>;
|
|
1753
|
+
/**
|
|
1754
|
+
* Mark a task as done. Called by the agent when it finishes.
|
|
1755
|
+
*/
|
|
1756
|
+
complete(taskId: string, _result?: string): Promise<void>;
|
|
1757
|
+
/**
|
|
1758
|
+
* Mark a task as failed. Optionally spawn a retry.
|
|
1759
|
+
*/
|
|
1760
|
+
fail(taskId: string, error: string): Promise<void>;
|
|
1761
|
+
/**
|
|
1762
|
+
* Find the best available tasks for an agent based on its capabilities.
|
|
1763
|
+
* Returns tasks sorted by match score (best first).
|
|
1764
|
+
*/
|
|
1765
|
+
findWork(_agentId: string, agentRole: string, limit?: number): Promise<{
|
|
1766
|
+
task: GoalNode;
|
|
1767
|
+
score: number;
|
|
1768
|
+
bids: number;
|
|
1769
|
+
}[]>;
|
|
1770
|
+
/** Get all pending tasks (available for bidding). */
|
|
1771
|
+
getPendingTasks(): GoalNode[];
|
|
1772
|
+
/** Get tasks assigned to a specific agent. */
|
|
1773
|
+
getTasksForAgent(agentId: string): GoalNode[];
|
|
1774
|
+
/** Get the current bid count for a task. */
|
|
1775
|
+
getBidCount(taskId: string): number;
|
|
1776
|
+
/** Get bids for a task. */
|
|
1777
|
+
getBids(taskId: string): TaskBid[];
|
|
1778
|
+
/** Get task stats for a project-wide dashboard. */
|
|
1779
|
+
getStats(): {
|
|
1780
|
+
total: number;
|
|
1781
|
+
pending: number;
|
|
1782
|
+
in_progress: number;
|
|
1783
|
+
done: number;
|
|
1784
|
+
failed: number;
|
|
1785
|
+
totalBids: number;
|
|
1786
|
+
avgBidsPerTask: number;
|
|
1787
|
+
};
|
|
1788
|
+
private _emit;
|
|
1789
|
+
private _broadcastTask;
|
|
1790
|
+
private _mailboxPublish;
|
|
1791
|
+
private _notifyAgent;
|
|
1792
|
+
private _startBidWindow;
|
|
1793
|
+
private _cancelBidWindow;
|
|
1794
|
+
private _evaluateBids;
|
|
1795
|
+
private _assignDirect;
|
|
1796
|
+
private _onBidEvent;
|
|
1797
|
+
private _onClaimedEvent;
|
|
1798
|
+
private _getAgentTaskCount;
|
|
1799
|
+
private agentTaskCount;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1274
1802
|
/**
|
|
1275
1803
|
* ConsensusProtocol — agent voting on proposed changes.
|
|
1276
1804
|
*
|
|
@@ -1471,343 +1999,56 @@ declare class ChangeManager {
|
|
|
1471
1999
|
private readonly checks;
|
|
1472
2000
|
/** Track applied changes for rollback lookup. */
|
|
1473
2001
|
private readonly appliedChanges;
|
|
1474
|
-
constructor(opts: ChangeManagerOptions);
|
|
1475
|
-
/**
|
|
1476
|
-
* Propose a new code change. Creates a ChangeNode in the knowledge graph.
|
|
1477
|
-
* Does NOT automatically initiate voting — call `submitForReview()` for that.
|
|
1478
|
-
*/
|
|
1479
|
-
propose(input: ChangeProposal): Promise<ChangeNode>;
|
|
1480
|
-
/**
|
|
1481
|
-
* Submit an approved change for application.
|
|
1482
|
-
* Returns the change node — actual file mutations are performed by agents
|
|
1483
|
-
* acting on this node's data from the knowledge graph.
|
|
1484
|
-
*/
|
|
1485
|
-
submitForReview(changeId: string): Promise<void>;
|
|
1486
|
-
/**
|
|
1487
|
-
* Apply an approved change. Updates the change node to 'applied'.
|
|
1488
|
-
* Agents should watch for 'applied' status and perform the actual file mutations.
|
|
1489
|
-
*/
|
|
1490
|
-
markApplied(changeId: string, appliedAt: string): Promise<ChangeNode | null>;
|
|
1491
|
-
/**
|
|
1492
|
-
* Mark a change as applied and trigger rollback for any satisfied goal
|
|
1493
|
-
* that turns out to be broken.
|
|
1494
|
-
*/
|
|
1495
|
-
markAppliedWithVerification(changeId: string, verify: () => Promise<QualityGateResult>): Promise<ApplyResult>;
|
|
1496
|
-
/**
|
|
1497
|
-
* Propose a rollback for an applied change. Creates a new change that
|
|
1498
|
-
* reverses the original. Goes through full consensus.
|
|
1499
|
-
*/
|
|
1500
|
-
proposeRollback(appliedChangeId: string, reason: string): Promise<ChangeNode | null>;
|
|
1501
|
-
/**
|
|
1502
|
-
* Mark a change as rolled back.
|
|
1503
|
-
*/
|
|
1504
|
-
markRolledBack(changeId: string, rolledBackAt: string): Promise<ChangeNode | null>;
|
|
1505
|
-
getPendingReviews(): ChangeNode[];
|
|
1506
|
-
getAppliedChanges(): ChangeNode[];
|
|
1507
|
-
getChange(id: string): ChangeNode | undefined;
|
|
1508
|
-
getChangesForGoal(goalId: string): ChangeNode[];
|
|
1509
|
-
/**
|
|
1510
|
-
* Run quality gate checks. This is informational — actual test/lint/typecheck
|
|
1511
|
-
* execution is done by agents spawned for this purpose. This method stores
|
|
1512
|
-
* the result in the change node.
|
|
1513
|
-
*/
|
|
1514
|
-
private _runQualityGate;
|
|
1515
|
-
/**
|
|
1516
|
-
* Update quality gate result for a change. Called by verify agents
|
|
1517
|
-
* after running their checks.
|
|
1518
|
-
*/
|
|
1519
|
-
updateQualityGate(changeId: string, checkName: string, result: {
|
|
1520
|
-
passed: boolean;
|
|
1521
|
-
detail?: string;
|
|
1522
|
-
}): Promise<void>;
|
|
1523
|
-
private _emit;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
type AutonomousDecisionType = 'spawn' | 'approve_change' | 'reject_change' | 'prioritize_goals' | 'escalate_task' | 'rollback_change' | 'retry_task' | 'merge_results' | 'decompose_goal' | 'assign_task';
|
|
1527
|
-
interface AutonomousDecisionRequest {
|
|
1528
|
-
id: string;
|
|
1529
|
-
source: BrainDecisionSource;
|
|
1530
|
-
decisionType: AutonomousDecisionType;
|
|
1531
|
-
question: string;
|
|
1532
|
-
context: {
|
|
1533
|
-
/** Relevant facts from the knowledge graph */
|
|
1534
|
-
facts?: FactNode[];
|
|
1535
|
-
/** Goals relevant to this decision */
|
|
1536
|
-
goals?: GoalNode[];
|
|
1537
|
-
/** Change being reviewed (for approval decisions) */
|
|
1538
|
-
change?: ChangeNode;
|
|
1539
|
-
/** Current fleet status */
|
|
1540
|
-
fleetStatus?: {
|
|
1541
|
-
running: number;
|
|
1542
|
-
idle: number;
|
|
1543
|
-
total: number;
|
|
1544
|
-
costSoFar: number;
|
|
1545
|
-
};
|
|
1546
|
-
/** Task that triggered this decision */
|
|
1547
|
-
taskDescription?: string;
|
|
1548
|
-
/** Error that triggered escalation, if any */
|
|
1549
|
-
error?: string;
|
|
1550
|
-
/** Number of times this task has been attempted */
|
|
1551
|
-
attempts?: number;
|
|
1552
|
-
};
|
|
1553
|
-
options: BrainDecisionOption[];
|
|
1554
|
-
risk: BrainRisk;
|
|
1555
|
-
/** Whether this decision requires consensus */
|
|
1556
|
-
requiresConsensus: boolean;
|
|
1557
|
-
}
|
|
1558
|
-
interface SpawnDecision {
|
|
1559
|
-
role: string;
|
|
1560
|
-
budget: {
|
|
1561
|
-
timeoutMs?: number;
|
|
1562
|
-
maxIterations?: number;
|
|
1563
|
-
maxToolCalls?: number;
|
|
1564
|
-
maxCostUsd?: number;
|
|
1565
|
-
};
|
|
1566
|
-
rationale: string;
|
|
1567
|
-
}
|
|
1568
|
-
interface ApprovalDecision {
|
|
1569
|
-
approved: boolean;
|
|
1570
|
-
rationale: string;
|
|
1571
|
-
waivers?: string[];
|
|
1572
|
-
conditions?: string[];
|
|
1573
|
-
}
|
|
1574
|
-
interface PrioritizationDecision {
|
|
1575
|
-
orderedGoals: string[];
|
|
1576
|
-
rationale: string;
|
|
1577
|
-
}
|
|
1578
|
-
interface EscalationDecision {
|
|
1579
|
-
action: 'retry' | 'delegate' | 'mark_failed' | 'ask_for_help';
|
|
1580
|
-
rationale: string;
|
|
1581
|
-
budgetAdjustment?: {
|
|
1582
|
-
increaseFactor?: number;
|
|
1583
|
-
newTimeoutMs?: number;
|
|
1584
|
-
addModel?: string;
|
|
1585
|
-
};
|
|
1586
|
-
}
|
|
1587
|
-
interface AutonomousBrainOptions {
|
|
1588
|
-
/** The LLM provider for making decisions */
|
|
1589
|
-
llmProvider: LLMProvider;
|
|
1590
|
-
graph: KnowledgeGraph;
|
|
1591
|
-
fleet?: FleetBus | undefined;
|
|
1592
|
-
/** Maximum retries before a task is marked failed. Default: 3. */
|
|
1593
|
-
maxRetries?: number | undefined;
|
|
1594
|
-
/** Risk threshold above which consensus is required. Default: 'high'. */
|
|
1595
|
-
consensusRiskThreshold?: BrainRisk | undefined;
|
|
1596
|
-
/** Self-improve: track decision history for learning. Default: true. */
|
|
1597
|
-
selfImprove?: boolean | undefined;
|
|
1598
|
-
}
|
|
1599
|
-
interface LLMProvider {
|
|
1600
|
-
/**
|
|
1601
|
-
* Generate a decision. Receives the full context as a structured prompt.
|
|
1602
|
-
* Returns the chosen option id and rationale.
|
|
1603
|
-
*/
|
|
1604
|
-
decide(prompt: DecisionPrompt): Promise<{
|
|
1605
|
-
optionId: string;
|
|
1606
|
-
rationale: string;
|
|
1607
|
-
}>;
|
|
1608
|
-
}
|
|
1609
|
-
interface DecisionPrompt {
|
|
1610
|
-
decisionType: AutonomousDecisionType;
|
|
1611
|
-
question: string;
|
|
1612
|
-
context: string;
|
|
1613
|
-
options: BrainDecisionOption[];
|
|
1614
|
-
risk: BrainRisk;
|
|
1615
|
-
decisionHistory: DecisionNode[];
|
|
1616
|
-
/** Hints derived from self-improvement data */
|
|
1617
|
-
selfImproveHints?: string[];
|
|
1618
|
-
}
|
|
1619
|
-
declare class AutonomousBrain implements BrainArbiter {
|
|
1620
|
-
private readonly graph;
|
|
1621
|
-
private readonly fleetBus?;
|
|
1622
|
-
private readonly llmProvider;
|
|
1623
|
-
private readonly maxRetries;
|
|
1624
|
-
private readonly consensusRiskThreshold;
|
|
1625
|
-
private readonly selfImprove;
|
|
1626
|
-
/** Decision history for self-improvement and audit. */
|
|
1627
|
-
private decisionHistory;
|
|
1628
|
-
/** Tracks failure patterns for self-improvement. */
|
|
1629
|
-
private failurePatterns;
|
|
1630
|
-
private readonly RISK_ORDER;
|
|
1631
|
-
private _emit;
|
|
1632
|
-
constructor(opts: AutonomousBrainOptions);
|
|
1633
|
-
/** Implements BrainArbiter — bridges standard brain.ts interface to autonomous engine. */
|
|
1634
|
-
decide(request: BrainDecisionRequest): Promise<BrainDecision>;
|
|
1635
|
-
/**
|
|
1636
|
-
* Primary autonomous decision engine — receives AutonomousDecisionRequest,
|
|
1637
|
-
* queries the LLM, records the decision, and returns a BrainDecision.
|
|
1638
|
-
*
|
|
1639
|
-
* Specialized methods (decideSpawn, decideApproval, etc.) should call this
|
|
1640
|
-
* directly with a pre-built AutonomousDecisionRequest.
|
|
1641
|
-
*/
|
|
1642
|
-
decideAuto(request: AutonomousDecisionRequest): Promise<BrainDecision>;
|
|
1643
|
-
/**
|
|
1644
|
-
* Decide whether to spawn a subagent, which role to use, and what budget.
|
|
1645
|
-
*/
|
|
1646
|
-
decideSpawn(source: BrainDecisionSource, taskDescription: string, availableFacts: FactNode[], fleetStatus: {
|
|
1647
|
-
running: number;
|
|
1648
|
-
idle: number;
|
|
1649
|
-
total: number;
|
|
1650
|
-
costSoFar: number;
|
|
1651
|
-
}): Promise<BrainDecision>;
|
|
1652
|
-
/**
|
|
1653
|
-
* Decide whether to approve a proposed change.
|
|
1654
|
-
*/
|
|
1655
|
-
decideApproval(source: BrainDecisionSource, change: ChangeNode, relevantFacts: FactNode[]): Promise<BrainDecision>;
|
|
1656
|
-
/**
|
|
1657
|
-
* Decide how to handle a failed task.
|
|
1658
|
-
*/
|
|
1659
|
-
decideEscalation(source: BrainDecisionSource, taskId: string, error: string, attempts: number): Promise<BrainDecision>;
|
|
1660
|
-
/**
|
|
1661
|
-
* Record the outcome of a decision for self-improvement.
|
|
1662
|
-
* Call this after a spawned agent completes or a change is applied.
|
|
1663
|
-
*/
|
|
1664
|
-
recordOutcome(decisionId: string, outcome: 'success' | 'failure', _detail?: string): void;
|
|
1665
|
-
private _getSelfImproveHints;
|
|
1666
|
-
private _toAutonomous;
|
|
1667
|
-
private _inferDecisionType;
|
|
1668
|
-
private _serializeContext;
|
|
1669
|
-
private _loadHistory;
|
|
1670
|
-
private _recordDecision;
|
|
1671
|
-
private _inferRoles;
|
|
1672
|
-
private _changeRisk;
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
interface TaskBid {
|
|
1676
|
-
id: string;
|
|
1677
|
-
taskId: string;
|
|
1678
|
-
agentId: string;
|
|
1679
|
-
agentName: string;
|
|
1680
|
-
agentRole: string;
|
|
1681
|
-
/** Dispatcher score for this task */
|
|
1682
|
-
score: number;
|
|
1683
|
-
/** Why this agent is a good fit */
|
|
1684
|
-
rationale: string;
|
|
1685
|
-
submittedAt: string;
|
|
1686
|
-
}
|
|
1687
|
-
interface TaskAuctionOptions {
|
|
1688
|
-
graph: KnowledgeGraph;
|
|
1689
|
-
fleet?: FleetBus | undefined;
|
|
1690
|
-
mailbox?: Mailbox | undefined;
|
|
1691
|
-
selfAgentId?: string | undefined;
|
|
1692
|
-
/** How long a bid window stays open before auto-awarding. Default: 30s */
|
|
1693
|
-
bidWindowMs?: number | undefined;
|
|
1694
|
-
/** Maximum concurrent tasks per agent. Default: 3 */
|
|
1695
|
-
maxTasksPerAgent?: number | undefined;
|
|
1696
|
-
/** Minimum confidence threshold for dispatcher scoring. Default: 0.3 */
|
|
1697
|
-
minConfidence?: number | undefined;
|
|
1698
|
-
/**
|
|
1699
|
-
* Maximum times a task can be republished when no bids are received.
|
|
1700
|
-
* After this, the task is marked as 'failed' with reason 'no_bids'.
|
|
1701
|
-
* Default: 3.
|
|
1702
|
-
*/
|
|
1703
|
-
maxBidRetries?: number | undefined;
|
|
1704
|
-
}
|
|
1705
|
-
declare class TaskAuctioneer {
|
|
1706
|
-
private readonly graph;
|
|
1707
|
-
private readonly fleet?;
|
|
1708
|
-
private readonly mailbox?;
|
|
1709
|
-
private readonly selfAgentId;
|
|
1710
|
-
private readonly bidWindowMs;
|
|
1711
|
-
private readonly maxTasksPerAgent;
|
|
1712
|
-
private readonly minConfidence;
|
|
1713
|
-
private readonly maxBidRetries;
|
|
1714
|
-
/** Pending bids keyed by taskId. */
|
|
1715
|
-
private readonly pendingBids;
|
|
1716
|
-
/** Active bid windows keyed by taskId. */
|
|
1717
|
-
private readonly bidTimers;
|
|
1718
|
-
/** FleetBus subscription disposers, detached in dispose(). */
|
|
1719
|
-
private readonly unsubs;
|
|
1720
|
-
/** How many times a task has been republished with no bids received. */
|
|
1721
|
-
private readonly bidRetryCounts;
|
|
1722
|
-
/** Agent → current task count (from graph + in-flight). */
|
|
1723
|
-
private readonly agentTaskCounts;
|
|
1724
|
-
constructor(opts: TaskAuctionOptions);
|
|
2002
|
+
constructor(opts: ChangeManagerOptions);
|
|
1725
2003
|
/**
|
|
1726
|
-
*
|
|
1727
|
-
*
|
|
1728
|
-
* don't accumulate across cycles.
|
|
2004
|
+
* Propose a new code change. Creates a ChangeNode in the knowledge graph.
|
|
2005
|
+
* Does NOT automatically initiate voting — call `submitForReview()` for that.
|
|
1729
2006
|
*/
|
|
1730
|
-
|
|
2007
|
+
propose(input: ChangeProposal): Promise<ChangeNode>;
|
|
1731
2008
|
/**
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1734
|
-
*
|
|
1735
|
-
* If `targetAgent` is specified, the task is assigned directly without auction.
|
|
2009
|
+
* Submit an approved change for application.
|
|
2010
|
+
* Returns the change node — actual file mutations are performed by agents
|
|
2011
|
+
* acting on this node's data from the knowledge graph.
|
|
1736
2012
|
*/
|
|
1737
|
-
|
|
1738
|
-
title: string;
|
|
1739
|
-
description: string;
|
|
1740
|
-
priority?: GoalPriority;
|
|
1741
|
-
tags?: string[];
|
|
1742
|
-
targetAgent?: string;
|
|
1743
|
-
parentGoal?: string;
|
|
1744
|
-
satisfiesGoals?: string[];
|
|
1745
|
-
/** Goal ids that must reach 'done' before this goal becomes workable. */
|
|
1746
|
-
blockedBy?: string[];
|
|
1747
|
-
deadline?: string;
|
|
1748
|
-
reward?: string;
|
|
1749
|
-
}): Promise<string>;
|
|
2013
|
+
submitForReview(changeId: string): Promise<void>;
|
|
1750
2014
|
/**
|
|
1751
|
-
*
|
|
1752
|
-
*
|
|
2015
|
+
* Apply an approved change. Updates the change node to 'applied'.
|
|
2016
|
+
* Agents should watch for 'applied' status and perform the actual file mutations.
|
|
1753
2017
|
*/
|
|
1754
|
-
|
|
1755
|
-
agentId: string;
|
|
1756
|
-
agentName: string;
|
|
1757
|
-
agentRole: string;
|
|
1758
|
-
}, rationale: string): Promise<boolean>;
|
|
2018
|
+
markApplied(changeId: string, appliedAt: string): Promise<ChangeNode | null>;
|
|
1759
2019
|
/**
|
|
1760
|
-
*
|
|
1761
|
-
*
|
|
2020
|
+
* Mark a change as applied and trigger rollback for any satisfied goal
|
|
2021
|
+
* that turns out to be broken.
|
|
1762
2022
|
*/
|
|
1763
|
-
|
|
2023
|
+
markAppliedWithVerification(changeId: string, verify: () => Promise<QualityGateResult>): Promise<ApplyResult>;
|
|
1764
2024
|
/**
|
|
1765
|
-
*
|
|
2025
|
+
* Propose a rollback for an applied change. Creates a new change that
|
|
2026
|
+
* reverses the original. Goes through full consensus.
|
|
1766
2027
|
*/
|
|
1767
|
-
|
|
2028
|
+
proposeRollback(appliedChangeId: string, reason: string): Promise<ChangeNode | null>;
|
|
1768
2029
|
/**
|
|
1769
|
-
* Mark a
|
|
2030
|
+
* Mark a change as rolled back.
|
|
1770
2031
|
*/
|
|
1771
|
-
|
|
2032
|
+
markRolledBack(changeId: string, rolledBackAt: string): Promise<ChangeNode | null>;
|
|
2033
|
+
getPendingReviews(): ChangeNode[];
|
|
2034
|
+
getAppliedChanges(): ChangeNode[];
|
|
2035
|
+
getChange(id: string): ChangeNode | undefined;
|
|
2036
|
+
getChangesForGoal(goalId: string): ChangeNode[];
|
|
1772
2037
|
/**
|
|
1773
|
-
*
|
|
1774
|
-
*
|
|
2038
|
+
* Run quality gate checks. This is informational — actual test/lint/typecheck
|
|
2039
|
+
* execution is done by agents spawned for this purpose. This method stores
|
|
2040
|
+
* the result in the change node.
|
|
1775
2041
|
*/
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
/** Get the current bid count for a task. */
|
|
1786
|
-
getBidCount(taskId: string): number;
|
|
1787
|
-
/** Get bids for a task. */
|
|
1788
|
-
getBids(taskId: string): TaskBid[];
|
|
1789
|
-
/** Get task stats for a project-wide dashboard. */
|
|
1790
|
-
getStats(): {
|
|
1791
|
-
total: number;
|
|
1792
|
-
pending: number;
|
|
1793
|
-
in_progress: number;
|
|
1794
|
-
done: number;
|
|
1795
|
-
failed: number;
|
|
1796
|
-
totalBids: number;
|
|
1797
|
-
avgBidsPerTask: number;
|
|
1798
|
-
};
|
|
2042
|
+
private _runQualityGate;
|
|
2043
|
+
/**
|
|
2044
|
+
* Update quality gate result for a change. Called by verify agents
|
|
2045
|
+
* after running their checks.
|
|
2046
|
+
*/
|
|
2047
|
+
updateQualityGate(changeId: string, checkName: string, result: {
|
|
2048
|
+
passed: boolean;
|
|
2049
|
+
detail?: string;
|
|
2050
|
+
}): Promise<void>;
|
|
1799
2051
|
private _emit;
|
|
1800
|
-
private _broadcastTask;
|
|
1801
|
-
private _mailboxPublish;
|
|
1802
|
-
private _notifyAgent;
|
|
1803
|
-
private _startBidWindow;
|
|
1804
|
-
private _cancelBidWindow;
|
|
1805
|
-
private _evaluateBids;
|
|
1806
|
-
private _assignDirect;
|
|
1807
|
-
private _onBidEvent;
|
|
1808
|
-
private _onClaimedEvent;
|
|
1809
|
-
private _getAgentTaskCount;
|
|
1810
|
-
private agentTaskCount;
|
|
1811
2052
|
}
|
|
1812
2053
|
|
|
1813
2054
|
/**
|
|
@@ -2038,156 +2279,4 @@ declare class AutonomousCoordinator {
|
|
|
2038
2279
|
private _emit;
|
|
2039
2280
|
}
|
|
2040
2281
|
|
|
2041
|
-
|
|
2042
|
-
/** Unique entry id (ULID or timestamp-based). */
|
|
2043
|
-
id: string;
|
|
2044
|
-
/** Subagent id this entry belongs to. */
|
|
2045
|
-
subagentId: string;
|
|
2046
|
-
/** Human-readable agent name/role. */
|
|
2047
|
-
agentName: string;
|
|
2048
|
-
/** ISO 8601 timestamp. */
|
|
2049
|
-
ts: string;
|
|
2050
|
-
/** Content type. */
|
|
2051
|
-
kind: 'text' | 'tool_use' | 'tool_result' | 'error' | 'status' | 'system';
|
|
2052
|
-
/** The message content (text, tool summary, error message, status text). */
|
|
2053
|
-
content: string;
|
|
2054
|
-
/** Iteration index within the subagent's run. */
|
|
2055
|
-
iteration: number;
|
|
2056
|
-
/** For tool entries: tool name. */
|
|
2057
|
-
toolName?: string | undefined;
|
|
2058
|
-
/** For tool entries: whether the tool succeeded. */
|
|
2059
|
-
toolOk?: boolean | undefined;
|
|
2060
|
-
/** Running cost estimate. */
|
|
2061
|
-
costUsd?: number | undefined;
|
|
2062
|
-
}
|
|
2063
|
-
interface AgentVirtualSession {
|
|
2064
|
-
subagentId: string;
|
|
2065
|
-
agentName: string;
|
|
2066
|
-
createdAt: string;
|
|
2067
|
-
status: string;
|
|
2068
|
-
task?: string | undefined;
|
|
2069
|
-
/** Ordered transcript entries (newest last). */
|
|
2070
|
-
transcript: AgentTimelineEntry[];
|
|
2071
|
-
}
|
|
2072
|
-
interface AgentMonitorOptions {
|
|
2073
|
-
/** Parent/host session id for emitted agent timeline/status events. */
|
|
2074
|
-
sessionId?: string | undefined;
|
|
2075
|
-
/** The FleetBus to listen on for subagent events. Optional — set via `setFleetBus()` before `start()`. */
|
|
2076
|
-
fleetBus?: FleetBus | undefined;
|
|
2077
|
-
/** Local EventBus for emitting agent.timeline.* and agent.status_changed events. */
|
|
2078
|
-
events: EventBus;
|
|
2079
|
-
/** Directory where per-subagent JSONL transcripts will be written. */
|
|
2080
|
-
transcriptsDir: string;
|
|
2081
|
-
/** Maximum in-memory entries per subagent (ring buffer). Default 500. */
|
|
2082
|
-
maxEntriesPerAgent?: number;
|
|
2083
|
-
/** Whether agent stream is initially enabled. Default false. */
|
|
2084
|
-
streamEnabled?: boolean;
|
|
2085
|
-
/** Called for each new timeline entry — used by HQ publisher bridge. */
|
|
2086
|
-
onEntry?: ((entry: AgentTimelineEntry) => void) | undefined;
|
|
2087
|
-
}
|
|
2088
|
-
declare class AgentMonitorService {
|
|
2089
|
-
private _fleetBus;
|
|
2090
|
-
private readonly _events;
|
|
2091
|
-
private readonly _sessionId;
|
|
2092
|
-
private readonly _transcriptsDir;
|
|
2093
|
-
private readonly _maxEntries;
|
|
2094
|
-
private _streamEnabled;
|
|
2095
|
-
private _onEntry;
|
|
2096
|
-
/** Per-subagent virtual sessions. */
|
|
2097
|
-
private readonly _sessions;
|
|
2098
|
-
/** Disposers for FleetBus subscriptions, keyed by subagentId. */
|
|
2099
|
-
private readonly _subscriptions;
|
|
2100
|
-
/** Generic fleet-wide subscription disposer. */
|
|
2101
|
-
private _fleetDisposer;
|
|
2102
|
-
/** Track whether service is running. */
|
|
2103
|
-
private _started;
|
|
2104
|
-
constructor(opts: AgentMonitorOptions);
|
|
2105
|
-
/** Set the FleetBus to listen on. Must be called before `start()`. */
|
|
2106
|
-
setFleetBus(bus: FleetBus): void;
|
|
2107
|
-
get streamEnabled(): boolean;
|
|
2108
|
-
/** Enable/disable streaming agent conversations to the main chat timeline. */
|
|
2109
|
-
setStreamEnabled(enabled: boolean): void;
|
|
2110
|
-
/** Get a snapshot of all known agent sessions. */
|
|
2111
|
-
getAllSessions(): AgentVirtualSession[];
|
|
2112
|
-
/** Get a specific agent's virtual session, or undefined. */
|
|
2113
|
-
getSession(subagentId: string): AgentVirtualSession | undefined;
|
|
2114
|
-
/** Get transcript entries for a specific agent, newest first. */
|
|
2115
|
-
getTranscript(subagentId: string, limit?: number): AgentTimelineEntry[];
|
|
2116
|
-
/** Set a callback for each new timeline entry (HQ bridge). */
|
|
2117
|
-
setOnEntry(handler: ((entry: AgentTimelineEntry) => void) | undefined): void;
|
|
2118
|
-
/** Start listening to FleetBus events. */
|
|
2119
|
-
start(): void;
|
|
2120
|
-
/** Stop listening and clean up all subscriptions. */
|
|
2121
|
-
stop(): void;
|
|
2122
|
-
/** Ensure a subagent is being tracked. Called when a subagent spawns. */
|
|
2123
|
-
trackSubagent(subagentId: string, agentName: string, task?: string): void;
|
|
2124
|
-
/** Mark a subagent as completed/failed/etc. Called on subagent finish. */
|
|
2125
|
-
completeSubagent(subagentId: string, status: 'completed' | 'failed' | 'timeout' | 'stopped' | 'budget_exhausted', summary?: string): void;
|
|
2126
|
-
private _routeEvent;
|
|
2127
|
-
private _addEntry;
|
|
2128
|
-
private _appendToFile;
|
|
2129
|
-
private _uid;
|
|
2130
|
-
}
|
|
2131
|
-
declare function createAgentMonitorService(opts: AgentMonitorOptions): AgentMonitorService;
|
|
2132
|
-
|
|
2133
|
-
/**
|
|
2134
|
-
* Adaptive Concurrency Controller
|
|
2135
|
-
*
|
|
2136
|
-
* Automatically adjusts `maxConcurrent` based on:
|
|
2137
|
-
* - Rate limit (429) errors → decrease concurrency
|
|
2138
|
-
* - Sustained successful requests → increase concurrency
|
|
2139
|
-
*
|
|
2140
|
-
* This provides automatic backpressure without manual tuning.
|
|
2141
|
-
*/
|
|
2142
|
-
|
|
2143
|
-
interface AdaptiveConcurrencyState {
|
|
2144
|
-
current: number;
|
|
2145
|
-
min: number;
|
|
2146
|
-
max: number;
|
|
2147
|
-
consecutiveSuccesses: number;
|
|
2148
|
-
consecutiveFailures: number;
|
|
2149
|
-
totalDecreases: number;
|
|
2150
|
-
totalIncreases: number;
|
|
2151
|
-
enabled: boolean;
|
|
2152
|
-
}
|
|
2153
|
-
/**
|
|
2154
|
-
* Adaptive Concurrency Controller
|
|
2155
|
-
*
|
|
2156
|
-
* Monitors fleet events for rate-limit (429) errors and adjusts concurrency
|
|
2157
|
-
* automatically to prevent overwhelming the API provider.
|
|
2158
|
-
*/
|
|
2159
|
-
declare class AdaptiveConcurrencyController {
|
|
2160
|
-
private readonly config;
|
|
2161
|
-
private state;
|
|
2162
|
-
private readonly disposers;
|
|
2163
|
-
private stateChangeHandlers;
|
|
2164
|
-
constructor(fleetBus: FleetBus, setMaxConcurrent: (n: number) => void, config?: Partial<AdaptiveConcurrencyConfig>, onStateChange?: (state: AdaptiveConcurrencyState) => void);
|
|
2165
|
-
private setupEventHandlers;
|
|
2166
|
-
/**
|
|
2167
|
-
* Handle a rate limit (429) error - decrease concurrency
|
|
2168
|
-
*/
|
|
2169
|
-
private handleRateLimit;
|
|
2170
|
-
/**
|
|
2171
|
-
* Force a decrease (e.g., manual trigger or other error types)
|
|
2172
|
-
*/
|
|
2173
|
-
decrease(target?: number): void;
|
|
2174
|
-
/**
|
|
2175
|
-
* Get the current state
|
|
2176
|
-
*/
|
|
2177
|
-
getState(): AdaptiveConcurrencyState;
|
|
2178
|
-
/**
|
|
2179
|
-
* Update configuration at runtime
|
|
2180
|
-
*/
|
|
2181
|
-
updateConfig(config: Partial<AdaptiveConcurrencyConfig>): void;
|
|
2182
|
-
/**
|
|
2183
|
-
* Dispose of the controller and clean up event listeners
|
|
2184
|
-
*/
|
|
2185
|
-
dispose(): void;
|
|
2186
|
-
private notifyStateChange;
|
|
2187
|
-
/**
|
|
2188
|
-
* Register a state change handler
|
|
2189
|
-
*/
|
|
2190
|
-
onStateChange(handler: (state: AdaptiveConcurrencyState) => void): () => void;
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2193
|
-
export { type AcquireOptions, type AcquireResult, AdaptiveConcurrencyController, type AdaptiveConcurrencyState, AgentDefinition, AgentHeartbeatInput, type AgentMonitorOptions, AgentMonitorService, AgentRegistrationInput, type AgentTimelineEntry, type AgentVirtualSession, type ApplyResult, type ApprovalDecision, AutonomousBrain, type AutonomousBrainOptions, AutonomousCoordinator, type AutonomousCoordinatorOptions, type AutonomousDecisionRequest, type AutonomousDecisionType, BUILD_AGENTS, BrainArbiter, BrainDecision, BrainDecisionOption, BrainDecisionRequest, BrainDecisionSource, type BrainInterventionInput, BrainMonitor, type BrainMonitorOptions, BrainRisk, type ChangeFile, ChangeManager, type ChangeManagerOptions, type ChangeNode, type ChangeProposal, type ChangeStatus, ClientHeartbeatInput, ClientRegistrationInput, ClientStatus, type ConsensusOptions, ConsensusProtocol, type ConsensusResult, type CoordinatorEvent, type CoordinatorStats, type DAGEdgeEvent, type DAGEdgeHandler, type DAGNode, type DAGNodeStatus, DEFAULT_QUALITY_CHECKS, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, type DecisionNode, type DecisionPrompt, DefaultMailbox, type DepWatchEntry, type DepWatcherBridgeOptions, type DependencyWatcherConfig, Director, type DownAlertInput, type EscalationDecision, type FactCategory, type FactNode, FleetBus, FleetManager, GlobalMailbox, type GoalNode, type GoalPriority, type GoalStatus, type GraphSubscription, KNOWLEDGE_AGENTS, KnowledgeGraph, type LLMProvider, type LiveLockResult, MAILBOX_BRIDGE_LOCK_FILENAME, MAILBOX_BRIDGE_TOKEN_FILENAME, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, META_AGENTS, type MailToolsOptions, Mailbox, MailboxAckBatchInput, MailboxAckInput, MailboxAgentStatus, type MailboxBridgeLock, type MailboxHealthEvent, MailboxHealthWatchdog, type MailboxHealthWatchdogOptions, type MailboxHooksOptions, MailboxMessage, MailboxQuery, type MailboxResolver, MailboxSendInput, type MailboxToolOptions, type NodeFilter, type NodeType, type OutdatedNotifyMessage, PLANNING_AGENTS, type PackageAuthorEntry, type PackageAuthorLog, type PackageAuthorTrackerOptions, type PackageOutdatedEntry, type PackageOutdatedResult, type PackageOutdatedWatcherOptions, type PrioritizationDecision, PurgeOptions, PurgeResult, type QualityCheck, type QualityGateChecks, type QualityGateResult, type QuorumRule, REVIEW_AGENTS, type RecoveryAlertInput, type RollbackResult, type RunOptions, type RunnablesHandler, type SpawnDecision, type TaskAuctionOptions, TaskAuctioneer, type TaskBid, TaskDAG, VERIFY_AGENTS, type VoteNode, type VoteRecord, type VoteValue, type VoterConfig, type WatchdogConfig, acquireOrJoin, attachDepWatcherBridge, buildDownAlert, buildRecoveryAlert, createAgentMonitorService, createMailboxHooks, detectEcosystem, finalize, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, mailboxSessionTag, makeDependencyWatcherConfig, makeMailInboxTool, makeMailSendTool, makeMailboxTool, readLiveLock, recordPackageAction, release, resolveMailboxIdentity, startPackageOutdatedWatcher, updatePackageOutdatedStatus, validateWatchdogOptions };
|
|
2282
|
+
export { type AcquireOptions, type AcquireResult, AdaptiveConcurrencyController, type AdaptiveConcurrencyState, AgentDefinition, AgentHeartbeatInput, type AgentMonitorOptions, AgentMonitorService, AgentRegistrationInput, type AgentTimelineEntry, type AgentVirtualSession, type ApplyResult, type ApprovalDecision, AutonomousBrain, type AutonomousBrainOptions, AutonomousCoordinator, type AutonomousCoordinatorOptions, type AutonomousDecisionRequest, type AutonomousDecisionType, BUILD_AGENTS, BrainArbiter, BrainDecision, BrainDecisionOption, BrainDecisionRequest, BrainDecisionSource, type BrainInterventionInput, BrainMonitor, type BrainMonitorOptions, BrainRisk, type ChangeFile, ChangeManager, type ChangeManagerOptions, type ChangeNode, type ChangeProposal, type ChangeStatus, ClientHeartbeatInput, ClientRegistrationInput, ClientStatus, type ConsensusOptions, ConsensusProtocol, type ConsensusResult, type CoordinatorEvent, type CoordinatorStats, type DAGEdgeEvent, type DAGEdgeHandler, type DAGNode, type DAGNodeStatus, DEFAULT_QUALITY_CHECKS, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, type DecisionNode, type DecisionPrompt, DefaultMailbox, type DepWatchEntry, type DepWatcherBridgeOptions, type DependencyWatcherConfig, Director, type DownAlertInput, type EscalationDecision, type FactCategory, type FactNode, FleetBus, FleetManager, GlobalMailbox, type GoalNode, type GoalPriority, type GoalStatus, type GraphSubscription, KNOWLEDGE_AGENTS, KnowledgeGraph, type LLMProvider, type LiveLockResult, MAILBOX_BRIDGE_LOCK_FILENAME, MAILBOX_BRIDGE_TOKEN_FILENAME, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, META_AGENTS, type MailToolsOptions, Mailbox, MailboxAckBatchInput, MailboxAckInput, type MailboxActionInput, type MailboxActionResult, MailboxAgentStatus, type MailboxBridgeLock, type MailboxHealthEvent, MailboxHealthWatchdog, type MailboxHealthWatchdogOptions, type MailboxHooksOptions, MailboxMessage, type MailboxMessageAction, MailboxQuery, type MailboxResolver, MailboxSendInput, type MailboxToolOptions, type NodeFilter, type NodeType, type OutdatedNotifyMessage, PLANNING_AGENTS, type PackageAuthorEntry, type PackageAuthorLog, type PackageAuthorTrackerOptions, type PackageOutdatedEntry, type PackageOutdatedResult, type PackageOutdatedWatcherOptions, type PrioritizationDecision, PurgeOptions, PurgeResult, type QualityCheck, type QualityGateChecks, type QualityGateResult, type QuorumRule, REVIEW_AGENTS, type RecoveryAlertInput, type RollbackResult, type RunOptions, type RunnablesHandler, type SpawnDecision, type TaskAuctionOptions, TaskAuctioneer, type TaskBid, TaskDAG, VERIFY_AGENTS, type VoteNode, type VoteRecord, type VoteValue, type VoterConfig, type WatchdogConfig, acquireOrJoin, actionToAckInput, attachDepWatcherBridge, buildDownAlert, buildRecoveryAlert, createAgentMonitorService, createMailboxHooks, detectEcosystem, finalize, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, mailboxSessionTag, makeDependencyWatcherConfig, makeMailInboxTool, makeMailSendTool, makeMailboxTool, readLiveLock, recordPackageAction, release, resolveMailboxIdentity, startPackageOutdatedWatcher, updatePackageOutdatedStatus, validateWatchdogOptions };
|