@mandipadk7/kavi 0.1.7 → 1.0.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/README.md +18 -5
- package/dist/adapters/claude.js +4 -1
- package/dist/config.js +4 -3
- package/dist/daemon.js +77 -3
- package/dist/git.js +61 -6
- package/dist/main.js +339 -65
- package/dist/paths.js +2 -0
- package/dist/recommendations.js +205 -19
- package/dist/reports.js +118 -0
- package/dist/rpc.js +20 -1
- package/dist/session.js +11 -0
- package/dist/tui.js +354 -37
- package/dist/workflow.js +450 -0
- package/package.json +1 -1
package/dist/workflow.js
ADDED
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { buildClaimHotspots } from "./decision-ledger.js";
|
|
2
|
+
import { buildOperatorRecommendations } from "./recommendations.js";
|
|
3
|
+
function taskArtifactIndex(artifacts) {
|
|
4
|
+
return new Map(artifacts.map((artifact)=>[
|
|
5
|
+
artifact.taskId,
|
|
6
|
+
artifact
|
|
7
|
+
]));
|
|
8
|
+
}
|
|
9
|
+
function taskIndex(snapshot) {
|
|
10
|
+
return new Map(snapshot.session.tasks.map((task)=>[
|
|
11
|
+
task.id,
|
|
12
|
+
task
|
|
13
|
+
]));
|
|
14
|
+
}
|
|
15
|
+
function shortJson(value) {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.stringify(value);
|
|
18
|
+
} catch {
|
|
19
|
+
return String(value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function summarizeTask(task, artifactByTask) {
|
|
23
|
+
const artifact = artifactByTask.get(task.id);
|
|
24
|
+
return {
|
|
25
|
+
taskId: task.id,
|
|
26
|
+
owner: task.owner,
|
|
27
|
+
title: task.title,
|
|
28
|
+
summary: artifact?.summary ?? task.summary ?? task.prompt,
|
|
29
|
+
finishedAt: artifact?.finishedAt ?? task.updatedAt,
|
|
30
|
+
claimedPaths: artifact?.claimedPaths ?? task.claimedPaths
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function deriveWorkflowStage(params) {
|
|
34
|
+
const totalChangedPaths = params.changedByAgent.reduce((count, item)=>count + item.paths.length, 0);
|
|
35
|
+
const completedTasks = params.snapshot.session.tasks.filter((task)=>task.status === "completed").length;
|
|
36
|
+
if (params.pendingApprovals > 0) {
|
|
37
|
+
return {
|
|
38
|
+
id: "waiting_for_approval",
|
|
39
|
+
label: "Waiting For Approval",
|
|
40
|
+
detail: `${params.pendingApprovals} approval request(s) are blocking progress.`
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (params.blockedTasks > 0 || params.hotspots.length > 0) {
|
|
44
|
+
return {
|
|
45
|
+
id: "integration",
|
|
46
|
+
label: "Integration Needed",
|
|
47
|
+
detail: params.hotspots.length > 0 ? `${params.hotspots.length} overlapping path hotspot(s) need integration work.` : `${params.blockedTasks} task(s) are blocked and need review.`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (params.runningTasks > 0 || params.pendingTasks > 0) {
|
|
51
|
+
return {
|
|
52
|
+
id: "working",
|
|
53
|
+
label: "Agents Working",
|
|
54
|
+
detail: `${params.runningTasks} running and ${params.pendingTasks} pending task(s) remain in flight.`
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (totalChangedPaths > 0) {
|
|
58
|
+
return {
|
|
59
|
+
id: "ready_to_land",
|
|
60
|
+
label: "Ready To Land",
|
|
61
|
+
detail: `${totalChangedPaths} changed path(s) are ready for final review and landing.`
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (params.latestLandReport) {
|
|
65
|
+
return {
|
|
66
|
+
id: "landed",
|
|
67
|
+
label: "Landed",
|
|
68
|
+
detail: `Latest merge landed in ${params.latestLandReport.targetBranch} at ${params.latestLandReport.createdAt}.`
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (completedTasks > 0) {
|
|
72
|
+
return {
|
|
73
|
+
id: "idle",
|
|
74
|
+
label: "Idle",
|
|
75
|
+
detail: "Completed task output exists, but there are no unlanded worktree changes."
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
id: "bootstrapping",
|
|
80
|
+
label: "Bootstrapping",
|
|
81
|
+
detail: "Kavi is ready for the initial kickoff or the next operator task."
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function buildAgentResults(snapshot, artifactByTask) {
|
|
85
|
+
const latestLandReport = snapshot.latestLandReport;
|
|
86
|
+
return [
|
|
87
|
+
"codex",
|
|
88
|
+
"claude"
|
|
89
|
+
].map((agent)=>{
|
|
90
|
+
const completedTasks = snapshot.session.tasks.filter((task)=>task.owner === agent && task.status === "completed").sort((left, right)=>right.updatedAt.localeCompare(left.updatedAt));
|
|
91
|
+
const latestTask = completedTasks[0] ?? null;
|
|
92
|
+
const landedPaths = latestLandReport?.changedByAgent.find((changeSet)=>changeSet.agent === agent)?.paths ?? [];
|
|
93
|
+
return {
|
|
94
|
+
agent,
|
|
95
|
+
latestTaskId: latestTask?.id ?? null,
|
|
96
|
+
latestTaskTitle: latestTask?.title ?? null,
|
|
97
|
+
latestSummary: latestTask ? summarizeTask(latestTask, artifactByTask).summary : snapshot.session.agentStatus[agent].summary,
|
|
98
|
+
completedTaskCount: completedTasks.length,
|
|
99
|
+
changedPaths: snapshot.worktreeDiffs.find((diff)=>diff.agent === agent)?.paths ?? [],
|
|
100
|
+
lastRunAt: snapshot.session.agentStatus[agent].lastRunAt,
|
|
101
|
+
landedPaths
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function toneForEvent(type) {
|
|
106
|
+
if (type === "task.failed") {
|
|
107
|
+
return "bad";
|
|
108
|
+
}
|
|
109
|
+
if (type === "approval.requested" || type === "land.overlap_detected" || type === "review.note_added") {
|
|
110
|
+
return "warn";
|
|
111
|
+
}
|
|
112
|
+
if (type === "task.completed" || type === "approval.resolved" || type === "land.completed" || type === "recommendation.applied") {
|
|
113
|
+
return "good";
|
|
114
|
+
}
|
|
115
|
+
return "normal";
|
|
116
|
+
}
|
|
117
|
+
function describeEvent(snapshot, event, artifactByTask) {
|
|
118
|
+
const payload = event.payload;
|
|
119
|
+
const tasks = taskIndex(snapshot);
|
|
120
|
+
const taskId = typeof payload.taskId === "string" ? payload.taskId : null;
|
|
121
|
+
const task = taskId ? tasks.get(taskId) ?? null : null;
|
|
122
|
+
const artifact = taskId ? artifactByTask.get(taskId) ?? null : null;
|
|
123
|
+
switch(event.type){
|
|
124
|
+
case "tasks.kickoff_enqueued":
|
|
125
|
+
return {
|
|
126
|
+
id: event.id,
|
|
127
|
+
timestamp: event.timestamp,
|
|
128
|
+
title: "Kickoff queued",
|
|
129
|
+
detail: snapshot.session.goal ? `Started a two-agent kickoff for goal: ${snapshot.session.goal}` : "Started the initial Codex and Claude kickoff tasks.",
|
|
130
|
+
tone: "good"
|
|
131
|
+
};
|
|
132
|
+
case "tasks.kickoff_created":
|
|
133
|
+
return {
|
|
134
|
+
id: event.id,
|
|
135
|
+
timestamp: event.timestamp,
|
|
136
|
+
title: "Kickoff tasks created",
|
|
137
|
+
detail: "Kavi created the initial Codex and Claude kickoff tasks.",
|
|
138
|
+
tone: "good"
|
|
139
|
+
};
|
|
140
|
+
case "daemon.started":
|
|
141
|
+
return {
|
|
142
|
+
id: event.id,
|
|
143
|
+
timestamp: event.timestamp,
|
|
144
|
+
title: "Session started",
|
|
145
|
+
detail: "The Kavi daemon is running and ready for operator commands.",
|
|
146
|
+
tone: "good"
|
|
147
|
+
};
|
|
148
|
+
case "daemon.stopped":
|
|
149
|
+
return {
|
|
150
|
+
id: event.id,
|
|
151
|
+
timestamp: event.timestamp,
|
|
152
|
+
title: "Session stopped",
|
|
153
|
+
detail: "The Kavi daemon has stopped for this repository session.",
|
|
154
|
+
tone: "muted"
|
|
155
|
+
};
|
|
156
|
+
case "repo.initialized":
|
|
157
|
+
return {
|
|
158
|
+
id: event.id,
|
|
159
|
+
timestamp: event.timestamp,
|
|
160
|
+
title: "Repository initialized",
|
|
161
|
+
detail: "Kavi initialized git for this project.",
|
|
162
|
+
tone: "good"
|
|
163
|
+
};
|
|
164
|
+
case "repo.bootstrap_committed":
|
|
165
|
+
return {
|
|
166
|
+
id: event.id,
|
|
167
|
+
timestamp: event.timestamp,
|
|
168
|
+
title: "Bootstrap commit created",
|
|
169
|
+
detail: "Kavi created the first base commit needed for managed worktrees.",
|
|
170
|
+
tone: "good"
|
|
171
|
+
};
|
|
172
|
+
case "task.enqueued":
|
|
173
|
+
return {
|
|
174
|
+
id: event.id,
|
|
175
|
+
timestamp: event.timestamp,
|
|
176
|
+
title: `Task queued for ${typeof payload.owner === "string" ? payload.owner : "agent"}`,
|
|
177
|
+
detail: task ? `${task.title} | ${task.prompt}` : shortJson(payload),
|
|
178
|
+
tone: "normal"
|
|
179
|
+
};
|
|
180
|
+
case "task.started":
|
|
181
|
+
return {
|
|
182
|
+
id: event.id,
|
|
183
|
+
timestamp: event.timestamp,
|
|
184
|
+
title: `Task started${task ? `: ${task.title}` : ""}`,
|
|
185
|
+
detail: task ? `${task.owner} is working on ${task.prompt}` : shortJson(payload),
|
|
186
|
+
tone: "normal"
|
|
187
|
+
};
|
|
188
|
+
case "task.completed":
|
|
189
|
+
return {
|
|
190
|
+
id: event.id,
|
|
191
|
+
timestamp: event.timestamp,
|
|
192
|
+
title: `Task completed${task ? `: ${task.title}` : ""}`,
|
|
193
|
+
detail: artifact?.summary ?? task?.summary ?? (typeof payload.summary === "string" ? payload.summary : shortJson(payload)),
|
|
194
|
+
tone: "good"
|
|
195
|
+
};
|
|
196
|
+
case "task.failed":
|
|
197
|
+
return {
|
|
198
|
+
id: event.id,
|
|
199
|
+
timestamp: event.timestamp,
|
|
200
|
+
title: `Task failed${task ? `: ${task.title}` : ""}`,
|
|
201
|
+
detail: typeof payload.error === "string" ? payload.error : artifact?.error ?? shortJson(payload),
|
|
202
|
+
tone: "bad"
|
|
203
|
+
};
|
|
204
|
+
case "approval.requested":
|
|
205
|
+
return {
|
|
206
|
+
id: event.id,
|
|
207
|
+
timestamp: event.timestamp,
|
|
208
|
+
title: "Approval requested",
|
|
209
|
+
detail: typeof payload.summary === "string" ? payload.summary : shortJson(payload),
|
|
210
|
+
tone: "warn"
|
|
211
|
+
};
|
|
212
|
+
case "approval.resolved":
|
|
213
|
+
case "approval.completed":
|
|
214
|
+
return {
|
|
215
|
+
id: event.id,
|
|
216
|
+
timestamp: event.timestamp,
|
|
217
|
+
title: "Approval resolved",
|
|
218
|
+
detail: shortJson(payload),
|
|
219
|
+
tone: "good"
|
|
220
|
+
};
|
|
221
|
+
case "recommendation.applied":
|
|
222
|
+
return {
|
|
223
|
+
id: event.id,
|
|
224
|
+
timestamp: event.timestamp,
|
|
225
|
+
title: "Recommendation applied",
|
|
226
|
+
detail: typeof payload.recommendationId === "string" ? `${payload.recommendationId} -> ${typeof payload.owner === "string" ? payload.owner : "agent"}` : shortJson(payload),
|
|
227
|
+
tone: "good"
|
|
228
|
+
};
|
|
229
|
+
case "recommendation.dismissed":
|
|
230
|
+
return {
|
|
231
|
+
id: event.id,
|
|
232
|
+
timestamp: event.timestamp,
|
|
233
|
+
title: "Recommendation dismissed",
|
|
234
|
+
detail: typeof payload.recommendationId === "string" ? `${payload.recommendationId}${typeof payload.reason === "string" ? ` | ${payload.reason}` : ""}` : shortJson(payload),
|
|
235
|
+
tone: "muted"
|
|
236
|
+
};
|
|
237
|
+
case "recommendation.restored":
|
|
238
|
+
return {
|
|
239
|
+
id: event.id,
|
|
240
|
+
timestamp: event.timestamp,
|
|
241
|
+
title: "Recommendation restored",
|
|
242
|
+
detail: typeof payload.recommendationId === "string" ? payload.recommendationId : shortJson(payload),
|
|
243
|
+
tone: "normal"
|
|
244
|
+
};
|
|
245
|
+
case "review.followup_queued":
|
|
246
|
+
return {
|
|
247
|
+
id: event.id,
|
|
248
|
+
timestamp: event.timestamp,
|
|
249
|
+
title: "Review follow-up queued",
|
|
250
|
+
detail: shortJson(payload),
|
|
251
|
+
tone: "normal"
|
|
252
|
+
};
|
|
253
|
+
case "review.note_added":
|
|
254
|
+
return {
|
|
255
|
+
id: event.id,
|
|
256
|
+
timestamp: event.timestamp,
|
|
257
|
+
title: "Review note added",
|
|
258
|
+
detail: shortJson(payload),
|
|
259
|
+
tone: "warn"
|
|
260
|
+
};
|
|
261
|
+
case "review.note_status_changed":
|
|
262
|
+
return {
|
|
263
|
+
id: event.id,
|
|
264
|
+
timestamp: event.timestamp,
|
|
265
|
+
title: "Review note status changed",
|
|
266
|
+
detail: shortJson(payload),
|
|
267
|
+
tone: "normal"
|
|
268
|
+
};
|
|
269
|
+
case "review.note_landed":
|
|
270
|
+
return {
|
|
271
|
+
id: event.id,
|
|
272
|
+
timestamp: event.timestamp,
|
|
273
|
+
title: "Review work landed",
|
|
274
|
+
detail: shortJson(payload),
|
|
275
|
+
tone: "good"
|
|
276
|
+
};
|
|
277
|
+
case "land.overlap_detected":
|
|
278
|
+
return {
|
|
279
|
+
id: event.id,
|
|
280
|
+
timestamp: event.timestamp,
|
|
281
|
+
title: "Landing blocked",
|
|
282
|
+
detail: `Overlapping paths detected before landing: ${Array.isArray(payload.overlappingPaths) ? payload.overlappingPaths.join(", ") : shortJson(payload)}`,
|
|
283
|
+
tone: "warn"
|
|
284
|
+
};
|
|
285
|
+
case "land.completed":
|
|
286
|
+
return {
|
|
287
|
+
id: event.id,
|
|
288
|
+
timestamp: event.timestamp,
|
|
289
|
+
title: "Landing completed",
|
|
290
|
+
detail: typeof payload.targetBranch === "string" ? `Merged managed work into ${payload.targetBranch}` : shortJson(payload),
|
|
291
|
+
tone: "good"
|
|
292
|
+
};
|
|
293
|
+
default:
|
|
294
|
+
return {
|
|
295
|
+
id: event.id,
|
|
296
|
+
timestamp: event.timestamp,
|
|
297
|
+
title: event.type,
|
|
298
|
+
detail: shortJson(payload),
|
|
299
|
+
tone: toneForEvent(event.type)
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
export function buildWorkflowActivity(snapshot, artifacts = [], limit = 40) {
|
|
304
|
+
const artifactByTask = taskArtifactIndex(artifacts);
|
|
305
|
+
const entries = snapshot.events.map((event)=>describeEvent(snapshot, event, artifactByTask)).sort((left, right)=>right.timestamp.localeCompare(left.timestamp));
|
|
306
|
+
if (snapshot.session.goal) {
|
|
307
|
+
entries.push({
|
|
308
|
+
id: `goal:${snapshot.session.id}`,
|
|
309
|
+
timestamp: snapshot.session.createdAt,
|
|
310
|
+
title: "Session goal set",
|
|
311
|
+
detail: snapshot.session.goal,
|
|
312
|
+
tone: "good"
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
return entries.sort((left, right)=>right.timestamp.localeCompare(left.timestamp)).slice(0, Math.max(1, limit));
|
|
316
|
+
}
|
|
317
|
+
export function buildWorkflowSummary(snapshot, artifacts = []) {
|
|
318
|
+
const artifactByTask = taskArtifactIndex(artifacts);
|
|
319
|
+
const activeRecommendations = buildOperatorRecommendations(snapshot.session);
|
|
320
|
+
const allRecommendations = buildOperatorRecommendations(snapshot.session, {
|
|
321
|
+
includeDismissed: true
|
|
322
|
+
});
|
|
323
|
+
const hotspots = buildClaimHotspots(snapshot.session);
|
|
324
|
+
const changedByAgent = [
|
|
325
|
+
"codex",
|
|
326
|
+
"claude"
|
|
327
|
+
].map((agent)=>({
|
|
328
|
+
agent,
|
|
329
|
+
paths: snapshot.worktreeDiffs.find((diff)=>diff.agent === agent)?.paths ?? []
|
|
330
|
+
}));
|
|
331
|
+
const completedTasks = snapshot.session.tasks.filter((task)=>task.status === "completed").sort((left, right)=>right.updatedAt.localeCompare(left.updatedAt)).map((task)=>summarizeTask(task, artifactByTask));
|
|
332
|
+
const blockers = [];
|
|
333
|
+
const warnings = [];
|
|
334
|
+
const pendingApprovals = snapshot.approvals.filter((approval)=>approval.status === "pending").length;
|
|
335
|
+
const runningTasks = snapshot.session.tasks.filter((task)=>task.status === "running").length;
|
|
336
|
+
const blockedTasks = snapshot.session.tasks.filter((task)=>task.status === "blocked").length;
|
|
337
|
+
const pendingTasks = snapshot.session.tasks.filter((task)=>task.status === "pending").length;
|
|
338
|
+
const openReviews = snapshot.session.reviewNotes.filter((note)=>note.status === "open").length;
|
|
339
|
+
if (pendingApprovals > 0) {
|
|
340
|
+
blockers.push(`${pendingApprovals} approval request(s) still need a decision.`);
|
|
341
|
+
}
|
|
342
|
+
if (runningTasks > 0) {
|
|
343
|
+
blockers.push(`${runningTasks} task(s) are still running.`);
|
|
344
|
+
}
|
|
345
|
+
if (blockedTasks > 0) {
|
|
346
|
+
blockers.push(`${blockedTasks} task(s) are blocked.`);
|
|
347
|
+
}
|
|
348
|
+
if (pendingTasks > 0) {
|
|
349
|
+
blockers.push(`${pendingTasks} task(s) are still pending.`);
|
|
350
|
+
}
|
|
351
|
+
if (hotspots.length > 0) {
|
|
352
|
+
blockers.push(`${hotspots.length} overlapping path hotspot(s) still need integration work.`);
|
|
353
|
+
}
|
|
354
|
+
if (openReviews > 0) {
|
|
355
|
+
warnings.push(`${openReviews} review thread(s) remain open.`);
|
|
356
|
+
}
|
|
357
|
+
if (activeRecommendations.length > 0) {
|
|
358
|
+
warnings.push(`${activeRecommendations.length} active recommendation(s) remain.`);
|
|
359
|
+
}
|
|
360
|
+
const totalChangedPaths = changedByAgent.reduce((count, item)=>count + item.paths.length, 0);
|
|
361
|
+
const state = blockers.length > 0 ? "blocked" : totalChangedPaths > 0 ? "ready" : "idle";
|
|
362
|
+
const stage = deriveWorkflowStage({
|
|
363
|
+
snapshot,
|
|
364
|
+
changedByAgent,
|
|
365
|
+
pendingApprovals,
|
|
366
|
+
runningTasks,
|
|
367
|
+
blockedTasks,
|
|
368
|
+
pendingTasks,
|
|
369
|
+
hotspots,
|
|
370
|
+
latestLandReport: snapshot.latestLandReport
|
|
371
|
+
});
|
|
372
|
+
const nextActions = [];
|
|
373
|
+
if (pendingApprovals > 0) {
|
|
374
|
+
nextActions.push("Resolve pending approvals.");
|
|
375
|
+
}
|
|
376
|
+
if (runningTasks > 0 || pendingTasks > 0) {
|
|
377
|
+
nextActions.push("Wait for active work to finish or review the activity stream for blockers.");
|
|
378
|
+
}
|
|
379
|
+
if (blockedTasks > 0 || hotspots.length > 0) {
|
|
380
|
+
nextActions.push("Address blocked work or overlap hotspots before landing.");
|
|
381
|
+
}
|
|
382
|
+
if (state === "ready") {
|
|
383
|
+
nextActions.push("Review the merged result summary, then run `kavi land`.");
|
|
384
|
+
}
|
|
385
|
+
if (state === "idle") {
|
|
386
|
+
nextActions.push("No unlanded worktree changes are currently present.");
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
goal: snapshot.session.goal,
|
|
390
|
+
stage,
|
|
391
|
+
taskCounts: {
|
|
392
|
+
pending: pendingTasks,
|
|
393
|
+
running: runningTasks,
|
|
394
|
+
blocked: blockedTasks,
|
|
395
|
+
completed: snapshot.session.tasks.filter((task)=>task.status === "completed").length,
|
|
396
|
+
failed: snapshot.session.tasks.filter((task)=>task.status === "failed").length
|
|
397
|
+
},
|
|
398
|
+
approvalCounts: {
|
|
399
|
+
pending: pendingApprovals
|
|
400
|
+
},
|
|
401
|
+
reviewCounts: {
|
|
402
|
+
open: openReviews
|
|
403
|
+
},
|
|
404
|
+
recommendationCounts: {
|
|
405
|
+
active: activeRecommendations.length,
|
|
406
|
+
dismissed: allRecommendations.filter((item)=>item.status === "dismissed").length
|
|
407
|
+
},
|
|
408
|
+
landReadiness: {
|
|
409
|
+
state,
|
|
410
|
+
blockers,
|
|
411
|
+
warnings,
|
|
412
|
+
nextActions
|
|
413
|
+
},
|
|
414
|
+
changedByAgent,
|
|
415
|
+
completedTasks,
|
|
416
|
+
recentActivity: buildWorkflowActivity(snapshot, artifacts, 8),
|
|
417
|
+
latestLandReport: snapshot.latestLandReport
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
export function buildWorkflowResult(snapshot, artifacts = []) {
|
|
421
|
+
const artifactByTask = taskArtifactIndex(artifacts);
|
|
422
|
+
const summary = buildWorkflowSummary(snapshot, artifacts);
|
|
423
|
+
const latestLandReport = snapshot.latestLandReport;
|
|
424
|
+
const agentResults = buildAgentResults(snapshot, artifactByTask);
|
|
425
|
+
const headline = summary.stage.id === "landed" && latestLandReport ? `Merged work landed in ${latestLandReport.targetBranch}.` : summary.stage.id === "ready_to_land" ? "Managed work is ready for final review and landing." : summary.stage.id === "integration" ? "Cross-agent integration needs attention before landing." : summary.stage.id === "waiting_for_approval" ? "Operator approval is needed before work can continue." : summary.stage.id === "working" ? "Managed agents are actively working through the session." : summary.stage.id === "bootstrapping" ? "Kavi is ready to begin the session workflow." : "The session is currently idle.";
|
|
426
|
+
const summaryLines = [];
|
|
427
|
+
if (latestLandReport) {
|
|
428
|
+
summaryLines.push(...latestLandReport.summary);
|
|
429
|
+
} else {
|
|
430
|
+
summaryLines.push(summary.stage.detail);
|
|
431
|
+
}
|
|
432
|
+
for (const agent of agentResults){
|
|
433
|
+
summaryLines.push(`${agent.agent}: ${agent.latestSummary ?? "No completed result yet."}${agent.changedPaths.length > 0 ? ` | unlanded paths=${agent.changedPaths.join(", ")}` : ""}`);
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
goal: summary.goal,
|
|
437
|
+
stage: summary.stage,
|
|
438
|
+
headline,
|
|
439
|
+
nextActions: summary.landReadiness.nextActions,
|
|
440
|
+
changedByAgent: summary.changedByAgent,
|
|
441
|
+
recentActivity: summary.recentActivity,
|
|
442
|
+
completedTasks: summary.completedTasks,
|
|
443
|
+
latestLandReport,
|
|
444
|
+
agentResults,
|
|
445
|
+
summaryLines
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
//# sourceURL=workflow.ts
|