@os-eco/overstory-cli 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +381 -0
- package/agents/builder.md +137 -0
- package/agents/coordinator.md +263 -0
- package/agents/lead.md +301 -0
- package/agents/merger.md +160 -0
- package/agents/monitor.md +214 -0
- package/agents/reviewer.md +140 -0
- package/agents/scout.md +119 -0
- package/agents/supervisor.md +423 -0
- package/package.json +47 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +101 -0
- package/src/agents/hooks-deployer.test.ts +2040 -0
- package/src/agents/hooks-deployer.ts +607 -0
- package/src/agents/identity.test.ts +603 -0
- package/src/agents/identity.ts +384 -0
- package/src/agents/lifecycle.test.ts +196 -0
- package/src/agents/lifecycle.ts +183 -0
- package/src/agents/manifest.test.ts +746 -0
- package/src/agents/manifest.ts +354 -0
- package/src/agents/overlay.test.ts +676 -0
- package/src/agents/overlay.ts +308 -0
- package/src/beads/client.test.ts +217 -0
- package/src/beads/client.ts +202 -0
- package/src/beads/molecules.test.ts +338 -0
- package/src/beads/molecules.ts +198 -0
- package/src/commands/agents.test.ts +322 -0
- package/src/commands/agents.ts +287 -0
- package/src/commands/clean.test.ts +670 -0
- package/src/commands/clean.ts +618 -0
- package/src/commands/completions.test.ts +342 -0
- package/src/commands/completions.ts +887 -0
- package/src/commands/coordinator.test.ts +1530 -0
- package/src/commands/coordinator.ts +733 -0
- package/src/commands/costs.test.ts +1119 -0
- package/src/commands/costs.ts +564 -0
- package/src/commands/dashboard.test.ts +308 -0
- package/src/commands/dashboard.ts +838 -0
- package/src/commands/doctor.test.ts +294 -0
- package/src/commands/doctor.ts +213 -0
- package/src/commands/errors.test.ts +647 -0
- package/src/commands/errors.ts +248 -0
- package/src/commands/feed.test.ts +578 -0
- package/src/commands/feed.ts +361 -0
- package/src/commands/group.test.ts +262 -0
- package/src/commands/group.ts +511 -0
- package/src/commands/hooks.test.ts +458 -0
- package/src/commands/hooks.ts +253 -0
- package/src/commands/init.test.ts +347 -0
- package/src/commands/init.ts +650 -0
- package/src/commands/inspect.test.ts +670 -0
- package/src/commands/inspect.ts +431 -0
- package/src/commands/log.test.ts +1454 -0
- package/src/commands/log.ts +724 -0
- package/src/commands/logs.test.ts +379 -0
- package/src/commands/logs.ts +546 -0
- package/src/commands/mail.test.ts +1270 -0
- package/src/commands/mail.ts +771 -0
- package/src/commands/merge.test.ts +670 -0
- package/src/commands/merge.ts +355 -0
- package/src/commands/metrics.test.ts +444 -0
- package/src/commands/metrics.ts +143 -0
- package/src/commands/monitor.test.ts +191 -0
- package/src/commands/monitor.ts +390 -0
- package/src/commands/nudge.test.ts +230 -0
- package/src/commands/nudge.ts +372 -0
- package/src/commands/prime.test.ts +470 -0
- package/src/commands/prime.ts +381 -0
- package/src/commands/replay.test.ts +741 -0
- package/src/commands/replay.ts +360 -0
- package/src/commands/run.test.ts +431 -0
- package/src/commands/run.ts +351 -0
- package/src/commands/sling.test.ts +657 -0
- package/src/commands/sling.ts +661 -0
- package/src/commands/spec.test.ts +203 -0
- package/src/commands/spec.ts +168 -0
- package/src/commands/status.test.ts +430 -0
- package/src/commands/status.ts +398 -0
- package/src/commands/stop.test.ts +420 -0
- package/src/commands/stop.ts +151 -0
- package/src/commands/supervisor.test.ts +187 -0
- package/src/commands/supervisor.ts +535 -0
- package/src/commands/trace.test.ts +745 -0
- package/src/commands/trace.ts +325 -0
- package/src/commands/watch.test.ts +145 -0
- package/src/commands/watch.ts +247 -0
- package/src/commands/worktree.test.ts +786 -0
- package/src/commands/worktree.ts +311 -0
- package/src/config.test.ts +822 -0
- package/src/config.ts +829 -0
- package/src/doctor/agents.test.ts +454 -0
- package/src/doctor/agents.ts +396 -0
- package/src/doctor/config-check.test.ts +190 -0
- package/src/doctor/config-check.ts +183 -0
- package/src/doctor/consistency.test.ts +651 -0
- package/src/doctor/consistency.ts +294 -0
- package/src/doctor/databases.test.ts +290 -0
- package/src/doctor/databases.ts +218 -0
- package/src/doctor/dependencies.test.ts +184 -0
- package/src/doctor/dependencies.ts +175 -0
- package/src/doctor/logs.test.ts +251 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +216 -0
- package/src/doctor/merge-queue.ts +144 -0
- package/src/doctor/structure.test.ts +291 -0
- package/src/doctor/structure.ts +198 -0
- package/src/doctor/types.ts +37 -0
- package/src/doctor/version.test.ts +136 -0
- package/src/doctor/version.ts +129 -0
- package/src/e2e/init-sling-lifecycle.test.ts +277 -0
- package/src/errors.ts +217 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +369 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/index.ts +316 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/logging/color.test.ts +142 -0
- package/src/logging/color.ts +71 -0
- package/src/logging/logger.test.ts +813 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +259 -0
- package/src/logging/reporter.ts +109 -0
- package/src/logging/sanitizer.test.ts +190 -0
- package/src/logging/sanitizer.ts +57 -0
- package/src/mail/broadcast.test.ts +203 -0
- package/src/mail/broadcast.ts +92 -0
- package/src/mail/client.test.ts +773 -0
- package/src/mail/client.ts +223 -0
- package/src/mail/store.test.ts +705 -0
- package/src/mail/store.ts +387 -0
- package/src/merge/queue.test.ts +359 -0
- package/src/merge/queue.ts +231 -0
- package/src/merge/resolver.test.ts +1345 -0
- package/src/merge/resolver.ts +645 -0
- package/src/metrics/store.test.ts +667 -0
- package/src/metrics/store.ts +445 -0
- package/src/metrics/summary.test.ts +398 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +356 -0
- package/src/metrics/transcript.ts +175 -0
- package/src/mulch/client.test.ts +671 -0
- package/src/mulch/client.ts +332 -0
- package/src/sessions/compat.test.ts +280 -0
- package/src/sessions/compat.ts +104 -0
- package/src/sessions/store.test.ts +873 -0
- package/src/sessions/store.ts +494 -0
- package/src/test-helpers.test.ts +124 -0
- package/src/test-helpers.ts +126 -0
- package/src/tracker/beads.ts +56 -0
- package/src/tracker/factory.test.ts +80 -0
- package/src/tracker/factory.ts +64 -0
- package/src/tracker/seeds.ts +182 -0
- package/src/tracker/types.ts +52 -0
- package/src/types.ts +724 -0
- package/src/watchdog/daemon.test.ts +1975 -0
- package/src/watchdog/daemon.ts +671 -0
- package/src/watchdog/health.test.ts +431 -0
- package/src/watchdog/health.ts +264 -0
- package/src/watchdog/triage.test.ts +164 -0
- package/src/watchdog/triage.ts +179 -0
- package/src/worktree/manager.test.ts +439 -0
- package/src/worktree/manager.ts +198 -0
- package/src/worktree/tmux.test.ts +1009 -0
- package/src/worktree/tmux.ts +509 -0
- package/templates/CLAUDE.md.tmpl +89 -0
- package/templates/hooks.json.tmpl +105 -0
- package/templates/overlay.md.tmpl +81 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
// === Model & Provider Types ===
|
|
2
|
+
|
|
3
|
+
/** Backward-compatible model alias for Anthropic models. */
|
|
4
|
+
export type ModelAlias = "sonnet" | "opus" | "haiku";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A model reference: either a simple alias ('sonnet') or a provider-qualified
|
|
8
|
+
* string ('provider/model', e.g. 'openrouter/openai/gpt-5.3').
|
|
9
|
+
*/
|
|
10
|
+
export type ModelRef = ModelAlias | (string & {});
|
|
11
|
+
|
|
12
|
+
/** Configuration for a model provider. */
|
|
13
|
+
export interface ProviderConfig {
|
|
14
|
+
type: "native" | "gateway";
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
authTokenEnv?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Resolved model with optional provider environment variables. */
|
|
20
|
+
export interface ResolvedModel {
|
|
21
|
+
model: string;
|
|
22
|
+
env?: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// === Task Tracker ===
|
|
26
|
+
|
|
27
|
+
/** Backend for the task tracker. Defined here for use in OverstoryConfig. */
|
|
28
|
+
export type TaskTrackerBackend = "auto" | "seeds" | "beads";
|
|
29
|
+
|
|
30
|
+
// === Project Configuration ===
|
|
31
|
+
|
|
32
|
+
/** A single quality gate command that agents must pass before reporting completion. */
|
|
33
|
+
export interface QualityGate {
|
|
34
|
+
/** Display name shown in the overlay (e.g., "Tests"). */
|
|
35
|
+
name: string;
|
|
36
|
+
/** Shell command to run (e.g., "bun test"). */
|
|
37
|
+
command: string;
|
|
38
|
+
/** Human-readable description of what passing means (e.g., "all tests must pass"). */
|
|
39
|
+
description: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface OverstoryConfig {
|
|
43
|
+
project: {
|
|
44
|
+
name: string;
|
|
45
|
+
root: string; // Absolute path to target repo
|
|
46
|
+
canonicalBranch: string; // "main" | "develop"
|
|
47
|
+
qualityGates?: QualityGate[];
|
|
48
|
+
};
|
|
49
|
+
agents: {
|
|
50
|
+
manifestPath: string; // Path to agent-manifest.json
|
|
51
|
+
baseDir: string; // Path to base agent definitions
|
|
52
|
+
maxConcurrent: number; // Rate limit ceiling
|
|
53
|
+
staggerDelayMs: number; // Delay between spawns
|
|
54
|
+
maxDepth: number; // Hierarchy depth limit (default 2)
|
|
55
|
+
maxSessionsPerRun: number; // Max total sessions per run (0 = unlimited)
|
|
56
|
+
};
|
|
57
|
+
worktrees: {
|
|
58
|
+
baseDir: string; // Where worktrees live
|
|
59
|
+
};
|
|
60
|
+
taskTracker: {
|
|
61
|
+
backend: TaskTrackerBackend; // "auto" | "seeds" | "beads"
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
};
|
|
64
|
+
mulch: {
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
domains: string[]; // Domains to prime (empty = auto-detect)
|
|
67
|
+
primeFormat: "markdown" | "xml" | "json";
|
|
68
|
+
};
|
|
69
|
+
merge: {
|
|
70
|
+
aiResolveEnabled: boolean;
|
|
71
|
+
reimagineEnabled: boolean;
|
|
72
|
+
};
|
|
73
|
+
providers: Record<string, ProviderConfig>;
|
|
74
|
+
watchdog: {
|
|
75
|
+
tier0Enabled: boolean; // Tier 0: Mechanical daemon (heartbeat, tmux/pid liveness)
|
|
76
|
+
tier0IntervalMs: number; // Default 30_000
|
|
77
|
+
tier1Enabled: boolean; // Tier 1: Triage agent (ephemeral AI analysis)
|
|
78
|
+
tier2Enabled: boolean; // Tier 2: Monitor agent (continuous patrol)
|
|
79
|
+
staleThresholdMs: number; // When to consider agent stale
|
|
80
|
+
zombieThresholdMs: number; // When to kill
|
|
81
|
+
nudgeIntervalMs: number; // Time between progressive nudge stages (default 60_000)
|
|
82
|
+
};
|
|
83
|
+
models: Partial<Record<string, ModelRef>>;
|
|
84
|
+
logging: {
|
|
85
|
+
verbose: boolean;
|
|
86
|
+
redactSecrets: boolean;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// === Agent Manifest ===
|
|
91
|
+
|
|
92
|
+
export interface AgentManifest {
|
|
93
|
+
version: string;
|
|
94
|
+
agents: Record<string, AgentDefinition>;
|
|
95
|
+
capabilityIndex: Record<string, string[]>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface AgentDefinition {
|
|
99
|
+
file: string; // Path to base agent definition (.md)
|
|
100
|
+
model: ModelRef;
|
|
101
|
+
tools: string[]; // Allowed tools
|
|
102
|
+
capabilities: string[]; // What this agent can do
|
|
103
|
+
canSpawn: boolean; // Can this agent spawn sub-workers?
|
|
104
|
+
constraints: string[]; // Machine-readable restrictions
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** All valid agent capability types. Used for compile-time validation. */
|
|
108
|
+
export const SUPPORTED_CAPABILITIES = [
|
|
109
|
+
"scout",
|
|
110
|
+
"builder",
|
|
111
|
+
"reviewer",
|
|
112
|
+
"lead",
|
|
113
|
+
"merger",
|
|
114
|
+
"coordinator",
|
|
115
|
+
"supervisor",
|
|
116
|
+
"monitor",
|
|
117
|
+
] as const;
|
|
118
|
+
|
|
119
|
+
/** Union type derived from the capabilities constant. */
|
|
120
|
+
export type Capability = (typeof SUPPORTED_CAPABILITIES)[number];
|
|
121
|
+
|
|
122
|
+
// === Agent Session ===
|
|
123
|
+
|
|
124
|
+
export type AgentState = "booting" | "working" | "completed" | "stalled" | "zombie";
|
|
125
|
+
|
|
126
|
+
export interface AgentSession {
|
|
127
|
+
id: string; // Unique session ID
|
|
128
|
+
agentName: string; // Unique per-session name
|
|
129
|
+
capability: string; // Which agent definition
|
|
130
|
+
worktreePath: string;
|
|
131
|
+
branchName: string;
|
|
132
|
+
beadId: string; // Task being worked
|
|
133
|
+
tmuxSession: string; // Tmux session name
|
|
134
|
+
state: AgentState;
|
|
135
|
+
pid: number | null; // Claude Code PID
|
|
136
|
+
parentAgent: string | null; // Who spawned this agent (null = orchestrator)
|
|
137
|
+
depth: number; // 0 = direct from orchestrator
|
|
138
|
+
runId: string | null; // Groups sessions in the same orchestrator run
|
|
139
|
+
startedAt: string;
|
|
140
|
+
lastActivity: string;
|
|
141
|
+
escalationLevel: number; // Progressive nudge stage: 0=warn, 1=nudge, 2=escalate, 3=terminate
|
|
142
|
+
stalledSince: string | null; // ISO timestamp when agent first entered stalled state
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// === Agent Identity ===
|
|
146
|
+
|
|
147
|
+
export interface AgentIdentity {
|
|
148
|
+
name: string;
|
|
149
|
+
capability: string;
|
|
150
|
+
created: string;
|
|
151
|
+
sessionsCompleted: number;
|
|
152
|
+
expertiseDomains: string[];
|
|
153
|
+
recentTasks: Array<{
|
|
154
|
+
beadId: string;
|
|
155
|
+
summary: string;
|
|
156
|
+
completedAt: string;
|
|
157
|
+
}>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// === Mail (Custom SQLite) ===
|
|
161
|
+
|
|
162
|
+
/** Semantic message types (original, human-readable). */
|
|
163
|
+
export type MailSemanticType = "status" | "question" | "result" | "error";
|
|
164
|
+
|
|
165
|
+
/** Protocol message types for structured agent coordination. */
|
|
166
|
+
export type MailProtocolType =
|
|
167
|
+
| "worker_done"
|
|
168
|
+
| "merge_ready"
|
|
169
|
+
| "merged"
|
|
170
|
+
| "merge_failed"
|
|
171
|
+
| "escalation"
|
|
172
|
+
| "health_check"
|
|
173
|
+
| "dispatch"
|
|
174
|
+
| "assign";
|
|
175
|
+
|
|
176
|
+
/** All valid mail message types. */
|
|
177
|
+
export type MailMessageType = MailSemanticType | MailProtocolType;
|
|
178
|
+
|
|
179
|
+
/** All protocol type strings as a runtime array for CHECK constraint generation. */
|
|
180
|
+
export const MAIL_MESSAGE_TYPES: readonly MailMessageType[] = [
|
|
181
|
+
"status",
|
|
182
|
+
"question",
|
|
183
|
+
"result",
|
|
184
|
+
"error",
|
|
185
|
+
"worker_done",
|
|
186
|
+
"merge_ready",
|
|
187
|
+
"merged",
|
|
188
|
+
"merge_failed",
|
|
189
|
+
"escalation",
|
|
190
|
+
"health_check",
|
|
191
|
+
"dispatch",
|
|
192
|
+
"assign",
|
|
193
|
+
] as const;
|
|
194
|
+
|
|
195
|
+
export interface MailMessage {
|
|
196
|
+
id: string; // "msg-" + nanoid(12)
|
|
197
|
+
from: string; // Agent name
|
|
198
|
+
to: string; // Agent name or "orchestrator"
|
|
199
|
+
subject: string;
|
|
200
|
+
body: string;
|
|
201
|
+
priority: "low" | "normal" | "high" | "urgent";
|
|
202
|
+
type: MailMessageType;
|
|
203
|
+
threadId: string | null; // Conversation threading
|
|
204
|
+
payload: string | null; // JSON-encoded structured data for protocol messages
|
|
205
|
+
read: boolean;
|
|
206
|
+
createdAt: string; // ISO timestamp
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// === Mail Protocol Payloads ===
|
|
210
|
+
|
|
211
|
+
/** Worker signals task completion to supervisor. */
|
|
212
|
+
export interface WorkerDonePayload {
|
|
213
|
+
beadId: string;
|
|
214
|
+
branch: string;
|
|
215
|
+
exitCode: number;
|
|
216
|
+
filesModified: string[];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Supervisor signals branch is verified and ready for merge. */
|
|
220
|
+
export interface MergeReadyPayload {
|
|
221
|
+
branch: string;
|
|
222
|
+
beadId: string;
|
|
223
|
+
agentName: string;
|
|
224
|
+
filesModified: string[];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Merger signals branch was merged successfully. */
|
|
228
|
+
export interface MergedPayload {
|
|
229
|
+
branch: string;
|
|
230
|
+
beadId: string;
|
|
231
|
+
tier: ResolutionTier;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Merger signals merge failed, needs rework. */
|
|
235
|
+
export interface MergeFailedPayload {
|
|
236
|
+
branch: string;
|
|
237
|
+
beadId: string;
|
|
238
|
+
conflictFiles: string[];
|
|
239
|
+
errorMessage: string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Any agent escalates an issue to a higher-level decision-maker. */
|
|
243
|
+
export interface EscalationPayload {
|
|
244
|
+
severity: "warning" | "error" | "critical";
|
|
245
|
+
beadId: string | null;
|
|
246
|
+
context: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** Watchdog probes agent liveness. */
|
|
250
|
+
export interface HealthCheckPayload {
|
|
251
|
+
agentName: string;
|
|
252
|
+
checkType: "liveness" | "readiness";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Coordinator dispatches work to a supervisor. */
|
|
256
|
+
export interface DispatchPayload {
|
|
257
|
+
beadId: string;
|
|
258
|
+
specPath: string;
|
|
259
|
+
capability: Capability;
|
|
260
|
+
fileScope: string[];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Supervisor assigns work to a specific worker. */
|
|
264
|
+
export interface AssignPayload {
|
|
265
|
+
beadId: string;
|
|
266
|
+
specPath: string;
|
|
267
|
+
workerName: string;
|
|
268
|
+
branch: string;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Maps protocol message types to their payload interfaces. */
|
|
272
|
+
export interface MailPayloadMap {
|
|
273
|
+
worker_done: WorkerDonePayload;
|
|
274
|
+
merge_ready: MergeReadyPayload;
|
|
275
|
+
merged: MergedPayload;
|
|
276
|
+
merge_failed: MergeFailedPayload;
|
|
277
|
+
escalation: EscalationPayload;
|
|
278
|
+
health_check: HealthCheckPayload;
|
|
279
|
+
dispatch: DispatchPayload;
|
|
280
|
+
assign: AssignPayload;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// === Overlay ===
|
|
284
|
+
|
|
285
|
+
export interface OverlayConfig {
|
|
286
|
+
agentName: string;
|
|
287
|
+
beadId: string;
|
|
288
|
+
specPath: string | null;
|
|
289
|
+
branchName: string;
|
|
290
|
+
worktreePath: string;
|
|
291
|
+
fileScope: string[];
|
|
292
|
+
mulchDomains: string[];
|
|
293
|
+
parentAgent: string | null;
|
|
294
|
+
depth: number;
|
|
295
|
+
canSpawn: boolean;
|
|
296
|
+
capability: string;
|
|
297
|
+
/** Full content of the base agent definition file (Layer 1: role-specific HOW). */
|
|
298
|
+
baseDefinition: string;
|
|
299
|
+
/** Pre-fetched mulch expertise output to embed directly in the overlay. */
|
|
300
|
+
mulchExpertise?: string;
|
|
301
|
+
/** When true, lead agents should skip Phase 1 (scout) and go straight to Phase 2 (build). */
|
|
302
|
+
skipScout?: boolean;
|
|
303
|
+
trackerCli?: string; // "sd" or "bd"
|
|
304
|
+
trackerName?: string; // "seeds" or "beads"
|
|
305
|
+
/** Quality gate commands for the agent overlay. Falls back to defaults if undefined. */
|
|
306
|
+
qualityGates?: QualityGate[];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// === Merge Queue ===
|
|
310
|
+
|
|
311
|
+
export type ResolutionTier = "clean-merge" | "auto-resolve" | "ai-resolve" | "reimagine";
|
|
312
|
+
|
|
313
|
+
export interface MergeEntry {
|
|
314
|
+
branchName: string;
|
|
315
|
+
beadId: string;
|
|
316
|
+
agentName: string;
|
|
317
|
+
filesModified: string[];
|
|
318
|
+
enqueuedAt: string;
|
|
319
|
+
status: "pending" | "merging" | "merged" | "conflict" | "failed";
|
|
320
|
+
resolvedTier: ResolutionTier | null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export interface MergeResult {
|
|
324
|
+
entry: MergeEntry;
|
|
325
|
+
success: boolean;
|
|
326
|
+
tier: ResolutionTier;
|
|
327
|
+
conflictFiles: string[];
|
|
328
|
+
errorMessage: string | null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Parsed conflict pattern from a single mulch record. */
|
|
332
|
+
export interface ParsedConflictPattern {
|
|
333
|
+
tier: ResolutionTier;
|
|
334
|
+
success: boolean;
|
|
335
|
+
files: string[];
|
|
336
|
+
agent: string;
|
|
337
|
+
branch: string;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Historical conflict data assembled from mulch search results. */
|
|
341
|
+
export interface ConflictHistory {
|
|
342
|
+
/** Tiers to skip based on historical failure rates for these files. */
|
|
343
|
+
skipTiers: ResolutionTier[];
|
|
344
|
+
/** Descriptions of past successful resolutions for AI prompt enrichment. */
|
|
345
|
+
pastResolutions: string[];
|
|
346
|
+
/** Files predicted to conflict based on historical patterns. */
|
|
347
|
+
predictedConflictFiles: string[];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// === Watchdog ===
|
|
351
|
+
|
|
352
|
+
export interface HealthCheck {
|
|
353
|
+
agentName: string;
|
|
354
|
+
timestamp: string;
|
|
355
|
+
processAlive: boolean;
|
|
356
|
+
tmuxAlive: boolean;
|
|
357
|
+
pidAlive: boolean | null; // null when pid is unavailable
|
|
358
|
+
lastActivity: string;
|
|
359
|
+
state: AgentState;
|
|
360
|
+
action: "none" | "escalate" | "terminate" | "investigate";
|
|
361
|
+
/** Describes any conflict between observable state and recorded state. */
|
|
362
|
+
reconciliationNote: string | null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// === Logging ===
|
|
366
|
+
|
|
367
|
+
export interface LogEvent {
|
|
368
|
+
timestamp: string;
|
|
369
|
+
level: "debug" | "info" | "warn" | "error";
|
|
370
|
+
event: string;
|
|
371
|
+
agentName: string | null;
|
|
372
|
+
data: Record<string, unknown>;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// === Metrics ===
|
|
376
|
+
|
|
377
|
+
export interface SessionMetrics {
|
|
378
|
+
agentName: string;
|
|
379
|
+
beadId: string;
|
|
380
|
+
capability: string;
|
|
381
|
+
startedAt: string;
|
|
382
|
+
completedAt: string | null;
|
|
383
|
+
durationMs: number;
|
|
384
|
+
exitCode: number | null;
|
|
385
|
+
mergeResult: ResolutionTier | null;
|
|
386
|
+
parentAgent: string | null;
|
|
387
|
+
inputTokens: number;
|
|
388
|
+
outputTokens: number;
|
|
389
|
+
cacheReadTokens: number;
|
|
390
|
+
cacheCreationTokens: number;
|
|
391
|
+
estimatedCostUsd: number | null;
|
|
392
|
+
modelUsed: string | null;
|
|
393
|
+
runId: string | null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** A point-in-time token usage snapshot for a running agent session. */
|
|
397
|
+
export interface TokenSnapshot {
|
|
398
|
+
agentName: string;
|
|
399
|
+
inputTokens: number;
|
|
400
|
+
outputTokens: number;
|
|
401
|
+
cacheReadTokens: number;
|
|
402
|
+
cacheCreationTokens: number;
|
|
403
|
+
estimatedCostUsd: number | null;
|
|
404
|
+
modelUsed: string | null;
|
|
405
|
+
createdAt: string;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// === Task Groups (Batch Coordination) ===
|
|
409
|
+
|
|
410
|
+
export interface TaskGroup {
|
|
411
|
+
id: string; // "group-" + nanoid(8)
|
|
412
|
+
name: string;
|
|
413
|
+
memberIssueIds: string[]; // beads issue IDs tracked by this group
|
|
414
|
+
status: "active" | "completed";
|
|
415
|
+
createdAt: string; // ISO timestamp
|
|
416
|
+
completedAt: string | null; // ISO timestamp when all members closed
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export interface TaskGroupProgress {
|
|
420
|
+
group: TaskGroup;
|
|
421
|
+
total: number;
|
|
422
|
+
completed: number;
|
|
423
|
+
inProgress: number;
|
|
424
|
+
blocked: number;
|
|
425
|
+
open: number;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// === Event Store (Observability) ===
|
|
429
|
+
|
|
430
|
+
/** Event types for agent activity tracking. */
|
|
431
|
+
export type EventType =
|
|
432
|
+
| "tool_start"
|
|
433
|
+
| "tool_end"
|
|
434
|
+
| "session_start"
|
|
435
|
+
| "session_end"
|
|
436
|
+
| "mail_sent"
|
|
437
|
+
| "mail_received"
|
|
438
|
+
| "spawn"
|
|
439
|
+
| "error"
|
|
440
|
+
| "custom";
|
|
441
|
+
|
|
442
|
+
/** Severity levels for events. */
|
|
443
|
+
export type EventLevel = "debug" | "info" | "warn" | "error";
|
|
444
|
+
|
|
445
|
+
/** All valid event level strings as a runtime array for CHECK constraint generation. */
|
|
446
|
+
export const EVENT_LEVELS: readonly EventLevel[] = ["debug", "info", "warn", "error"] as const;
|
|
447
|
+
|
|
448
|
+
/** An event as stored in the SQLite events table. */
|
|
449
|
+
export interface StoredEvent {
|
|
450
|
+
id: number;
|
|
451
|
+
runId: string | null;
|
|
452
|
+
agentName: string;
|
|
453
|
+
sessionId: string | null;
|
|
454
|
+
eventType: EventType;
|
|
455
|
+
toolName: string | null;
|
|
456
|
+
toolArgs: string | null;
|
|
457
|
+
toolDurationMs: number | null;
|
|
458
|
+
level: EventLevel;
|
|
459
|
+
data: string | null;
|
|
460
|
+
createdAt: string;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** Input for inserting a new event (id and createdAt are auto-generated). */
|
|
464
|
+
export type InsertEvent = Omit<StoredEvent, "id" | "createdAt">;
|
|
465
|
+
|
|
466
|
+
/** Options for filtering event queries. */
|
|
467
|
+
export interface EventQueryOptions {
|
|
468
|
+
limit?: number;
|
|
469
|
+
since?: string; // ISO timestamp
|
|
470
|
+
until?: string; // ISO timestamp
|
|
471
|
+
level?: EventLevel;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/** Tool usage statistics returned by getToolStats. */
|
|
475
|
+
export interface ToolStats {
|
|
476
|
+
toolName: string;
|
|
477
|
+
count: number;
|
|
478
|
+
avgDurationMs: number;
|
|
479
|
+
maxDurationMs: number;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** Interface for the SQLite-backed event store. */
|
|
483
|
+
export interface EventStore {
|
|
484
|
+
/** Insert a new event. Returns the auto-generated row ID. */
|
|
485
|
+
insert(event: InsertEvent): number;
|
|
486
|
+
/** Find the most recent unmatched tool_start for correlation. Returns start ID and duration. */
|
|
487
|
+
correlateToolEnd(
|
|
488
|
+
agentName: string,
|
|
489
|
+
toolName: string,
|
|
490
|
+
): { startId: number; durationMs: number } | null;
|
|
491
|
+
/** Get events for a specific agent. */
|
|
492
|
+
getByAgent(agentName: string, opts?: EventQueryOptions): StoredEvent[];
|
|
493
|
+
/** Get events for a specific run. */
|
|
494
|
+
getByRun(runId: string, opts?: EventQueryOptions): StoredEvent[];
|
|
495
|
+
/** Get error-level events. */
|
|
496
|
+
getErrors(opts?: EventQueryOptions): StoredEvent[];
|
|
497
|
+
/** Get a timeline of events with required options. */
|
|
498
|
+
getTimeline(opts: EventQueryOptions & { since: string }): StoredEvent[];
|
|
499
|
+
/** Get aggregated tool usage statistics. */
|
|
500
|
+
getToolStats(opts?: { agentName?: string; since?: string }): ToolStats[];
|
|
501
|
+
/** Delete events matching criteria. Returns number of rows deleted. */
|
|
502
|
+
purge(opts: { all?: boolean; olderThanMs?: number; agentName?: string }): number;
|
|
503
|
+
/** Close the database connection. */
|
|
504
|
+
close(): void;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// === Run (Coordinator Session Grouping) ===
|
|
508
|
+
|
|
509
|
+
/** Status of a run (coordinator session grouping agents). */
|
|
510
|
+
export type RunStatus = "active" | "completed" | "failed";
|
|
511
|
+
|
|
512
|
+
/** A run groups all agents spawned from one coordinator session. */
|
|
513
|
+
export interface Run {
|
|
514
|
+
id: string; // Format: run-{ISO timestamp}
|
|
515
|
+
startedAt: string;
|
|
516
|
+
completedAt: string | null;
|
|
517
|
+
agentCount: number;
|
|
518
|
+
coordinatorSessionId: string | null;
|
|
519
|
+
status: RunStatus;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/** Input for creating a new run. */
|
|
523
|
+
export type InsertRun = Omit<Run, "completedAt" | "agentCount"> & {
|
|
524
|
+
agentCount?: number;
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
/** Interface for run management operations. */
|
|
528
|
+
export interface RunStore {
|
|
529
|
+
/** Create a new run. */
|
|
530
|
+
createRun(run: InsertRun): void;
|
|
531
|
+
/** Get a run by ID, or null if not found. */
|
|
532
|
+
getRun(id: string): Run | null;
|
|
533
|
+
/** Get the most recently started active run. */
|
|
534
|
+
getActiveRun(): Run | null;
|
|
535
|
+
/** List runs, optionally limited. */
|
|
536
|
+
listRuns(opts?: { limit?: number; status?: RunStatus }): Run[];
|
|
537
|
+
/** Increment agent count for a run. */
|
|
538
|
+
incrementAgentCount(runId: string): void;
|
|
539
|
+
/** Complete a run (set status and completedAt). */
|
|
540
|
+
completeRun(runId: string, status: "completed" | "failed"): void;
|
|
541
|
+
/** Close the store (if standalone — in practice may share DB with SessionStore). */
|
|
542
|
+
close(): void;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// === Mulch CLI Results ===
|
|
546
|
+
|
|
547
|
+
/** Mulch status result (domain statistics). */
|
|
548
|
+
export interface MulchStatus {
|
|
549
|
+
domains: Array<{ name: string; recordCount: number; lastUpdated: string }>;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Result from mulch diff command. */
|
|
553
|
+
export interface MulchDiffResult {
|
|
554
|
+
success: boolean;
|
|
555
|
+
command: string;
|
|
556
|
+
since: string;
|
|
557
|
+
domains: string[];
|
|
558
|
+
message: string;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** Result from mulch learn command. */
|
|
562
|
+
export interface MulchLearnResult {
|
|
563
|
+
success: boolean;
|
|
564
|
+
command: string;
|
|
565
|
+
changedFiles: string[];
|
|
566
|
+
suggestedDomains: string[];
|
|
567
|
+
unmatchedFiles: string[];
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/** Result from mulch prune command. */
|
|
571
|
+
export interface MulchPruneResult {
|
|
572
|
+
success: boolean;
|
|
573
|
+
command: string;
|
|
574
|
+
dryRun: boolean;
|
|
575
|
+
totalPruned: number;
|
|
576
|
+
results: Array<{
|
|
577
|
+
domain: string;
|
|
578
|
+
pruned: number;
|
|
579
|
+
records: string[];
|
|
580
|
+
}>;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/** Health check result from mulch doctor. */
|
|
584
|
+
export interface MulchDoctorResult {
|
|
585
|
+
success: boolean;
|
|
586
|
+
command: string;
|
|
587
|
+
checks: Array<{
|
|
588
|
+
name: string;
|
|
589
|
+
status: "pass" | "warn" | "fail";
|
|
590
|
+
message: string;
|
|
591
|
+
fixable: boolean;
|
|
592
|
+
details: string[];
|
|
593
|
+
}>;
|
|
594
|
+
summary: {
|
|
595
|
+
pass: number;
|
|
596
|
+
warn: number;
|
|
597
|
+
fail: number;
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/** Ready records result from mulch ready. */
|
|
602
|
+
export interface MulchReadyResult {
|
|
603
|
+
success: boolean;
|
|
604
|
+
command: string;
|
|
605
|
+
count: number;
|
|
606
|
+
entries: Array<{
|
|
607
|
+
domain: string;
|
|
608
|
+
id: string;
|
|
609
|
+
type: string;
|
|
610
|
+
recorded_at: string;
|
|
611
|
+
summary: string;
|
|
612
|
+
record: Record<string, unknown>;
|
|
613
|
+
}>;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/** Result from mulch compact command. */
|
|
617
|
+
export interface MulchCompactResult {
|
|
618
|
+
success: boolean;
|
|
619
|
+
command: string;
|
|
620
|
+
action: string;
|
|
621
|
+
candidates?: Array<{
|
|
622
|
+
domain: string;
|
|
623
|
+
type: string;
|
|
624
|
+
records: Array<{
|
|
625
|
+
id: string;
|
|
626
|
+
summary: string;
|
|
627
|
+
recorded_at: string;
|
|
628
|
+
}>;
|
|
629
|
+
}>;
|
|
630
|
+
compacted?: Array<{
|
|
631
|
+
domain: string;
|
|
632
|
+
type: string;
|
|
633
|
+
before: number;
|
|
634
|
+
after: number;
|
|
635
|
+
recordIds: string[];
|
|
636
|
+
}>;
|
|
637
|
+
message?: string;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// === Session Lifecycle (Checkpoint / Handoff / Continuity) ===
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Snapshot of agent progress, saved before compaction or handoff.
|
|
644
|
+
* Stored as JSON in .overstory/agents/{name}/checkpoint.json.
|
|
645
|
+
*/
|
|
646
|
+
export interface SessionCheckpoint {
|
|
647
|
+
agentName: string;
|
|
648
|
+
beadId: string;
|
|
649
|
+
sessionId: string; // The AgentSession.id that created this checkpoint
|
|
650
|
+
timestamp: string; // ISO
|
|
651
|
+
progressSummary: string; // Human-readable summary of work done so far
|
|
652
|
+
filesModified: string[]; // Paths modified since session start
|
|
653
|
+
currentBranch: string;
|
|
654
|
+
pendingWork: string; // What remains to be done
|
|
655
|
+
mulchDomains: string[]; // Domains the agent has been working in
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Record of a session handoff — when one session ends and another picks up.
|
|
660
|
+
*/
|
|
661
|
+
export interface SessionHandoff {
|
|
662
|
+
fromSessionId: string;
|
|
663
|
+
toSessionId: string | null; // null until the new session starts
|
|
664
|
+
checkpoint: SessionCheckpoint;
|
|
665
|
+
reason: "compaction" | "crash" | "manual" | "timeout";
|
|
666
|
+
handoffAt: string; // ISO timestamp
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Three-layer model for agent persistence.
|
|
671
|
+
* Session = ephemeral Claude runtime
|
|
672
|
+
* Sandbox = git worktree (persists across sessions)
|
|
673
|
+
* Identity = permanent agent record (persists across assignments)
|
|
674
|
+
*/
|
|
675
|
+
export interface AgentLayers {
|
|
676
|
+
identity: AgentIdentity;
|
|
677
|
+
sandbox: {
|
|
678
|
+
worktreePath: string;
|
|
679
|
+
branchName: string;
|
|
680
|
+
beadId: string;
|
|
681
|
+
};
|
|
682
|
+
session: {
|
|
683
|
+
id: string;
|
|
684
|
+
pid: number | null;
|
|
685
|
+
tmuxSession: string;
|
|
686
|
+
startedAt: string;
|
|
687
|
+
checkpoint: SessionCheckpoint | null;
|
|
688
|
+
} | null; // null when sandbox exists but no active session
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// === Session Insight Analysis ===
|
|
692
|
+
|
|
693
|
+
/** A single structured insight extracted from a completed session. */
|
|
694
|
+
export interface SessionInsight {
|
|
695
|
+
/** Mulch record type for this insight. */
|
|
696
|
+
type: "pattern" | "convention" | "failure";
|
|
697
|
+
/** Mulch domain this insight belongs to. */
|
|
698
|
+
domain: string;
|
|
699
|
+
/** Human-readable description of the insight. */
|
|
700
|
+
description: string;
|
|
701
|
+
/** Tags for mulch record categorization. */
|
|
702
|
+
tags: string[];
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/** Aggregated tool usage profile for a session. */
|
|
706
|
+
export interface ToolProfile {
|
|
707
|
+
topTools: Array<{ name: string; count: number; avgMs: number }>;
|
|
708
|
+
totalToolCalls: number;
|
|
709
|
+
errorCount: number;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/** File edit frequency profile for a session. */
|
|
713
|
+
export interface FileProfile {
|
|
714
|
+
/** Files edited more than once, sorted by edit count descending. */
|
|
715
|
+
hotFiles: Array<{ path: string; editCount: number }>;
|
|
716
|
+
totalEdits: number;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/** Complete insight analysis result for a completed session. */
|
|
720
|
+
export interface InsightAnalysis {
|
|
721
|
+
insights: SessionInsight[];
|
|
722
|
+
toolProfile: ToolProfile;
|
|
723
|
+
fileProfile: FileProfile;
|
|
724
|
+
}
|