@overdeck/contracts 0.30.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/index.cjs +4505 -0
- package/dist/index.d.ts +13516 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +4199 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,4199 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import * as Rpc from "effect/unstable/rpc/Rpc";
|
|
3
|
+
import * as RpcGroup from "effect/unstable/rpc/RpcGroup";
|
|
4
|
+
//#region src/types.ts
|
|
5
|
+
const IssueId = Schema.String;
|
|
6
|
+
const AgentId = Schema.String;
|
|
7
|
+
const SequenceNumber = Schema.Number;
|
|
8
|
+
const AgentStatus = Schema.Literals([
|
|
9
|
+
"starting",
|
|
10
|
+
"running",
|
|
11
|
+
"stopped",
|
|
12
|
+
"error",
|
|
13
|
+
"unknown"
|
|
14
|
+
]);
|
|
15
|
+
const Role = Schema.Literals([
|
|
16
|
+
"plan",
|
|
17
|
+
"work",
|
|
18
|
+
"review",
|
|
19
|
+
"test",
|
|
20
|
+
"ship",
|
|
21
|
+
"flywheel",
|
|
22
|
+
"strike",
|
|
23
|
+
"sequencer"
|
|
24
|
+
]);
|
|
25
|
+
const AgentResolution = Schema.Literals([
|
|
26
|
+
"working",
|
|
27
|
+
"done",
|
|
28
|
+
"needs_input",
|
|
29
|
+
"stuck",
|
|
30
|
+
"completed",
|
|
31
|
+
"unclear",
|
|
32
|
+
"abandoned",
|
|
33
|
+
"api_error"
|
|
34
|
+
]);
|
|
35
|
+
const ReviewStatusValue = Schema.Literals([
|
|
36
|
+
"pending",
|
|
37
|
+
"reviewing",
|
|
38
|
+
"passed",
|
|
39
|
+
"failed",
|
|
40
|
+
"blocked"
|
|
41
|
+
]);
|
|
42
|
+
const TestStatusValue = Schema.Literals([
|
|
43
|
+
"pending",
|
|
44
|
+
"testing",
|
|
45
|
+
"passed",
|
|
46
|
+
"failed",
|
|
47
|
+
"skipped",
|
|
48
|
+
"dispatch_failed"
|
|
49
|
+
]);
|
|
50
|
+
const UatStatusValue = Schema.Literals([
|
|
51
|
+
"pending",
|
|
52
|
+
"testing",
|
|
53
|
+
"passed",
|
|
54
|
+
"failed"
|
|
55
|
+
]);
|
|
56
|
+
const MergeStatusValue = Schema.Literals([
|
|
57
|
+
"pending",
|
|
58
|
+
"queued",
|
|
59
|
+
"merging",
|
|
60
|
+
"verifying",
|
|
61
|
+
"merged",
|
|
62
|
+
"failed"
|
|
63
|
+
]);
|
|
64
|
+
const VerificationStatusValue = Schema.Literals([
|
|
65
|
+
"pending",
|
|
66
|
+
"running",
|
|
67
|
+
"passed",
|
|
68
|
+
"failed",
|
|
69
|
+
"skipped"
|
|
70
|
+
]);
|
|
71
|
+
const KNOWN_HARNESSES = new Set([
|
|
72
|
+
"claude-code",
|
|
73
|
+
"pi",
|
|
74
|
+
"codex"
|
|
75
|
+
]);
|
|
76
|
+
/**
|
|
77
|
+
* Normalize a snapshot's runtime field to a known Harness value.
|
|
78
|
+
* Unknown or missing values fall back to 'claude-code' (the default harness).
|
|
79
|
+
*/
|
|
80
|
+
function getHarness(snapshot) {
|
|
81
|
+
const raw = snapshot?.runtime;
|
|
82
|
+
if (raw && KNOWN_HARNESSES.has(raw)) return raw;
|
|
83
|
+
return "claude-code";
|
|
84
|
+
}
|
|
85
|
+
const Activity = Schema.Literals([
|
|
86
|
+
"working",
|
|
87
|
+
"thinking",
|
|
88
|
+
"waiting",
|
|
89
|
+
"idle",
|
|
90
|
+
"stopped"
|
|
91
|
+
]);
|
|
92
|
+
const WaitingReason = Schema.Literals([
|
|
93
|
+
"tool_permission",
|
|
94
|
+
"user_question",
|
|
95
|
+
"disambiguation",
|
|
96
|
+
"other"
|
|
97
|
+
]);
|
|
98
|
+
const ClaudeChannelPermissionBehavior = Schema.Literals(["allow", "deny"]);
|
|
99
|
+
const ThinkingState = Schema.Struct({
|
|
100
|
+
since: Schema.String,
|
|
101
|
+
lastToolAt: Schema.String
|
|
102
|
+
});
|
|
103
|
+
const WaitingState = Schema.Struct({
|
|
104
|
+
reason: WaitingReason,
|
|
105
|
+
startedAt: Schema.String,
|
|
106
|
+
message: Schema.optional(Schema.String),
|
|
107
|
+
notificationSent: Schema.optional(Schema.Boolean)
|
|
108
|
+
});
|
|
109
|
+
const CHANNEL_REPLY_KIND_VALUES = [
|
|
110
|
+
"status",
|
|
111
|
+
"done",
|
|
112
|
+
"needs_input"
|
|
113
|
+
];
|
|
114
|
+
const MAX_CHANNEL_REPLY_SUMMARY_LENGTH = 4 * 1024;
|
|
115
|
+
const MAX_CHANNEL_REPLY_ARTIFACT_REFS = 20;
|
|
116
|
+
const MAX_CHANNEL_REPLY_ARTIFACT_URI_LENGTH = 512;
|
|
117
|
+
const MAX_CHANNEL_REPLY_ARTIFACT_LABEL_LENGTH = 512;
|
|
118
|
+
const CHANNEL_REPLY_ARTIFACT_URI_PATTERN = /^(?:file:\/\/|https:\/\/|\/)/;
|
|
119
|
+
const ChannelReplyKind = Schema.Literals(CHANNEL_REPLY_KIND_VALUES);
|
|
120
|
+
function isChannelReplyKind(value) {
|
|
121
|
+
return typeof value === "string" && CHANNEL_REPLY_KIND_VALUES.includes(value);
|
|
122
|
+
}
|
|
123
|
+
const ChannelReplyArtifactRef = Schema.Struct({
|
|
124
|
+
uri: Schema.String,
|
|
125
|
+
label: Schema.optional(Schema.String)
|
|
126
|
+
});
|
|
127
|
+
const AgentChannelReply = Schema.Struct({
|
|
128
|
+
kind: ChannelReplyKind,
|
|
129
|
+
summary: Schema.String,
|
|
130
|
+
artifactRefs: Schema.Array(ChannelReplyArtifactRef),
|
|
131
|
+
reportedAt: Schema.String
|
|
132
|
+
});
|
|
133
|
+
function normalizeChannelReplyPayload(payload, fieldPrefix = "channel_reply") {
|
|
134
|
+
if (payload === null || typeof payload !== "object") throw new Error(`${fieldPrefix} payload must be an object`);
|
|
135
|
+
const source = payload;
|
|
136
|
+
if (!isChannelReplyKind(source.kind)) throw new Error(`${fieldPrefix}.kind must be one of: ${CHANNEL_REPLY_KIND_VALUES.join(", ")}`);
|
|
137
|
+
if (typeof source.summary !== "string") throw new Error(`${fieldPrefix}.summary must be a non-empty string`);
|
|
138
|
+
const summary = source.summary.trim();
|
|
139
|
+
if (summary.length === 0) throw new Error(`${fieldPrefix}.summary must be a non-empty string`);
|
|
140
|
+
if (summary.length > 4096) throw new Error(`${fieldPrefix}.summary must be at most ${MAX_CHANNEL_REPLY_SUMMARY_LENGTH} characters`);
|
|
141
|
+
if (source.artifactRefs !== void 0 && !Array.isArray(source.artifactRefs)) throw new Error(`${fieldPrefix}.artifactRefs must be an array when provided`);
|
|
142
|
+
const rawArtifactRefs = source.artifactRefs ?? [];
|
|
143
|
+
if (rawArtifactRefs.length > 20) throw new Error(`${fieldPrefix}.artifactRefs must contain at most 20 entries`);
|
|
144
|
+
const artifactRefs = rawArtifactRefs.map((item, index) => {
|
|
145
|
+
if (item === null || typeof item !== "object") throw new Error(`${fieldPrefix}.artifactRefs[${index}] must be an object`);
|
|
146
|
+
const ref = item;
|
|
147
|
+
if (typeof ref.uri !== "string") throw new Error(`${fieldPrefix}.artifactRefs[${index}].uri must be a non-empty string`);
|
|
148
|
+
const uri = ref.uri.trim();
|
|
149
|
+
if (uri.length === 0) throw new Error(`${fieldPrefix}.artifactRefs[${index}].uri must be a non-empty string`);
|
|
150
|
+
if (uri.length > 512) throw new Error(`${fieldPrefix}.artifactRefs[${index}].uri must be at most 512 characters`);
|
|
151
|
+
if (!CHANNEL_REPLY_ARTIFACT_URI_PATTERN.test(uri)) throw new Error(`${fieldPrefix}.artifactRefs[${index}].uri must start with file://, https://, or /`);
|
|
152
|
+
if (ref.label !== void 0 && typeof ref.label !== "string") throw new Error(`${fieldPrefix}.artifactRefs[${index}].label must be a string when provided`);
|
|
153
|
+
const label = typeof ref.label === "string" ? ref.label.trim() : void 0;
|
|
154
|
+
if (label !== void 0 && label.length > 512) throw new Error(`${fieldPrefix}.artifactRefs[${index}].label must be at most 512 characters`);
|
|
155
|
+
return {
|
|
156
|
+
uri,
|
|
157
|
+
...label ? { label } : {}
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
kind: source.kind,
|
|
162
|
+
summary,
|
|
163
|
+
artifactRefs
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const AgentRuntimeSnapshot = Schema.Struct({
|
|
167
|
+
id: AgentId,
|
|
168
|
+
activity: Activity,
|
|
169
|
+
lastActivity: Schema.String,
|
|
170
|
+
currentTool: Schema.optional(Schema.String),
|
|
171
|
+
thinking: Schema.optional(ThinkingState),
|
|
172
|
+
waiting: Schema.optional(WaitingState),
|
|
173
|
+
claudeSessionId: Schema.optional(Schema.String),
|
|
174
|
+
sessionModel: Schema.optional(Schema.String),
|
|
175
|
+
sessionHarness: Schema.optional(Schema.String),
|
|
176
|
+
model: Schema.optional(Schema.String),
|
|
177
|
+
lastMessageAt: Schema.optional(Schema.String),
|
|
178
|
+
channelReply: Schema.optional(AgentChannelReply),
|
|
179
|
+
resolution: Schema.optional(AgentResolution),
|
|
180
|
+
resolutionCount: Schema.optional(Schema.Number),
|
|
181
|
+
resolutionUpdatedAt: Schema.optional(Schema.String),
|
|
182
|
+
currentIssue: Schema.optional(IssueId),
|
|
183
|
+
contextSaturatedAt: Schema.optional(Schema.String),
|
|
184
|
+
updatedAtSequence: SequenceNumber
|
|
185
|
+
});
|
|
186
|
+
const ChannelPermissionRequestSnapshot = Schema.Struct({
|
|
187
|
+
requestId: Schema.String,
|
|
188
|
+
agentId: AgentId,
|
|
189
|
+
issueId: Schema.optional(IssueId),
|
|
190
|
+
toolName: Schema.String,
|
|
191
|
+
description: Schema.String,
|
|
192
|
+
inputPreview: Schema.String,
|
|
193
|
+
createdAt: Schema.String
|
|
194
|
+
});
|
|
195
|
+
const AgentSnapshot = Schema.Struct({
|
|
196
|
+
id: AgentId,
|
|
197
|
+
issueId: IssueId,
|
|
198
|
+
workspace: Schema.optional(Schema.String),
|
|
199
|
+
runtime: Schema.optional(Schema.String),
|
|
200
|
+
model: Schema.optional(Schema.String),
|
|
201
|
+
status: AgentStatus,
|
|
202
|
+
startedAt: Schema.optional(Schema.String),
|
|
203
|
+
lastActivity: Schema.optional(Schema.String),
|
|
204
|
+
branch: Schema.optional(Schema.String),
|
|
205
|
+
costSoFar: Schema.optional(Schema.Number),
|
|
206
|
+
sessionId: Schema.optional(Schema.String),
|
|
207
|
+
role: Schema.optional(Role),
|
|
208
|
+
phase: Schema.optional(Schema.String),
|
|
209
|
+
workType: Schema.optional(Schema.String),
|
|
210
|
+
roleRunHead: Schema.optional(Schema.String),
|
|
211
|
+
hasLiveTmuxSession: Schema.optional(Schema.Boolean),
|
|
212
|
+
stoppedByUser: Schema.optional(Schema.Boolean),
|
|
213
|
+
paused: Schema.optional(Schema.Boolean),
|
|
214
|
+
pausedReason: Schema.optional(Schema.String),
|
|
215
|
+
pausedAt: Schema.optional(Schema.String),
|
|
216
|
+
troubled: Schema.optional(Schema.Boolean),
|
|
217
|
+
troubledAt: Schema.optional(Schema.String),
|
|
218
|
+
consecutiveFailures: Schema.optional(Schema.Number),
|
|
219
|
+
firstFailureInRunAt: Schema.optional(Schema.String),
|
|
220
|
+
lastFailureAt: Schema.optional(Schema.String),
|
|
221
|
+
lastFailureReason: Schema.optional(Schema.String),
|
|
222
|
+
lastFailureNextRetryAt: Schema.optional(Schema.String),
|
|
223
|
+
runtimeState: Schema.optional(Schema.String),
|
|
224
|
+
hasPendingQuestion: Schema.optional(Schema.Boolean),
|
|
225
|
+
pendingQuestionCount: Schema.optional(Schema.Number),
|
|
226
|
+
pendingQuestionPrompt: Schema.optional(Schema.String),
|
|
227
|
+
pendingQuestionReason: Schema.optional(Schema.String),
|
|
228
|
+
pendingInputCount: Schema.optional(Schema.Number),
|
|
229
|
+
pendingInputKinds: Schema.optional(Schema.Array(Schema.String)),
|
|
230
|
+
pendingAskUserQuestion: Schema.optional(Schema.Struct({
|
|
231
|
+
toolUseId: Schema.String,
|
|
232
|
+
askedAt: Schema.String,
|
|
233
|
+
questions: Schema.Array(Schema.Struct({
|
|
234
|
+
question: Schema.String,
|
|
235
|
+
header: Schema.optional(Schema.String),
|
|
236
|
+
multiSelect: Schema.optional(Schema.Boolean),
|
|
237
|
+
options: Schema.Array(Schema.Struct({
|
|
238
|
+
label: Schema.String,
|
|
239
|
+
description: Schema.optional(Schema.String)
|
|
240
|
+
}))
|
|
241
|
+
}))
|
|
242
|
+
})),
|
|
243
|
+
resolution: Schema.optional(AgentResolution),
|
|
244
|
+
resolutionCount: Schema.optional(Schema.Number),
|
|
245
|
+
runtimeSnapshotSequence: Schema.optional(SequenceNumber)
|
|
246
|
+
});
|
|
247
|
+
const ReviewStatusSnapshot = Schema.Struct({
|
|
248
|
+
issueId: IssueId,
|
|
249
|
+
reviewStatus: Schema.optional(ReviewStatusValue),
|
|
250
|
+
testStatus: Schema.optional(TestStatusValue),
|
|
251
|
+
uatStatus: Schema.optional(UatStatusValue),
|
|
252
|
+
uatNotes: Schema.optional(Schema.String),
|
|
253
|
+
mergeStatus: Schema.optional(MergeStatusValue),
|
|
254
|
+
verificationStatus: Schema.optional(VerificationStatusValue),
|
|
255
|
+
verificationNotes: Schema.optional(Schema.String),
|
|
256
|
+
verificationCycleCount: Schema.optional(Schema.Number),
|
|
257
|
+
readyForMerge: Schema.optional(Schema.Boolean),
|
|
258
|
+
updatedAt: Schema.optional(Schema.String),
|
|
259
|
+
prUrl: Schema.optional(Schema.String),
|
|
260
|
+
/** Persistent stuck flag — set by divergence guard, cleared by /unstick */
|
|
261
|
+
stuck: Schema.optional(Schema.Boolean),
|
|
262
|
+
stuckReason: Schema.optional(Schema.String),
|
|
263
|
+
stuckAt: Schema.optional(Schema.String),
|
|
264
|
+
stuckDetails: Schema.optional(Schema.String),
|
|
265
|
+
/** Commit SHA at which review passed; deacon uses this to detect new pushes after review */
|
|
266
|
+
reviewedAtCommit: Schema.optional(Schema.String),
|
|
267
|
+
/** Commit SHA at which the pre-review verification gate last passed */
|
|
268
|
+
lastVerifiedCommit: Schema.optional(Schema.String),
|
|
269
|
+
/** Current merge pipeline step (granular visibility for the merge step tracker) */
|
|
270
|
+
mergeStep: Schema.optional(Schema.String),
|
|
271
|
+
/** PAN-699: timestamp when review agents were dispatched */
|
|
272
|
+
reviewSpawnedAt: Schema.optional(Schema.String),
|
|
273
|
+
/** PAN-699: number of test-agent dispatch retries */
|
|
274
|
+
testRetryCount: Schema.optional(Schema.Number),
|
|
275
|
+
/** PAN-794: parallel-review re-dispatch retry counter (current recovery cycle) */
|
|
276
|
+
reviewRetryCount: Schema.optional(Schema.Number),
|
|
277
|
+
/** PAN-796: review auto-requeue count (circuit breaker threshold) */
|
|
278
|
+
autoRequeueCount: Schema.optional(Schema.Number),
|
|
279
|
+
/** PAN-794: ISO timestamp marking the start of the current recovery cycle */
|
|
280
|
+
recoveryStartedAt: Schema.optional(Schema.String),
|
|
281
|
+
/** Human-requested patrol opt-out — when true, Deacon ignores this issue. */
|
|
282
|
+
deaconIgnored: Schema.optional(Schema.Boolean),
|
|
283
|
+
deaconIgnoredAt: Schema.optional(Schema.String),
|
|
284
|
+
deaconIgnoredReason: Schema.optional(Schema.String),
|
|
285
|
+
/** PAN-1691: per-issue auto-merge routing key. undefined = project default, true = auto-merge (fast lane), false = hold for UAT. */
|
|
286
|
+
autoMerge: Schema.optional(Schema.Boolean),
|
|
287
|
+
/** Active review orchestrator tmux session name (e.g. agent-pan-540-review). */
|
|
288
|
+
reviewCoordinatorSessionName: Schema.optional(Schema.String),
|
|
289
|
+
/** Active review sub-role tmux session names (e.g. agent-pan-540-review-correctness). Discovered at emission time. */
|
|
290
|
+
reviewSessionNames: Schema.optional(Schema.Array(Schema.String)),
|
|
291
|
+
/** Per-role review completion status (keyed by role: 'correctness' | 'security' | ...) */
|
|
292
|
+
reviewSubStatuses: Schema.optional(Schema.Record(Schema.String, Schema.Literals(["running", "done"]))),
|
|
293
|
+
/** PAN-905: queue position in the merge queue */
|
|
294
|
+
queuePosition: Schema.optional(Schema.Number),
|
|
295
|
+
/** PAN-905: currently active specialist (e.g. 'merge-agent') */
|
|
296
|
+
activeSpecialist: Schema.optional(Schema.String),
|
|
297
|
+
/** PAN-905: number of merge retries attempted */
|
|
298
|
+
mergeRetryCount: Schema.optional(Schema.Number),
|
|
299
|
+
/** PAN-905: free-form notes about the merge attempt */
|
|
300
|
+
mergeNotes: Schema.optional(Schema.String),
|
|
301
|
+
/** PAN-905: GitHub-native merge blocker reasons */
|
|
302
|
+
blockerReasons: Schema.optional(Schema.Array(Schema.Struct({
|
|
303
|
+
type: Schema.Literals([
|
|
304
|
+
"failing_checks",
|
|
305
|
+
"merge_conflict",
|
|
306
|
+
"unresolved_conversations",
|
|
307
|
+
"changes_requested",
|
|
308
|
+
"draft_pr",
|
|
309
|
+
"not_mergeable"
|
|
310
|
+
]),
|
|
311
|
+
summary: Schema.String,
|
|
312
|
+
details: Schema.optional(Schema.String),
|
|
313
|
+
detectedAt: Schema.String
|
|
314
|
+
})))
|
|
315
|
+
});
|
|
316
|
+
const TurnDiffFileChange = Schema.Struct({
|
|
317
|
+
path: Schema.String,
|
|
318
|
+
kind: Schema.optional(Schema.String),
|
|
319
|
+
additions: Schema.optional(Schema.Number),
|
|
320
|
+
deletions: Schema.optional(Schema.Number)
|
|
321
|
+
});
|
|
322
|
+
const TurnDiffSummary = Schema.Struct({
|
|
323
|
+
turnId: Schema.String,
|
|
324
|
+
completedAt: Schema.String,
|
|
325
|
+
status: Schema.optional(Schema.String),
|
|
326
|
+
files: Schema.Array(TurnDiffFileChange),
|
|
327
|
+
checkpointRef: Schema.optional(Schema.String),
|
|
328
|
+
assistantMessageId: Schema.optional(Schema.String),
|
|
329
|
+
checkpointTurnCount: Schema.optional(Schema.Number)
|
|
330
|
+
});
|
|
331
|
+
const ScanProgressSnapshot = Schema.Struct({
|
|
332
|
+
active: Schema.Boolean,
|
|
333
|
+
mode: Schema.Literals([
|
|
334
|
+
"targeted",
|
|
335
|
+
"watched",
|
|
336
|
+
"system"
|
|
337
|
+
]),
|
|
338
|
+
dirs: Schema.Array(Schema.String),
|
|
339
|
+
dirsProcessed: Schema.Number,
|
|
340
|
+
dirsTotal: Schema.Number,
|
|
341
|
+
sessionsFound: Schema.Number,
|
|
342
|
+
elapsedMs: Schema.Number,
|
|
343
|
+
inserted: Schema.Number,
|
|
344
|
+
updated: Schema.Number,
|
|
345
|
+
skipped: Schema.Number,
|
|
346
|
+
errors: Schema.Number,
|
|
347
|
+
durationMs: Schema.Number
|
|
348
|
+
});
|
|
349
|
+
const EnrichStatsSnapshot = Schema.Struct({
|
|
350
|
+
processed: Schema.Number,
|
|
351
|
+
totalCost: Schema.Number,
|
|
352
|
+
failures: Schema.Number,
|
|
353
|
+
durationMs: Schema.Number
|
|
354
|
+
});
|
|
355
|
+
const EnrichProgressSnapshot = Schema.Struct({
|
|
356
|
+
sessionId: Schema.Number,
|
|
357
|
+
level: Schema.Number,
|
|
358
|
+
model: Schema.String,
|
|
359
|
+
cost: Schema.Number,
|
|
360
|
+
success: Schema.Boolean,
|
|
361
|
+
error: Schema.optional(Schema.String),
|
|
362
|
+
timestamp: Schema.String
|
|
363
|
+
});
|
|
364
|
+
const EmbedProgressSnapshot = Schema.Struct({
|
|
365
|
+
sessionId: Schema.Number,
|
|
366
|
+
model: Schema.String,
|
|
367
|
+
success: Schema.Boolean,
|
|
368
|
+
error: Schema.optional(Schema.String),
|
|
369
|
+
timestamp: Schema.String
|
|
370
|
+
});
|
|
371
|
+
const DashboardSnapshot = Schema.Struct({
|
|
372
|
+
sequence: SequenceNumber,
|
|
373
|
+
agents: Schema.Array(AgentSnapshot),
|
|
374
|
+
specialists: Schema.Array(Schema.Unknown),
|
|
375
|
+
reviewStatuses: Schema.Array(ReviewStatusSnapshot),
|
|
376
|
+
issues: Schema.Array(Schema.Unknown),
|
|
377
|
+
resources: Schema.optional(Schema.Unknown),
|
|
378
|
+
memory: Schema.optional(Schema.Unknown),
|
|
379
|
+
agentRuntimeById: Schema.optional(Schema.Record(Schema.String, AgentRuntimeSnapshot)),
|
|
380
|
+
channelPermissionRequests: Schema.optional(Schema.Array(ChannelPermissionRequestSnapshot)),
|
|
381
|
+
scanProgress: Schema.optional(Schema.NullOr(ScanProgressSnapshot)),
|
|
382
|
+
enrichStats: Schema.optional(Schema.NullOr(EnrichStatsSnapshot)),
|
|
383
|
+
enrichProgressBySessionId: Schema.optional(Schema.Record(Schema.String, EnrichProgressSnapshot)),
|
|
384
|
+
embedProgressBySessionId: Schema.optional(Schema.Record(Schema.String, EmbedProgressSnapshot)),
|
|
385
|
+
timestamp: Schema.String
|
|
386
|
+
});
|
|
387
|
+
const WorkspaceDetail = Schema.Struct({
|
|
388
|
+
workspace: Schema.Unknown,
|
|
389
|
+
reviewStatus: Schema.Unknown,
|
|
390
|
+
planning: Schema.Unknown,
|
|
391
|
+
costs: Schema.Unknown,
|
|
392
|
+
agentOutput: Schema.Array(Schema.String)
|
|
393
|
+
});
|
|
394
|
+
const ResourceStats = Schema.Struct({ containers: Schema.Array(Schema.Struct({
|
|
395
|
+
name: Schema.String,
|
|
396
|
+
cpu: Schema.optional(Schema.String),
|
|
397
|
+
mem: Schema.optional(Schema.String),
|
|
398
|
+
status: Schema.optional(Schema.String)
|
|
399
|
+
})) });
|
|
400
|
+
const SessionNodePresence = Schema.Literals([
|
|
401
|
+
"active",
|
|
402
|
+
"idle",
|
|
403
|
+
"suspended",
|
|
404
|
+
"ended"
|
|
405
|
+
]);
|
|
406
|
+
const SessionNodeType = Schema.Literals([
|
|
407
|
+
"planning",
|
|
408
|
+
"work",
|
|
409
|
+
"strike",
|
|
410
|
+
"review",
|
|
411
|
+
"reviewer",
|
|
412
|
+
"test",
|
|
413
|
+
"ship",
|
|
414
|
+
"merge",
|
|
415
|
+
"legacy"
|
|
416
|
+
]);
|
|
417
|
+
const ReviewerRoundSummary = Schema.Struct({
|
|
418
|
+
round: Schema.Number,
|
|
419
|
+
status: Schema.optional(Schema.String),
|
|
420
|
+
reviewResult: Schema.optional(Schema.String),
|
|
421
|
+
startedAt: Schema.optional(Schema.String),
|
|
422
|
+
endedAt: Schema.optional(Schema.String),
|
|
423
|
+
durationSec: Schema.optional(Schema.Number),
|
|
424
|
+
cost: Schema.optional(Schema.Number),
|
|
425
|
+
findings: Schema.optional(Schema.Number),
|
|
426
|
+
summary: Schema.optional(Schema.String)
|
|
427
|
+
});
|
|
428
|
+
const ReviewerRoundMetadata = Schema.Struct({
|
|
429
|
+
roundCount: Schema.Number,
|
|
430
|
+
latestRound: Schema.Number,
|
|
431
|
+
latestStatus: Schema.optional(Schema.String),
|
|
432
|
+
latestReviewResult: Schema.optional(Schema.String),
|
|
433
|
+
history: Schema.Array(ReviewerRoundSummary)
|
|
434
|
+
});
|
|
435
|
+
const SessionNode = Schema.Struct({
|
|
436
|
+
type: SessionNodeType,
|
|
437
|
+
role: Schema.optional(Schema.String),
|
|
438
|
+
sessionId: Schema.String,
|
|
439
|
+
tmuxSession: Schema.optional(Schema.String),
|
|
440
|
+
model: Schema.String,
|
|
441
|
+
harness: Schema.optional(Schema.String),
|
|
442
|
+
startedAt: Schema.String,
|
|
443
|
+
endedAt: Schema.optional(Schema.String),
|
|
444
|
+
duration: Schema.NullOr(Schema.Number),
|
|
445
|
+
status: AgentStatus,
|
|
446
|
+
hasJsonl: Schema.optional(Schema.Boolean),
|
|
447
|
+
transcript: Schema.optional(Schema.String),
|
|
448
|
+
presence: SessionNodePresence,
|
|
449
|
+
awaitingInput: Schema.optional(Schema.Boolean),
|
|
450
|
+
awaitingInputPrompt: Schema.optional(Schema.String),
|
|
451
|
+
awaitingInputReason: Schema.optional(Schema.String),
|
|
452
|
+
roundMetadata: Schema.optional(ReviewerRoundMetadata),
|
|
453
|
+
deliveryMethod: Schema.optional(Schema.Literals([
|
|
454
|
+
"auto",
|
|
455
|
+
"channels",
|
|
456
|
+
"tmux"
|
|
457
|
+
])),
|
|
458
|
+
paused: Schema.optional(Schema.Boolean),
|
|
459
|
+
pausedReason: Schema.optional(Schema.String),
|
|
460
|
+
pausedAt: Schema.optional(Schema.String)
|
|
461
|
+
});
|
|
462
|
+
const FeatureNode = Schema.Struct({
|
|
463
|
+
issueId: IssueId,
|
|
464
|
+
title: Schema.String,
|
|
465
|
+
sessions: Schema.Array(SessionNode)
|
|
466
|
+
});
|
|
467
|
+
const ProjectSessionTree = Schema.Struct({
|
|
468
|
+
projectKey: Schema.String,
|
|
469
|
+
features: Schema.Array(FeatureNode)
|
|
470
|
+
});
|
|
471
|
+
/** Snapshot of a discovered session for RPC responses and frontend display */
|
|
472
|
+
const DiscoveredSessionSnapshot = Schema.Struct({
|
|
473
|
+
id: Schema.Number,
|
|
474
|
+
jsonlPath: Schema.String,
|
|
475
|
+
sessionId: Schema.optional(Schema.String),
|
|
476
|
+
workspacePath: Schema.optional(Schema.String),
|
|
477
|
+
workspaceHash: Schema.optional(Schema.String),
|
|
478
|
+
messageCount: Schema.Number,
|
|
479
|
+
firstTs: Schema.optional(Schema.String),
|
|
480
|
+
lastTs: Schema.optional(Schema.String),
|
|
481
|
+
modelsUsed: Schema.Array(Schema.String),
|
|
482
|
+
primaryModel: Schema.optional(Schema.String),
|
|
483
|
+
tokenInput: Schema.Number,
|
|
484
|
+
tokenOutput: Schema.Number,
|
|
485
|
+
estimatedCost: Schema.Number,
|
|
486
|
+
toolsUsed: Schema.Array(Schema.String),
|
|
487
|
+
filesTouched: Schema.Array(Schema.String),
|
|
488
|
+
tags: Schema.Array(Schema.String),
|
|
489
|
+
summary: Schema.optional(Schema.String),
|
|
490
|
+
summaryDetailed: Schema.optional(Schema.String),
|
|
491
|
+
enrichmentLevel: Schema.Number,
|
|
492
|
+
enrichmentModel: Schema.optional(Schema.String),
|
|
493
|
+
enrichedAt: Schema.optional(Schema.String),
|
|
494
|
+
enrichmentFailed: Schema.Boolean,
|
|
495
|
+
overdeckManaged: Schema.Boolean,
|
|
496
|
+
panIssueId: Schema.optional(Schema.String),
|
|
497
|
+
panAgentId: Schema.optional(Schema.String),
|
|
498
|
+
scannedAt: Schema.String
|
|
499
|
+
});
|
|
500
|
+
/** Filter parameters for conversation search */
|
|
501
|
+
const ConversationFilter = Schema.Struct({
|
|
502
|
+
workspacePath: Schema.optional(Schema.String),
|
|
503
|
+
primaryModel: Schema.optional(Schema.String),
|
|
504
|
+
managed: Schema.optional(Schema.Boolean),
|
|
505
|
+
unmanaged: Schema.optional(Schema.Boolean),
|
|
506
|
+
since: Schema.optional(Schema.String),
|
|
507
|
+
before: Schema.optional(Schema.String),
|
|
508
|
+
after: Schema.optional(Schema.String),
|
|
509
|
+
minCost: Schema.optional(Schema.Number),
|
|
510
|
+
maxCost: Schema.optional(Schema.Number),
|
|
511
|
+
minMessages: Schema.optional(Schema.Number),
|
|
512
|
+
tags: Schema.optional(Schema.Array(Schema.String)),
|
|
513
|
+
tools: Schema.optional(Schema.Array(Schema.String)),
|
|
514
|
+
files: Schema.optional(Schema.Array(Schema.String)),
|
|
515
|
+
issueId: Schema.optional(Schema.String),
|
|
516
|
+
enrichmentLevel: Schema.optional(Schema.Number),
|
|
517
|
+
enriched: Schema.optional(Schema.Boolean),
|
|
518
|
+
notEnriched: Schema.optional(Schema.Boolean),
|
|
519
|
+
query: Schema.optional(Schema.String),
|
|
520
|
+
semantic: Schema.optional(Schema.Boolean),
|
|
521
|
+
similarTo: Schema.optional(Schema.Number),
|
|
522
|
+
limit: Schema.optional(Schema.Number),
|
|
523
|
+
offset: Schema.optional(Schema.Number),
|
|
524
|
+
format: Schema.optional(Schema.Literals([
|
|
525
|
+
"table",
|
|
526
|
+
"json",
|
|
527
|
+
"brief",
|
|
528
|
+
"ids"
|
|
529
|
+
]))
|
|
530
|
+
});
|
|
531
|
+
/** Aggregate cost breakdown for conversations */
|
|
532
|
+
const ConversationCostSummary = Schema.Struct({
|
|
533
|
+
groupBy: Schema.Literals([
|
|
534
|
+
"workspace",
|
|
535
|
+
"model",
|
|
536
|
+
"day",
|
|
537
|
+
"month"
|
|
538
|
+
]),
|
|
539
|
+
entries: Schema.Array(Schema.Struct({
|
|
540
|
+
key: Schema.String,
|
|
541
|
+
totalCost: Schema.Number,
|
|
542
|
+
sessionCount: Schema.Number,
|
|
543
|
+
totalTokensIn: Schema.Number,
|
|
544
|
+
totalTokensOut: Schema.Number
|
|
545
|
+
})),
|
|
546
|
+
grandTotal: Schema.Number,
|
|
547
|
+
totalTokensIn: Schema.Number,
|
|
548
|
+
totalTokensOut: Schema.Number
|
|
549
|
+
});
|
|
550
|
+
/** Scan result summary */
|
|
551
|
+
const ScanResult = Schema.Struct({
|
|
552
|
+
inserted: Schema.Number,
|
|
553
|
+
updated: Schema.Number,
|
|
554
|
+
skipped: Schema.Number,
|
|
555
|
+
errors: Schema.Number,
|
|
556
|
+
durationMs: Schema.Number
|
|
557
|
+
});
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/memory.ts
|
|
560
|
+
const MemoryIdentity = Schema.Struct({
|
|
561
|
+
projectId: Schema.String,
|
|
562
|
+
workspaceId: Schema.String,
|
|
563
|
+
issueId: IssueId,
|
|
564
|
+
runId: Schema.String,
|
|
565
|
+
sessionId: Schema.String,
|
|
566
|
+
agentRole: Role,
|
|
567
|
+
agentHarness: Schema.String
|
|
568
|
+
});
|
|
569
|
+
const MemoryTokenUsage = Schema.Struct({
|
|
570
|
+
prompt: Schema.Number,
|
|
571
|
+
completion: Schema.Number,
|
|
572
|
+
total: Schema.Number
|
|
573
|
+
});
|
|
574
|
+
const MemoryObservation = Schema.Struct({
|
|
575
|
+
id: Schema.String,
|
|
576
|
+
timestamp: Schema.String,
|
|
577
|
+
projectId: Schema.String,
|
|
578
|
+
workspaceId: Schema.String,
|
|
579
|
+
issueId: IssueId,
|
|
580
|
+
runId: Schema.String,
|
|
581
|
+
sessionId: Schema.String,
|
|
582
|
+
agentRole: Role,
|
|
583
|
+
agentHarness: Schema.String,
|
|
584
|
+
gitBranch: Schema.String,
|
|
585
|
+
sourceTranscriptOffset: Schema.Number,
|
|
586
|
+
actionStatus: Schema.NullOr(Schema.String),
|
|
587
|
+
narrative: Schema.String,
|
|
588
|
+
summary: Schema.String,
|
|
589
|
+
files: Schema.Array(Schema.String),
|
|
590
|
+
tags: Schema.Array(Schema.String),
|
|
591
|
+
tokens: MemoryTokenUsage,
|
|
592
|
+
model: Schema.String
|
|
593
|
+
});
|
|
594
|
+
const MemoryStatusPhase = Schema.Literals([
|
|
595
|
+
"exploring",
|
|
596
|
+
"planning",
|
|
597
|
+
"building",
|
|
598
|
+
"verifying",
|
|
599
|
+
"cleaning",
|
|
600
|
+
"shipping"
|
|
601
|
+
]);
|
|
602
|
+
const MemoryStatus = Schema.Struct({
|
|
603
|
+
name: Schema.String,
|
|
604
|
+
headline: Schema.String,
|
|
605
|
+
summary: Schema.String,
|
|
606
|
+
goal: Schema.NullOr(Schema.String),
|
|
607
|
+
phase: MemoryStatusPhase,
|
|
608
|
+
accomplished: Schema.Array(Schema.String),
|
|
609
|
+
decided: Schema.Array(Schema.String),
|
|
610
|
+
open: Schema.Array(Schema.String),
|
|
611
|
+
nextSteps: Schema.Array(Schema.String),
|
|
612
|
+
confidence: Schema.Number,
|
|
613
|
+
workingSet: Schema.Array(Schema.String),
|
|
614
|
+
tags: Schema.Array(Schema.String)
|
|
615
|
+
});
|
|
616
|
+
const PendingTurn = Schema.Struct({
|
|
617
|
+
id: Schema.String,
|
|
618
|
+
createdAt: Schema.String,
|
|
619
|
+
identity: MemoryIdentity,
|
|
620
|
+
trigger: Schema.Literals([
|
|
621
|
+
"stop-hook",
|
|
622
|
+
"poller",
|
|
623
|
+
"reconciliation",
|
|
624
|
+
"manual"
|
|
625
|
+
]),
|
|
626
|
+
transcriptPath: Schema.String,
|
|
627
|
+
fromOffset: Schema.Number,
|
|
628
|
+
toOffset: Schema.Number,
|
|
629
|
+
lastFullLineOffset: Schema.Number,
|
|
630
|
+
eventsConsumed: Schema.Number,
|
|
631
|
+
compressedText: Schema.String
|
|
632
|
+
});
|
|
633
|
+
const ResetMarkerScope = Schema.Literals([
|
|
634
|
+
"project",
|
|
635
|
+
"workspace",
|
|
636
|
+
"issue",
|
|
637
|
+
"session"
|
|
638
|
+
]);
|
|
639
|
+
const ResetMarker = Schema.Struct({
|
|
640
|
+
id: Schema.String,
|
|
641
|
+
scope: ResetMarkerScope,
|
|
642
|
+
scopeId: Schema.String,
|
|
643
|
+
fromTimestamp: Schema.String,
|
|
644
|
+
reason: Schema.String,
|
|
645
|
+
createdAt: Schema.String
|
|
646
|
+
});
|
|
647
|
+
const RagDecisionSource = Schema.Struct({
|
|
648
|
+
id: Schema.String,
|
|
649
|
+
docType: Schema.Literals([
|
|
650
|
+
"observation",
|
|
651
|
+
"summary",
|
|
652
|
+
"status",
|
|
653
|
+
"sibling"
|
|
654
|
+
]),
|
|
655
|
+
scope: Schema.String,
|
|
656
|
+
score: Schema.Number,
|
|
657
|
+
tokens: Schema.Number
|
|
658
|
+
});
|
|
659
|
+
const RagDecision = Schema.Struct({
|
|
660
|
+
id: Schema.String,
|
|
661
|
+
timestamp: Schema.String,
|
|
662
|
+
identity: MemoryIdentity,
|
|
663
|
+
surface: Schema.Literals(["spawn", "user-prompt"]),
|
|
664
|
+
outcome: Schema.Literals([
|
|
665
|
+
"injected",
|
|
666
|
+
"skipped",
|
|
667
|
+
"no-hits",
|
|
668
|
+
"expansion-failed",
|
|
669
|
+
"context-too-large",
|
|
670
|
+
"budget-truncated"
|
|
671
|
+
]),
|
|
672
|
+
query: Schema.String,
|
|
673
|
+
expandedTerms: Schema.Array(Schema.String),
|
|
674
|
+
allocations: Schema.Struct({
|
|
675
|
+
status: Schema.Number,
|
|
676
|
+
observations: Schema.Number,
|
|
677
|
+
summaries: Schema.Number,
|
|
678
|
+
sibling: Schema.Number
|
|
679
|
+
}),
|
|
680
|
+
sources: Schema.Array(RagDecisionSource),
|
|
681
|
+
reason: Schema.NullOr(Schema.String)
|
|
682
|
+
});
|
|
683
|
+
const ExtractionProviderTarget = Schema.Struct({
|
|
684
|
+
provider: Schema.String,
|
|
685
|
+
model: Schema.String
|
|
686
|
+
});
|
|
687
|
+
const ExtractionProviderConfig = Schema.Struct({
|
|
688
|
+
provider: Schema.String,
|
|
689
|
+
model: Schema.String,
|
|
690
|
+
providerEnvVar: Schema.optional(Schema.String),
|
|
691
|
+
modelEnvVar: Schema.optional(Schema.String),
|
|
692
|
+
perDayCostCapUsd: Schema.Number,
|
|
693
|
+
fallbackChain: Schema.Array(ExtractionProviderTarget)
|
|
694
|
+
});
|
|
695
|
+
//#endregion
|
|
696
|
+
//#region src/events.ts
|
|
697
|
+
/** App-level liveness frame for the /ws/rpc domain-events stream. */
|
|
698
|
+
const SystemHeartbeatEvent = Schema.Struct({
|
|
699
|
+
type: Schema.Literal("system.heartbeat"),
|
|
700
|
+
timestamp: Schema.String,
|
|
701
|
+
payload: Schema.Struct({ ts: Schema.Number })
|
|
702
|
+
});
|
|
703
|
+
/** Replaces socket.io `agents:changed` (event: 'started') */
|
|
704
|
+
const AgentStartedEvent = Schema.Struct({
|
|
705
|
+
type: Schema.Literal("agent.started"),
|
|
706
|
+
sequence: SequenceNumber,
|
|
707
|
+
timestamp: Schema.String,
|
|
708
|
+
payload: Schema.Struct({
|
|
709
|
+
agentId: AgentId,
|
|
710
|
+
issueId: IssueId,
|
|
711
|
+
agent: AgentSnapshot
|
|
712
|
+
})
|
|
713
|
+
});
|
|
714
|
+
/** Replaces socket.io `agents:changed` (event: 'stopped') */
|
|
715
|
+
const AgentStoppedEvent = Schema.Struct({
|
|
716
|
+
type: Schema.Literal("agent.stopped"),
|
|
717
|
+
sequence: SequenceNumber,
|
|
718
|
+
timestamp: Schema.String,
|
|
719
|
+
payload: Schema.Struct({
|
|
720
|
+
agentId: AgentId,
|
|
721
|
+
issueId: IssueId,
|
|
722
|
+
sessionId: Schema.optional(Schema.String)
|
|
723
|
+
})
|
|
724
|
+
});
|
|
725
|
+
const AgentHeartbeatDeadEvent = Schema.Struct({
|
|
726
|
+
type: Schema.Literal("agent.heartbeat_dead"),
|
|
727
|
+
sequence: SequenceNumber,
|
|
728
|
+
timestamp: Schema.String,
|
|
729
|
+
payload: Schema.Struct({
|
|
730
|
+
agentId: AgentId,
|
|
731
|
+
issueId: Schema.optional(IssueId),
|
|
732
|
+
sessionId: Schema.optional(Schema.String)
|
|
733
|
+
})
|
|
734
|
+
});
|
|
735
|
+
/** Role lifecycle — work agent completed implementation and is ready for review. */
|
|
736
|
+
const WorkCompletedEvent = Schema.Struct({
|
|
737
|
+
type: Schema.Literal("work.completed"),
|
|
738
|
+
sequence: SequenceNumber,
|
|
739
|
+
timestamp: Schema.String,
|
|
740
|
+
payload: Schema.Struct({
|
|
741
|
+
issueId: IssueId,
|
|
742
|
+
agentId: Schema.optional(AgentId)
|
|
743
|
+
})
|
|
744
|
+
});
|
|
745
|
+
/** Role lifecycle — generic agent completion signal, normalized by Cloister by role. */
|
|
746
|
+
const AgentCompletedEvent = Schema.Struct({
|
|
747
|
+
type: Schema.Literal("agent.completed"),
|
|
748
|
+
sequence: SequenceNumber,
|
|
749
|
+
timestamp: Schema.String,
|
|
750
|
+
payload: Schema.Struct({
|
|
751
|
+
issueId: IssueId,
|
|
752
|
+
agentId: Schema.optional(AgentId),
|
|
753
|
+
role: Schema.optional(Role)
|
|
754
|
+
})
|
|
755
|
+
});
|
|
756
|
+
/** Role lifecycle — review approved the branch and testing should start. */
|
|
757
|
+
const ReviewApprovedEvent = Schema.Struct({
|
|
758
|
+
type: Schema.Literal("review.approved"),
|
|
759
|
+
sequence: SequenceNumber,
|
|
760
|
+
timestamp: Schema.String,
|
|
761
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
762
|
+
});
|
|
763
|
+
/** Role lifecycle — tests passed and shipping should prepare the branch. */
|
|
764
|
+
const TestPassedEvent = Schema.Struct({
|
|
765
|
+
type: Schema.Literal("test.passed"),
|
|
766
|
+
sequence: SequenceNumber,
|
|
767
|
+
timestamp: Schema.String,
|
|
768
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
769
|
+
});
|
|
770
|
+
/** Replaces socket.io `godview:status-change` */
|
|
771
|
+
const AgentStatusChangedEvent = Schema.Struct({
|
|
772
|
+
type: Schema.Literal("agent.status_changed"),
|
|
773
|
+
sequence: SequenceNumber,
|
|
774
|
+
timestamp: Schema.String,
|
|
775
|
+
payload: Schema.Struct({
|
|
776
|
+
agentId: AgentId,
|
|
777
|
+
issueId: Schema.optional(IssueId),
|
|
778
|
+
status: AgentStatus,
|
|
779
|
+
previousStatus: Schema.optional(AgentStatus),
|
|
780
|
+
hasLiveTmuxSession: Schema.optional(Schema.Boolean),
|
|
781
|
+
stoppedByUser: Schema.optional(Schema.Boolean),
|
|
782
|
+
stoppedByPause: Schema.optional(Schema.Boolean),
|
|
783
|
+
paused: Schema.optional(Schema.Boolean),
|
|
784
|
+
pausedReason: Schema.optional(Schema.NullOr(Schema.String)),
|
|
785
|
+
pausedAt: Schema.optional(Schema.NullOr(Schema.String)),
|
|
786
|
+
troubled: Schema.optional(Schema.Boolean),
|
|
787
|
+
troubledAt: Schema.optional(Schema.NullOr(Schema.String)),
|
|
788
|
+
consecutiveFailures: Schema.optional(Schema.Number),
|
|
789
|
+
firstFailureInRunAt: Schema.optional(Schema.NullOr(Schema.String)),
|
|
790
|
+
lastFailureAt: Schema.optional(Schema.NullOr(Schema.String)),
|
|
791
|
+
lastFailureReason: Schema.optional(Schema.NullOr(Schema.String)),
|
|
792
|
+
lastFailureNextRetryAt: Schema.optional(Schema.NullOr(Schema.String)),
|
|
793
|
+
kickoffDelivered: Schema.optional(Schema.Boolean),
|
|
794
|
+
hostOverride: Schema.optional(Schema.Boolean),
|
|
795
|
+
role: Schema.optional(Role),
|
|
796
|
+
model: Schema.optional(Schema.String),
|
|
797
|
+
workspace: Schema.optional(Schema.String),
|
|
798
|
+
sessionId: Schema.optional(Schema.String),
|
|
799
|
+
lastActivity: Schema.optional(Schema.String),
|
|
800
|
+
lastResumeAt: Schema.optional(Schema.String),
|
|
801
|
+
stoppedAt: Schema.optional(Schema.String),
|
|
802
|
+
branch: Schema.optional(Schema.String),
|
|
803
|
+
costSoFar: Schema.optional(Schema.Number),
|
|
804
|
+
phase: Schema.optional(Schema.String),
|
|
805
|
+
workType: Schema.optional(Schema.String),
|
|
806
|
+
roleRunHead: Schema.optional(Schema.String),
|
|
807
|
+
flywheelRunId: Schema.optional(Schema.String),
|
|
808
|
+
reviewSubRole: Schema.optional(Schema.String),
|
|
809
|
+
reviewRunId: Schema.optional(Schema.String),
|
|
810
|
+
reviewOutputPath: Schema.optional(Schema.String),
|
|
811
|
+
reviewSynthesisAgentId: Schema.optional(Schema.String),
|
|
812
|
+
reviewDeadlineAt: Schema.optional(Schema.String),
|
|
813
|
+
reviewMonitorSignaled: Schema.optional(Schema.String),
|
|
814
|
+
reviewRetryAttempt: Schema.optional(Schema.Number),
|
|
815
|
+
inspectSubRole: Schema.optional(Schema.String),
|
|
816
|
+
deliveryMethod: Schema.optional(Schema.String),
|
|
817
|
+
supervisorEnabled: Schema.optional(Schema.Boolean),
|
|
818
|
+
channelsEnabled: Schema.optional(Schema.Boolean)
|
|
819
|
+
})
|
|
820
|
+
});
|
|
821
|
+
/** Replaces socket.io `godview:agent-output` */
|
|
822
|
+
const AgentOutputReceivedEvent = Schema.Struct({
|
|
823
|
+
type: Schema.Literal("agent.output_received"),
|
|
824
|
+
sequence: SequenceNumber,
|
|
825
|
+
timestamp: Schema.String,
|
|
826
|
+
payload: Schema.Struct({
|
|
827
|
+
agentId: AgentId,
|
|
828
|
+
lines: Schema.Array(Schema.String)
|
|
829
|
+
})
|
|
830
|
+
});
|
|
831
|
+
/** New — agent enrichment fields updated (PAN-440) */
|
|
832
|
+
const AgentEnrichmentChangedEvent = Schema.Struct({
|
|
833
|
+
type: Schema.Literal("agent.enrichment_changed"),
|
|
834
|
+
sequence: SequenceNumber,
|
|
835
|
+
timestamp: Schema.String,
|
|
836
|
+
payload: Schema.Struct({
|
|
837
|
+
agentId: AgentId,
|
|
838
|
+
role: Schema.optional(Role),
|
|
839
|
+
hasPendingQuestion: Schema.optional(Schema.Boolean),
|
|
840
|
+
pendingQuestionCount: Schema.optional(Schema.Number),
|
|
841
|
+
pendingQuestionPrompt: Schema.optional(Schema.String),
|
|
842
|
+
pendingQuestionReason: Schema.optional(Schema.String),
|
|
843
|
+
pendingInputCount: Schema.optional(Schema.Number),
|
|
844
|
+
pendingInputKinds: Schema.optional(Schema.Array(Schema.String)),
|
|
845
|
+
pendingAskUserQuestion: Schema.optional(Schema.Struct({
|
|
846
|
+
toolUseId: Schema.String,
|
|
847
|
+
askedAt: Schema.String,
|
|
848
|
+
questions: Schema.Array(Schema.Struct({
|
|
849
|
+
question: Schema.String,
|
|
850
|
+
header: Schema.optional(Schema.String),
|
|
851
|
+
multiSelect: Schema.optional(Schema.Boolean),
|
|
852
|
+
options: Schema.Array(Schema.Struct({
|
|
853
|
+
label: Schema.String,
|
|
854
|
+
description: Schema.optional(Schema.String)
|
|
855
|
+
}))
|
|
856
|
+
}))
|
|
857
|
+
})),
|
|
858
|
+
resolution: Schema.optional(AgentResolution),
|
|
859
|
+
resolutionCount: Schema.optional(Schema.Number)
|
|
860
|
+
})
|
|
861
|
+
});
|
|
862
|
+
/** New — agent created in database */
|
|
863
|
+
const AgentCreatedEvent = Schema.Struct({
|
|
864
|
+
type: Schema.Literal("agent.created"),
|
|
865
|
+
sequence: SequenceNumber,
|
|
866
|
+
timestamp: Schema.String,
|
|
867
|
+
payload: Schema.Struct({
|
|
868
|
+
agentId: AgentId,
|
|
869
|
+
issueId: IssueId,
|
|
870
|
+
agent: AgentSnapshot
|
|
871
|
+
})
|
|
872
|
+
});
|
|
873
|
+
const AgentActivityChangedEvent = Schema.Struct({
|
|
874
|
+
type: Schema.Literal("agent.activity_changed"),
|
|
875
|
+
sequence: SequenceNumber,
|
|
876
|
+
timestamp: Schema.String,
|
|
877
|
+
payload: Schema.Struct({
|
|
878
|
+
agentId: AgentId,
|
|
879
|
+
activity: Activity,
|
|
880
|
+
currentTool: Schema.optional(Schema.String)
|
|
881
|
+
})
|
|
882
|
+
});
|
|
883
|
+
const AgentThinkingStartedEvent = Schema.Struct({
|
|
884
|
+
type: Schema.Literal("agent.thinking_started"),
|
|
885
|
+
sequence: SequenceNumber,
|
|
886
|
+
timestamp: Schema.String,
|
|
887
|
+
payload: Schema.Struct({
|
|
888
|
+
agentId: AgentId,
|
|
889
|
+
lastToolAt: Schema.String
|
|
890
|
+
})
|
|
891
|
+
});
|
|
892
|
+
const AgentThinkingStoppedEvent = Schema.Struct({
|
|
893
|
+
type: Schema.Literal("agent.thinking_stopped"),
|
|
894
|
+
sequence: SequenceNumber,
|
|
895
|
+
timestamp: Schema.String,
|
|
896
|
+
payload: Schema.Struct({
|
|
897
|
+
agentId: AgentId,
|
|
898
|
+
resolvedBy: Schema.Literals([
|
|
899
|
+
"tool",
|
|
900
|
+
"waiting",
|
|
901
|
+
"idle",
|
|
902
|
+
"stopped"
|
|
903
|
+
])
|
|
904
|
+
})
|
|
905
|
+
});
|
|
906
|
+
const AgentWaitingStartedEvent = Schema.Struct({
|
|
907
|
+
type: Schema.Literal("agent.waiting_started"),
|
|
908
|
+
sequence: SequenceNumber,
|
|
909
|
+
timestamp: Schema.String,
|
|
910
|
+
payload: Schema.Struct({
|
|
911
|
+
agentId: AgentId,
|
|
912
|
+
reason: WaitingReason,
|
|
913
|
+
message: Schema.optional(Schema.String)
|
|
914
|
+
})
|
|
915
|
+
});
|
|
916
|
+
const AgentWaitingClearedEvent = Schema.Struct({
|
|
917
|
+
type: Schema.Literal("agent.waiting_cleared"),
|
|
918
|
+
sequence: SequenceNumber,
|
|
919
|
+
timestamp: Schema.String,
|
|
920
|
+
payload: Schema.Struct({
|
|
921
|
+
agentId: AgentId,
|
|
922
|
+
clearedBy: Schema.Literals([
|
|
923
|
+
"user_response",
|
|
924
|
+
"timeout",
|
|
925
|
+
"stopped",
|
|
926
|
+
"tool_resumed"
|
|
927
|
+
])
|
|
928
|
+
})
|
|
929
|
+
});
|
|
930
|
+
const AgentPermissionRequestedEvent = Schema.Struct({
|
|
931
|
+
type: Schema.Literal("agent.permission_requested"),
|
|
932
|
+
sequence: SequenceNumber,
|
|
933
|
+
timestamp: Schema.String,
|
|
934
|
+
payload: ChannelPermissionRequestSnapshot
|
|
935
|
+
});
|
|
936
|
+
const AgentPermissionResolvedEvent = Schema.Struct({
|
|
937
|
+
type: Schema.Literal("agent.permission_resolved"),
|
|
938
|
+
sequence: SequenceNumber,
|
|
939
|
+
timestamp: Schema.String,
|
|
940
|
+
payload: Schema.Struct({
|
|
941
|
+
requestId: Schema.String,
|
|
942
|
+
agentId: AgentId,
|
|
943
|
+
issueId: Schema.optional(IssueId),
|
|
944
|
+
behavior: ClaudeChannelPermissionBehavior
|
|
945
|
+
})
|
|
946
|
+
});
|
|
947
|
+
const AgentMessageReceivedEvent = Schema.Struct({
|
|
948
|
+
type: Schema.Literal("agent.message_received"),
|
|
949
|
+
sequence: SequenceNumber,
|
|
950
|
+
timestamp: Schema.String,
|
|
951
|
+
payload: Schema.Struct({
|
|
952
|
+
agentId: AgentId,
|
|
953
|
+
direction: Schema.Literals(["to_agent", "from_agent"]),
|
|
954
|
+
source: Schema.Literals([
|
|
955
|
+
"user",
|
|
956
|
+
"cloister",
|
|
957
|
+
"specialist",
|
|
958
|
+
"automated"
|
|
959
|
+
])
|
|
960
|
+
})
|
|
961
|
+
});
|
|
962
|
+
const AgentChannelReplyEvent = Schema.Struct({
|
|
963
|
+
type: Schema.Literal("agent.channel_reply"),
|
|
964
|
+
sequence: SequenceNumber,
|
|
965
|
+
timestamp: Schema.String,
|
|
966
|
+
payload: Schema.Struct({
|
|
967
|
+
agentId: AgentId,
|
|
968
|
+
reply: AgentChannelReply
|
|
969
|
+
})
|
|
970
|
+
});
|
|
971
|
+
const AgentModelSetEvent = Schema.Struct({
|
|
972
|
+
type: Schema.Literal("agent.model_set"),
|
|
973
|
+
sequence: SequenceNumber,
|
|
974
|
+
timestamp: Schema.String,
|
|
975
|
+
payload: Schema.Struct({
|
|
976
|
+
agentId: AgentId,
|
|
977
|
+
model: Schema.String,
|
|
978
|
+
claudeSessionId: Schema.optional(Schema.String),
|
|
979
|
+
sessionModel: Schema.optional(Schema.String),
|
|
980
|
+
sessionHarness: Schema.optional(Schema.String)
|
|
981
|
+
})
|
|
982
|
+
});
|
|
983
|
+
const AgentCurrentIssueSetEvent = Schema.Struct({
|
|
984
|
+
type: Schema.Literal("agent.current_issue_set"),
|
|
985
|
+
sequence: SequenceNumber,
|
|
986
|
+
timestamp: Schema.String,
|
|
987
|
+
payload: Schema.Struct({
|
|
988
|
+
agentId: AgentId,
|
|
989
|
+
currentIssue: Schema.optional(IssueId)
|
|
990
|
+
})
|
|
991
|
+
});
|
|
992
|
+
const AgentContextSaturationChangedEvent = Schema.Struct({
|
|
993
|
+
type: Schema.Literal("agent.context_saturation_changed"),
|
|
994
|
+
sequence: SequenceNumber,
|
|
995
|
+
timestamp: Schema.String,
|
|
996
|
+
payload: Schema.Struct({
|
|
997
|
+
agentId: AgentId,
|
|
998
|
+
contextSaturatedAt: Schema.optional(Schema.String)
|
|
999
|
+
})
|
|
1000
|
+
});
|
|
1001
|
+
const AgentResolutionChangedEvent = Schema.Struct({
|
|
1002
|
+
type: Schema.Literal("agent.resolution_changed"),
|
|
1003
|
+
sequence: SequenceNumber,
|
|
1004
|
+
timestamp: Schema.String,
|
|
1005
|
+
payload: Schema.Struct({
|
|
1006
|
+
agentId: AgentId,
|
|
1007
|
+
resolution: AgentResolution,
|
|
1008
|
+
resolutionCount: Schema.Number
|
|
1009
|
+
})
|
|
1010
|
+
});
|
|
1011
|
+
/**
|
|
1012
|
+
* Bootstrap-only event emitted by AgentStateService when it seeds a runtime
|
|
1013
|
+
* snapshot during bootstrap (reconstruction from sources, PAN-1920). Not
|
|
1014
|
+
* emitted by hooks.
|
|
1015
|
+
*/
|
|
1016
|
+
const AgentStateRestoredEvent = Schema.Struct({
|
|
1017
|
+
type: Schema.Literal("agent.state_restored"),
|
|
1018
|
+
sequence: SequenceNumber,
|
|
1019
|
+
timestamp: Schema.String,
|
|
1020
|
+
payload: Schema.Struct({
|
|
1021
|
+
agentId: AgentId,
|
|
1022
|
+
snapshot: AgentRuntimeSnapshot
|
|
1023
|
+
})
|
|
1024
|
+
});
|
|
1025
|
+
/** Emitted when a turn diff checkpoint is captured and diff computed */
|
|
1026
|
+
const AgentTurnDiffCompletedEvent = Schema.Struct({
|
|
1027
|
+
type: Schema.Literal("agent.turn_diff_completed"),
|
|
1028
|
+
sequence: SequenceNumber,
|
|
1029
|
+
timestamp: Schema.String,
|
|
1030
|
+
payload: Schema.Struct({
|
|
1031
|
+
agentId: AgentId,
|
|
1032
|
+
turnId: Schema.String,
|
|
1033
|
+
completedAt: Schema.String,
|
|
1034
|
+
files: Schema.Array(Schema.Struct({
|
|
1035
|
+
path: Schema.String,
|
|
1036
|
+
kind: Schema.optional(Schema.String),
|
|
1037
|
+
additions: Schema.optional(Schema.Number),
|
|
1038
|
+
deletions: Schema.optional(Schema.Number)
|
|
1039
|
+
})),
|
|
1040
|
+
checkpointRef: Schema.optional(Schema.String),
|
|
1041
|
+
assistantMessageId: Schema.optional(Schema.String),
|
|
1042
|
+
checkpointTurnCount: Schema.optional(Schema.Number)
|
|
1043
|
+
})
|
|
1044
|
+
});
|
|
1045
|
+
/** Replaces socket.io `planning:started` */
|
|
1046
|
+
const PlanningStartedEvent = Schema.Struct({
|
|
1047
|
+
type: Schema.Literal("planning.started"),
|
|
1048
|
+
sequence: SequenceNumber,
|
|
1049
|
+
timestamp: Schema.String,
|
|
1050
|
+
payload: Schema.Struct({
|
|
1051
|
+
issueId: IssueId,
|
|
1052
|
+
sessionName: Schema.String,
|
|
1053
|
+
harness: Schema.optional(Schema.String)
|
|
1054
|
+
})
|
|
1055
|
+
});
|
|
1056
|
+
/** Replaces socket.io `planning:failed` */
|
|
1057
|
+
const PlanningFailedEvent = Schema.Struct({
|
|
1058
|
+
type: Schema.Literal("planning.failed"),
|
|
1059
|
+
sequence: SequenceNumber,
|
|
1060
|
+
timestamp: Schema.String,
|
|
1061
|
+
payload: Schema.Struct({
|
|
1062
|
+
issueId: IssueId,
|
|
1063
|
+
error: Schema.String
|
|
1064
|
+
})
|
|
1065
|
+
});
|
|
1066
|
+
/** Replaces socket.io `planning:sync` */
|
|
1067
|
+
const PlanningSyncEvent = Schema.Struct({
|
|
1068
|
+
type: Schema.Literal("planning.sync"),
|
|
1069
|
+
sequence: SequenceNumber,
|
|
1070
|
+
timestamp: Schema.String,
|
|
1071
|
+
payload: Schema.Struct({
|
|
1072
|
+
issueId: IssueId,
|
|
1073
|
+
status: Schema.String,
|
|
1074
|
+
progress: Schema.optional(Schema.Number),
|
|
1075
|
+
message: Schema.optional(Schema.String)
|
|
1076
|
+
})
|
|
1077
|
+
});
|
|
1078
|
+
/** Replaces socket.io `plan:item-status-changed` */
|
|
1079
|
+
const PlanItemStatusChangedEvent = Schema.Struct({
|
|
1080
|
+
type: Schema.Literal("plan.item_status_changed"),
|
|
1081
|
+
sequence: SequenceNumber,
|
|
1082
|
+
timestamp: Schema.String,
|
|
1083
|
+
payload: Schema.Struct({
|
|
1084
|
+
issueId: IssueId,
|
|
1085
|
+
itemId: Schema.String,
|
|
1086
|
+
status: Schema.String
|
|
1087
|
+
})
|
|
1088
|
+
});
|
|
1089
|
+
/** Replaces socket.io `plan:subitem-status-changed` */
|
|
1090
|
+
const PlanSubitemStatusChangedEvent = Schema.Struct({
|
|
1091
|
+
type: Schema.Literal("plan.subitem_status_changed"),
|
|
1092
|
+
sequence: SequenceNumber,
|
|
1093
|
+
timestamp: Schema.String,
|
|
1094
|
+
payload: Schema.Struct({
|
|
1095
|
+
issueId: IssueId,
|
|
1096
|
+
itemId: Schema.String,
|
|
1097
|
+
subItemId: Schema.String,
|
|
1098
|
+
status: Schema.String
|
|
1099
|
+
})
|
|
1100
|
+
});
|
|
1101
|
+
/** Replaces socket.io `plan:items-unblocked` */
|
|
1102
|
+
const PlanItemsUnblockedEvent = Schema.Struct({
|
|
1103
|
+
type: Schema.Literal("plan.items_unblocked"),
|
|
1104
|
+
sequence: SequenceNumber,
|
|
1105
|
+
timestamp: Schema.String,
|
|
1106
|
+
payload: Schema.Struct({
|
|
1107
|
+
issueId: IssueId,
|
|
1108
|
+
items: Schema.Array(Schema.String)
|
|
1109
|
+
})
|
|
1110
|
+
});
|
|
1111
|
+
/** Replaces socket.io `pipeline:status` */
|
|
1112
|
+
const PipelineStatusChangedEvent = Schema.Struct({
|
|
1113
|
+
type: Schema.Literal("pipeline.status_changed"),
|
|
1114
|
+
sequence: SequenceNumber,
|
|
1115
|
+
timestamp: Schema.String,
|
|
1116
|
+
payload: Schema.Struct({
|
|
1117
|
+
issueId: IssueId,
|
|
1118
|
+
status: ReviewStatusSnapshot
|
|
1119
|
+
})
|
|
1120
|
+
});
|
|
1121
|
+
/** Replaces socket.io `merge:ready` */
|
|
1122
|
+
const MergeReadyEvent = Schema.Struct({
|
|
1123
|
+
type: Schema.Literal("merge.ready"),
|
|
1124
|
+
sequence: SequenceNumber,
|
|
1125
|
+
timestamp: Schema.String,
|
|
1126
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
1127
|
+
});
|
|
1128
|
+
/** New — review status changed */
|
|
1129
|
+
const ReviewStatusChangedEvent = Schema.Struct({
|
|
1130
|
+
type: Schema.Literal("review.status_changed"),
|
|
1131
|
+
sequence: SequenceNumber,
|
|
1132
|
+
timestamp: Schema.String,
|
|
1133
|
+
payload: Schema.Struct({
|
|
1134
|
+
issueId: IssueId,
|
|
1135
|
+
status: ReviewStatusSnapshot
|
|
1136
|
+
})
|
|
1137
|
+
});
|
|
1138
|
+
/** New — review specialist dispatched */
|
|
1139
|
+
const PipelineReviewStartedEvent = Schema.Struct({
|
|
1140
|
+
type: Schema.Literal("pipeline.review-started"),
|
|
1141
|
+
sequence: SequenceNumber,
|
|
1142
|
+
timestamp: Schema.String,
|
|
1143
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
1144
|
+
});
|
|
1145
|
+
/** New — review specialist finished (passed or failed) */
|
|
1146
|
+
const PipelineReviewCompletedEvent = Schema.Struct({
|
|
1147
|
+
type: Schema.Literal("pipeline.review-completed"),
|
|
1148
|
+
sequence: SequenceNumber,
|
|
1149
|
+
timestamp: Schema.String,
|
|
1150
|
+
payload: Schema.Struct({
|
|
1151
|
+
issueId: IssueId,
|
|
1152
|
+
passed: Schema.Boolean
|
|
1153
|
+
})
|
|
1154
|
+
});
|
|
1155
|
+
/** New — test specialist dispatched */
|
|
1156
|
+
const PipelineTestStartedEvent = Schema.Struct({
|
|
1157
|
+
type: Schema.Literal("pipeline.test-started"),
|
|
1158
|
+
sequence: SequenceNumber,
|
|
1159
|
+
timestamp: Schema.String,
|
|
1160
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
1161
|
+
});
|
|
1162
|
+
/** New — test specialist finished (passed or failed) */
|
|
1163
|
+
const PipelineTestCompletedEvent = Schema.Struct({
|
|
1164
|
+
type: Schema.Literal("pipeline.test-completed"),
|
|
1165
|
+
sequence: SequenceNumber,
|
|
1166
|
+
timestamp: Schema.String,
|
|
1167
|
+
payload: Schema.Struct({
|
|
1168
|
+
issueId: IssueId,
|
|
1169
|
+
passed: Schema.Boolean
|
|
1170
|
+
})
|
|
1171
|
+
});
|
|
1172
|
+
const OperatorInterventionEvent = Schema.Struct({
|
|
1173
|
+
type: Schema.Literal("operator.intervention"),
|
|
1174
|
+
sequence: SequenceNumber,
|
|
1175
|
+
timestamp: Schema.String,
|
|
1176
|
+
payload: Schema.Struct({
|
|
1177
|
+
issueId: IssueId,
|
|
1178
|
+
kind: Schema.Literals([
|
|
1179
|
+
"tell",
|
|
1180
|
+
"pause",
|
|
1181
|
+
"restart",
|
|
1182
|
+
"manual_edit",
|
|
1183
|
+
"deep_wipe",
|
|
1184
|
+
"unpause",
|
|
1185
|
+
"untroubled"
|
|
1186
|
+
]),
|
|
1187
|
+
source: Schema.String
|
|
1188
|
+
})
|
|
1189
|
+
});
|
|
1190
|
+
const SubstrateBugFiledEvent = Schema.Struct({
|
|
1191
|
+
type: Schema.Literal("substrate.bug_filed"),
|
|
1192
|
+
sequence: SequenceNumber,
|
|
1193
|
+
timestamp: Schema.String,
|
|
1194
|
+
payload: Schema.Struct({
|
|
1195
|
+
issueId: IssueId,
|
|
1196
|
+
runId: Schema.optional(Schema.String),
|
|
1197
|
+
filedBy: Schema.Literals(["agent", "operator"]),
|
|
1198
|
+
discoveredIn: Schema.optional(IssueId),
|
|
1199
|
+
severity: Schema.Literals([
|
|
1200
|
+
"P0",
|
|
1201
|
+
"P1",
|
|
1202
|
+
"P2"
|
|
1203
|
+
])
|
|
1204
|
+
})
|
|
1205
|
+
});
|
|
1206
|
+
/**
|
|
1207
|
+
* PAN-915 — reviewer session received a new prompt (spawn or resume of a
|
|
1208
|
+
* canonical PAN-830 session). Drives event-driven `reviewSubStatuses[role] =
|
|
1209
|
+
* 'running'` and tracking of `reviewSessionNames` without polling tmux.
|
|
1210
|
+
*/
|
|
1211
|
+
const ReviewReviewerStartedEvent = Schema.Struct({
|
|
1212
|
+
type: Schema.Literal("review.reviewer_started"),
|
|
1213
|
+
sequence: SequenceNumber,
|
|
1214
|
+
timestamp: Schema.String,
|
|
1215
|
+
payload: Schema.Struct({
|
|
1216
|
+
issueId: IssueId,
|
|
1217
|
+
role: Schema.String,
|
|
1218
|
+
sessionName: Schema.String
|
|
1219
|
+
})
|
|
1220
|
+
});
|
|
1221
|
+
/**
|
|
1222
|
+
* PAN-915 — reviewer wrote its output file (round complete for that role).
|
|
1223
|
+
* Updates `reviewSubStatuses[role] = 'done'` event-driven.
|
|
1224
|
+
*/
|
|
1225
|
+
const ReviewReviewerCompletedEvent = Schema.Struct({
|
|
1226
|
+
type: Schema.Literal("review.reviewer_completed"),
|
|
1227
|
+
sequence: SequenceNumber,
|
|
1228
|
+
timestamp: Schema.String,
|
|
1229
|
+
payload: Schema.Struct({
|
|
1230
|
+
issueId: IssueId,
|
|
1231
|
+
role: Schema.String
|
|
1232
|
+
})
|
|
1233
|
+
});
|
|
1234
|
+
/**
|
|
1235
|
+
* Review specialist timeout telemetry. Emitted once per timed-out reviewer wait
|
|
1236
|
+
* attempt so operators can distinguish transient auto-retries from terminal
|
|
1237
|
+
* review failures.
|
|
1238
|
+
*/
|
|
1239
|
+
const ReviewSpecialistTimedOutEvent = Schema.Struct({
|
|
1240
|
+
type: Schema.Literal("review.specialist.timed_out"),
|
|
1241
|
+
sequence: SequenceNumber,
|
|
1242
|
+
timestamp: Schema.String,
|
|
1243
|
+
payload: Schema.Struct({
|
|
1244
|
+
issueId: IssueId,
|
|
1245
|
+
role: Schema.String,
|
|
1246
|
+
sessionName: Schema.String,
|
|
1247
|
+
attempt: Schema.Number,
|
|
1248
|
+
maxRetries: Schema.Number,
|
|
1249
|
+
willRetry: Schema.Boolean
|
|
1250
|
+
})
|
|
1251
|
+
});
|
|
1252
|
+
/**
|
|
1253
|
+
* PAN-915 — review coordinator session spawned. Surfaces in the dashboard so
|
|
1254
|
+
* the kanban card can show "review in progress" the instant the coordinator
|
|
1255
|
+
* starts, not after the first reviewer finishes.
|
|
1256
|
+
*/
|
|
1257
|
+
const ReviewCoordinatorStartedEvent = Schema.Struct({
|
|
1258
|
+
type: Schema.Literal("review.coordinator_started"),
|
|
1259
|
+
sequence: SequenceNumber,
|
|
1260
|
+
timestamp: Schema.String,
|
|
1261
|
+
payload: Schema.Struct({
|
|
1262
|
+
issueId: IssueId,
|
|
1263
|
+
sessionName: Schema.String
|
|
1264
|
+
})
|
|
1265
|
+
});
|
|
1266
|
+
/** Review coordinator died before writing a terminal exit marker. */
|
|
1267
|
+
const ReviewCoordinatorDiedEvent = Schema.Struct({
|
|
1268
|
+
type: Schema.Literal("review.coordinator.died"),
|
|
1269
|
+
sequence: SequenceNumber,
|
|
1270
|
+
timestamp: Schema.String,
|
|
1271
|
+
payload: Schema.Struct({
|
|
1272
|
+
issueId: IssueId,
|
|
1273
|
+
sessionName: Schema.String,
|
|
1274
|
+
reason: Schema.String
|
|
1275
|
+
})
|
|
1276
|
+
});
|
|
1277
|
+
const SpecialistLifecycleState = Schema.Literals([
|
|
1278
|
+
"active",
|
|
1279
|
+
"sleeping",
|
|
1280
|
+
"uninitialized"
|
|
1281
|
+
]);
|
|
1282
|
+
/** New — role-backed specialist became active */
|
|
1283
|
+
const SpecialistStartedEvent = Schema.Struct({
|
|
1284
|
+
type: Schema.Literal("specialist.started"),
|
|
1285
|
+
sequence: SequenceNumber,
|
|
1286
|
+
timestamp: Schema.String,
|
|
1287
|
+
payload: Schema.Struct({
|
|
1288
|
+
name: Role,
|
|
1289
|
+
state: SpecialistLifecycleState,
|
|
1290
|
+
isRunning: Schema.Boolean,
|
|
1291
|
+
currentIssue: Schema.optional(Schema.String),
|
|
1292
|
+
lastWake: Schema.optional(Schema.String)
|
|
1293
|
+
})
|
|
1294
|
+
});
|
|
1295
|
+
/** New — role-backed specialist completed work */
|
|
1296
|
+
const SpecialistCompletedEvent = Schema.Struct({
|
|
1297
|
+
type: Schema.Literal("specialist.completed"),
|
|
1298
|
+
sequence: SequenceNumber,
|
|
1299
|
+
timestamp: Schema.String,
|
|
1300
|
+
payload: Schema.Struct({
|
|
1301
|
+
name: Role,
|
|
1302
|
+
issueId: Schema.optional(IssueId)
|
|
1303
|
+
})
|
|
1304
|
+
});
|
|
1305
|
+
/** New — role-backed specialist failed */
|
|
1306
|
+
const SpecialistFailedEvent = Schema.Struct({
|
|
1307
|
+
type: Schema.Literal("specialist.failed"),
|
|
1308
|
+
sequence: SequenceNumber,
|
|
1309
|
+
timestamp: Schema.String,
|
|
1310
|
+
payload: Schema.Struct({
|
|
1311
|
+
name: Role,
|
|
1312
|
+
issueId: Schema.optional(IssueId),
|
|
1313
|
+
error: Schema.String
|
|
1314
|
+
})
|
|
1315
|
+
});
|
|
1316
|
+
/** Replaces socket.io `resources:updated` */
|
|
1317
|
+
const ResourcesUpdatedEvent = Schema.Struct({
|
|
1318
|
+
type: Schema.Literal("resources.updated"),
|
|
1319
|
+
sequence: SequenceNumber,
|
|
1320
|
+
timestamp: Schema.String,
|
|
1321
|
+
payload: Schema.Struct({ resources: ResourceStats })
|
|
1322
|
+
});
|
|
1323
|
+
const SystemHealthSeverityChangedEvent = Schema.Struct({
|
|
1324
|
+
type: Schema.Literal("system.health_severity_changed"),
|
|
1325
|
+
sequence: SequenceNumber,
|
|
1326
|
+
timestamp: Schema.String,
|
|
1327
|
+
payload: Schema.Struct({
|
|
1328
|
+
previousSeverity: Schema.String,
|
|
1329
|
+
severity: Schema.String,
|
|
1330
|
+
reasons: Schema.Array(Schema.String),
|
|
1331
|
+
leakedSpecialistCount: Schema.Number
|
|
1332
|
+
})
|
|
1333
|
+
});
|
|
1334
|
+
/** Replaces socket.io `issues:snapshot` */
|
|
1335
|
+
const IssuesSnapshotEvent = Schema.Struct({
|
|
1336
|
+
type: Schema.Literal("issues.snapshot"),
|
|
1337
|
+
sequence: SequenceNumber,
|
|
1338
|
+
timestamp: Schema.String,
|
|
1339
|
+
payload: Schema.Struct({ issues: Schema.Array(Schema.Unknown) })
|
|
1340
|
+
});
|
|
1341
|
+
/** Replaces socket.io `issues:updated` */
|
|
1342
|
+
const IssuesUpdatedEvent = Schema.Struct({
|
|
1343
|
+
type: Schema.Literal("issues.updated"),
|
|
1344
|
+
sequence: SequenceNumber,
|
|
1345
|
+
timestamp: Schema.String,
|
|
1346
|
+
payload: Schema.Struct({ issueId: Schema.optional(IssueId) })
|
|
1347
|
+
});
|
|
1348
|
+
/** Patch a single issue's status in the read model without a full snapshot refresh. */
|
|
1349
|
+
const IssueStatusChangedEvent = Schema.Struct({
|
|
1350
|
+
type: Schema.Literal("issue.statusChanged"),
|
|
1351
|
+
sequence: SequenceNumber,
|
|
1352
|
+
timestamp: Schema.String,
|
|
1353
|
+
payload: Schema.Struct({
|
|
1354
|
+
issueId: IssueId,
|
|
1355
|
+
status: Schema.String,
|
|
1356
|
+
canonicalStatus: Schema.String,
|
|
1357
|
+
labels: Schema.optional(Schema.Array(Schema.String))
|
|
1358
|
+
})
|
|
1359
|
+
});
|
|
1360
|
+
/** Replaces socket.io `godview:activity` */
|
|
1361
|
+
const ActivityUpdatedEvent = Schema.Struct({
|
|
1362
|
+
type: Schema.Literal("activity.updated"),
|
|
1363
|
+
sequence: SequenceNumber,
|
|
1364
|
+
timestamp: Schema.String,
|
|
1365
|
+
payload: Schema.Struct({ events: Schema.Array(Schema.Unknown) })
|
|
1366
|
+
});
|
|
1367
|
+
/** Individual activity log entry — emitted by merge-agent, cloister, specialists (PAN-520) */
|
|
1368
|
+
const ActivityEntryEvent = Schema.Struct({
|
|
1369
|
+
type: Schema.Literal("activity.entry"),
|
|
1370
|
+
sequence: SequenceNumber,
|
|
1371
|
+
timestamp: Schema.String,
|
|
1372
|
+
payload: Schema.Struct({
|
|
1373
|
+
id: Schema.String,
|
|
1374
|
+
source: Schema.String,
|
|
1375
|
+
level: Schema.String,
|
|
1376
|
+
message: Schema.String,
|
|
1377
|
+
details: Schema.optional(Schema.String),
|
|
1378
|
+
issueId: Schema.optional(IssueId),
|
|
1379
|
+
/** Dashboard route the feed navigates to on click (e.g. /conv/<name>, /flywheel). */
|
|
1380
|
+
link: Schema.optional(Schema.String)
|
|
1381
|
+
})
|
|
1382
|
+
});
|
|
1383
|
+
/** Detailed activity log — auto-generated from domain state changes */
|
|
1384
|
+
const ActivityDetailedEvent = Schema.Struct({
|
|
1385
|
+
type: Schema.Literal("activity.detailed"),
|
|
1386
|
+
sequence: SequenceNumber,
|
|
1387
|
+
timestamp: Schema.String,
|
|
1388
|
+
payload: Schema.Struct({
|
|
1389
|
+
id: Schema.String,
|
|
1390
|
+
source: Schema.String,
|
|
1391
|
+
level: Schema.String,
|
|
1392
|
+
message: Schema.String,
|
|
1393
|
+
details: Schema.optional(Schema.String),
|
|
1394
|
+
issueId: Schema.optional(IssueId),
|
|
1395
|
+
triggeringEvent: Schema.optional(Schema.String)
|
|
1396
|
+
})
|
|
1397
|
+
});
|
|
1398
|
+
/** TTS activity log — upleveled utterances for text-to-speech */
|
|
1399
|
+
const ActivityTtsEvent = Schema.Struct({
|
|
1400
|
+
type: Schema.Literal("activity.tts"),
|
|
1401
|
+
sequence: SequenceNumber,
|
|
1402
|
+
timestamp: Schema.String,
|
|
1403
|
+
payload: Schema.Struct({
|
|
1404
|
+
id: Schema.String,
|
|
1405
|
+
utterance: Schema.String,
|
|
1406
|
+
priority: Schema.optional(Schema.Number),
|
|
1407
|
+
issueId: Schema.optional(IssueId),
|
|
1408
|
+
source: Schema.optional(Schema.String),
|
|
1409
|
+
eventType: Schema.optional(Schema.String)
|
|
1410
|
+
})
|
|
1411
|
+
});
|
|
1412
|
+
/** Dashboard is restarting (post-merge deploy, pan restart, etc.) (PAN-520) */
|
|
1413
|
+
const DashboardLifecycleStartedEvent = Schema.Struct({
|
|
1414
|
+
type: Schema.Literal("dashboard.lifecycle_started"),
|
|
1415
|
+
sequence: SequenceNumber,
|
|
1416
|
+
timestamp: Schema.String,
|
|
1417
|
+
payload: Schema.Struct({
|
|
1418
|
+
reason: Schema.String,
|
|
1419
|
+
issueId: Schema.optional(IssueId),
|
|
1420
|
+
trigger: Schema.String
|
|
1421
|
+
})
|
|
1422
|
+
});
|
|
1423
|
+
/** Dashboard restarted successfully after a lifecycle event (PAN-520) */
|
|
1424
|
+
const DashboardLifecycleCompletedEvent = Schema.Struct({
|
|
1425
|
+
type: Schema.Literal("dashboard.lifecycle_completed"),
|
|
1426
|
+
sequence: SequenceNumber,
|
|
1427
|
+
timestamp: Schema.String,
|
|
1428
|
+
payload: Schema.Struct({
|
|
1429
|
+
reason: Schema.String,
|
|
1430
|
+
issueId: Schema.optional(IssueId),
|
|
1431
|
+
durationMs: Schema.Number
|
|
1432
|
+
})
|
|
1433
|
+
});
|
|
1434
|
+
/** Dashboard restart failed (PAN-520) */
|
|
1435
|
+
const DashboardLifecycleFailedEvent = Schema.Struct({
|
|
1436
|
+
type: Schema.Literal("dashboard.lifecycle_failed"),
|
|
1437
|
+
sequence: SequenceNumber,
|
|
1438
|
+
timestamp: Schema.String,
|
|
1439
|
+
payload: Schema.Struct({
|
|
1440
|
+
reason: Schema.String,
|
|
1441
|
+
issueId: Schema.optional(IssueId),
|
|
1442
|
+
error: Schema.String
|
|
1443
|
+
})
|
|
1444
|
+
});
|
|
1445
|
+
/** Replaces socket.io `shadow:inference-update` */
|
|
1446
|
+
const ShadowInferenceUpdateEvent = Schema.Struct({
|
|
1447
|
+
type: Schema.Literal("shadow.inference_update"),
|
|
1448
|
+
sequence: SequenceNumber,
|
|
1449
|
+
timestamp: Schema.String,
|
|
1450
|
+
payload: Schema.Struct({
|
|
1451
|
+
issueId: IssueId,
|
|
1452
|
+
content: Schema.String
|
|
1453
|
+
})
|
|
1454
|
+
});
|
|
1455
|
+
/** New — workspace worktree created (before planning.started) */
|
|
1456
|
+
const WorkspaceCreatedEvent = Schema.Struct({
|
|
1457
|
+
type: Schema.Literal("workspace.created"),
|
|
1458
|
+
sequence: SequenceNumber,
|
|
1459
|
+
timestamp: Schema.String,
|
|
1460
|
+
payload: Schema.Struct({
|
|
1461
|
+
issueId: IssueId,
|
|
1462
|
+
workspacePath: Schema.String
|
|
1463
|
+
})
|
|
1464
|
+
});
|
|
1465
|
+
/** New — deep-wipe started (transitional state for UI spinner) */
|
|
1466
|
+
const WorkspaceWipeStartedEvent = Schema.Struct({
|
|
1467
|
+
type: Schema.Literal("workspace.wipe_started"),
|
|
1468
|
+
sequence: SequenceNumber,
|
|
1469
|
+
timestamp: Schema.String,
|
|
1470
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
1471
|
+
});
|
|
1472
|
+
/** New — deep-wipe completed, workspace fully destroyed */
|
|
1473
|
+
const WorkspaceDestroyedEvent = Schema.Struct({
|
|
1474
|
+
type: Schema.Literal("workspace.destroyed"),
|
|
1475
|
+
sequence: SequenceNumber,
|
|
1476
|
+
timestamp: Schema.String,
|
|
1477
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
1478
|
+
});
|
|
1479
|
+
/** New — cleanup-workspace completed, workspace directory removed */
|
|
1480
|
+
const WorkspaceDeletedEvent = Schema.Struct({
|
|
1481
|
+
type: Schema.Literal("workspace.deleted"),
|
|
1482
|
+
sequence: SequenceNumber,
|
|
1483
|
+
timestamp: Schema.String,
|
|
1484
|
+
payload: Schema.Struct({ issueId: IssueId })
|
|
1485
|
+
});
|
|
1486
|
+
/** New — planning aborted, workspace returned to idle state */
|
|
1487
|
+
const WorkspaceAbortedEvent = Schema.Struct({
|
|
1488
|
+
type: Schema.Literal("workspace.aborted"),
|
|
1489
|
+
sequence: SequenceNumber,
|
|
1490
|
+
timestamp: Schema.String,
|
|
1491
|
+
payload: Schema.Struct({
|
|
1492
|
+
issueId: IssueId,
|
|
1493
|
+
sessionName: Schema.optional(Schema.String)
|
|
1494
|
+
})
|
|
1495
|
+
});
|
|
1496
|
+
const MemoryObservationCreatedEvent = Schema.Struct({
|
|
1497
|
+
type: Schema.Literal("memory.observation_created"),
|
|
1498
|
+
sequence: SequenceNumber,
|
|
1499
|
+
timestamp: Schema.String,
|
|
1500
|
+
payload: Schema.Struct({ observation: MemoryObservation })
|
|
1501
|
+
});
|
|
1502
|
+
const MemoryStatusUpdatedEvent = Schema.Struct({
|
|
1503
|
+
type: Schema.Literal("memory.status_updated"),
|
|
1504
|
+
sequence: SequenceNumber,
|
|
1505
|
+
timestamp: Schema.String,
|
|
1506
|
+
payload: Schema.Struct({
|
|
1507
|
+
identity: Schema.Struct({
|
|
1508
|
+
projectId: Schema.String,
|
|
1509
|
+
workspaceId: Schema.String,
|
|
1510
|
+
issueId: IssueId
|
|
1511
|
+
}),
|
|
1512
|
+
status: MemoryStatus,
|
|
1513
|
+
previousStatus: Schema.optional(MemoryStatus)
|
|
1514
|
+
})
|
|
1515
|
+
});
|
|
1516
|
+
const MemoryRollupTriggeredEvent = Schema.Struct({
|
|
1517
|
+
type: Schema.Literal("memory.rollup_triggered"),
|
|
1518
|
+
sequence: SequenceNumber,
|
|
1519
|
+
timestamp: Schema.String,
|
|
1520
|
+
payload: Schema.Struct({
|
|
1521
|
+
projectId: Schema.String,
|
|
1522
|
+
workspaceId: Schema.String,
|
|
1523
|
+
issueId: IssueId,
|
|
1524
|
+
pendingCount: Schema.Number,
|
|
1525
|
+
turnIds: Schema.Array(Schema.String),
|
|
1526
|
+
threshold: Schema.Number
|
|
1527
|
+
})
|
|
1528
|
+
});
|
|
1529
|
+
const MemoryResetMarkerCreatedEvent = Schema.Struct({
|
|
1530
|
+
type: Schema.Literal("memory.reset_marker_created"),
|
|
1531
|
+
sequence: SequenceNumber,
|
|
1532
|
+
timestamp: Schema.String,
|
|
1533
|
+
payload: Schema.Struct({ marker: ResetMarker })
|
|
1534
|
+
});
|
|
1535
|
+
const MemoryHealthChangedEvent = Schema.Struct({
|
|
1536
|
+
type: Schema.Literal("memory.health_changed"),
|
|
1537
|
+
sequence: SequenceNumber,
|
|
1538
|
+
timestamp: Schema.String,
|
|
1539
|
+
payload: Schema.Struct({
|
|
1540
|
+
projectId: Schema.String,
|
|
1541
|
+
issueId: IssueId,
|
|
1542
|
+
status: Schema.Literals([
|
|
1543
|
+
"healthy",
|
|
1544
|
+
"degraded",
|
|
1545
|
+
"failing"
|
|
1546
|
+
]),
|
|
1547
|
+
reason: Schema.NullOr(Schema.String),
|
|
1548
|
+
detail: Schema.optional(Schema.String),
|
|
1549
|
+
ragDecision: Schema.optional(RagDecision)
|
|
1550
|
+
})
|
|
1551
|
+
});
|
|
1552
|
+
/** New — cost event recorded in the store */
|
|
1553
|
+
const CostEventRecordedEvent = Schema.Struct({
|
|
1554
|
+
type: Schema.Literal("cost.event_recorded"),
|
|
1555
|
+
sequence: SequenceNumber,
|
|
1556
|
+
timestamp: Schema.String,
|
|
1557
|
+
payload: Schema.Struct({
|
|
1558
|
+
agentId: AgentId,
|
|
1559
|
+
issueId: IssueId,
|
|
1560
|
+
cost: Schema.Number,
|
|
1561
|
+
inputTokens: Schema.Number,
|
|
1562
|
+
outputTokens: Schema.Number
|
|
1563
|
+
})
|
|
1564
|
+
});
|
|
1565
|
+
/** Emitted (in-memory only, not persisted) when a Overdeck-native compaction starts or completes. */
|
|
1566
|
+
const ConversationCompactingChangedEvent = Schema.Struct({
|
|
1567
|
+
type: Schema.Literal("conversation.compacting_changed"),
|
|
1568
|
+
sequence: SequenceNumber,
|
|
1569
|
+
timestamp: Schema.String,
|
|
1570
|
+
payload: Schema.Struct({
|
|
1571
|
+
conversationName: Schema.String,
|
|
1572
|
+
compacting: Schema.Boolean
|
|
1573
|
+
})
|
|
1574
|
+
});
|
|
1575
|
+
/** Emitted (in-memory only) when a new conversation row is created, so the
|
|
1576
|
+
* sidebar list can refresh immediately instead of waiting for its poll tick. */
|
|
1577
|
+
const ConversationCreatedEvent = Schema.Struct({
|
|
1578
|
+
type: Schema.Literal("conversation.created"),
|
|
1579
|
+
sequence: SequenceNumber,
|
|
1580
|
+
timestamp: Schema.String,
|
|
1581
|
+
payload: Schema.Struct({ conversationName: Schema.String })
|
|
1582
|
+
});
|
|
1583
|
+
/** Emitted (in-memory only) when a PermissionRequest hook fires or resolves for a conversation. */
|
|
1584
|
+
const ConversationPermissionChangedEvent = Schema.Struct({
|
|
1585
|
+
type: Schema.Literal("conversation.permission_changed"),
|
|
1586
|
+
sequence: SequenceNumber,
|
|
1587
|
+
timestamp: Schema.String,
|
|
1588
|
+
payload: Schema.Struct({
|
|
1589
|
+
conversationName: Schema.String,
|
|
1590
|
+
waiting: Schema.Boolean,
|
|
1591
|
+
toolName: Schema.optional(Schema.String)
|
|
1592
|
+
})
|
|
1593
|
+
});
|
|
1594
|
+
/** Scan started */
|
|
1595
|
+
const ScanStartedEvent = Schema.Struct({
|
|
1596
|
+
type: Schema.Literal("scan.started"),
|
|
1597
|
+
sequence: SequenceNumber,
|
|
1598
|
+
timestamp: Schema.String,
|
|
1599
|
+
payload: Schema.Struct({
|
|
1600
|
+
mode: Schema.Literals([
|
|
1601
|
+
"targeted",
|
|
1602
|
+
"watched",
|
|
1603
|
+
"system"
|
|
1604
|
+
]),
|
|
1605
|
+
dirs: Schema.Array(Schema.String)
|
|
1606
|
+
})
|
|
1607
|
+
});
|
|
1608
|
+
/** Scan progress tick */
|
|
1609
|
+
const ScanProgressEvent = Schema.Struct({
|
|
1610
|
+
type: Schema.Literal("scan.progress"),
|
|
1611
|
+
sequence: SequenceNumber,
|
|
1612
|
+
timestamp: Schema.String,
|
|
1613
|
+
payload: Schema.Struct({
|
|
1614
|
+
dirsProcessed: Schema.Number,
|
|
1615
|
+
dirsTotal: Schema.Number,
|
|
1616
|
+
sessionsFound: Schema.Number,
|
|
1617
|
+
elapsedMs: Schema.Number
|
|
1618
|
+
})
|
|
1619
|
+
});
|
|
1620
|
+
/** Scan completed */
|
|
1621
|
+
const ScanCompleteEvent = Schema.Struct({
|
|
1622
|
+
type: Schema.Literal("scan.complete"),
|
|
1623
|
+
sequence: SequenceNumber,
|
|
1624
|
+
timestamp: Schema.String,
|
|
1625
|
+
payload: Schema.Struct({
|
|
1626
|
+
inserted: Schema.Number,
|
|
1627
|
+
updated: Schema.Number,
|
|
1628
|
+
skipped: Schema.Number,
|
|
1629
|
+
errors: Schema.Number,
|
|
1630
|
+
durationMs: Schema.Number
|
|
1631
|
+
})
|
|
1632
|
+
});
|
|
1633
|
+
/** Per-session enrichment progress */
|
|
1634
|
+
const EnrichProgressEvent = Schema.Struct({
|
|
1635
|
+
type: Schema.Literal("enrich.progress"),
|
|
1636
|
+
sequence: SequenceNumber,
|
|
1637
|
+
timestamp: Schema.String,
|
|
1638
|
+
payload: Schema.Struct({
|
|
1639
|
+
sessionId: Schema.Number,
|
|
1640
|
+
level: Schema.Number,
|
|
1641
|
+
model: Schema.String,
|
|
1642
|
+
cost: Schema.Number,
|
|
1643
|
+
success: Schema.Boolean,
|
|
1644
|
+
error: Schema.optional(Schema.String)
|
|
1645
|
+
})
|
|
1646
|
+
});
|
|
1647
|
+
/** Enrichment batch completed */
|
|
1648
|
+
const EnrichCompleteEvent = Schema.Struct({
|
|
1649
|
+
type: Schema.Literal("enrich.complete"),
|
|
1650
|
+
sequence: SequenceNumber,
|
|
1651
|
+
timestamp: Schema.String,
|
|
1652
|
+
payload: Schema.Struct({
|
|
1653
|
+
processed: Schema.Number,
|
|
1654
|
+
totalCost: Schema.Number,
|
|
1655
|
+
failures: Schema.Number,
|
|
1656
|
+
durationMs: Schema.Number
|
|
1657
|
+
})
|
|
1658
|
+
});
|
|
1659
|
+
/** Per-session embedding progress */
|
|
1660
|
+
const EmbedProgressEvent = Schema.Struct({
|
|
1661
|
+
type: Schema.Literal("embed.progress"),
|
|
1662
|
+
sequence: SequenceNumber,
|
|
1663
|
+
timestamp: Schema.String,
|
|
1664
|
+
payload: Schema.Struct({
|
|
1665
|
+
sessionId: Schema.Number,
|
|
1666
|
+
model: Schema.String,
|
|
1667
|
+
success: Schema.Boolean,
|
|
1668
|
+
error: Schema.optional(Schema.String)
|
|
1669
|
+
})
|
|
1670
|
+
});
|
|
1671
|
+
/** All domain events — the shape streamed via subscribeDomainEvents RPC */
|
|
1672
|
+
const DomainEvent = Schema.Union([
|
|
1673
|
+
SystemHeartbeatEvent,
|
|
1674
|
+
AgentCreatedEvent,
|
|
1675
|
+
AgentEnrichmentChangedEvent,
|
|
1676
|
+
AgentStartedEvent,
|
|
1677
|
+
AgentStoppedEvent,
|
|
1678
|
+
AgentHeartbeatDeadEvent,
|
|
1679
|
+
WorkCompletedEvent,
|
|
1680
|
+
AgentCompletedEvent,
|
|
1681
|
+
ReviewApprovedEvent,
|
|
1682
|
+
TestPassedEvent,
|
|
1683
|
+
AgentStatusChangedEvent,
|
|
1684
|
+
AgentOutputReceivedEvent,
|
|
1685
|
+
AgentActivityChangedEvent,
|
|
1686
|
+
AgentThinkingStartedEvent,
|
|
1687
|
+
AgentThinkingStoppedEvent,
|
|
1688
|
+
AgentWaitingStartedEvent,
|
|
1689
|
+
AgentWaitingClearedEvent,
|
|
1690
|
+
AgentPermissionRequestedEvent,
|
|
1691
|
+
AgentPermissionResolvedEvent,
|
|
1692
|
+
AgentMessageReceivedEvent,
|
|
1693
|
+
AgentChannelReplyEvent,
|
|
1694
|
+
AgentModelSetEvent,
|
|
1695
|
+
AgentCurrentIssueSetEvent,
|
|
1696
|
+
AgentContextSaturationChangedEvent,
|
|
1697
|
+
AgentResolutionChangedEvent,
|
|
1698
|
+
AgentStateRestoredEvent,
|
|
1699
|
+
AgentTurnDiffCompletedEvent,
|
|
1700
|
+
PlanningStartedEvent,
|
|
1701
|
+
PlanningFailedEvent,
|
|
1702
|
+
PlanningSyncEvent,
|
|
1703
|
+
PlanItemStatusChangedEvent,
|
|
1704
|
+
PlanSubitemStatusChangedEvent,
|
|
1705
|
+
PlanItemsUnblockedEvent,
|
|
1706
|
+
PipelineStatusChangedEvent,
|
|
1707
|
+
MergeReadyEvent,
|
|
1708
|
+
ReviewStatusChangedEvent,
|
|
1709
|
+
PipelineReviewStartedEvent,
|
|
1710
|
+
PipelineReviewCompletedEvent,
|
|
1711
|
+
PipelineTestStartedEvent,
|
|
1712
|
+
PipelineTestCompletedEvent,
|
|
1713
|
+
OperatorInterventionEvent,
|
|
1714
|
+
SubstrateBugFiledEvent,
|
|
1715
|
+
ReviewReviewerStartedEvent,
|
|
1716
|
+
ReviewReviewerCompletedEvent,
|
|
1717
|
+
ReviewSpecialistTimedOutEvent,
|
|
1718
|
+
ReviewCoordinatorStartedEvent,
|
|
1719
|
+
ReviewCoordinatorDiedEvent,
|
|
1720
|
+
SpecialistStartedEvent,
|
|
1721
|
+
SpecialistCompletedEvent,
|
|
1722
|
+
SpecialistFailedEvent,
|
|
1723
|
+
ResourcesUpdatedEvent,
|
|
1724
|
+
SystemHealthSeverityChangedEvent,
|
|
1725
|
+
IssuesSnapshotEvent,
|
|
1726
|
+
IssuesUpdatedEvent,
|
|
1727
|
+
IssueStatusChangedEvent,
|
|
1728
|
+
ActivityUpdatedEvent,
|
|
1729
|
+
ActivityEntryEvent,
|
|
1730
|
+
ActivityDetailedEvent,
|
|
1731
|
+
ActivityTtsEvent,
|
|
1732
|
+
ShadowInferenceUpdateEvent,
|
|
1733
|
+
MemoryObservationCreatedEvent,
|
|
1734
|
+
MemoryStatusUpdatedEvent,
|
|
1735
|
+
MemoryRollupTriggeredEvent,
|
|
1736
|
+
MemoryResetMarkerCreatedEvent,
|
|
1737
|
+
MemoryHealthChangedEvent,
|
|
1738
|
+
CostEventRecordedEvent,
|
|
1739
|
+
WorkspaceCreatedEvent,
|
|
1740
|
+
WorkspaceWipeStartedEvent,
|
|
1741
|
+
WorkspaceDestroyedEvent,
|
|
1742
|
+
WorkspaceDeletedEvent,
|
|
1743
|
+
WorkspaceAbortedEvent,
|
|
1744
|
+
DashboardLifecycleStartedEvent,
|
|
1745
|
+
DashboardLifecycleCompletedEvent,
|
|
1746
|
+
DashboardLifecycleFailedEvent,
|
|
1747
|
+
ConversationCompactingChangedEvent,
|
|
1748
|
+
ConversationCreatedEvent,
|
|
1749
|
+
ConversationPermissionChangedEvent,
|
|
1750
|
+
ScanStartedEvent,
|
|
1751
|
+
ScanProgressEvent,
|
|
1752
|
+
ScanCompleteEvent,
|
|
1753
|
+
EnrichProgressEvent,
|
|
1754
|
+
EnrichCompleteEvent,
|
|
1755
|
+
EmbedProgressEvent
|
|
1756
|
+
]);
|
|
1757
|
+
//#endregion
|
|
1758
|
+
//#region src/editor.ts
|
|
1759
|
+
const EDITORS = [
|
|
1760
|
+
{
|
|
1761
|
+
id: "cursor",
|
|
1762
|
+
label: "Cursor",
|
|
1763
|
+
command: "cursor",
|
|
1764
|
+
supportsGoto: true
|
|
1765
|
+
},
|
|
1766
|
+
{
|
|
1767
|
+
id: "windsurf",
|
|
1768
|
+
label: "Windsurf",
|
|
1769
|
+
command: "windsurf",
|
|
1770
|
+
supportsGoto: true
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
id: "trae",
|
|
1774
|
+
label: "Trae",
|
|
1775
|
+
command: "trae",
|
|
1776
|
+
supportsGoto: true
|
|
1777
|
+
},
|
|
1778
|
+
{
|
|
1779
|
+
id: "kiro",
|
|
1780
|
+
label: "Kiro",
|
|
1781
|
+
command: "kiro",
|
|
1782
|
+
supportsGoto: true
|
|
1783
|
+
},
|
|
1784
|
+
{
|
|
1785
|
+
id: "vscode",
|
|
1786
|
+
label: "VS Code",
|
|
1787
|
+
command: "code",
|
|
1788
|
+
supportsGoto: true
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
id: "vscode-insiders",
|
|
1792
|
+
label: "VS Code Insiders",
|
|
1793
|
+
command: "code-insiders",
|
|
1794
|
+
supportsGoto: true
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
id: "vscodium",
|
|
1798
|
+
label: "VSCodium",
|
|
1799
|
+
command: "codium",
|
|
1800
|
+
supportsGoto: true
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
id: "zed",
|
|
1804
|
+
label: "Zed",
|
|
1805
|
+
command: "zed",
|
|
1806
|
+
supportsGoto: false
|
|
1807
|
+
},
|
|
1808
|
+
{
|
|
1809
|
+
id: "antigravity",
|
|
1810
|
+
label: "Antigravity",
|
|
1811
|
+
command: "agy",
|
|
1812
|
+
supportsGoto: false
|
|
1813
|
+
},
|
|
1814
|
+
{
|
|
1815
|
+
id: "idea",
|
|
1816
|
+
label: "IntelliJ IDEA",
|
|
1817
|
+
command: "idea",
|
|
1818
|
+
supportsGoto: true
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
id: "aqua",
|
|
1822
|
+
label: "Aqua",
|
|
1823
|
+
command: "aqua",
|
|
1824
|
+
supportsGoto: true
|
|
1825
|
+
},
|
|
1826
|
+
{
|
|
1827
|
+
id: "clion",
|
|
1828
|
+
label: "CLion",
|
|
1829
|
+
command: "clion",
|
|
1830
|
+
supportsGoto: true
|
|
1831
|
+
},
|
|
1832
|
+
{
|
|
1833
|
+
id: "datagrip",
|
|
1834
|
+
label: "DataGrip",
|
|
1835
|
+
command: "datagrip",
|
|
1836
|
+
supportsGoto: true
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
id: "dataspell",
|
|
1840
|
+
label: "DataSpell",
|
|
1841
|
+
command: "dataspell",
|
|
1842
|
+
supportsGoto: true
|
|
1843
|
+
},
|
|
1844
|
+
{
|
|
1845
|
+
id: "goland",
|
|
1846
|
+
label: "GoLand",
|
|
1847
|
+
command: "goland",
|
|
1848
|
+
supportsGoto: true
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
id: "phpstorm",
|
|
1852
|
+
label: "PhpStorm",
|
|
1853
|
+
command: "phpstorm",
|
|
1854
|
+
supportsGoto: true
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
id: "pycharm",
|
|
1858
|
+
label: "PyCharm",
|
|
1859
|
+
command: "pycharm",
|
|
1860
|
+
supportsGoto: true
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
id: "rider",
|
|
1864
|
+
label: "Rider",
|
|
1865
|
+
command: "rider",
|
|
1866
|
+
supportsGoto: true
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
id: "rubymine",
|
|
1870
|
+
label: "RubyMine",
|
|
1871
|
+
command: "rubymine",
|
|
1872
|
+
supportsGoto: true
|
|
1873
|
+
},
|
|
1874
|
+
{
|
|
1875
|
+
id: "rustrover",
|
|
1876
|
+
label: "RustRover",
|
|
1877
|
+
command: "rustrover",
|
|
1878
|
+
supportsGoto: true
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
id: "webstorm",
|
|
1882
|
+
label: "WebStorm",
|
|
1883
|
+
command: "webstorm",
|
|
1884
|
+
supportsGoto: true
|
|
1885
|
+
},
|
|
1886
|
+
{
|
|
1887
|
+
id: "file-manager",
|
|
1888
|
+
label: "File Manager",
|
|
1889
|
+
command: null,
|
|
1890
|
+
supportsGoto: false
|
|
1891
|
+
}
|
|
1892
|
+
];
|
|
1893
|
+
const EditorIdSchema = Schema.Literals([
|
|
1894
|
+
"cursor",
|
|
1895
|
+
"windsurf",
|
|
1896
|
+
"trae",
|
|
1897
|
+
"kiro",
|
|
1898
|
+
"vscode",
|
|
1899
|
+
"vscode-insiders",
|
|
1900
|
+
"vscodium",
|
|
1901
|
+
"zed",
|
|
1902
|
+
"antigravity",
|
|
1903
|
+
"idea",
|
|
1904
|
+
"aqua",
|
|
1905
|
+
"clion",
|
|
1906
|
+
"datagrip",
|
|
1907
|
+
"dataspell",
|
|
1908
|
+
"goland",
|
|
1909
|
+
"phpstorm",
|
|
1910
|
+
"pycharm",
|
|
1911
|
+
"rider",
|
|
1912
|
+
"rubymine",
|
|
1913
|
+
"rustrover",
|
|
1914
|
+
"webstorm",
|
|
1915
|
+
"file-manager"
|
|
1916
|
+
]);
|
|
1917
|
+
const OpenInEditorInput = Schema.Struct({
|
|
1918
|
+
cwd: Schema.String,
|
|
1919
|
+
editor: EditorIdSchema
|
|
1920
|
+
});
|
|
1921
|
+
//#endregion
|
|
1922
|
+
//#region src/flywheel.ts
|
|
1923
|
+
const FlywheelRunId = Schema.String.check(Schema.isPattern(/^RUN-\d+$/));
|
|
1924
|
+
const FlywheelHttpUrl = Schema.String.check(Schema.isPattern(/^https?:\/\/\S+$/i));
|
|
1925
|
+
const FlywheelHarness = Schema.Literals([
|
|
1926
|
+
"claude-code",
|
|
1927
|
+
"pi",
|
|
1928
|
+
"codex"
|
|
1929
|
+
]);
|
|
1930
|
+
const FlywheelEffort = Schema.Literals([
|
|
1931
|
+
"low",
|
|
1932
|
+
"medium",
|
|
1933
|
+
"high",
|
|
1934
|
+
"xhigh",
|
|
1935
|
+
"max"
|
|
1936
|
+
]);
|
|
1937
|
+
const FlywheelOrchestrator = Schema.Struct({
|
|
1938
|
+
harness: FlywheelHarness,
|
|
1939
|
+
model: Schema.String,
|
|
1940
|
+
effort: FlywheelEffort,
|
|
1941
|
+
ctxPercent: Schema.Number
|
|
1942
|
+
});
|
|
1943
|
+
const FlywheelHeadline = Schema.Struct({
|
|
1944
|
+
bugsFixed: Schema.Number,
|
|
1945
|
+
swarmItemsMerged: Schema.Number,
|
|
1946
|
+
swarmItemsTotal: Schema.Number,
|
|
1947
|
+
prsMerged: Schema.Number,
|
|
1948
|
+
awaitingUat: Schema.Number
|
|
1949
|
+
});
|
|
1950
|
+
/**
|
|
1951
|
+
* Pipeline verbs and the merge-queue contract (PAN-1736):
|
|
1952
|
+
*
|
|
1953
|
+
* `computeMergeQueue` treats an item as AT THE MERGE GATE when its verb is
|
|
1954
|
+
* "shipping" OR "merging" — both are natural emissions for a merge-ready
|
|
1955
|
+
* issue, and orchestrators have used each. Emitting any OTHER verb for an
|
|
1956
|
+
* issue that is ready_for_merge in the review DB silently drops it from the
|
|
1957
|
+
* merge queue and from UAT batch assembly (PAN-1737). RUN-18 shipped an
|
|
1958
|
+
* empty queue with five ready issues exactly this way.
|
|
1959
|
+
*
|
|
1960
|
+
* If you add a verb that can describe a merge-ready issue, extend
|
|
1961
|
+
* MERGE_GATE_VERBS in src/lib/flywheel-merge-order.ts in the same change.
|
|
1962
|
+
*/
|
|
1963
|
+
const FlywheelPipelineVerb = Schema.Literals([
|
|
1964
|
+
"planning",
|
|
1965
|
+
"working",
|
|
1966
|
+
"reviewing",
|
|
1967
|
+
"testing",
|
|
1968
|
+
"shipping",
|
|
1969
|
+
"merging",
|
|
1970
|
+
"blocked",
|
|
1971
|
+
"parked"
|
|
1972
|
+
]);
|
|
1973
|
+
const FlywheelPipelineStatus = Schema.Literals([
|
|
1974
|
+
"queued",
|
|
1975
|
+
"running",
|
|
1976
|
+
"blocked",
|
|
1977
|
+
"passed",
|
|
1978
|
+
"failed",
|
|
1979
|
+
"merged",
|
|
1980
|
+
"parked"
|
|
1981
|
+
]);
|
|
1982
|
+
const FlywheelPipelineItem = Schema.Struct({
|
|
1983
|
+
issueId: Schema.String,
|
|
1984
|
+
title: Schema.String,
|
|
1985
|
+
verb: FlywheelPipelineVerb,
|
|
1986
|
+
status: FlywheelPipelineStatus,
|
|
1987
|
+
progressPercent: Schema.optional(Schema.Number),
|
|
1988
|
+
agentId: Schema.optional(Schema.String),
|
|
1989
|
+
pr: Schema.optional(Schema.Number),
|
|
1990
|
+
mergeOrder: Schema.optional(Schema.Number),
|
|
1991
|
+
conflictsWith: Schema.optional(Schema.Array(Schema.String))
|
|
1992
|
+
});
|
|
1993
|
+
const FlywheelSubstrateBugStatus = Schema.Literals([
|
|
1994
|
+
"filed",
|
|
1995
|
+
"fixed",
|
|
1996
|
+
"workaround"
|
|
1997
|
+
]);
|
|
1998
|
+
const FlywheelSubstrateBug = Schema.Struct({
|
|
1999
|
+
issueId: Schema.String,
|
|
2000
|
+
title: Schema.String,
|
|
2001
|
+
status: FlywheelSubstrateBugStatus,
|
|
2002
|
+
commitSha: Schema.optional(Schema.String),
|
|
2003
|
+
url: Schema.optional(FlywheelHttpUrl)
|
|
2004
|
+
});
|
|
2005
|
+
const FlywheelAgentStatus = Schema.Literals([
|
|
2006
|
+
"starting",
|
|
2007
|
+
"running",
|
|
2008
|
+
"waiting",
|
|
2009
|
+
"idle",
|
|
2010
|
+
"stopped",
|
|
2011
|
+
"error"
|
|
2012
|
+
]);
|
|
2013
|
+
const FlywheelAgent = Schema.Struct({
|
|
2014
|
+
id: Schema.String,
|
|
2015
|
+
label: Schema.String,
|
|
2016
|
+
status: FlywheelAgentStatus,
|
|
2017
|
+
issueId: Schema.optional(Schema.String),
|
|
2018
|
+
role: Schema.optional(Schema.String),
|
|
2019
|
+
model: Schema.optional(Schema.String),
|
|
2020
|
+
ctxPercent: Schema.optional(Schema.Number),
|
|
2021
|
+
currentAction: Schema.optional(Schema.String)
|
|
2022
|
+
});
|
|
2023
|
+
const FlywheelParkedItem = Schema.Struct({
|
|
2024
|
+
issueId: Schema.String,
|
|
2025
|
+
title: Schema.String,
|
|
2026
|
+
reason: Schema.String,
|
|
2027
|
+
parkedAt: Schema.optional(Schema.String)
|
|
2028
|
+
});
|
|
2029
|
+
const FlywheelSuggestionAction = Schema.Literals([
|
|
2030
|
+
"start",
|
|
2031
|
+
"resume",
|
|
2032
|
+
"plan",
|
|
2033
|
+
"review",
|
|
2034
|
+
"merge",
|
|
2035
|
+
"unblock",
|
|
2036
|
+
"park",
|
|
2037
|
+
"investigate",
|
|
2038
|
+
"wait"
|
|
2039
|
+
]);
|
|
2040
|
+
const FlywheelSuggestionPriority = Schema.Literals([
|
|
2041
|
+
"urgent",
|
|
2042
|
+
"high",
|
|
2043
|
+
"medium",
|
|
2044
|
+
"low"
|
|
2045
|
+
]);
|
|
2046
|
+
const FlywheelSuggestion = Schema.Struct({
|
|
2047
|
+
action: FlywheelSuggestionAction,
|
|
2048
|
+
issueId: Schema.optional(Schema.String),
|
|
2049
|
+
rationale: Schema.String,
|
|
2050
|
+
priority: FlywheelSuggestionPriority
|
|
2051
|
+
});
|
|
2052
|
+
const FlywheelSystemStatus = Schema.Struct({
|
|
2053
|
+
mainHead: Schema.String,
|
|
2054
|
+
ramUsedMb: Schema.Number,
|
|
2055
|
+
ramTotalMb: Schema.Number,
|
|
2056
|
+
swapUsedMb: Schema.Number,
|
|
2057
|
+
swapTotalMb: Schema.Number,
|
|
2058
|
+
agentsActive: Schema.Number,
|
|
2059
|
+
agentsCap: Schema.Number
|
|
2060
|
+
});
|
|
2061
|
+
const FlywheelStatus = Schema.Struct({
|
|
2062
|
+
runId: FlywheelRunId,
|
|
2063
|
+
startedAt: Schema.String,
|
|
2064
|
+
elapsedMs: Schema.Number,
|
|
2065
|
+
orchestrator: FlywheelOrchestrator,
|
|
2066
|
+
headline: FlywheelHeadline,
|
|
2067
|
+
activePipeline: Schema.Array(FlywheelPipelineItem),
|
|
2068
|
+
substrateBugs: Schema.Array(FlywheelSubstrateBug),
|
|
2069
|
+
agents: Schema.Array(FlywheelAgent),
|
|
2070
|
+
parked: Schema.Array(FlywheelParkedItem),
|
|
2071
|
+
suggestions: Schema.Array(FlywheelSuggestion).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
2072
|
+
system: FlywheelSystemStatus,
|
|
2073
|
+
openQuestions: Schema.Array(Schema.String),
|
|
2074
|
+
ticks: Schema.Number,
|
|
2075
|
+
lastTickAt: Schema.String
|
|
2076
|
+
});
|
|
2077
|
+
//#endregion
|
|
2078
|
+
//#region src/rpc.ts
|
|
2079
|
+
const WS_METHODS = {
|
|
2080
|
+
scanConversations: "pan.scanConversations",
|
|
2081
|
+
searchConversations: "pan.searchConversations",
|
|
2082
|
+
listDiscoveredSessions: "pan.listDiscoveredSessions",
|
|
2083
|
+
getDiscoveredSession: "pan.getDiscoveredSession",
|
|
2084
|
+
enrichSessions: "pan.enrichSessions",
|
|
2085
|
+
embedSessions: "pan.embedSessions",
|
|
2086
|
+
getConversationCost: "pan.getConversationCost",
|
|
2087
|
+
getConversationCostByWorkspace: "pan.getConversationCostByWorkspace",
|
|
2088
|
+
getConversationStats: "pan.getConversationStats",
|
|
2089
|
+
subscribeDomainEvents: "pan.subscribeDomainEvents",
|
|
2090
|
+
subscribeIssueEvents: "pan.subscribeIssueEvents",
|
|
2091
|
+
subscribeTerminal: "pan.subscribeTerminal",
|
|
2092
|
+
subscribeAgentOutput: "pan.subscribeAgentOutput",
|
|
2093
|
+
subscribeConversationMessages: "pan.subscribeConversationMessages",
|
|
2094
|
+
subscribeProjectSessionTree: "pan.subscribeProjectSessionTree",
|
|
2095
|
+
subscribeFlywheelStatus: "pan.subscribeFlywheelStatus",
|
|
2096
|
+
getSnapshot: "pan.getSnapshot",
|
|
2097
|
+
replayEvents: "pan.replayEvents",
|
|
2098
|
+
getWorkspaceDetail: "pan.getWorkspaceDetail",
|
|
2099
|
+
readWorkspaceFile: "pan.readWorkspaceFile",
|
|
2100
|
+
resolveFilePathExists: "pan.resolveFilePathExists",
|
|
2101
|
+
terminalOpen: "pan.terminalOpen",
|
|
2102
|
+
terminalWrite: "pan.terminalWrite",
|
|
2103
|
+
terminalResize: "pan.terminalResize",
|
|
2104
|
+
terminalClose: "pan.terminalClose",
|
|
2105
|
+
startPlanning: "pan.startPlanning",
|
|
2106
|
+
startAgent: "pan.startAgent",
|
|
2107
|
+
deepWipe: "pan.deepWipe",
|
|
2108
|
+
sendTerminalInput: "pan.sendTerminalInput",
|
|
2109
|
+
resizeTerminal: "pan.resizeTerminal",
|
|
2110
|
+
shellOpenInEditor: "pan.shellOpenInEditor",
|
|
2111
|
+
getAvailableEditors: "pan.getAvailableEditors"
|
|
2112
|
+
};
|
|
2113
|
+
var PanRpcError = class extends Schema.TaggedErrorClass()("PanRpcError", {
|
|
2114
|
+
message: Schema.String,
|
|
2115
|
+
code: Schema.optional(Schema.String)
|
|
2116
|
+
}) {};
|
|
2117
|
+
const TerminalOutput = Schema.Struct({
|
|
2118
|
+
sessionName: Schema.String,
|
|
2119
|
+
data: Schema.String
|
|
2120
|
+
});
|
|
2121
|
+
const AgentOutput = Schema.Struct({
|
|
2122
|
+
agentId: Schema.String,
|
|
2123
|
+
line: Schema.String
|
|
2124
|
+
});
|
|
2125
|
+
const ProposedPlan = Schema.Struct({
|
|
2126
|
+
id: Schema.String,
|
|
2127
|
+
plan: Schema.String,
|
|
2128
|
+
planFilePath: Schema.optional(Schema.String),
|
|
2129
|
+
status: Schema.Literals([
|
|
2130
|
+
"pending",
|
|
2131
|
+
"approved",
|
|
2132
|
+
"rejected"
|
|
2133
|
+
]),
|
|
2134
|
+
createdAt: Schema.String,
|
|
2135
|
+
resolvedAt: Schema.optional(Schema.String)
|
|
2136
|
+
});
|
|
2137
|
+
const CompactBoundary = Schema.Struct({
|
|
2138
|
+
id: Schema.String,
|
|
2139
|
+
timestamp: Schema.String,
|
|
2140
|
+
trigger: Schema.optional(Schema.String),
|
|
2141
|
+
preTokens: Schema.optional(Schema.Number),
|
|
2142
|
+
model: Schema.optional(Schema.String)
|
|
2143
|
+
});
|
|
2144
|
+
const ContextUsage = Schema.Struct({
|
|
2145
|
+
activeBytes: Schema.Number,
|
|
2146
|
+
estimatedTokens: Schema.Number,
|
|
2147
|
+
contextWindow: Schema.Number,
|
|
2148
|
+
percentUsed: Schema.Number,
|
|
2149
|
+
/**
|
|
2150
|
+
* Optional breakdown of the last assistant turn — surfaced by the click
|
|
2151
|
+
* popover on the ContextWindowMeter so users can see WHY the meter says
|
|
2152
|
+
* what it does. Computed by `computeContextUsage()` from JSONL `usage`.
|
|
2153
|
+
*/
|
|
2154
|
+
lastInputTokens: Schema.optional(Schema.Number),
|
|
2155
|
+
lastCacheReadTokens: Schema.optional(Schema.Number),
|
|
2156
|
+
lastCacheCreationTokens: Schema.optional(Schema.Number),
|
|
2157
|
+
/** Highest input_tokens ever observed in this window — triggers 1M detection. */
|
|
2158
|
+
maxObservedInputTokens: Schema.optional(Schema.Number),
|
|
2159
|
+
/** Model the most recent assistant turn ran under (from JSONL). */
|
|
2160
|
+
lastModel: Schema.optional(Schema.NullOr(Schema.String)),
|
|
2161
|
+
/** ISO timestamp of the most recent assistant turn. */
|
|
2162
|
+
lastTurnAt: Schema.optional(Schema.NullOr(Schema.String))
|
|
2163
|
+
});
|
|
2164
|
+
const ChatMessage = Schema.Struct({
|
|
2165
|
+
id: Schema.String,
|
|
2166
|
+
role: Schema.Literals([
|
|
2167
|
+
"user",
|
|
2168
|
+
"assistant",
|
|
2169
|
+
"system"
|
|
2170
|
+
]),
|
|
2171
|
+
text: Schema.String,
|
|
2172
|
+
turnId: Schema.optional(Schema.String),
|
|
2173
|
+
createdAt: Schema.String,
|
|
2174
|
+
completedAt: Schema.optional(Schema.String),
|
|
2175
|
+
streaming: Schema.optional(Schema.Boolean),
|
|
2176
|
+
sequence: Schema.optional(Schema.Number)
|
|
2177
|
+
});
|
|
2178
|
+
const WorkLogEntry = Schema.Struct({
|
|
2179
|
+
id: Schema.String,
|
|
2180
|
+
createdAt: Schema.String,
|
|
2181
|
+
label: Schema.String,
|
|
2182
|
+
detail: Schema.optional(Schema.String),
|
|
2183
|
+
/** Tool result output (populated when tool_result is received). */
|
|
2184
|
+
result: Schema.optional(Schema.String),
|
|
2185
|
+
command: Schema.optional(Schema.String),
|
|
2186
|
+
changedFiles: Schema.optional(Schema.Array(Schema.String)),
|
|
2187
|
+
tone: Schema.Literals([
|
|
2188
|
+
"thinking",
|
|
2189
|
+
"tool",
|
|
2190
|
+
"info",
|
|
2191
|
+
"error"
|
|
2192
|
+
]),
|
|
2193
|
+
toolTitle: Schema.optional(Schema.String),
|
|
2194
|
+
/** Raw tool_use input dict — drives per-tool expanded rendering (PAN-1459). */
|
|
2195
|
+
toolInput: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
|
2196
|
+
sequence: Schema.optional(Schema.Number)
|
|
2197
|
+
});
|
|
2198
|
+
const ConversationEvent = Schema.Union([Schema.Struct({
|
|
2199
|
+
kind: Schema.Literal("messages"),
|
|
2200
|
+
messages: Schema.Array(ChatMessage),
|
|
2201
|
+
workLog: Schema.Array(WorkLogEntry),
|
|
2202
|
+
streaming: Schema.Boolean,
|
|
2203
|
+
snapshot: Schema.optional(Schema.Boolean),
|
|
2204
|
+
proposedPlan: Schema.optional(ProposedPlan),
|
|
2205
|
+
compactBoundaries: Schema.optional(Schema.Array(CompactBoundary)),
|
|
2206
|
+
contextUsage: Schema.optional(Schema.NullOr(ContextUsage))
|
|
2207
|
+
}), Schema.Struct({ kind: Schema.Literal("discovering") })]);
|
|
2208
|
+
const SessionTreeDelta = Schema.Struct({
|
|
2209
|
+
kind: Schema.Literals([
|
|
2210
|
+
"session_added",
|
|
2211
|
+
"session_removed",
|
|
2212
|
+
"presence_changed",
|
|
2213
|
+
"status_changed"
|
|
2214
|
+
]),
|
|
2215
|
+
issueId: Schema.String,
|
|
2216
|
+
sessionId: Schema.String,
|
|
2217
|
+
presence: Schema.optional(SessionNodePresence),
|
|
2218
|
+
status: Schema.optional(AgentStatus),
|
|
2219
|
+
timestamp: Schema.String
|
|
2220
|
+
});
|
|
2221
|
+
/** 1. Subscribe to the live domain event stream (stream) */
|
|
2222
|
+
const SubscribeDomainEventsRpc = Rpc.make(WS_METHODS.subscribeDomainEvents, {
|
|
2223
|
+
payload: Schema.Struct({}),
|
|
2224
|
+
success: DomainEvent,
|
|
2225
|
+
stream: true
|
|
2226
|
+
});
|
|
2227
|
+
/** 1b. Subscribe to the live domain event stream for one issue (stream) */
|
|
2228
|
+
const SubscribeIssueEventsRpc = Rpc.make(WS_METHODS.subscribeIssueEvents, {
|
|
2229
|
+
payload: Schema.Struct({ issueId: IssueId }),
|
|
2230
|
+
success: DomainEvent,
|
|
2231
|
+
stream: true
|
|
2232
|
+
});
|
|
2233
|
+
/** 2. Subscribe to raw terminal output for a tmux session (stream) */
|
|
2234
|
+
const SubscribeTerminalRpc = Rpc.make(WS_METHODS.subscribeTerminal, {
|
|
2235
|
+
payload: Schema.Struct({
|
|
2236
|
+
sessionName: Schema.String,
|
|
2237
|
+
cols: Schema.Number,
|
|
2238
|
+
rows: Schema.Number
|
|
2239
|
+
}),
|
|
2240
|
+
success: TerminalOutput,
|
|
2241
|
+
error: PanRpcError,
|
|
2242
|
+
stream: true
|
|
2243
|
+
});
|
|
2244
|
+
/** 3. Subscribe to buffered agent stdout (stream) */
|
|
2245
|
+
const SubscribeAgentOutputRpc = Rpc.make(WS_METHODS.subscribeAgentOutput, {
|
|
2246
|
+
payload: Schema.Struct({ agentId: Schema.String }),
|
|
2247
|
+
success: AgentOutput,
|
|
2248
|
+
error: PanRpcError,
|
|
2249
|
+
stream: true
|
|
2250
|
+
});
|
|
2251
|
+
/** 4. Get current dashboard snapshot (unary) */
|
|
2252
|
+
const GetSnapshotRpc = Rpc.make(WS_METHODS.getSnapshot, {
|
|
2253
|
+
payload: Schema.Struct({}),
|
|
2254
|
+
success: DashboardSnapshot,
|
|
2255
|
+
error: PanRpcError
|
|
2256
|
+
});
|
|
2257
|
+
/** 5. Replay events since a given sequence number (unary) */
|
|
2258
|
+
const ReplayEventsRpc = Rpc.make(WS_METHODS.replayEvents, {
|
|
2259
|
+
payload: Schema.Struct({ fromSequence: SequenceNumber }),
|
|
2260
|
+
success: Schema.Array(DomainEvent),
|
|
2261
|
+
error: PanRpcError
|
|
2262
|
+
});
|
|
2263
|
+
/** 6. Open a terminal session / attach PTY (unary) */
|
|
2264
|
+
const TerminalOpenRpc = Rpc.make(WS_METHODS.terminalOpen, {
|
|
2265
|
+
payload: Schema.Struct({
|
|
2266
|
+
sessionName: Schema.String,
|
|
2267
|
+
cols: Schema.Number,
|
|
2268
|
+
rows: Schema.Number
|
|
2269
|
+
}),
|
|
2270
|
+
success: Schema.Struct({ sessionName: Schema.String }),
|
|
2271
|
+
error: PanRpcError
|
|
2272
|
+
});
|
|
2273
|
+
/** 7. Write data to a terminal session (unary) */
|
|
2274
|
+
const TerminalWriteRpc = Rpc.make(WS_METHODS.terminalWrite, {
|
|
2275
|
+
payload: Schema.Struct({
|
|
2276
|
+
sessionName: Schema.String,
|
|
2277
|
+
data: Schema.String
|
|
2278
|
+
}),
|
|
2279
|
+
error: PanRpcError
|
|
2280
|
+
});
|
|
2281
|
+
/** 8. Resize a terminal session (unary) */
|
|
2282
|
+
const TerminalResizeRpc = Rpc.make(WS_METHODS.terminalResize, {
|
|
2283
|
+
payload: Schema.Struct({
|
|
2284
|
+
sessionName: Schema.String,
|
|
2285
|
+
cols: Schema.Number,
|
|
2286
|
+
rows: Schema.Number
|
|
2287
|
+
}),
|
|
2288
|
+
error: PanRpcError
|
|
2289
|
+
});
|
|
2290
|
+
/** 9. Close a terminal session (unary) */
|
|
2291
|
+
const TerminalCloseRpc = Rpc.make(WS_METHODS.terminalClose, {
|
|
2292
|
+
payload: Schema.Struct({ sessionName: Schema.String }),
|
|
2293
|
+
error: PanRpcError
|
|
2294
|
+
});
|
|
2295
|
+
/** 10. Get batched workspace detail (unary) — replaces 5 separate HTTP calls */
|
|
2296
|
+
const GetWorkspaceDetailRpc = Rpc.make(WS_METHODS.getWorkspaceDetail, {
|
|
2297
|
+
payload: Schema.Struct({ issueId: IssueId }),
|
|
2298
|
+
success: WorkspaceDetail,
|
|
2299
|
+
error: PanRpcError
|
|
2300
|
+
});
|
|
2301
|
+
const ReadWorkspaceFileInput = Schema.Struct({
|
|
2302
|
+
issueId: IssueId,
|
|
2303
|
+
relativePath: Schema.String,
|
|
2304
|
+
line: Schema.optional(Schema.Number),
|
|
2305
|
+
contextLines: Schema.optional(Schema.Number)
|
|
2306
|
+
});
|
|
2307
|
+
const ReadWorkspaceFileResult = Schema.Struct({
|
|
2308
|
+
text: Schema.String,
|
|
2309
|
+
lang: Schema.String,
|
|
2310
|
+
truncated: Schema.Boolean,
|
|
2311
|
+
totalLines: Schema.Number
|
|
2312
|
+
});
|
|
2313
|
+
/** 10b. Read a workspace file for inline previews (unary) */
|
|
2314
|
+
const ReadWorkspaceFileRpc = Rpc.make(WS_METHODS.readWorkspaceFile, {
|
|
2315
|
+
payload: ReadWorkspaceFileInput,
|
|
2316
|
+
success: ReadWorkspaceFileResult,
|
|
2317
|
+
error: PanRpcError
|
|
2318
|
+
});
|
|
2319
|
+
/**
|
|
2320
|
+
* 10c. Resolve whether a file path candidate exists on disk (PAN-1457).
|
|
2321
|
+
*
|
|
2322
|
+
* Used by MarkdownFileLink to decide whether a path-like token in chat
|
|
2323
|
+
* markdown should render as a clickable chip. Returns exists=false for
|
|
2324
|
+
* phantom paths (`conv/2209`, `users/foo`) and exists=true with kind for
|
|
2325
|
+
* real files and directories (including bare directory references like
|
|
2326
|
+
* `src/components/Foo` that the regex heuristic alone cannot validate).
|
|
2327
|
+
*
|
|
2328
|
+
* Security:
|
|
2329
|
+
* - Pure stat — never reads file contents, never enumerates directories.
|
|
2330
|
+
* - Relative paths resolve under cwd; absolute paths are statted directly.
|
|
2331
|
+
* - Caller is responsible for sending only paths surfaced from their own
|
|
2332
|
+
* conversation context; the resolver does not gate by issueId because
|
|
2333
|
+
* chat happens outside any single workspace.
|
|
2334
|
+
*/
|
|
2335
|
+
const ResolveFilePathExistsInput = Schema.Struct({
|
|
2336
|
+
cwd: Schema.String,
|
|
2337
|
+
path: Schema.String
|
|
2338
|
+
});
|
|
2339
|
+
const ResolveFilePathExistsResult = Schema.Struct({
|
|
2340
|
+
exists: Schema.Boolean,
|
|
2341
|
+
kind: Schema.NullOr(Schema.Literals(["file", "dir"]))
|
|
2342
|
+
});
|
|
2343
|
+
const ResolveFilePathExistsRpc = Rpc.make(WS_METHODS.resolveFilePathExists, {
|
|
2344
|
+
payload: ResolveFilePathExistsInput,
|
|
2345
|
+
success: ResolveFilePathExistsResult,
|
|
2346
|
+
error: PanRpcError
|
|
2347
|
+
});
|
|
2348
|
+
/** 11. Start planning for an issue (command) */
|
|
2349
|
+
const StartPlanningRpc = Rpc.make(WS_METHODS.startPlanning, {
|
|
2350
|
+
payload: Schema.Struct({
|
|
2351
|
+
issueId: IssueId,
|
|
2352
|
+
options: Schema.optional(Schema.Unknown)
|
|
2353
|
+
}),
|
|
2354
|
+
success: Schema.Struct({ queued: Schema.Boolean }),
|
|
2355
|
+
error: PanRpcError
|
|
2356
|
+
});
|
|
2357
|
+
/** 12. Start a work agent for an issue (command) */
|
|
2358
|
+
const StartAgentRpc = Rpc.make(WS_METHODS.startAgent, {
|
|
2359
|
+
payload: Schema.Struct({
|
|
2360
|
+
issueId: IssueId,
|
|
2361
|
+
options: Schema.optional(Schema.Unknown)
|
|
2362
|
+
}),
|
|
2363
|
+
success: Schema.Struct({ agentId: Schema.String }),
|
|
2364
|
+
error: PanRpcError
|
|
2365
|
+
});
|
|
2366
|
+
/** 13. Deep-wipe a workspace (destructive command — requires explicit confirmation) */
|
|
2367
|
+
const DeepWipeRpc = Rpc.make(WS_METHODS.deepWipe, {
|
|
2368
|
+
payload: Schema.Struct({
|
|
2369
|
+
issueId: IssueId,
|
|
2370
|
+
deleteWorkspace: Schema.optional(Schema.Boolean)
|
|
2371
|
+
}),
|
|
2372
|
+
success: Schema.Struct({ wiped: Schema.Boolean }),
|
|
2373
|
+
error: PanRpcError
|
|
2374
|
+
});
|
|
2375
|
+
/** 14. Send input to a terminal session (command) */
|
|
2376
|
+
const SendTerminalInputRpc = Rpc.make(WS_METHODS.sendTerminalInput, {
|
|
2377
|
+
payload: Schema.Struct({
|
|
2378
|
+
sessionName: Schema.String,
|
|
2379
|
+
data: Schema.String
|
|
2380
|
+
}),
|
|
2381
|
+
error: PanRpcError
|
|
2382
|
+
});
|
|
2383
|
+
/** 15. Resize a terminal session (command) */
|
|
2384
|
+
const ResizeTerminalRpc = Rpc.make(WS_METHODS.resizeTerminal, {
|
|
2385
|
+
payload: Schema.Struct({
|
|
2386
|
+
sessionName: Schema.String,
|
|
2387
|
+
cols: Schema.Number,
|
|
2388
|
+
rows: Schema.Number
|
|
2389
|
+
}),
|
|
2390
|
+
error: PanRpcError
|
|
2391
|
+
});
|
|
2392
|
+
/** 16. Subscribe to structured conversation messages from a JSONL session file (stream, PAN-451) */
|
|
2393
|
+
const SubscribeConversationMessagesRpc = Rpc.make(WS_METHODS.subscribeConversationMessages, {
|
|
2394
|
+
payload: Schema.Struct({ conversationName: Schema.String }),
|
|
2395
|
+
success: ConversationEvent,
|
|
2396
|
+
error: PanRpcError,
|
|
2397
|
+
stream: true
|
|
2398
|
+
});
|
|
2399
|
+
/** 17. Subscribe to live session tree deltas for a project (stream, PAN-821) */
|
|
2400
|
+
const SubscribeProjectSessionTreeRpc = Rpc.make(WS_METHODS.subscribeProjectSessionTree, {
|
|
2401
|
+
payload: Schema.Struct({ projectKey: Schema.String }),
|
|
2402
|
+
success: SessionTreeDelta,
|
|
2403
|
+
error: PanRpcError,
|
|
2404
|
+
stream: true
|
|
2405
|
+
});
|
|
2406
|
+
/** 18. Subscribe to latest Flywheel status snapshots (stream) */
|
|
2407
|
+
const SubscribeFlywheelStatusRpc = Rpc.make(WS_METHODS.subscribeFlywheelStatus, {
|
|
2408
|
+
payload: Schema.Struct({}),
|
|
2409
|
+
success: Schema.NullOr(FlywheelStatus),
|
|
2410
|
+
error: PanRpcError,
|
|
2411
|
+
stream: true
|
|
2412
|
+
});
|
|
2413
|
+
/** 19. Open a workspace in an editor (PAN-966) */
|
|
2414
|
+
const ShellOpenInEditorRpc = Rpc.make(WS_METHODS.shellOpenInEditor, {
|
|
2415
|
+
payload: OpenInEditorInput,
|
|
2416
|
+
error: PanRpcError
|
|
2417
|
+
});
|
|
2418
|
+
/** 19. Get available (installed) editors (PAN-966) */
|
|
2419
|
+
const GetAvailableEditorsRpc = Rpc.make(WS_METHODS.getAvailableEditors, {
|
|
2420
|
+
success: Schema.Struct({
|
|
2421
|
+
editors: Schema.Array(EditorIdSchema),
|
|
2422
|
+
/**
|
|
2423
|
+
* Default cwd to open when no project/workspace is selected — the
|
|
2424
|
+
* "devroot" fallback. `~/Projects` if it exists, else `$HOME`.
|
|
2425
|
+
*/
|
|
2426
|
+
defaultCwd: Schema.String
|
|
2427
|
+
}),
|
|
2428
|
+
error: PanRpcError
|
|
2429
|
+
});
|
|
2430
|
+
const DiscoveredSessionListResult = Schema.Struct({
|
|
2431
|
+
sessions: Schema.Array(DiscoveredSessionSnapshot),
|
|
2432
|
+
count: Schema.Number,
|
|
2433
|
+
total: Schema.Number
|
|
2434
|
+
});
|
|
2435
|
+
const DiscoveredSessionSearchResult = Schema.Struct({
|
|
2436
|
+
sessions: Schema.Array(DiscoveredSessionSnapshot),
|
|
2437
|
+
total: Schema.Number,
|
|
2438
|
+
mode: Schema.String,
|
|
2439
|
+
durationMs: Schema.Number,
|
|
2440
|
+
error: Schema.optional(Schema.String)
|
|
2441
|
+
});
|
|
2442
|
+
const DiscoveredSessionStatsResult = Schema.Struct({
|
|
2443
|
+
total: Schema.Number,
|
|
2444
|
+
enriched: Schema.Number,
|
|
2445
|
+
embedded: Schema.Number,
|
|
2446
|
+
managedCount: Schema.Number,
|
|
2447
|
+
embeddingModels: Schema.optional(Schema.Array(Schema.Struct({
|
|
2448
|
+
model: Schema.String,
|
|
2449
|
+
embedded: Schema.Number
|
|
2450
|
+
})))
|
|
2451
|
+
});
|
|
2452
|
+
const ConversationCostTotals = Schema.Struct({
|
|
2453
|
+
sessionCount: Schema.Number,
|
|
2454
|
+
totalCost: Schema.Number,
|
|
2455
|
+
totalTokensIn: Schema.Number,
|
|
2456
|
+
totalTokensOut: Schema.Number
|
|
2457
|
+
});
|
|
2458
|
+
/** Scan conversations (trigger discovery) */
|
|
2459
|
+
const ScanConversationsRpc = Rpc.make(WS_METHODS.scanConversations, {
|
|
2460
|
+
payload: Schema.Struct({
|
|
2461
|
+
mode: Schema.Literals([
|
|
2462
|
+
"targeted",
|
|
2463
|
+
"watched",
|
|
2464
|
+
"system"
|
|
2465
|
+
]),
|
|
2466
|
+
dirs: Schema.optional(Schema.Array(Schema.String)),
|
|
2467
|
+
dryRun: Schema.optional(Schema.Boolean)
|
|
2468
|
+
}),
|
|
2469
|
+
success: ScanResult,
|
|
2470
|
+
error: PanRpcError
|
|
2471
|
+
});
|
|
2472
|
+
/** Search discovered sessions with filters + optional FTS query */
|
|
2473
|
+
const SearchConversationsRpc = Rpc.make(WS_METHODS.searchConversations, {
|
|
2474
|
+
payload: ConversationFilter,
|
|
2475
|
+
success: DiscoveredSessionSearchResult,
|
|
2476
|
+
error: PanRpcError
|
|
2477
|
+
});
|
|
2478
|
+
/** List discovered sessions (recent, with optional managed/unmanaged filter) */
|
|
2479
|
+
const ListDiscoveredSessionsRpc = Rpc.make(WS_METHODS.listDiscoveredSessions, {
|
|
2480
|
+
payload: ConversationFilter,
|
|
2481
|
+
success: DiscoveredSessionListResult,
|
|
2482
|
+
error: PanRpcError
|
|
2483
|
+
});
|
|
2484
|
+
/** Get a single discovered session by ID */
|
|
2485
|
+
const GetDiscoveredSessionRpc = Rpc.make(WS_METHODS.getDiscoveredSession, {
|
|
2486
|
+
payload: Schema.Struct({ id: Schema.Number }),
|
|
2487
|
+
success: DiscoveredSessionSnapshot,
|
|
2488
|
+
error: PanRpcError
|
|
2489
|
+
});
|
|
2490
|
+
/** Enrich sessions by ID or filter */
|
|
2491
|
+
const EnrichSessionsRpc = Rpc.make(WS_METHODS.enrichSessions, {
|
|
2492
|
+
payload: Schema.Struct({
|
|
2493
|
+
ids: Schema.optional(Schema.Array(Schema.Number)),
|
|
2494
|
+
filter: Schema.optional(ConversationFilter),
|
|
2495
|
+
level: Schema.Literals([
|
|
2496
|
+
1,
|
|
2497
|
+
2,
|
|
2498
|
+
3
|
|
2499
|
+
]),
|
|
2500
|
+
model: Schema.optional(Schema.String),
|
|
2501
|
+
fullTranscript: Schema.optional(Schema.Boolean),
|
|
2502
|
+
customPrompt: Schema.optional(Schema.String),
|
|
2503
|
+
upgrade: Schema.optional(Schema.Boolean),
|
|
2504
|
+
limit: Schema.optional(Schema.Number),
|
|
2505
|
+
confirmed: Schema.optional(Schema.Boolean),
|
|
2506
|
+
force: Schema.optional(Schema.Boolean)
|
|
2507
|
+
}),
|
|
2508
|
+
success: Schema.Struct({
|
|
2509
|
+
processed: Schema.Number,
|
|
2510
|
+
totalCost: Schema.Number,
|
|
2511
|
+
failures: Schema.Number
|
|
2512
|
+
}),
|
|
2513
|
+
error: PanRpcError
|
|
2514
|
+
});
|
|
2515
|
+
/** Generate or update embeddings for enriched sessions */
|
|
2516
|
+
const EmbedSessionsRpc = Rpc.make(WS_METHODS.embedSessions, {
|
|
2517
|
+
payload: Schema.Struct({
|
|
2518
|
+
ids: Schema.optional(Schema.Array(Schema.Number)),
|
|
2519
|
+
regenerate: Schema.optional(Schema.Boolean)
|
|
2520
|
+
}),
|
|
2521
|
+
success: Schema.Struct({
|
|
2522
|
+
total: Schema.Number,
|
|
2523
|
+
embedded: Schema.Number,
|
|
2524
|
+
model: Schema.String
|
|
2525
|
+
}),
|
|
2526
|
+
error: PanRpcError
|
|
2527
|
+
});
|
|
2528
|
+
/** Aggregate cost totals for discovered sessions */
|
|
2529
|
+
const GetConversationCostRpc = Rpc.make(WS_METHODS.getConversationCost, {
|
|
2530
|
+
payload: ConversationFilter,
|
|
2531
|
+
success: ConversationCostTotals,
|
|
2532
|
+
error: PanRpcError
|
|
2533
|
+
});
|
|
2534
|
+
/** Aggregate workspace cost totals for the full filtered corpus */
|
|
2535
|
+
const GetConversationCostByWorkspaceRpc = Rpc.make(WS_METHODS.getConversationCostByWorkspace, {
|
|
2536
|
+
payload: ConversationFilter,
|
|
2537
|
+
success: ConversationCostSummary,
|
|
2538
|
+
error: PanRpcError
|
|
2539
|
+
});
|
|
2540
|
+
/** Discovery index statistics */
|
|
2541
|
+
const GetConversationStatsRpc = Rpc.make(WS_METHODS.getConversationStats, {
|
|
2542
|
+
payload: Schema.Struct({}),
|
|
2543
|
+
success: DiscoveredSessionStatsResult,
|
|
2544
|
+
error: PanRpcError
|
|
2545
|
+
});
|
|
2546
|
+
/** All Overdeck WebSocket RPC methods */
|
|
2547
|
+
const PanRpcGroup = RpcGroup.make(SubscribeDomainEventsRpc, SubscribeIssueEventsRpc, SubscribeTerminalRpc, SubscribeAgentOutputRpc, GetSnapshotRpc, ReplayEventsRpc, GetWorkspaceDetailRpc, ReadWorkspaceFileRpc, ResolveFilePathExistsRpc, TerminalOpenRpc, TerminalWriteRpc, TerminalResizeRpc, TerminalCloseRpc, StartPlanningRpc, StartAgentRpc, DeepWipeRpc, SendTerminalInputRpc, ResizeTerminalRpc, SubscribeConversationMessagesRpc, SubscribeProjectSessionTreeRpc, SubscribeFlywheelStatusRpc, ShellOpenInEditorRpc, GetAvailableEditorsRpc, ScanConversationsRpc, SearchConversationsRpc, ListDiscoveredSessionsRpc, GetDiscoveredSessionRpc, EnrichSessionsRpc, EmbedSessionsRpc, GetConversationCostRpc, GetConversationCostByWorkspaceRpc, GetConversationStatsRpc);
|
|
2548
|
+
//#endregion
|
|
2549
|
+
//#region src/event-reducers.ts
|
|
2550
|
+
const INITIAL_READ_MODEL_STATE = {
|
|
2551
|
+
sequence: 0,
|
|
2552
|
+
agentsById: {},
|
|
2553
|
+
agentRuntimeById: {},
|
|
2554
|
+
reviewStatusByIssueId: {},
|
|
2555
|
+
resources: null,
|
|
2556
|
+
agentOutputById: {},
|
|
2557
|
+
issuesRaw: [],
|
|
2558
|
+
recentActivity: [],
|
|
2559
|
+
detailedActivity: [],
|
|
2560
|
+
ttsActivity: [],
|
|
2561
|
+
shadowInferenceByIssueId: {},
|
|
2562
|
+
turnDiffSummariesByAgentId: {},
|
|
2563
|
+
channelPermissionRequestsById: {},
|
|
2564
|
+
channelPermissionRequestIdsByAgentId: {},
|
|
2565
|
+
resolvedChannelPermissionDecisionsById: {},
|
|
2566
|
+
resolvedChannelPermissionDecisionIdsByAgentId: {},
|
|
2567
|
+
conversationsCompactingByName: {},
|
|
2568
|
+
conversationsAwaitingPermissionByName: {},
|
|
2569
|
+
conversationsListRevision: 0,
|
|
2570
|
+
observationsByIssueId: {},
|
|
2571
|
+
statusByIssueId: {},
|
|
2572
|
+
rollupsByIssueId: {},
|
|
2573
|
+
resetMarkersByScopeId: {},
|
|
2574
|
+
healthByIssueId: {},
|
|
2575
|
+
scanProgress: null,
|
|
2576
|
+
enrichStats: null,
|
|
2577
|
+
enrichProgressBySessionId: {},
|
|
2578
|
+
embedProgressBySessionId: {},
|
|
2579
|
+
agentIdBySessionId: {},
|
|
2580
|
+
dashboardLifecycle: {
|
|
2581
|
+
active: false,
|
|
2582
|
+
reason: null,
|
|
2583
|
+
issueId: null,
|
|
2584
|
+
trigger: null,
|
|
2585
|
+
startedAt: null,
|
|
2586
|
+
completedAt: null,
|
|
2587
|
+
failedAt: null,
|
|
2588
|
+
error: null
|
|
2589
|
+
}
|
|
2590
|
+
};
|
|
2591
|
+
const MAX_AGENT_OUTPUT_LINES = 200;
|
|
2592
|
+
const MAX_ACTIVITY_ENTRIES = 50;
|
|
2593
|
+
const MAX_DETAILED_ENTRIES = 200;
|
|
2594
|
+
const MAX_TTS_ENTRIES = 50;
|
|
2595
|
+
const MAX_SESSION_PROGRESS_ENTRIES = 100;
|
|
2596
|
+
const DEFAULT_MAX_TURN_DIFF_SUMMARIES_PER_AGENT = 200;
|
|
2597
|
+
const DEFAULT_MAX_MEMORY_OBSERVATIONS_PER_ISSUE = 50;
|
|
2598
|
+
function getMaxMemoryObservationsPerIssue() {
|
|
2599
|
+
const raw = globalThis.process?.env?.OVERDECK_MEMORY_OBSERVATION_LIMIT;
|
|
2600
|
+
const parsed = raw ? Number.parseInt(raw, 10) : NaN;
|
|
2601
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : 50;
|
|
2602
|
+
}
|
|
2603
|
+
function trimMemoryObservations(observations) {
|
|
2604
|
+
const max = getMaxMemoryObservationsPerIssue();
|
|
2605
|
+
return observations.length > max ? observations.slice(-max) : observations;
|
|
2606
|
+
}
|
|
2607
|
+
function getMaxTurnDiffSummariesPerAgent() {
|
|
2608
|
+
const raw = globalThis.process?.env?.OVERDECK_TURN_DIFF_SUMMARY_LIMIT;
|
|
2609
|
+
const parsed = raw ? Number.parseInt(raw, 10) : NaN;
|
|
2610
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : 200;
|
|
2611
|
+
}
|
|
2612
|
+
function isTerminalTurnDiffSummaryStatus(status) {
|
|
2613
|
+
return status === "stopped" || status === "done" || status === "archived" || status === "closed";
|
|
2614
|
+
}
|
|
2615
|
+
function trimTurnDiffSummaries(summaries) {
|
|
2616
|
+
const max = getMaxTurnDiffSummariesPerAgent();
|
|
2617
|
+
return summaries.length > max ? summaries.slice(-max) : summaries;
|
|
2618
|
+
}
|
|
2619
|
+
function upsertBoundedSessionProgress(bySessionId, progress) {
|
|
2620
|
+
const existing = bySessionId[progress.sessionId];
|
|
2621
|
+
const entries = Object.values(bySessionId);
|
|
2622
|
+
if (existing || entries.length < MAX_SESSION_PROGRESS_ENTRIES) return {
|
|
2623
|
+
...bySessionId,
|
|
2624
|
+
[progress.sessionId]: progress
|
|
2625
|
+
};
|
|
2626
|
+
const keep = entries.sort((a, b) => a.timestamp.localeCompare(b.timestamp)).slice(-(MAX_SESSION_PROGRESS_ENTRIES - 1));
|
|
2627
|
+
const next = {};
|
|
2628
|
+
for (const entry of [...keep, progress]) next[entry.sessionId] = entry;
|
|
2629
|
+
return next;
|
|
2630
|
+
}
|
|
2631
|
+
function omitTurnDiffSummariesForAgent(turnDiffSummariesByAgentId, agentId) {
|
|
2632
|
+
const { [agentId]: _removed, ...rest } = turnDiffSummariesByAgentId ?? {};
|
|
2633
|
+
return rest;
|
|
2634
|
+
}
|
|
2635
|
+
/** Remove all entries in agentIdBySessionId that point to the given agentId. */
|
|
2636
|
+
function removeAgentFromSessionIndex(agentIdBySessionId, agentId) {
|
|
2637
|
+
const next = {};
|
|
2638
|
+
for (const [sessionId, id] of Object.entries(agentIdBySessionId ?? {})) if (id !== agentId) next[sessionId] = id;
|
|
2639
|
+
return next;
|
|
2640
|
+
}
|
|
2641
|
+
function defaultRuntimeSnapshot(agentId, timestamp, sequence) {
|
|
2642
|
+
return {
|
|
2643
|
+
id: agentId,
|
|
2644
|
+
activity: "idle",
|
|
2645
|
+
lastActivity: timestamp,
|
|
2646
|
+
updatedAtSequence: sequence
|
|
2647
|
+
};
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Bump runtimeSnapshotSequence on the corresponding AgentSnapshot (if present)
|
|
2651
|
+
* so low-frequency subscribers can cheaply detect a runtime change. No-op if
|
|
2652
|
+
* the agent has no lifecycle snapshot yet (a runtime event arrived before
|
|
2653
|
+
* agent.created — unusual but defensive).
|
|
2654
|
+
*/
|
|
2655
|
+
function bumpRuntimeSnapshotSequence(agentsById, agentId, sequence) {
|
|
2656
|
+
const agent = agentsById[agentId];
|
|
2657
|
+
if (!agent) return agentsById;
|
|
2658
|
+
return {
|
|
2659
|
+
...agentsById,
|
|
2660
|
+
[agentId]: {
|
|
2661
|
+
...agent,
|
|
2662
|
+
runtimeSnapshotSequence: sequence
|
|
2663
|
+
}
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
function syncSnapshot(state, snapshot) {
|
|
2667
|
+
const agentsById = {};
|
|
2668
|
+
for (const agent of snapshot.agents) agentsById[agent.id] = agent;
|
|
2669
|
+
const reviewStatusByIssueId = {};
|
|
2670
|
+
for (const rs of snapshot.reviewStatuses) reviewStatusByIssueId[rs.issueId] = rs;
|
|
2671
|
+
const channelPermissionRequestsById = {};
|
|
2672
|
+
const channelPermissionRequestIdsByAgentId = {};
|
|
2673
|
+
for (const request of snapshot.channelPermissionRequests ?? []) {
|
|
2674
|
+
channelPermissionRequestsById[request.requestId] = request;
|
|
2675
|
+
const existing = channelPermissionRequestIdsByAgentId[request.agentId] ?? [];
|
|
2676
|
+
channelPermissionRequestIdsByAgentId[request.agentId] = [...existing, request.requestId];
|
|
2677
|
+
}
|
|
2678
|
+
const memory = snapshot.memory;
|
|
2679
|
+
const agentIdBySessionId = {};
|
|
2680
|
+
for (const agent of snapshot.agents) if (agent.sessionId) agentIdBySessionId[agent.sessionId] = agent.id;
|
|
2681
|
+
for (const [agentId, runtime] of Object.entries(snapshot.agentRuntimeById ?? {})) if (runtime.claudeSessionId) agentIdBySessionId[runtime.claudeSessionId] = agentId;
|
|
2682
|
+
return {
|
|
2683
|
+
...state,
|
|
2684
|
+
sequence: snapshot.sequence,
|
|
2685
|
+
agentsById,
|
|
2686
|
+
reviewStatusByIssueId,
|
|
2687
|
+
agentRuntimeById: snapshot.agentRuntimeById ?? state.agentRuntimeById,
|
|
2688
|
+
channelPermissionRequestsById,
|
|
2689
|
+
channelPermissionRequestIdsByAgentId,
|
|
2690
|
+
resolvedChannelPermissionDecisionsById: {},
|
|
2691
|
+
resolvedChannelPermissionDecisionIdsByAgentId: {},
|
|
2692
|
+
resources: snapshot.resources ?? null,
|
|
2693
|
+
issuesRaw: snapshot.issues ?? state.issuesRaw,
|
|
2694
|
+
observationsByIssueId: memory?.observationsByIssueId ?? state.observationsByIssueId,
|
|
2695
|
+
statusByIssueId: memory?.statusByIssueId ?? state.statusByIssueId,
|
|
2696
|
+
rollupsByIssueId: memory?.rollupsByIssueId ?? state.rollupsByIssueId,
|
|
2697
|
+
resetMarkersByScopeId: memory?.resetMarkersByScopeId ?? state.resetMarkersByScopeId,
|
|
2698
|
+
healthByIssueId: memory?.healthByIssueId ?? state.healthByIssueId,
|
|
2699
|
+
scanProgress: snapshot.scanProgress ?? null,
|
|
2700
|
+
enrichStats: snapshot.enrichStats ?? null,
|
|
2701
|
+
enrichProgressBySessionId: snapshot.enrichProgressBySessionId ?? {},
|
|
2702
|
+
embedProgressBySessionId: snapshot.embedProgressBySessionId ?? {},
|
|
2703
|
+
agentIdBySessionId
|
|
2704
|
+
};
|
|
2705
|
+
}
|
|
2706
|
+
function applyEvent(state, event) {
|
|
2707
|
+
switch (event.type) {
|
|
2708
|
+
case "agent.created": {
|
|
2709
|
+
const existing = state.agentsById[event.payload.agentId];
|
|
2710
|
+
const agent = event.payload.agent;
|
|
2711
|
+
const nextAgentIdBySessionId = agent.sessionId ? {
|
|
2712
|
+
...state.agentIdBySessionId,
|
|
2713
|
+
[agent.sessionId]: agent.id
|
|
2714
|
+
} : state.agentIdBySessionId;
|
|
2715
|
+
return {
|
|
2716
|
+
...state,
|
|
2717
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2718
|
+
agentsById: {
|
|
2719
|
+
...state.agentsById,
|
|
2720
|
+
[event.payload.agentId]: existing ? {
|
|
2721
|
+
...existing,
|
|
2722
|
+
...agent
|
|
2723
|
+
} : agent
|
|
2724
|
+
},
|
|
2725
|
+
agentIdBySessionId: nextAgentIdBySessionId
|
|
2726
|
+
};
|
|
2727
|
+
}
|
|
2728
|
+
case "agent.started": {
|
|
2729
|
+
const agent = event.payload.agent;
|
|
2730
|
+
const nextAgentIdBySessionId = agent.sessionId ? {
|
|
2731
|
+
...state.agentIdBySessionId,
|
|
2732
|
+
[agent.sessionId]: agent.id
|
|
2733
|
+
} : state.agentIdBySessionId;
|
|
2734
|
+
return {
|
|
2735
|
+
...state,
|
|
2736
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2737
|
+
agentsById: {
|
|
2738
|
+
...state.agentsById,
|
|
2739
|
+
[event.payload.agentId]: agent
|
|
2740
|
+
},
|
|
2741
|
+
agentIdBySessionId: nextAgentIdBySessionId
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
case "agent.enrichment_changed": {
|
|
2745
|
+
const agent = state.agentsById[event.payload.agentId];
|
|
2746
|
+
if (!agent) return {
|
|
2747
|
+
...state,
|
|
2748
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
2749
|
+
};
|
|
2750
|
+
return {
|
|
2751
|
+
...state,
|
|
2752
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2753
|
+
agentsById: {
|
|
2754
|
+
...state.agentsById,
|
|
2755
|
+
[event.payload.agentId]: {
|
|
2756
|
+
...agent,
|
|
2757
|
+
role: event.payload.role ?? agent.role,
|
|
2758
|
+
hasPendingQuestion: event.payload.hasPendingQuestion ?? false,
|
|
2759
|
+
pendingQuestionCount: event.payload.pendingQuestionCount ?? 0,
|
|
2760
|
+
pendingQuestionPrompt: event.payload.pendingQuestionPrompt,
|
|
2761
|
+
pendingQuestionReason: event.payload.pendingQuestionReason,
|
|
2762
|
+
pendingInputCount: event.payload.pendingInputCount,
|
|
2763
|
+
pendingInputKinds: event.payload.pendingInputKinds,
|
|
2764
|
+
pendingAskUserQuestion: event.payload.pendingAskUserQuestion,
|
|
2765
|
+
resolution: event.payload.resolution,
|
|
2766
|
+
resolutionCount: event.payload.resolutionCount
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
};
|
|
2770
|
+
}
|
|
2771
|
+
case "agent.stopped": {
|
|
2772
|
+
const { [event.payload.agentId]: _removed, ...rest } = state.agentsById;
|
|
2773
|
+
const runtimeById = state.agentRuntimeById ?? {};
|
|
2774
|
+
const prevRuntime = runtimeById[event.payload.agentId];
|
|
2775
|
+
const nextRuntimeById = prevRuntime ? {
|
|
2776
|
+
...runtimeById,
|
|
2777
|
+
[event.payload.agentId]: {
|
|
2778
|
+
...prevRuntime,
|
|
2779
|
+
activity: "stopped",
|
|
2780
|
+
currentTool: void 0,
|
|
2781
|
+
thinking: void 0,
|
|
2782
|
+
waiting: void 0,
|
|
2783
|
+
channelReply: void 0,
|
|
2784
|
+
lastActivity: event.timestamp,
|
|
2785
|
+
updatedAtSequence: event.sequence
|
|
2786
|
+
}
|
|
2787
|
+
} : runtimeById;
|
|
2788
|
+
const permissionRequestIdsByAgentId = state.channelPermissionRequestIdsByAgentId ?? {};
|
|
2789
|
+
const pendingIds = permissionRequestIdsByAgentId[event.payload.agentId] ?? [];
|
|
2790
|
+
const nextPermissionRequestsById = { ...state.channelPermissionRequestsById };
|
|
2791
|
+
for (const requestId of pendingIds) delete nextPermissionRequestsById[requestId];
|
|
2792
|
+
const { [event.payload.agentId]: _removedPendingIds, ...restPendingIds } = permissionRequestIdsByAgentId;
|
|
2793
|
+
const resolvedDecisionIdsByAgentId = state.resolvedChannelPermissionDecisionIdsByAgentId ?? {};
|
|
2794
|
+
const resolvedIds = resolvedDecisionIdsByAgentId[event.payload.agentId] ?? [];
|
|
2795
|
+
const nextResolvedDecisionsById = { ...state.resolvedChannelPermissionDecisionsById ?? {} };
|
|
2796
|
+
for (const requestId of resolvedIds) delete nextResolvedDecisionsById[requestId];
|
|
2797
|
+
const { [event.payload.agentId]: _removedResolvedIds, ...restResolvedIds } = resolvedDecisionIdsByAgentId;
|
|
2798
|
+
return {
|
|
2799
|
+
...state,
|
|
2800
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2801
|
+
agentsById: rest,
|
|
2802
|
+
agentRuntimeById: nextRuntimeById,
|
|
2803
|
+
channelPermissionRequestsById: nextPermissionRequestsById,
|
|
2804
|
+
channelPermissionRequestIdsByAgentId: restPendingIds,
|
|
2805
|
+
resolvedChannelPermissionDecisionsById: nextResolvedDecisionsById,
|
|
2806
|
+
resolvedChannelPermissionDecisionIdsByAgentId: restResolvedIds,
|
|
2807
|
+
turnDiffSummariesByAgentId: omitTurnDiffSummariesForAgent(state.turnDiffSummariesByAgentId, event.payload.agentId),
|
|
2808
|
+
agentIdBySessionId: removeAgentFromSessionIndex(state.agentIdBySessionId, event.payload.agentId)
|
|
2809
|
+
};
|
|
2810
|
+
}
|
|
2811
|
+
case "agent.status_changed": {
|
|
2812
|
+
const agent = state.agentsById[event.payload.agentId];
|
|
2813
|
+
if (!agent) return {
|
|
2814
|
+
...state,
|
|
2815
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
2816
|
+
};
|
|
2817
|
+
const nextTurnDiffSummariesByAgentId = isTerminalTurnDiffSummaryStatus(event.payload.status) ? omitTurnDiffSummariesForAgent(state.turnDiffSummariesByAgentId, event.payload.agentId) : state.turnDiffSummariesByAgentId;
|
|
2818
|
+
const nextAgent = (() => {
|
|
2819
|
+
const base = {
|
|
2820
|
+
...agent,
|
|
2821
|
+
status: event.payload.status
|
|
2822
|
+
};
|
|
2823
|
+
for (const field of [
|
|
2824
|
+
"hasLiveTmuxSession",
|
|
2825
|
+
"stoppedByUser",
|
|
2826
|
+
"stoppedByPause",
|
|
2827
|
+
"paused",
|
|
2828
|
+
"pausedReason",
|
|
2829
|
+
"pausedAt",
|
|
2830
|
+
"troubled",
|
|
2831
|
+
"troubledAt",
|
|
2832
|
+
"consecutiveFailures",
|
|
2833
|
+
"firstFailureInRunAt",
|
|
2834
|
+
"lastFailureAt",
|
|
2835
|
+
"lastFailureReason",
|
|
2836
|
+
"lastFailureNextRetryAt",
|
|
2837
|
+
"kickoffDelivered",
|
|
2838
|
+
"hostOverride",
|
|
2839
|
+
"role",
|
|
2840
|
+
"model",
|
|
2841
|
+
"workspace",
|
|
2842
|
+
"sessionId",
|
|
2843
|
+
"lastActivity",
|
|
2844
|
+
"lastResumeAt",
|
|
2845
|
+
"stoppedAt",
|
|
2846
|
+
"branch",
|
|
2847
|
+
"costSoFar",
|
|
2848
|
+
"phase",
|
|
2849
|
+
"workType",
|
|
2850
|
+
"roleRunHead",
|
|
2851
|
+
"flywheelRunId",
|
|
2852
|
+
"reviewSubRole",
|
|
2853
|
+
"reviewRunId",
|
|
2854
|
+
"reviewOutputPath",
|
|
2855
|
+
"reviewSynthesisAgentId",
|
|
2856
|
+
"reviewDeadlineAt",
|
|
2857
|
+
"reviewMonitorSignaled",
|
|
2858
|
+
"reviewRetryAttempt",
|
|
2859
|
+
"inspectSubRole",
|
|
2860
|
+
"deliveryMethod",
|
|
2861
|
+
"supervisorEnabled",
|
|
2862
|
+
"channelsEnabled"
|
|
2863
|
+
]) if (field in event.payload) {
|
|
2864
|
+
const value = event.payload[field];
|
|
2865
|
+
if (value === null || value === void 0) delete base[field];
|
|
2866
|
+
else base[field] = value;
|
|
2867
|
+
}
|
|
2868
|
+
if (event.payload.status !== "running" && event.payload.status !== "starting") {
|
|
2869
|
+
delete base["hasPendingQuestion"];
|
|
2870
|
+
delete base["pendingQuestionCount"];
|
|
2871
|
+
delete base["pendingQuestionPrompt"];
|
|
2872
|
+
delete base["pendingQuestionReason"];
|
|
2873
|
+
delete base["pendingInputCount"];
|
|
2874
|
+
delete base["pendingInputKinds"];
|
|
2875
|
+
delete base["pendingAskUserQuestion"];
|
|
2876
|
+
}
|
|
2877
|
+
return base;
|
|
2878
|
+
})();
|
|
2879
|
+
return {
|
|
2880
|
+
...state,
|
|
2881
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2882
|
+
agentsById: {
|
|
2883
|
+
...state.agentsById,
|
|
2884
|
+
[event.payload.agentId]: nextAgent
|
|
2885
|
+
},
|
|
2886
|
+
turnDiffSummariesByAgentId: nextTurnDiffSummariesByAgentId
|
|
2887
|
+
};
|
|
2888
|
+
}
|
|
2889
|
+
case "agent.heartbeat_dead": {
|
|
2890
|
+
const agent = state.agentsById[event.payload.agentId];
|
|
2891
|
+
if (!agent) return {
|
|
2892
|
+
...state,
|
|
2893
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
2894
|
+
};
|
|
2895
|
+
const runtimeById = state.agentRuntimeById ?? {};
|
|
2896
|
+
const prevRuntime = runtimeById[event.payload.agentId];
|
|
2897
|
+
const nextRuntimeById = prevRuntime ? {
|
|
2898
|
+
...runtimeById,
|
|
2899
|
+
[event.payload.agentId]: {
|
|
2900
|
+
...prevRuntime,
|
|
2901
|
+
activity: "stopped",
|
|
2902
|
+
currentTool: void 0,
|
|
2903
|
+
thinking: void 0,
|
|
2904
|
+
waiting: void 0,
|
|
2905
|
+
channelReply: void 0,
|
|
2906
|
+
lastActivity: event.timestamp,
|
|
2907
|
+
updatedAtSequence: event.sequence
|
|
2908
|
+
}
|
|
2909
|
+
} : runtimeById;
|
|
2910
|
+
return {
|
|
2911
|
+
...state,
|
|
2912
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2913
|
+
agentsById: {
|
|
2914
|
+
...state.agentsById,
|
|
2915
|
+
[event.payload.agentId]: {
|
|
2916
|
+
...agent,
|
|
2917
|
+
status: "error"
|
|
2918
|
+
}
|
|
2919
|
+
},
|
|
2920
|
+
agentRuntimeById: nextRuntimeById
|
|
2921
|
+
};
|
|
2922
|
+
}
|
|
2923
|
+
case "agent.output_received": {
|
|
2924
|
+
const updated = [...state.agentOutputById[event.payload.agentId] ?? [], ...event.payload.lines].slice(-MAX_AGENT_OUTPUT_LINES);
|
|
2925
|
+
return {
|
|
2926
|
+
...state,
|
|
2927
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2928
|
+
agentOutputById: {
|
|
2929
|
+
...state.agentOutputById,
|
|
2930
|
+
[event.payload.agentId]: updated
|
|
2931
|
+
}
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
case "pipeline.status_changed":
|
|
2935
|
+
case "review.status_changed": return {
|
|
2936
|
+
...state,
|
|
2937
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2938
|
+
reviewStatusByIssueId: {
|
|
2939
|
+
...state.reviewStatusByIssueId,
|
|
2940
|
+
[event.payload.issueId]: event.payload.status
|
|
2941
|
+
}
|
|
2942
|
+
};
|
|
2943
|
+
case "review.reviewer_started": {
|
|
2944
|
+
const { issueId, role, sessionName } = event.payload;
|
|
2945
|
+
const existing = state.reviewStatusByIssueId[issueId];
|
|
2946
|
+
const prevSubs = existing?.reviewSubStatuses ?? {};
|
|
2947
|
+
const prevNames = existing?.reviewSessionNames ?? [];
|
|
2948
|
+
const nextNames = prevNames.includes(sessionName) ? prevNames : [...prevNames, sessionName];
|
|
2949
|
+
const nextStatus = {
|
|
2950
|
+
...existing ?? { issueId },
|
|
2951
|
+
reviewSubStatuses: {
|
|
2952
|
+
...prevSubs,
|
|
2953
|
+
[role]: "running"
|
|
2954
|
+
},
|
|
2955
|
+
reviewSessionNames: nextNames
|
|
2956
|
+
};
|
|
2957
|
+
return {
|
|
2958
|
+
...state,
|
|
2959
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2960
|
+
reviewStatusByIssueId: {
|
|
2961
|
+
...state.reviewStatusByIssueId,
|
|
2962
|
+
[issueId]: nextStatus
|
|
2963
|
+
}
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
case "review.reviewer_completed": {
|
|
2967
|
+
const { issueId, role } = event.payload;
|
|
2968
|
+
const existing = state.reviewStatusByIssueId[issueId];
|
|
2969
|
+
if (!existing) return {
|
|
2970
|
+
...state,
|
|
2971
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
2972
|
+
};
|
|
2973
|
+
const prevSubs = existing.reviewSubStatuses ?? {};
|
|
2974
|
+
const nextStatus = {
|
|
2975
|
+
...existing,
|
|
2976
|
+
reviewSubStatuses: {
|
|
2977
|
+
...prevSubs,
|
|
2978
|
+
[role]: "done"
|
|
2979
|
+
}
|
|
2980
|
+
};
|
|
2981
|
+
return {
|
|
2982
|
+
...state,
|
|
2983
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
2984
|
+
reviewStatusByIssueId: {
|
|
2985
|
+
...state.reviewStatusByIssueId,
|
|
2986
|
+
[issueId]: nextStatus
|
|
2987
|
+
}
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
case "review.specialist.timed_out": return {
|
|
2991
|
+
...state,
|
|
2992
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
2993
|
+
};
|
|
2994
|
+
case "review.coordinator_started": {
|
|
2995
|
+
const { issueId, sessionName } = event.payload;
|
|
2996
|
+
const nextStatus = {
|
|
2997
|
+
...state.reviewStatusByIssueId[issueId] ?? { issueId },
|
|
2998
|
+
reviewCoordinatorSessionName: sessionName
|
|
2999
|
+
};
|
|
3000
|
+
return {
|
|
3001
|
+
...state,
|
|
3002
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3003
|
+
reviewStatusByIssueId: {
|
|
3004
|
+
...state.reviewStatusByIssueId,
|
|
3005
|
+
[issueId]: nextStatus
|
|
3006
|
+
}
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
case "review.coordinator.died": return {
|
|
3010
|
+
...state,
|
|
3011
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3012
|
+
};
|
|
3013
|
+
case "pipeline.review-started":
|
|
3014
|
+
case "pipeline.review-completed":
|
|
3015
|
+
case "pipeline.test-started":
|
|
3016
|
+
case "pipeline.test-completed": return {
|
|
3017
|
+
...state,
|
|
3018
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3019
|
+
};
|
|
3020
|
+
case "merge.ready": return {
|
|
3021
|
+
...state,
|
|
3022
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3023
|
+
};
|
|
3024
|
+
case "specialist.started":
|
|
3025
|
+
case "specialist.completed":
|
|
3026
|
+
case "specialist.failed": return {
|
|
3027
|
+
...state,
|
|
3028
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3029
|
+
};
|
|
3030
|
+
case "resources.updated": return {
|
|
3031
|
+
...state,
|
|
3032
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3033
|
+
resources: event.payload.resources
|
|
3034
|
+
};
|
|
3035
|
+
case "issues.snapshot": return {
|
|
3036
|
+
...state,
|
|
3037
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3038
|
+
issuesRaw: event.payload.issues
|
|
3039
|
+
};
|
|
3040
|
+
case "issues.updated": return {
|
|
3041
|
+
...state,
|
|
3042
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3043
|
+
};
|
|
3044
|
+
case "issue.statusChanged": {
|
|
3045
|
+
const { issueId, status, canonicalStatus, labels } = event.payload;
|
|
3046
|
+
const updatedIssues = state.issuesRaw.map((issue) => {
|
|
3047
|
+
if (issue["identifier"] === issueId || issue["id"] === issueId) {
|
|
3048
|
+
const patch = {
|
|
3049
|
+
...issue,
|
|
3050
|
+
status,
|
|
3051
|
+
canonicalStatus,
|
|
3052
|
+
state: canonicalStatus
|
|
3053
|
+
};
|
|
3054
|
+
if (labels) patch.labels = labels;
|
|
3055
|
+
return patch;
|
|
3056
|
+
}
|
|
3057
|
+
return issue;
|
|
3058
|
+
});
|
|
3059
|
+
return {
|
|
3060
|
+
...state,
|
|
3061
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3062
|
+
issuesRaw: updatedIssues
|
|
3063
|
+
};
|
|
3064
|
+
}
|
|
3065
|
+
case "activity.updated": return {
|
|
3066
|
+
...state,
|
|
3067
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3068
|
+
recentActivity: event.payload.events.slice(0, MAX_ACTIVITY_ENTRIES)
|
|
3069
|
+
};
|
|
3070
|
+
case "shadow.inference_update": return {
|
|
3071
|
+
...state,
|
|
3072
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3073
|
+
shadowInferenceByIssueId: {
|
|
3074
|
+
...state.shadowInferenceByIssueId,
|
|
3075
|
+
[event.payload.issueId]: event.payload.content
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
case "planning.started": {
|
|
3079
|
+
const sessionName = event.payload.sessionName;
|
|
3080
|
+
const issueId = event.payload.issueId;
|
|
3081
|
+
if (sessionName) return {
|
|
3082
|
+
...state,
|
|
3083
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3084
|
+
agentsById: {
|
|
3085
|
+
...state.agentsById,
|
|
3086
|
+
[sessionName]: {
|
|
3087
|
+
...state.agentsById[sessionName],
|
|
3088
|
+
id: sessionName,
|
|
3089
|
+
issueId,
|
|
3090
|
+
status: "running",
|
|
3091
|
+
startedAt: event.timestamp,
|
|
3092
|
+
runtime: event.payload.harness ?? "claude-code",
|
|
3093
|
+
role: "plan"
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
};
|
|
3097
|
+
return {
|
|
3098
|
+
...state,
|
|
3099
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3100
|
+
};
|
|
3101
|
+
}
|
|
3102
|
+
case "workspace.created": return {
|
|
3103
|
+
...state,
|
|
3104
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3105
|
+
};
|
|
3106
|
+
case "workspace.wipe_started": {
|
|
3107
|
+
const { issueId } = event.payload;
|
|
3108
|
+
const updatedIssues = state.issuesRaw.map((issue) => {
|
|
3109
|
+
if (issue["identifier"] === issueId || issue["id"] === issueId) return {
|
|
3110
|
+
...issue,
|
|
3111
|
+
canonicalStatus: "wiping",
|
|
3112
|
+
state: "wiping"
|
|
3113
|
+
};
|
|
3114
|
+
return issue;
|
|
3115
|
+
});
|
|
3116
|
+
return {
|
|
3117
|
+
...state,
|
|
3118
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3119
|
+
issuesRaw: updatedIssues
|
|
3120
|
+
};
|
|
3121
|
+
}
|
|
3122
|
+
case "workspace.destroyed":
|
|
3123
|
+
case "workspace.deleted": {
|
|
3124
|
+
const { issueId } = event.payload;
|
|
3125
|
+
const removedAgentIds = Object.entries(state.agentsById).filter(([, agent]) => agent.issueId === issueId).map(([agentId]) => agentId);
|
|
3126
|
+
const updatedAgents = Object.fromEntries(Object.entries(state.agentsById).filter(([, agent]) => agent.issueId !== issueId));
|
|
3127
|
+
let nextTurnDiffSummariesByAgentId = state.turnDiffSummariesByAgentId;
|
|
3128
|
+
let nextAgentIdBySessionId = state.agentIdBySessionId;
|
|
3129
|
+
for (const agentId of removedAgentIds) {
|
|
3130
|
+
nextTurnDiffSummariesByAgentId = omitTurnDiffSummariesForAgent(nextTurnDiffSummariesByAgentId, agentId);
|
|
3131
|
+
nextAgentIdBySessionId = removeAgentFromSessionIndex(nextAgentIdBySessionId, agentId);
|
|
3132
|
+
}
|
|
3133
|
+
const updatedIssues = state.issuesRaw.map((issue) => {
|
|
3134
|
+
if (issue["identifier"] === issueId || issue["id"] === issueId) return {
|
|
3135
|
+
...issue,
|
|
3136
|
+
status: "Todo",
|
|
3137
|
+
canonicalStatus: "todo",
|
|
3138
|
+
state: "todo"
|
|
3139
|
+
};
|
|
3140
|
+
return issue;
|
|
3141
|
+
});
|
|
3142
|
+
return {
|
|
3143
|
+
...state,
|
|
3144
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3145
|
+
agentsById: updatedAgents,
|
|
3146
|
+
turnDiffSummariesByAgentId: nextTurnDiffSummariesByAgentId,
|
|
3147
|
+
agentIdBySessionId: nextAgentIdBySessionId,
|
|
3148
|
+
issuesRaw: updatedIssues
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
case "workspace.aborted": {
|
|
3152
|
+
const { issueId, sessionName } = event.payload;
|
|
3153
|
+
let updatedAgents;
|
|
3154
|
+
let nextTurnDiffSummariesByAgentId = state.turnDiffSummariesByAgentId;
|
|
3155
|
+
let nextAgentIdBySessionId = state.agentIdBySessionId;
|
|
3156
|
+
if (sessionName) {
|
|
3157
|
+
const { [sessionName]: _removed, ...rest } = state.agentsById;
|
|
3158
|
+
updatedAgents = rest;
|
|
3159
|
+
nextTurnDiffSummariesByAgentId = omitTurnDiffSummariesForAgent(nextTurnDiffSummariesByAgentId, sessionName);
|
|
3160
|
+
nextAgentIdBySessionId = removeAgentFromSessionIndex(nextAgentIdBySessionId, sessionName);
|
|
3161
|
+
} else {
|
|
3162
|
+
const removedAgentIds = Object.entries(state.agentsById).filter(([, agent]) => agent.issueId === issueId).map(([agentId]) => agentId);
|
|
3163
|
+
updatedAgents = Object.fromEntries(Object.entries(state.agentsById).filter(([, agent]) => agent.issueId !== issueId));
|
|
3164
|
+
for (const agentId of removedAgentIds) {
|
|
3165
|
+
nextTurnDiffSummariesByAgentId = omitTurnDiffSummariesForAgent(nextTurnDiffSummariesByAgentId, agentId);
|
|
3166
|
+
nextAgentIdBySessionId = removeAgentFromSessionIndex(nextAgentIdBySessionId, agentId);
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
return {
|
|
3170
|
+
...state,
|
|
3171
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3172
|
+
agentsById: updatedAgents,
|
|
3173
|
+
turnDiffSummariesByAgentId: nextTurnDiffSummariesByAgentId,
|
|
3174
|
+
agentIdBySessionId: nextAgentIdBySessionId
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
case "planning.failed":
|
|
3178
|
+
case "planning.sync":
|
|
3179
|
+
case "plan.item_status_changed":
|
|
3180
|
+
case "plan.subitem_status_changed":
|
|
3181
|
+
case "plan.items_unblocked":
|
|
3182
|
+
case "operator.intervention":
|
|
3183
|
+
case "substrate.bug_filed":
|
|
3184
|
+
case "cost.event_recorded": return {
|
|
3185
|
+
...state,
|
|
3186
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3187
|
+
};
|
|
3188
|
+
case "memory.observation_created": {
|
|
3189
|
+
const observation = event.payload.observation;
|
|
3190
|
+
const existing = state.observationsByIssueId[observation.issueId] ?? [];
|
|
3191
|
+
const index = existing.findIndex((entry) => entry.id === observation.id);
|
|
3192
|
+
const updated = trimMemoryObservations(index === -1 ? [...existing, observation] : existing.map((entry, entryIndex) => entryIndex === index ? observation : entry));
|
|
3193
|
+
return {
|
|
3194
|
+
...state,
|
|
3195
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3196
|
+
observationsByIssueId: {
|
|
3197
|
+
...state.observationsByIssueId,
|
|
3198
|
+
[observation.issueId]: updated
|
|
3199
|
+
}
|
|
3200
|
+
};
|
|
3201
|
+
}
|
|
3202
|
+
case "memory.status_updated": {
|
|
3203
|
+
const { identity, status } = event.payload;
|
|
3204
|
+
return {
|
|
3205
|
+
...state,
|
|
3206
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3207
|
+
statusByIssueId: {
|
|
3208
|
+
...state.statusByIssueId,
|
|
3209
|
+
[identity.issueId]: status
|
|
3210
|
+
}
|
|
3211
|
+
};
|
|
3212
|
+
}
|
|
3213
|
+
case "memory.rollup_triggered": {
|
|
3214
|
+
const trigger = {
|
|
3215
|
+
projectId: event.payload.projectId,
|
|
3216
|
+
workspaceId: event.payload.workspaceId,
|
|
3217
|
+
issueId: event.payload.issueId,
|
|
3218
|
+
pendingTurns: [],
|
|
3219
|
+
pendingCount: event.payload.pendingCount,
|
|
3220
|
+
threshold: event.payload.threshold,
|
|
3221
|
+
triggeredAt: event.timestamp
|
|
3222
|
+
};
|
|
3223
|
+
const updated = [...state.rollupsByIssueId[event.payload.issueId] ?? [], trigger].slice(-10);
|
|
3224
|
+
return {
|
|
3225
|
+
...state,
|
|
3226
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3227
|
+
rollupsByIssueId: {
|
|
3228
|
+
...state.rollupsByIssueId,
|
|
3229
|
+
[event.payload.issueId]: updated
|
|
3230
|
+
}
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
case "memory.reset_marker_created": {
|
|
3234
|
+
const { marker } = event.payload;
|
|
3235
|
+
const key = `${marker.scope}:${marker.scopeId}`;
|
|
3236
|
+
const existing = state.resetMarkersByScopeId[key] ?? [];
|
|
3237
|
+
const index = existing.findIndex((entry) => entry.id === marker.id);
|
|
3238
|
+
const updated = index === -1 ? [...existing, marker] : existing.map((entry, entryIndex) => entryIndex === index ? marker : entry);
|
|
3239
|
+
return {
|
|
3240
|
+
...state,
|
|
3241
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3242
|
+
resetMarkersByScopeId: {
|
|
3243
|
+
...state.resetMarkersByScopeId,
|
|
3244
|
+
[key]: updated
|
|
3245
|
+
}
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3248
|
+
case "memory.health_changed": {
|
|
3249
|
+
const health = {
|
|
3250
|
+
projectId: event.payload.projectId,
|
|
3251
|
+
issueId: event.payload.issueId,
|
|
3252
|
+
status: event.payload.status,
|
|
3253
|
+
reason: event.payload.reason,
|
|
3254
|
+
...event.payload.detail !== void 0 ? { detail: event.payload.detail } : {},
|
|
3255
|
+
...event.payload.ragDecision !== void 0 ? { ragDecision: event.payload.ragDecision } : {},
|
|
3256
|
+
updatedAt: event.timestamp
|
|
3257
|
+
};
|
|
3258
|
+
return {
|
|
3259
|
+
...state,
|
|
3260
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3261
|
+
healthByIssueId: {
|
|
3262
|
+
...state.healthByIssueId,
|
|
3263
|
+
[event.payload.issueId]: health
|
|
3264
|
+
}
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3267
|
+
case "agent.activity_changed": {
|
|
3268
|
+
const { agentId, activity, currentTool } = event.payload;
|
|
3269
|
+
const prev = state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence);
|
|
3270
|
+
const next = {
|
|
3271
|
+
...prev,
|
|
3272
|
+
activity,
|
|
3273
|
+
currentTool: activity === "working" ? currentTool : void 0,
|
|
3274
|
+
thinking: activity === "thinking" ? prev.thinking : void 0,
|
|
3275
|
+
waiting: activity === "waiting" ? prev.waiting : void 0,
|
|
3276
|
+
channelReply: activity === "working" ? void 0 : prev.channelReply,
|
|
3277
|
+
lastActivity: event.timestamp,
|
|
3278
|
+
updatedAtSequence: event.sequence
|
|
3279
|
+
};
|
|
3280
|
+
return {
|
|
3281
|
+
...state,
|
|
3282
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3283
|
+
agentRuntimeById: {
|
|
3284
|
+
...state.agentRuntimeById,
|
|
3285
|
+
[agentId]: next
|
|
3286
|
+
},
|
|
3287
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3288
|
+
};
|
|
3289
|
+
}
|
|
3290
|
+
case "agent.thinking_started": {
|
|
3291
|
+
const { agentId, lastToolAt } = event.payload;
|
|
3292
|
+
const next = {
|
|
3293
|
+
...state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence),
|
|
3294
|
+
activity: "thinking",
|
|
3295
|
+
currentTool: void 0,
|
|
3296
|
+
thinking: {
|
|
3297
|
+
since: event.timestamp,
|
|
3298
|
+
lastToolAt
|
|
3299
|
+
},
|
|
3300
|
+
waiting: void 0,
|
|
3301
|
+
channelReply: void 0,
|
|
3302
|
+
lastActivity: event.timestamp,
|
|
3303
|
+
updatedAtSequence: event.sequence
|
|
3304
|
+
};
|
|
3305
|
+
return {
|
|
3306
|
+
...state,
|
|
3307
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3308
|
+
agentRuntimeById: {
|
|
3309
|
+
...state.agentRuntimeById,
|
|
3310
|
+
[agentId]: next
|
|
3311
|
+
},
|
|
3312
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3313
|
+
};
|
|
3314
|
+
}
|
|
3315
|
+
case "agent.thinking_stopped": {
|
|
3316
|
+
const { agentId } = event.payload;
|
|
3317
|
+
const prev = state.agentRuntimeById[agentId];
|
|
3318
|
+
if (!prev) return {
|
|
3319
|
+
...state,
|
|
3320
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3321
|
+
};
|
|
3322
|
+
const next = {
|
|
3323
|
+
...prev,
|
|
3324
|
+
thinking: void 0,
|
|
3325
|
+
lastActivity: event.timestamp,
|
|
3326
|
+
updatedAtSequence: event.sequence
|
|
3327
|
+
};
|
|
3328
|
+
return {
|
|
3329
|
+
...state,
|
|
3330
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3331
|
+
agentRuntimeById: {
|
|
3332
|
+
...state.agentRuntimeById,
|
|
3333
|
+
[agentId]: next
|
|
3334
|
+
},
|
|
3335
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3338
|
+
case "agent.waiting_started": {
|
|
3339
|
+
const { agentId, reason, message } = event.payload;
|
|
3340
|
+
const next = {
|
|
3341
|
+
...state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence),
|
|
3342
|
+
activity: "waiting",
|
|
3343
|
+
currentTool: void 0,
|
|
3344
|
+
thinking: void 0,
|
|
3345
|
+
waiting: {
|
|
3346
|
+
reason,
|
|
3347
|
+
startedAt: event.timestamp,
|
|
3348
|
+
message
|
|
3349
|
+
},
|
|
3350
|
+
lastActivity: event.timestamp,
|
|
3351
|
+
updatedAtSequence: event.sequence
|
|
3352
|
+
};
|
|
3353
|
+
return {
|
|
3354
|
+
...state,
|
|
3355
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3356
|
+
agentRuntimeById: {
|
|
3357
|
+
...state.agentRuntimeById,
|
|
3358
|
+
[agentId]: next
|
|
3359
|
+
},
|
|
3360
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3363
|
+
case "agent.waiting_cleared": {
|
|
3364
|
+
const { agentId } = event.payload;
|
|
3365
|
+
const prev = state.agentRuntimeById[agentId];
|
|
3366
|
+
if (!prev) return {
|
|
3367
|
+
...state,
|
|
3368
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3369
|
+
};
|
|
3370
|
+
const next = {
|
|
3371
|
+
...prev,
|
|
3372
|
+
waiting: void 0,
|
|
3373
|
+
lastActivity: event.timestamp,
|
|
3374
|
+
updatedAtSequence: event.sequence
|
|
3375
|
+
};
|
|
3376
|
+
return {
|
|
3377
|
+
...state,
|
|
3378
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3379
|
+
agentRuntimeById: {
|
|
3380
|
+
...state.agentRuntimeById,
|
|
3381
|
+
[agentId]: next
|
|
3382
|
+
},
|
|
3383
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3384
|
+
};
|
|
3385
|
+
}
|
|
3386
|
+
case "agent.permission_requested": {
|
|
3387
|
+
const request = event.payload;
|
|
3388
|
+
const permissionRequestIdsByAgentId = state.channelPermissionRequestIdsByAgentId ?? {};
|
|
3389
|
+
const resolvedDecisionsById = state.resolvedChannelPermissionDecisionsById ?? {};
|
|
3390
|
+
const resolvedDecisionIdsByAgentId = state.resolvedChannelPermissionDecisionIdsByAgentId ?? {};
|
|
3391
|
+
const nextPendingIds = permissionRequestIdsByAgentId[request.agentId] ?? [];
|
|
3392
|
+
const resolvedDecision = resolvedDecisionsById[request.requestId];
|
|
3393
|
+
const nextResolvedDecisionsById = { ...resolvedDecisionsById };
|
|
3394
|
+
const nextResolvedIdsByAgentId = { ...resolvedDecisionIdsByAgentId };
|
|
3395
|
+
if (resolvedDecision) {
|
|
3396
|
+
delete nextResolvedDecisionsById[request.requestId];
|
|
3397
|
+
const filteredResolvedIds = (nextResolvedIdsByAgentId[resolvedDecision.agentId] ?? []).filter((id) => id !== request.requestId);
|
|
3398
|
+
if (filteredResolvedIds.length > 0) nextResolvedIdsByAgentId[resolvedDecision.agentId] = filteredResolvedIds;
|
|
3399
|
+
else delete nextResolvedIdsByAgentId[resolvedDecision.agentId];
|
|
3400
|
+
}
|
|
3401
|
+
return {
|
|
3402
|
+
...state,
|
|
3403
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3404
|
+
channelPermissionRequestsById: {
|
|
3405
|
+
...state.channelPermissionRequestsById,
|
|
3406
|
+
[request.requestId]: request
|
|
3407
|
+
},
|
|
3408
|
+
channelPermissionRequestIdsByAgentId: {
|
|
3409
|
+
...permissionRequestIdsByAgentId,
|
|
3410
|
+
[request.agentId]: nextPendingIds.includes(request.requestId) ? nextPendingIds : [...nextPendingIds, request.requestId]
|
|
3411
|
+
},
|
|
3412
|
+
resolvedChannelPermissionDecisionsById: nextResolvedDecisionsById,
|
|
3413
|
+
resolvedChannelPermissionDecisionIdsByAgentId: nextResolvedIdsByAgentId
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
case "agent.permission_resolved": {
|
|
3417
|
+
const { [event.payload.requestId]: _removed, ...rest } = state.channelPermissionRequestsById;
|
|
3418
|
+
const nextPendingIdsByAgentId = { ...state.channelPermissionRequestIdsByAgentId ?? {} };
|
|
3419
|
+
const filteredPendingIds = (nextPendingIdsByAgentId[event.payload.agentId] ?? []).filter((id) => id !== event.payload.requestId);
|
|
3420
|
+
if (filteredPendingIds.length > 0) nextPendingIdsByAgentId[event.payload.agentId] = filteredPendingIds;
|
|
3421
|
+
else delete nextPendingIdsByAgentId[event.payload.agentId];
|
|
3422
|
+
const resolvedDecisionIdsByAgentId = state.resolvedChannelPermissionDecisionIdsByAgentId ?? {};
|
|
3423
|
+
const nextResolvedIds = resolvedDecisionIdsByAgentId[event.payload.agentId] ?? [];
|
|
3424
|
+
return {
|
|
3425
|
+
...state,
|
|
3426
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3427
|
+
channelPermissionRequestsById: rest,
|
|
3428
|
+
channelPermissionRequestIdsByAgentId: nextPendingIdsByAgentId,
|
|
3429
|
+
resolvedChannelPermissionDecisionsById: {
|
|
3430
|
+
...state.resolvedChannelPermissionDecisionsById ?? {},
|
|
3431
|
+
[event.payload.requestId]: {
|
|
3432
|
+
requestId: event.payload.requestId,
|
|
3433
|
+
agentId: event.payload.agentId,
|
|
3434
|
+
issueId: event.payload.issueId,
|
|
3435
|
+
behavior: event.payload.behavior
|
|
3436
|
+
}
|
|
3437
|
+
},
|
|
3438
|
+
resolvedChannelPermissionDecisionIdsByAgentId: {
|
|
3439
|
+
...resolvedDecisionIdsByAgentId,
|
|
3440
|
+
[event.payload.agentId]: nextResolvedIds.includes(event.payload.requestId) ? nextResolvedIds : [...nextResolvedIds, event.payload.requestId]
|
|
3441
|
+
}
|
|
3442
|
+
};
|
|
3443
|
+
}
|
|
3444
|
+
case "agent.message_received": {
|
|
3445
|
+
const { agentId, direction } = event.payload;
|
|
3446
|
+
const prev = state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence);
|
|
3447
|
+
const next = {
|
|
3448
|
+
...prev,
|
|
3449
|
+
lastMessageAt: event.timestamp,
|
|
3450
|
+
channelReply: direction === "to_agent" ? void 0 : prev.channelReply,
|
|
3451
|
+
lastActivity: event.timestamp,
|
|
3452
|
+
updatedAtSequence: event.sequence
|
|
3453
|
+
};
|
|
3454
|
+
return {
|
|
3455
|
+
...state,
|
|
3456
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3457
|
+
agentRuntimeById: {
|
|
3458
|
+
...state.agentRuntimeById,
|
|
3459
|
+
[agentId]: next
|
|
3460
|
+
},
|
|
3461
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3462
|
+
};
|
|
3463
|
+
}
|
|
3464
|
+
case "agent.channel_reply": {
|
|
3465
|
+
const { agentId, reply } = event.payload;
|
|
3466
|
+
const prev = state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence);
|
|
3467
|
+
const next = {
|
|
3468
|
+
...prev,
|
|
3469
|
+
channelReply: {
|
|
3470
|
+
...reply,
|
|
3471
|
+
reportedAt: event.timestamp
|
|
3472
|
+
},
|
|
3473
|
+
resolution: reply.kind === "done" ? "done" : reply.kind === "needs_input" ? "needs_input" : prev.resolution,
|
|
3474
|
+
resolutionUpdatedAt: reply.kind === "done" || reply.kind === "needs_input" ? event.timestamp : prev.resolutionUpdatedAt,
|
|
3475
|
+
lastActivity: event.timestamp,
|
|
3476
|
+
updatedAtSequence: event.sequence
|
|
3477
|
+
};
|
|
3478
|
+
return {
|
|
3479
|
+
...state,
|
|
3480
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3481
|
+
agentRuntimeById: {
|
|
3482
|
+
...state.agentRuntimeById,
|
|
3483
|
+
[agentId]: next
|
|
3484
|
+
},
|
|
3485
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3486
|
+
};
|
|
3487
|
+
}
|
|
3488
|
+
case "agent.model_set": {
|
|
3489
|
+
const { agentId, model, claudeSessionId, sessionModel, sessionHarness } = event.payload;
|
|
3490
|
+
const prev = state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence);
|
|
3491
|
+
const next = {
|
|
3492
|
+
...prev,
|
|
3493
|
+
model,
|
|
3494
|
+
claudeSessionId: claudeSessionId ?? prev.claudeSessionId,
|
|
3495
|
+
sessionModel: sessionModel ?? prev.sessionModel,
|
|
3496
|
+
sessionHarness: sessionHarness ?? prev.sessionHarness,
|
|
3497
|
+
lastActivity: event.timestamp,
|
|
3498
|
+
updatedAtSequence: event.sequence
|
|
3499
|
+
};
|
|
3500
|
+
let nextAgentIdBySessionId = state.agentIdBySessionId;
|
|
3501
|
+
if (claudeSessionId && claudeSessionId !== prev.claudeSessionId) {
|
|
3502
|
+
nextAgentIdBySessionId = {
|
|
3503
|
+
...state.agentIdBySessionId,
|
|
3504
|
+
[claudeSessionId]: agentId
|
|
3505
|
+
};
|
|
3506
|
+
if (prev.claudeSessionId && state.agentIdBySessionId[prev.claudeSessionId] === agentId) {
|
|
3507
|
+
const { [prev.claudeSessionId]: _removed, ...rest } = state.agentIdBySessionId;
|
|
3508
|
+
nextAgentIdBySessionId = {
|
|
3509
|
+
...rest,
|
|
3510
|
+
[claudeSessionId]: agentId
|
|
3511
|
+
};
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
return {
|
|
3515
|
+
...state,
|
|
3516
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3517
|
+
agentRuntimeById: {
|
|
3518
|
+
...state.agentRuntimeById,
|
|
3519
|
+
[agentId]: next
|
|
3520
|
+
},
|
|
3521
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence),
|
|
3522
|
+
agentIdBySessionId: nextAgentIdBySessionId
|
|
3523
|
+
};
|
|
3524
|
+
}
|
|
3525
|
+
case "agent.current_issue_set": {
|
|
3526
|
+
const { agentId, currentIssue } = event.payload;
|
|
3527
|
+
const next = {
|
|
3528
|
+
...state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence),
|
|
3529
|
+
currentIssue,
|
|
3530
|
+
lastActivity: event.timestamp,
|
|
3531
|
+
updatedAtSequence: event.sequence
|
|
3532
|
+
};
|
|
3533
|
+
return {
|
|
3534
|
+
...state,
|
|
3535
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3536
|
+
agentRuntimeById: {
|
|
3537
|
+
...state.agentRuntimeById,
|
|
3538
|
+
[agentId]: next
|
|
3539
|
+
},
|
|
3540
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3541
|
+
};
|
|
3542
|
+
}
|
|
3543
|
+
case "agent.context_saturation_changed": {
|
|
3544
|
+
const { agentId, contextSaturatedAt } = event.payload;
|
|
3545
|
+
const next = {
|
|
3546
|
+
...state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence),
|
|
3547
|
+
contextSaturatedAt,
|
|
3548
|
+
updatedAtSequence: event.sequence
|
|
3549
|
+
};
|
|
3550
|
+
return {
|
|
3551
|
+
...state,
|
|
3552
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3553
|
+
agentRuntimeById: {
|
|
3554
|
+
...state.agentRuntimeById,
|
|
3555
|
+
[agentId]: next
|
|
3556
|
+
},
|
|
3557
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3558
|
+
};
|
|
3559
|
+
}
|
|
3560
|
+
case "agent.resolution_changed": {
|
|
3561
|
+
const { agentId, resolution, resolutionCount } = event.payload;
|
|
3562
|
+
const next = {
|
|
3563
|
+
...state.agentRuntimeById[agentId] ?? defaultRuntimeSnapshot(agentId, event.timestamp, event.sequence),
|
|
3564
|
+
resolution,
|
|
3565
|
+
resolutionCount,
|
|
3566
|
+
resolutionUpdatedAt: event.timestamp,
|
|
3567
|
+
lastActivity: event.timestamp,
|
|
3568
|
+
updatedAtSequence: event.sequence
|
|
3569
|
+
};
|
|
3570
|
+
return {
|
|
3571
|
+
...state,
|
|
3572
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3573
|
+
agentRuntimeById: {
|
|
3574
|
+
...state.agentRuntimeById,
|
|
3575
|
+
[agentId]: next
|
|
3576
|
+
},
|
|
3577
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3578
|
+
};
|
|
3579
|
+
}
|
|
3580
|
+
case "agent.state_restored": {
|
|
3581
|
+
const { agentId, snapshot } = event.payload;
|
|
3582
|
+
const next = {
|
|
3583
|
+
...snapshot,
|
|
3584
|
+
updatedAtSequence: event.sequence
|
|
3585
|
+
};
|
|
3586
|
+
return {
|
|
3587
|
+
...state,
|
|
3588
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3589
|
+
agentRuntimeById: {
|
|
3590
|
+
...state.agentRuntimeById,
|
|
3591
|
+
[agentId]: next
|
|
3592
|
+
},
|
|
3593
|
+
agentsById: bumpRuntimeSnapshotSequence(state.agentsById, agentId, event.sequence)
|
|
3594
|
+
};
|
|
3595
|
+
}
|
|
3596
|
+
case "activity.entry": {
|
|
3597
|
+
const entry = event.payload;
|
|
3598
|
+
const updated = [{
|
|
3599
|
+
id: entry.id,
|
|
3600
|
+
timestamp: event.timestamp,
|
|
3601
|
+
...entry
|
|
3602
|
+
}, ...state.recentActivity].slice(0, MAX_ACTIVITY_ENTRIES);
|
|
3603
|
+
return {
|
|
3604
|
+
...state,
|
|
3605
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3606
|
+
recentActivity: updated
|
|
3607
|
+
};
|
|
3608
|
+
}
|
|
3609
|
+
case "activity.detailed": {
|
|
3610
|
+
const entry = event.payload;
|
|
3611
|
+
const updated = [{
|
|
3612
|
+
id: entry.id,
|
|
3613
|
+
timestamp: event.timestamp,
|
|
3614
|
+
...entry
|
|
3615
|
+
}, ...state.detailedActivity].slice(0, MAX_DETAILED_ENTRIES);
|
|
3616
|
+
return {
|
|
3617
|
+
...state,
|
|
3618
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3619
|
+
detailedActivity: updated
|
|
3620
|
+
};
|
|
3621
|
+
}
|
|
3622
|
+
case "activity.tts": {
|
|
3623
|
+
const entry = event.payload;
|
|
3624
|
+
const updated = [{
|
|
3625
|
+
id: entry.id,
|
|
3626
|
+
timestamp: event.timestamp,
|
|
3627
|
+
...entry
|
|
3628
|
+
}, ...state.ttsActivity].slice(0, MAX_TTS_ENTRIES);
|
|
3629
|
+
return {
|
|
3630
|
+
...state,
|
|
3631
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3632
|
+
ttsActivity: updated
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3635
|
+
case "dashboard.lifecycle_started": {
|
|
3636
|
+
const { reason, issueId, trigger } = event.payload;
|
|
3637
|
+
return {
|
|
3638
|
+
...state,
|
|
3639
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3640
|
+
dashboardLifecycle: {
|
|
3641
|
+
active: true,
|
|
3642
|
+
reason,
|
|
3643
|
+
issueId,
|
|
3644
|
+
trigger,
|
|
3645
|
+
startedAt: event.timestamp,
|
|
3646
|
+
completedAt: null,
|
|
3647
|
+
failedAt: null,
|
|
3648
|
+
error: null
|
|
3649
|
+
}
|
|
3650
|
+
};
|
|
3651
|
+
}
|
|
3652
|
+
case "dashboard.lifecycle_completed": {
|
|
3653
|
+
const { reason, issueId } = event.payload;
|
|
3654
|
+
return {
|
|
3655
|
+
...state,
|
|
3656
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3657
|
+
dashboardLifecycle: {
|
|
3658
|
+
...state.dashboardLifecycle,
|
|
3659
|
+
active: false,
|
|
3660
|
+
reason: reason ?? state.dashboardLifecycle.reason,
|
|
3661
|
+
issueId: issueId ?? state.dashboardLifecycle.issueId,
|
|
3662
|
+
completedAt: event.timestamp
|
|
3663
|
+
}
|
|
3664
|
+
};
|
|
3665
|
+
}
|
|
3666
|
+
case "dashboard.lifecycle_failed": {
|
|
3667
|
+
const { reason, issueId, error } = event.payload;
|
|
3668
|
+
return {
|
|
3669
|
+
...state,
|
|
3670
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3671
|
+
dashboardLifecycle: {
|
|
3672
|
+
...state.dashboardLifecycle,
|
|
3673
|
+
active: false,
|
|
3674
|
+
reason: reason ?? state.dashboardLifecycle.reason,
|
|
3675
|
+
issueId: issueId ?? state.dashboardLifecycle.issueId,
|
|
3676
|
+
failedAt: event.timestamp,
|
|
3677
|
+
error
|
|
3678
|
+
}
|
|
3679
|
+
};
|
|
3680
|
+
}
|
|
3681
|
+
case "agent.turn_diff_completed": {
|
|
3682
|
+
const p = event.payload;
|
|
3683
|
+
const existing = state.turnDiffSummariesByAgentId[p.agentId] ?? [];
|
|
3684
|
+
const summary = {
|
|
3685
|
+
turnId: p.turnId,
|
|
3686
|
+
completedAt: p.completedAt,
|
|
3687
|
+
files: p.files,
|
|
3688
|
+
checkpointRef: p.checkpointRef,
|
|
3689
|
+
assistantMessageId: p.assistantMessageId ?? void 0,
|
|
3690
|
+
checkpointTurnCount: p.checkpointTurnCount
|
|
3691
|
+
};
|
|
3692
|
+
const idx = existing.findIndex((s) => s.turnId === p.turnId);
|
|
3693
|
+
const updated = trimTurnDiffSummaries(idx >= 0 ? existing.map((s, i) => i === idx ? summary : s) : [...existing, summary]);
|
|
3694
|
+
return {
|
|
3695
|
+
...state,
|
|
3696
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3697
|
+
turnDiffSummariesByAgentId: {
|
|
3698
|
+
...state.turnDiffSummariesByAgentId,
|
|
3699
|
+
[p.agentId]: updated
|
|
3700
|
+
}
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3703
|
+
case "conversation.compacting_changed": {
|
|
3704
|
+
const { conversationName, compacting } = event.payload;
|
|
3705
|
+
if (!compacting) {
|
|
3706
|
+
const { [conversationName]: _removed, ...rest } = state.conversationsCompactingByName;
|
|
3707
|
+
return {
|
|
3708
|
+
...state,
|
|
3709
|
+
conversationsCompactingByName: rest
|
|
3710
|
+
};
|
|
3711
|
+
}
|
|
3712
|
+
return {
|
|
3713
|
+
...state,
|
|
3714
|
+
conversationsCompactingByName: {
|
|
3715
|
+
...state.conversationsCompactingByName,
|
|
3716
|
+
[conversationName]: true
|
|
3717
|
+
}
|
|
3718
|
+
};
|
|
3719
|
+
}
|
|
3720
|
+
case "conversation.created": return {
|
|
3721
|
+
...state,
|
|
3722
|
+
conversationsListRevision: state.conversationsListRevision + 1
|
|
3723
|
+
};
|
|
3724
|
+
case "conversation.permission_changed": {
|
|
3725
|
+
const { conversationName, waiting } = event.payload;
|
|
3726
|
+
if (!waiting) {
|
|
3727
|
+
const { [conversationName]: _removed, ...rest } = state.conversationsAwaitingPermissionByName;
|
|
3728
|
+
return {
|
|
3729
|
+
...state,
|
|
3730
|
+
conversationsAwaitingPermissionByName: rest
|
|
3731
|
+
};
|
|
3732
|
+
}
|
|
3733
|
+
return {
|
|
3734
|
+
...state,
|
|
3735
|
+
conversationsAwaitingPermissionByName: {
|
|
3736
|
+
...state.conversationsAwaitingPermissionByName,
|
|
3737
|
+
[conversationName]: true
|
|
3738
|
+
}
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3741
|
+
case "scan.started": {
|
|
3742
|
+
const { mode, dirs } = event.payload;
|
|
3743
|
+
return {
|
|
3744
|
+
...state,
|
|
3745
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3746
|
+
scanProgress: {
|
|
3747
|
+
active: true,
|
|
3748
|
+
mode,
|
|
3749
|
+
dirs,
|
|
3750
|
+
dirsProcessed: 0,
|
|
3751
|
+
dirsTotal: 0,
|
|
3752
|
+
sessionsFound: 0,
|
|
3753
|
+
elapsedMs: 0,
|
|
3754
|
+
inserted: 0,
|
|
3755
|
+
updated: 0,
|
|
3756
|
+
skipped: 0,
|
|
3757
|
+
errors: 0,
|
|
3758
|
+
durationMs: 0
|
|
3759
|
+
}
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3762
|
+
case "scan.progress": {
|
|
3763
|
+
if (!state.scanProgress) return {
|
|
3764
|
+
...state,
|
|
3765
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3766
|
+
};
|
|
3767
|
+
const { dirsProcessed, dirsTotal, sessionsFound, elapsedMs } = event.payload;
|
|
3768
|
+
return {
|
|
3769
|
+
...state,
|
|
3770
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3771
|
+
scanProgress: {
|
|
3772
|
+
...state.scanProgress,
|
|
3773
|
+
dirsProcessed,
|
|
3774
|
+
dirsTotal,
|
|
3775
|
+
sessionsFound,
|
|
3776
|
+
elapsedMs
|
|
3777
|
+
}
|
|
3778
|
+
};
|
|
3779
|
+
}
|
|
3780
|
+
case "scan.complete": {
|
|
3781
|
+
if (!state.scanProgress) return {
|
|
3782
|
+
...state,
|
|
3783
|
+
sequence: Math.max(state.sequence, event.sequence)
|
|
3784
|
+
};
|
|
3785
|
+
const { inserted, updated, skipped, errors, durationMs } = event.payload;
|
|
3786
|
+
return {
|
|
3787
|
+
...state,
|
|
3788
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3789
|
+
scanProgress: {
|
|
3790
|
+
...state.scanProgress,
|
|
3791
|
+
active: false,
|
|
3792
|
+
inserted,
|
|
3793
|
+
updated,
|
|
3794
|
+
skipped,
|
|
3795
|
+
errors,
|
|
3796
|
+
durationMs
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3799
|
+
}
|
|
3800
|
+
case "enrich.progress": {
|
|
3801
|
+
const { sessionId, level, model, cost, success, error } = event.payload;
|
|
3802
|
+
const prev = state.enrichStats ?? {
|
|
3803
|
+
processed: 0,
|
|
3804
|
+
totalCost: 0,
|
|
3805
|
+
failures: 0,
|
|
3806
|
+
durationMs: 0
|
|
3807
|
+
};
|
|
3808
|
+
const progress = {
|
|
3809
|
+
sessionId,
|
|
3810
|
+
level,
|
|
3811
|
+
model,
|
|
3812
|
+
cost,
|
|
3813
|
+
success,
|
|
3814
|
+
error,
|
|
3815
|
+
timestamp: event.timestamp
|
|
3816
|
+
};
|
|
3817
|
+
return {
|
|
3818
|
+
...state,
|
|
3819
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3820
|
+
enrichStats: {
|
|
3821
|
+
processed: prev.processed + 1,
|
|
3822
|
+
totalCost: prev.totalCost + (success ? cost : 0),
|
|
3823
|
+
failures: prev.failures + (success ? 0 : 1),
|
|
3824
|
+
durationMs: 0
|
|
3825
|
+
},
|
|
3826
|
+
enrichProgressBySessionId: upsertBoundedSessionProgress(state.enrichProgressBySessionId, progress)
|
|
3827
|
+
};
|
|
3828
|
+
}
|
|
3829
|
+
case "enrich.complete": {
|
|
3830
|
+
const { processed, totalCost, failures, durationMs } = event.payload;
|
|
3831
|
+
return {
|
|
3832
|
+
...state,
|
|
3833
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3834
|
+
enrichStats: {
|
|
3835
|
+
processed,
|
|
3836
|
+
totalCost,
|
|
3837
|
+
failures,
|
|
3838
|
+
durationMs
|
|
3839
|
+
},
|
|
3840
|
+
enrichProgressBySessionId: {}
|
|
3841
|
+
};
|
|
3842
|
+
}
|
|
3843
|
+
case "embed.progress": {
|
|
3844
|
+
const { sessionId, model, success, error } = event.payload;
|
|
3845
|
+
const progress = {
|
|
3846
|
+
sessionId,
|
|
3847
|
+
model,
|
|
3848
|
+
success,
|
|
3849
|
+
error,
|
|
3850
|
+
timestamp: event.timestamp
|
|
3851
|
+
};
|
|
3852
|
+
return {
|
|
3853
|
+
...state,
|
|
3854
|
+
sequence: Math.max(state.sequence, event.sequence),
|
|
3855
|
+
embedProgressBySessionId: upsertBoundedSessionProgress(state.embedProgressBySessionId, progress)
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
default: return state;
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
function applyEvents(state, events) {
|
|
3862
|
+
return events.reduce(applyEvent, state);
|
|
3863
|
+
}
|
|
3864
|
+
//#endregion
|
|
3865
|
+
//#region src/flywheel-stats.ts
|
|
3866
|
+
const FlywheelStatsCriterionStatus = Schema.Literals([
|
|
3867
|
+
"green",
|
|
3868
|
+
"yellow",
|
|
3869
|
+
"red",
|
|
3870
|
+
"insufficient_data"
|
|
3871
|
+
]);
|
|
3872
|
+
const FlywheelStatsTrend = Schema.Literals([
|
|
3873
|
+
"up",
|
|
3874
|
+
"down",
|
|
3875
|
+
"flat"
|
|
3876
|
+
]);
|
|
3877
|
+
const FlywheelStatsCriterionValueObject = Schema.Record(Schema.String, Schema.Json);
|
|
3878
|
+
const FlywheelStatsCriterionValue = Schema.Union([Schema.Number, FlywheelStatsCriterionValueObject]);
|
|
3879
|
+
const FlywheelStatsCriterion = Schema.Struct({
|
|
3880
|
+
label: Schema.String,
|
|
3881
|
+
value: FlywheelStatsCriterionValue,
|
|
3882
|
+
target: FlywheelStatsCriterionValue,
|
|
3883
|
+
status: FlywheelStatsCriterionStatus,
|
|
3884
|
+
trend: Schema.optional(FlywheelStatsTrend),
|
|
3885
|
+
sampleSize: Schema.Number,
|
|
3886
|
+
dataSufficient: Schema.Boolean
|
|
3887
|
+
});
|
|
3888
|
+
const FlywheelStatsCriteria = Schema.Struct({
|
|
3889
|
+
c1_bugRate: FlywheelStatsCriterion,
|
|
3890
|
+
c2_p0Bugs: FlywheelStatsCriterion,
|
|
3891
|
+
c3_passRate: FlywheelStatsCriterion,
|
|
3892
|
+
c4_mttr: FlywheelStatsCriterion,
|
|
3893
|
+
c5_intervention: FlywheelStatsCriterion,
|
|
3894
|
+
c6_timeConsistency: FlywheelStatsCriterion,
|
|
3895
|
+
c7_flake: FlywheelStatsCriterion
|
|
3896
|
+
});
|
|
3897
|
+
const FlywheelStats = Schema.Struct({
|
|
3898
|
+
window: Schema.String,
|
|
3899
|
+
generatedAt: Schema.String,
|
|
3900
|
+
criteria: FlywheelStatsCriteria
|
|
3901
|
+
});
|
|
3902
|
+
const decodeFlywheelStats = Schema.decodeUnknownSync(FlywheelStats);
|
|
3903
|
+
const encodeFlywheelStats = Schema.encodeSync(FlywheelStats);
|
|
3904
|
+
//#endregion
|
|
3905
|
+
//#region src/context-layers.ts
|
|
3906
|
+
const CONTEXT_LAYER_KINDS = [
|
|
3907
|
+
"global",
|
|
3908
|
+
"project",
|
|
3909
|
+
"workspace"
|
|
3910
|
+
];
|
|
3911
|
+
const CONTEXT_PREVIEW_HARNESSES = [
|
|
3912
|
+
"claude-code",
|
|
3913
|
+
"pi",
|
|
3914
|
+
"codex"
|
|
3915
|
+
];
|
|
3916
|
+
const ContextLayerKind = Schema.Literals(CONTEXT_LAYER_KINDS);
|
|
3917
|
+
const ContextPreviewHarness = Schema.Literals(CONTEXT_PREVIEW_HARNESSES);
|
|
3918
|
+
const ContextProjectSummary = Schema.Struct({
|
|
3919
|
+
projectKey: Schema.String,
|
|
3920
|
+
name: Schema.String,
|
|
3921
|
+
path: Schema.String,
|
|
3922
|
+
issuePrefix: Schema.optional(Schema.String),
|
|
3923
|
+
tracker: Schema.optional(Schema.Literals([
|
|
3924
|
+
"linear",
|
|
3925
|
+
"github",
|
|
3926
|
+
"gitlab",
|
|
3927
|
+
"rally"
|
|
3928
|
+
])),
|
|
3929
|
+
workspaceRoot: Schema.optional(Schema.String)
|
|
3930
|
+
});
|
|
3931
|
+
const ContextWorkspaceSummary = Schema.Struct({
|
|
3932
|
+
projectKey: Schema.String,
|
|
3933
|
+
path: Schema.String,
|
|
3934
|
+
name: Schema.String,
|
|
3935
|
+
issueId: Schema.optional(Schema.String),
|
|
3936
|
+
branch: Schema.optional(Schema.String)
|
|
3937
|
+
});
|
|
3938
|
+
const ContextLayerBase = {
|
|
3939
|
+
file: Schema.String,
|
|
3940
|
+
exists: Schema.Boolean,
|
|
3941
|
+
content: Schema.String,
|
|
3942
|
+
editable: Schema.Boolean
|
|
3943
|
+
};
|
|
3944
|
+
const GlobalContextLayerRecord = Schema.Struct({
|
|
3945
|
+
kind: Schema.Literal("global"),
|
|
3946
|
+
...ContextLayerBase
|
|
3947
|
+
});
|
|
3948
|
+
const ProjectContextLayerRecord = Schema.Struct({
|
|
3949
|
+
kind: Schema.Literal("project"),
|
|
3950
|
+
projectKey: Schema.String,
|
|
3951
|
+
...ContextLayerBase
|
|
3952
|
+
});
|
|
3953
|
+
const WorkspaceContextLayerRecord = Schema.Struct({
|
|
3954
|
+
kind: Schema.Literal("workspace"),
|
|
3955
|
+
projectKey: Schema.String,
|
|
3956
|
+
workspacePath: Schema.String,
|
|
3957
|
+
...ContextLayerBase
|
|
3958
|
+
});
|
|
3959
|
+
const ContextEditableLayerRecord = Schema.Union([
|
|
3960
|
+
GlobalContextLayerRecord,
|
|
3961
|
+
ProjectContextLayerRecord,
|
|
3962
|
+
WorkspaceContextLayerRecord
|
|
3963
|
+
]);
|
|
3964
|
+
const GlobalContextLayerTarget = Schema.Struct({ kind: Schema.Literal("global") });
|
|
3965
|
+
const ProjectContextLayerTarget = Schema.Struct({
|
|
3966
|
+
kind: Schema.Literal("project"),
|
|
3967
|
+
projectKey: Schema.String
|
|
3968
|
+
});
|
|
3969
|
+
const WorkspaceContextLayerTarget = Schema.Struct({
|
|
3970
|
+
kind: Schema.Literal("workspace"),
|
|
3971
|
+
projectKey: Schema.String,
|
|
3972
|
+
workspacePath: Schema.String
|
|
3973
|
+
});
|
|
3974
|
+
const ContextLayerTarget = Schema.Union([
|
|
3975
|
+
GlobalContextLayerTarget,
|
|
3976
|
+
ProjectContextLayerTarget,
|
|
3977
|
+
WorkspaceContextLayerTarget
|
|
3978
|
+
]);
|
|
3979
|
+
const ContextLayerDraft = Schema.Struct({
|
|
3980
|
+
target: ContextLayerTarget,
|
|
3981
|
+
content: Schema.String
|
|
3982
|
+
});
|
|
3983
|
+
/**
|
|
3984
|
+
* A rendered output file `pan sync` writes a Overdeck-managed region into
|
|
3985
|
+
* (e.g. ~/.claude/CLAUDE.md, a project's CLAUDE.md or AGENTS.md). Distinct from
|
|
3986
|
+
* the editable *layer source* files — this describes the injection *target* so
|
|
3987
|
+
* the dashboard can show the user exactly where context lands and reassure them
|
|
3988
|
+
* their own content is preserved.
|
|
3989
|
+
*/
|
|
3990
|
+
const ContextSyncTarget = Schema.Struct({
|
|
3991
|
+
harness: ContextPreviewHarness,
|
|
3992
|
+
layerKind: Schema.Literals(["global", "project"]),
|
|
3993
|
+
projectKey: Schema.optional(Schema.String),
|
|
3994
|
+
/** Short human label, e.g. "Claude Code · global". */
|
|
3995
|
+
label: Schema.String,
|
|
3996
|
+
/** Resolved absolute path of the target file. */
|
|
3997
|
+
path: Schema.String,
|
|
3998
|
+
exists: Schema.Boolean,
|
|
3999
|
+
/** True when the file already contains a Overdeck-managed region. */
|
|
4000
|
+
hasManagedRegion: Schema.Boolean,
|
|
4001
|
+
/** True when the file has hand-authored content outside the managed region. */
|
|
4002
|
+
hasUserContent: Schema.Boolean
|
|
4003
|
+
});
|
|
4004
|
+
const ContextLayersResponse = Schema.Struct({
|
|
4005
|
+
operation: Schema.Literal("load"),
|
|
4006
|
+
projects: Schema.Array(ContextProjectSummary),
|
|
4007
|
+
workspaces: Schema.Array(ContextWorkspaceSummary),
|
|
4008
|
+
layers: Schema.Array(ContextEditableLayerRecord),
|
|
4009
|
+
/** Injection targets `pan sync` writes managed regions into. */
|
|
4010
|
+
targets: Schema.Array(ContextSyncTarget)
|
|
4011
|
+
});
|
|
4012
|
+
const ContextPreviewRequest = Schema.Struct({
|
|
4013
|
+
operation: Schema.Literal("preview"),
|
|
4014
|
+
selectedLayer: ContextLayerTarget,
|
|
4015
|
+
drafts: Schema.Array(ContextLayerDraft)
|
|
4016
|
+
});
|
|
4017
|
+
const ContextHarnessPreviews = Schema.Struct({
|
|
4018
|
+
"claude-code": Schema.String,
|
|
4019
|
+
pi: Schema.String,
|
|
4020
|
+
codex: Schema.String,
|
|
4021
|
+
fullPrompt: Schema.String
|
|
4022
|
+
});
|
|
4023
|
+
const ContextPreviewDiagnostic = Schema.Struct({
|
|
4024
|
+
level: Schema.Literals([
|
|
4025
|
+
"info",
|
|
4026
|
+
"warning",
|
|
4027
|
+
"error"
|
|
4028
|
+
]),
|
|
4029
|
+
message: Schema.String,
|
|
4030
|
+
layer: Schema.optional(ContextLayerTarget)
|
|
4031
|
+
});
|
|
4032
|
+
const ContextPreviewResponse = Schema.Struct({
|
|
4033
|
+
operation: Schema.Literal("preview"),
|
|
4034
|
+
previews: ContextHarnessPreviews,
|
|
4035
|
+
diagnostics: Schema.Array(ContextPreviewDiagnostic)
|
|
4036
|
+
});
|
|
4037
|
+
const ContextLayerSaveRequest = Schema.Struct({
|
|
4038
|
+
operation: Schema.Literal("save"),
|
|
4039
|
+
target: ContextLayerTarget,
|
|
4040
|
+
content: Schema.String
|
|
4041
|
+
});
|
|
4042
|
+
const ContextLayerSaveResponse = Schema.Struct({
|
|
4043
|
+
operation: Schema.Literal("save"),
|
|
4044
|
+
layer: ContextEditableLayerRecord,
|
|
4045
|
+
savedAt: Schema.String
|
|
4046
|
+
});
|
|
4047
|
+
const ContextSyncRequest = Schema.Struct({ operation: Schema.Literal("sync") });
|
|
4048
|
+
const ContextSyncResponse = Schema.Struct({
|
|
4049
|
+
operation: Schema.Literal("sync"),
|
|
4050
|
+
success: Schema.Boolean,
|
|
4051
|
+
exitCode: Schema.optional(Schema.Number),
|
|
4052
|
+
stdout: Schema.String,
|
|
4053
|
+
stderr: Schema.String,
|
|
4054
|
+
syncedAt: Schema.String
|
|
4055
|
+
});
|
|
4056
|
+
//#endregion
|
|
4057
|
+
//#region src/artifacts.ts
|
|
4058
|
+
const ArtifactId = Schema.String;
|
|
4059
|
+
const ArtifactSlug = Schema.String;
|
|
4060
|
+
const ArtifactHash = Schema.String;
|
|
4061
|
+
const ArtifactAgentRole = Schema.Literals([
|
|
4062
|
+
"plan",
|
|
4063
|
+
"work",
|
|
4064
|
+
"review",
|
|
4065
|
+
"test",
|
|
4066
|
+
"ship",
|
|
4067
|
+
"flywheel",
|
|
4068
|
+
"user"
|
|
4069
|
+
]);
|
|
4070
|
+
const ArtifactAgentHarness = Schema.Literals([
|
|
4071
|
+
"claude-code",
|
|
4072
|
+
"pi",
|
|
4073
|
+
"codex",
|
|
4074
|
+
"user"
|
|
4075
|
+
]);
|
|
4076
|
+
const ArtifactLifecycleState = Schema.Literals([
|
|
4077
|
+
"published",
|
|
4078
|
+
"pending_changes",
|
|
4079
|
+
"unshared"
|
|
4080
|
+
]);
|
|
4081
|
+
const ArtifactValidationCode = Schema.Literals([
|
|
4082
|
+
"invalid_file_type",
|
|
4083
|
+
"not_a_file",
|
|
4084
|
+
"size_limit_exceeded",
|
|
4085
|
+
"forbidden_asset_url",
|
|
4086
|
+
"secret_detected",
|
|
4087
|
+
"secret_allowed",
|
|
4088
|
+
"high_entropy_string",
|
|
4089
|
+
"inline_event_handler",
|
|
4090
|
+
"missing_image_alt"
|
|
4091
|
+
]);
|
|
4092
|
+
const ArtifactValidationFinding = Schema.Struct({
|
|
4093
|
+
code: ArtifactValidationCode,
|
|
4094
|
+
message: Schema.String,
|
|
4095
|
+
line: Schema.optional(Schema.Number),
|
|
4096
|
+
column: Schema.optional(Schema.Number),
|
|
4097
|
+
rule: Schema.optional(Schema.String),
|
|
4098
|
+
strict: Schema.optional(Schema.Boolean)
|
|
4099
|
+
});
|
|
4100
|
+
const ArtifactValidationResult = Schema.Struct({
|
|
4101
|
+
ok: Schema.Boolean,
|
|
4102
|
+
filePath: Schema.optional(Schema.String),
|
|
4103
|
+
size: Schema.Number,
|
|
4104
|
+
hash: ArtifactHash,
|
|
4105
|
+
strict: Schema.Boolean,
|
|
4106
|
+
errors: Schema.Array(ArtifactValidationFinding),
|
|
4107
|
+
warnings: Schema.Array(ArtifactValidationFinding)
|
|
4108
|
+
});
|
|
4109
|
+
const ArtifactMetadata = Schema.Struct({
|
|
4110
|
+
artifactId: ArtifactId,
|
|
4111
|
+
slug: ArtifactSlug,
|
|
4112
|
+
issueId: Schema.optional(Schema.NullOr(Schema.String)),
|
|
4113
|
+
workspaceId: Schema.optional(Schema.NullOr(Schema.String)),
|
|
4114
|
+
agentRole: Schema.optional(Schema.NullOr(ArtifactAgentRole)),
|
|
4115
|
+
agentHarness: Schema.optional(Schema.NullOr(ArtifactAgentHarness)),
|
|
4116
|
+
runId: Schema.optional(Schema.NullOr(Schema.String)),
|
|
4117
|
+
sessionId: Schema.optional(Schema.NullOr(Schema.String)),
|
|
4118
|
+
filePath: Schema.String,
|
|
4119
|
+
currentHash: ArtifactHash,
|
|
4120
|
+
lastPublishedHash: Schema.optional(Schema.NullOr(ArtifactHash)),
|
|
4121
|
+
supersedes: Schema.optional(Schema.NullOr(ArtifactId)),
|
|
4122
|
+
title: Schema.optional(Schema.NullOr(Schema.String)),
|
|
4123
|
+
description: Schema.optional(Schema.NullOr(Schema.String)),
|
|
4124
|
+
createdAt: Schema.String,
|
|
4125
|
+
publishedAt: Schema.optional(Schema.NullOr(Schema.String)),
|
|
4126
|
+
unsharedAt: Schema.optional(Schema.NullOr(Schema.String))
|
|
4127
|
+
});
|
|
4128
|
+
const ArtifactUrls = Schema.Struct({
|
|
4129
|
+
wrapperUrl: Schema.String,
|
|
4130
|
+
rawUrl: Schema.String
|
|
4131
|
+
});
|
|
4132
|
+
const ArtifactStatusResponse = Schema.Struct({
|
|
4133
|
+
artifact: Schema.optional(ArtifactMetadata),
|
|
4134
|
+
filePath: Schema.String,
|
|
4135
|
+
currentHash: ArtifactHash,
|
|
4136
|
+
lastPublishedHash: Schema.optional(Schema.NullOr(ArtifactHash)),
|
|
4137
|
+
pendingChanges: Schema.Boolean,
|
|
4138
|
+
validation: Schema.optional(ArtifactValidationResult)
|
|
4139
|
+
});
|
|
4140
|
+
const ArtifactCreateResponse = Schema.Struct({
|
|
4141
|
+
artifact: ArtifactMetadata,
|
|
4142
|
+
urls: ArtifactUrls,
|
|
4143
|
+
validation: ArtifactValidationResult,
|
|
4144
|
+
published: Schema.Boolean
|
|
4145
|
+
});
|
|
4146
|
+
const ArtifactPublishResponse = Schema.Struct({
|
|
4147
|
+
artifact: ArtifactMetadata,
|
|
4148
|
+
urls: ArtifactUrls,
|
|
4149
|
+
validation: ArtifactValidationResult,
|
|
4150
|
+
published: Schema.Boolean,
|
|
4151
|
+
pendingChanges: Schema.Boolean
|
|
4152
|
+
});
|
|
4153
|
+
const ArtifactUnshareResponse = Schema.Struct({
|
|
4154
|
+
artifact: ArtifactMetadata,
|
|
4155
|
+
unshared: Schema.Boolean
|
|
4156
|
+
});
|
|
4157
|
+
const ArtifactListEntry = Schema.Struct({
|
|
4158
|
+
artifact: ArtifactMetadata,
|
|
4159
|
+
urls: ArtifactUrls,
|
|
4160
|
+
status: ArtifactLifecycleState,
|
|
4161
|
+
pendingChanges: Schema.Boolean,
|
|
4162
|
+
thumbnailUrl: Schema.optional(Schema.String)
|
|
4163
|
+
});
|
|
4164
|
+
const ArtifactListResponse = Schema.Struct({ artifacts: Schema.Array(ArtifactListEntry) });
|
|
4165
|
+
const ArtifactDetailResponse = Schema.Struct({
|
|
4166
|
+
artifact: ArtifactMetadata,
|
|
4167
|
+
urls: ArtifactUrls,
|
|
4168
|
+
status: ArtifactLifecycleState,
|
|
4169
|
+
pendingChanges: Schema.Boolean
|
|
4170
|
+
});
|
|
4171
|
+
const WorkspaceArtifactsResponse = Schema.Struct({
|
|
4172
|
+
issueId: Schema.optional(Schema.String),
|
|
4173
|
+
workspaceId: Schema.optional(Schema.String),
|
|
4174
|
+
artifacts: Schema.Array(ArtifactListEntry)
|
|
4175
|
+
});
|
|
4176
|
+
//#endregion
|
|
4177
|
+
//#region src/feature-registry.ts
|
|
4178
|
+
const FeatureRegistryStatus = Schema.Literals([
|
|
4179
|
+
"active",
|
|
4180
|
+
"archived",
|
|
4181
|
+
"merged",
|
|
4182
|
+
"deferred"
|
|
4183
|
+
]);
|
|
4184
|
+
const FeatureRegistryEntry = Schema.Struct({
|
|
4185
|
+
featureId: Schema.String,
|
|
4186
|
+
featureName: Schema.String,
|
|
4187
|
+
description: Schema.NullOr(Schema.String),
|
|
4188
|
+
owningWorkspaceId: Schema.NullOr(Schema.String),
|
|
4189
|
+
owningIssueId: Schema.NullOr(Schema.String),
|
|
4190
|
+
owningAgentId: Schema.NullOr(Schema.String),
|
|
4191
|
+
status: FeatureRegistryStatus,
|
|
4192
|
+
createdAt: Schema.String,
|
|
4193
|
+
updatedAt: Schema.String,
|
|
4194
|
+
tags: Schema.Array(Schema.String)
|
|
4195
|
+
});
|
|
4196
|
+
//#endregion
|
|
4197
|
+
export { Activity, ActivityDetailedEvent, ActivityEntryEvent, ActivityTtsEvent, ActivityUpdatedEvent, AgentActivityChangedEvent, AgentChannelReply, AgentChannelReplyEvent, AgentCompletedEvent, AgentContextSaturationChangedEvent, AgentCreatedEvent, AgentCurrentIssueSetEvent, AgentEnrichmentChangedEvent, AgentHeartbeatDeadEvent, AgentId, AgentMessageReceivedEvent, AgentModelSetEvent, AgentOutput, AgentOutputReceivedEvent, AgentPermissionRequestedEvent, AgentPermissionResolvedEvent, AgentResolution, AgentResolutionChangedEvent, AgentRuntimeSnapshot, AgentSnapshot, AgentStartedEvent, AgentStateRestoredEvent, AgentStatus, AgentStatusChangedEvent, AgentStoppedEvent, AgentThinkingStartedEvent, AgentThinkingStoppedEvent, AgentTurnDiffCompletedEvent, AgentWaitingClearedEvent, AgentWaitingStartedEvent, ArtifactAgentHarness, ArtifactAgentRole, ArtifactCreateResponse, ArtifactDetailResponse, ArtifactHash, ArtifactId, ArtifactLifecycleState, ArtifactListEntry, ArtifactListResponse, ArtifactMetadata, ArtifactPublishResponse, ArtifactSlug, ArtifactStatusResponse, ArtifactUnshareResponse, ArtifactUrls, ArtifactValidationCode, ArtifactValidationFinding, ArtifactValidationResult, CHANNEL_REPLY_KIND_VALUES, CONTEXT_LAYER_KINDS, CONTEXT_PREVIEW_HARNESSES, ChannelPermissionRequestSnapshot, ChannelReplyArtifactRef, ChannelReplyKind, ChatMessage, ClaudeChannelPermissionBehavior, CompactBoundary, ContextEditableLayerRecord, ContextHarnessPreviews, ContextLayerDraft, ContextLayerKind, ContextLayerSaveRequest, ContextLayerSaveResponse, ContextLayerTarget, ContextLayersResponse, ContextPreviewDiagnostic, ContextPreviewHarness, ContextPreviewRequest, ContextPreviewResponse, ContextProjectSummary, ContextSyncRequest, ContextSyncResponse, ContextSyncTarget, ContextUsage, ContextWorkspaceSummary, ConversationCompactingChangedEvent, ConversationCostSummary, ConversationCreatedEvent, ConversationEvent, ConversationFilter, ConversationPermissionChangedEvent, CostEventRecordedEvent, DEFAULT_MAX_MEMORY_OBSERVATIONS_PER_ISSUE, DEFAULT_MAX_TURN_DIFF_SUMMARIES_PER_AGENT, DashboardLifecycleCompletedEvent, DashboardLifecycleFailedEvent, DashboardLifecycleStartedEvent, DashboardSnapshot, DeepWipeRpc, DiscoveredSessionSnapshot, DomainEvent, EDITORS, EditorIdSchema, EmbedProgressEvent, EmbedProgressSnapshot, EmbedSessionsRpc, EnrichCompleteEvent, EnrichProgressEvent, EnrichProgressSnapshot, EnrichSessionsRpc, EnrichStatsSnapshot, ExtractionProviderConfig, ExtractionProviderTarget, FeatureNode, FeatureRegistryEntry, FeatureRegistryStatus, FlywheelAgent, FlywheelAgentStatus, FlywheelEffort, FlywheelHarness, FlywheelHeadline, FlywheelHttpUrl, FlywheelOrchestrator, FlywheelParkedItem, FlywheelPipelineItem, FlywheelPipelineStatus, FlywheelPipelineVerb, FlywheelRunId, FlywheelStats, FlywheelStatsCriteria, FlywheelStatsCriterion, FlywheelStatsCriterionStatus, FlywheelStatsCriterionValue, FlywheelStatsCriterionValueObject, FlywheelStatsTrend, FlywheelStatus, FlywheelSubstrateBug, FlywheelSubstrateBugStatus, FlywheelSuggestion, FlywheelSuggestionAction, FlywheelSuggestionPriority, FlywheelSystemStatus, GetAvailableEditorsRpc, GetConversationCostByWorkspaceRpc, GetConversationCostRpc, GetConversationStatsRpc, GetDiscoveredSessionRpc, GetSnapshotRpc, GetWorkspaceDetailRpc, GlobalContextLayerRecord, GlobalContextLayerTarget, INITIAL_READ_MODEL_STATE, IssueId, IssueStatusChangedEvent, IssuesSnapshotEvent, IssuesUpdatedEvent, ListDiscoveredSessionsRpc, MAX_CHANNEL_REPLY_ARTIFACT_LABEL_LENGTH, MAX_CHANNEL_REPLY_ARTIFACT_REFS, MAX_CHANNEL_REPLY_ARTIFACT_URI_LENGTH, MAX_CHANNEL_REPLY_SUMMARY_LENGTH, MemoryHealthChangedEvent, MemoryIdentity, MemoryObservation, MemoryObservationCreatedEvent, MemoryResetMarkerCreatedEvent, MemoryRollupTriggeredEvent, MemoryStatus, MemoryStatusPhase, MemoryStatusUpdatedEvent, MemoryTokenUsage, MergeReadyEvent, MergeStatusValue, OpenInEditorInput, OperatorInterventionEvent, PanRpcError, PanRpcGroup, PendingTurn, PipelineReviewCompletedEvent, PipelineReviewStartedEvent, PipelineStatusChangedEvent, PipelineTestCompletedEvent, PipelineTestStartedEvent, PlanItemStatusChangedEvent, PlanItemsUnblockedEvent, PlanSubitemStatusChangedEvent, PlanningFailedEvent, PlanningStartedEvent, PlanningSyncEvent, ProjectContextLayerRecord, ProjectContextLayerTarget, ProjectSessionTree, ProposedPlan, RagDecision, RagDecisionSource, ReadWorkspaceFileInput, ReadWorkspaceFileResult, ReadWorkspaceFileRpc, ReplayEventsRpc, ResetMarker, ResetMarkerScope, ResizeTerminalRpc, ResolveFilePathExistsInput, ResolveFilePathExistsResult, ResolveFilePathExistsRpc, ResourceStats, ResourcesUpdatedEvent, ReviewApprovedEvent, ReviewCoordinatorDiedEvent, ReviewCoordinatorStartedEvent, ReviewReviewerCompletedEvent, ReviewReviewerStartedEvent, ReviewSpecialistTimedOutEvent, ReviewStatusChangedEvent, ReviewStatusSnapshot, ReviewStatusValue, ReviewerRoundMetadata, ReviewerRoundSummary, Role, ScanCompleteEvent, ScanConversationsRpc, ScanProgressEvent, ScanProgressSnapshot, ScanResult, ScanStartedEvent, SearchConversationsRpc, SendTerminalInputRpc, SequenceNumber, SessionNode, SessionNodePresence, SessionNodeType, SessionTreeDelta, ShadowInferenceUpdateEvent, ShellOpenInEditorRpc, SpecialistCompletedEvent, SpecialistFailedEvent, SpecialistStartedEvent, StartAgentRpc, StartPlanningRpc, SubscribeAgentOutputRpc, SubscribeConversationMessagesRpc, SubscribeDomainEventsRpc, SubscribeFlywheelStatusRpc, SubscribeIssueEventsRpc, SubscribeProjectSessionTreeRpc, SubscribeTerminalRpc, SubstrateBugFiledEvent, SystemHealthSeverityChangedEvent, SystemHeartbeatEvent, TerminalCloseRpc, TerminalOpenRpc, TerminalOutput, TerminalResizeRpc, TerminalWriteRpc, TestPassedEvent, TestStatusValue, ThinkingState, TurnDiffFileChange, TurnDiffSummary, UatStatusValue, VerificationStatusValue, WS_METHODS, WaitingReason, WaitingState, WorkCompletedEvent, WorkLogEntry, WorkspaceAbortedEvent, WorkspaceArtifactsResponse, WorkspaceContextLayerRecord, WorkspaceContextLayerTarget, WorkspaceCreatedEvent, WorkspaceDeletedEvent, WorkspaceDestroyedEvent, WorkspaceDetail, WorkspaceWipeStartedEvent, applyEvent, applyEvents, decodeFlywheelStats, encodeFlywheelStats, getHarness, getMaxMemoryObservationsPerIssue, getMaxTurnDiffSummariesPerAgent, isChannelReplyKind, isTerminalTurnDiffSummaryStatus, normalizeChannelReplyPayload, omitTurnDiffSummariesForAgent, syncSnapshot, trimMemoryObservations, trimTurnDiffSummaries };
|
|
4198
|
+
|
|
4199
|
+
//# sourceMappingURL=index.mjs.map
|