@kb-labs/agent-cli 0.5.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 +56 -0
- package/dist/cli/commands/diff.d.ts +17 -0
- package/dist/cli/commands/diff.js +182 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/history.d.ts +16 -0
- package/dist/cli/commands/history.js +216 -0
- package/dist/cli/commands/history.js.map +1 -0
- package/dist/cli/commands/quality-report.d.ts +21 -0
- package/dist/cli/commands/quality-report.js +457 -0
- package/dist/cli/commands/quality-report.js.map +1 -0
- package/dist/cli/commands/rollback.d.ts +27 -0
- package/dist/cli/commands/rollback.js +109 -0
- package/dist/cli/commands/rollback.js.map +1 -0
- package/dist/cli/commands/run.d.ts +42 -0
- package/dist/cli/commands/run.js +923 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/trace-context.d.ts +22 -0
- package/dist/cli/commands/trace-context.js +131 -0
- package/dist/cli/commands/trace-context.js.map +1 -0
- package/dist/cli/commands/trace-diagnose.d.ts +20 -0
- package/dist/cli/commands/trace-diagnose.js +434 -0
- package/dist/cli/commands/trace-diagnose.js.map +1 -0
- package/dist/cli/commands/trace-event-normalizer.d.ts +13 -0
- package/dist/cli/commands/trace-event-normalizer.js +39 -0
- package/dist/cli/commands/trace-event-normalizer.js.map +1 -0
- package/dist/cli/commands/trace-filter.d.ts +19 -0
- package/dist/cli/commands/trace-filter.js +153 -0
- package/dist/cli/commands/trace-filter.js.map +1 -0
- package/dist/cli/commands/trace-iteration.d.ts +18 -0
- package/dist/cli/commands/trace-iteration.js +192 -0
- package/dist/cli/commands/trace-iteration.js.map +1 -0
- package/dist/cli/commands/trace-stats.d.ts +17 -0
- package/dist/cli/commands/trace-stats.js +247 -0
- package/dist/cli/commands/trace-stats.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +473 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +184 -0
- package/dist/manifest.js +473 -0
- package/dist/manifest.js.map +1 -0
- package/dist/rest/handlers/approve-handler.d.ts +15 -0
- package/dist/rest/handlers/approve-handler.js +60 -0
- package/dist/rest/handlers/approve-handler.js.map +1 -0
- package/dist/rest/handlers/approve-session-plan-handler.d.ts +10 -0
- package/dist/rest/handlers/approve-session-plan-handler.js +52 -0
- package/dist/rest/handlers/approve-session-plan-handler.js.map +1 -0
- package/dist/rest/handlers/correct-handler.d.ts +7 -0
- package/dist/rest/handlers/correct-handler.js +326 -0
- package/dist/rest/handlers/correct-handler.js.map +1 -0
- package/dist/rest/handlers/create-session-handler.d.ts +7 -0
- package/dist/rest/handlers/create-session-handler.js +25 -0
- package/dist/rest/handlers/create-session-handler.js.map +1 -0
- package/dist/rest/handlers/execute-session-plan-handler.d.ts +10 -0
- package/dist/rest/handlers/execute-session-plan-handler.js +635 -0
- package/dist/rest/handlers/execute-session-plan-handler.js.map +1 -0
- package/dist/rest/handlers/generate-spec-handler.d.ts +10 -0
- package/dist/rest/handlers/generate-spec-handler.js +389 -0
- package/dist/rest/handlers/generate-spec-handler.js.map +1 -0
- package/dist/rest/handlers/get-file-diff-handler.d.ts +24 -0
- package/dist/rest/handlers/get-file-diff-handler.js +44 -0
- package/dist/rest/handlers/get-file-diff-handler.js.map +1 -0
- package/dist/rest/handlers/get-session-handler.d.ts +10 -0
- package/dist/rest/handlers/get-session-handler.js +23 -0
- package/dist/rest/handlers/get-session-handler.js.map +1 -0
- package/dist/rest/handlers/get-session-plan-handler.d.ts +10 -0
- package/dist/rest/handlers/get-session-plan-handler.js +53 -0
- package/dist/rest/handlers/get-session-plan-handler.js.map +1 -0
- package/dist/rest/handlers/get-session-turns-handler.d.ts +16 -0
- package/dist/rest/handlers/get-session-turns-handler.js +35 -0
- package/dist/rest/handlers/get-session-turns-handler.js.map +1 -0
- package/dist/rest/handlers/get-spec-handler.d.ts +10 -0
- package/dist/rest/handlers/get-spec-handler.js +39 -0
- package/dist/rest/handlers/get-spec-handler.js.map +1 -0
- package/dist/rest/handlers/list-file-changes-handler.d.ts +13 -0
- package/dist/rest/handlers/list-file-changes-handler.js +34 -0
- package/dist/rest/handlers/list-file-changes-handler.js.map +1 -0
- package/dist/rest/handlers/list-sessions-handler.d.ts +7 -0
- package/dist/rest/handlers/list-sessions-handler.js +23 -0
- package/dist/rest/handlers/list-sessions-handler.js.map +1 -0
- package/dist/rest/handlers/rollback-handler.d.ts +22 -0
- package/dist/rest/handlers/rollback-handler.js +91 -0
- package/dist/rest/handlers/rollback-handler.js.map +1 -0
- package/dist/rest/handlers/run-handler.d.ts +7 -0
- package/dist/rest/handlers/run-handler.js +516 -0
- package/dist/rest/handlers/run-handler.js.map +1 -0
- package/dist/rest/handlers/sessions-handler.d.ts +18 -0
- package/dist/rest/handlers/sessions-handler.js +56 -0
- package/dist/rest/handlers/sessions-handler.js.map +1 -0
- package/dist/rest/handlers/status-handler.d.ts +7 -0
- package/dist/rest/handlers/status-handler.js +313 -0
- package/dist/rest/handlers/status-handler.js.map +1 -0
- package/dist/rest/handlers/stop-handler.d.ts +7 -0
- package/dist/rest/handlers/stop-handler.js +317 -0
- package/dist/rest/handlers/stop-handler.js.map +1 -0
- package/dist/widgets/220.js +446 -0
- package/dist/widgets/220.js.map +1 -0
- package/dist/widgets/331.js +2 -0
- package/dist/widgets/331.js.map +1 -0
- package/dist/widgets/403.js +2 -0
- package/dist/widgets/403.js.map +1 -0
- package/dist/widgets/406.js +35 -0
- package/dist/widgets/406.js.map +1 -0
- package/dist/widgets/455.js +2 -0
- package/dist/widgets/455.js.map +1 -0
- package/dist/widgets/482.js +2 -0
- package/dist/widgets/482.js.map +1 -0
- package/dist/widgets/485.js +2 -0
- package/dist/widgets/485.js.map +1 -0
- package/dist/widgets/527.js +2 -0
- package/dist/widgets/527.js.map +1 -0
- package/dist/widgets/628.js +2 -0
- package/dist/widgets/628.js.map +1 -0
- package/dist/widgets/694.js +2 -0
- package/dist/widgets/694.js.map +1 -0
- package/dist/widgets/712.js +2 -0
- package/dist/widgets/712.js.map +1 -0
- package/dist/widgets/866.js +2 -0
- package/dist/widgets/866.js.map +1 -0
- package/dist/widgets/915.js +39 -0
- package/dist/widgets/915.js.map +1 -0
- package/dist/widgets/957.js +10 -0
- package/dist/widgets/957.js.map +1 -0
- package/dist/widgets/983.js +2 -0
- package/dist/widgets/983.js.map +1 -0
- package/dist/widgets/@mf-types.d.ts +3 -0
- package/dist/widgets/@mf-types.zip +0 -0
- package/dist/widgets/__federation_expose_AgentsPage.js +2 -0
- package/dist/widgets/__federation_expose_AgentsPage.js.map +1 -0
- package/dist/widgets/mf-manifest.json +260 -0
- package/dist/widgets/mf-stats.json +305 -0
- package/dist/widgets/remoteEntry.js +7 -0
- package/dist/widgets/remoteEntry.js.map +1 -0
- package/dist/ws/session-stream-handler.d.ts +8 -0
- package/dist/ws/session-stream-handler.js +409 -0
- package/dist/ws/session-stream-handler.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,923 @@
|
|
|
1
|
+
import { defineCommand, useCache, useConfig, useAnalytics } from '@kb-labs/sdk';
|
|
2
|
+
import { bootstrapAgentSDK, SessionManager, PlanDocumentService, createSessionMemoryBridge, SpecModeHandler, createCoreToolPack } from '@kb-labs/agent-core';
|
|
3
|
+
import { AgentSDK } from '@kb-labs/agent-sdk';
|
|
4
|
+
import { createDefaultResponseRequirementsSelector } from '@kb-labs/agent-runtime';
|
|
5
|
+
import { IncrementalTraceWriter } from '@kb-labs/agent-tracing';
|
|
6
|
+
import { createToolRegistry } from '@kb-labs/agent-tools';
|
|
7
|
+
import { promises } from 'fs';
|
|
8
|
+
|
|
9
|
+
// src/cli/commands/run.ts
|
|
10
|
+
|
|
11
|
+
// src/cli/ui/event-renderer.ts
|
|
12
|
+
var CSI = "\x1B[";
|
|
13
|
+
var RESET = "\x1B[0m";
|
|
14
|
+
var color = {
|
|
15
|
+
// Status colors
|
|
16
|
+
success: (t) => `${CSI}32m${t}${RESET}`,
|
|
17
|
+
error: (t) => `${CSI}31m${t}${RESET}`,
|
|
18
|
+
warning: (t) => `${CSI}33m${t}${RESET}`,
|
|
19
|
+
info: (t) => `${CSI}36m${t}${RESET}`,
|
|
20
|
+
// UI colors
|
|
21
|
+
dim: (t) => `${CSI}90m${t}${RESET}`,
|
|
22
|
+
bold: (t) => `${CSI}1m${t}${RESET}`,
|
|
23
|
+
accent: (t) => `${CSI}38;5;99m${t}${RESET}`,
|
|
24
|
+
// Purple - orchestrator
|
|
25
|
+
primary: (t) => `${CSI}38;5;39m${t}${RESET}`,
|
|
26
|
+
// Blue - agent
|
|
27
|
+
highlight: (t) => `${CSI}38;5;51m${t}${RESET}`,
|
|
28
|
+
// Cyan - tools
|
|
29
|
+
secondary: (t) => `${CSI}38;5;208m${t}${RESET}`
|
|
30
|
+
// Orange - subtask
|
|
31
|
+
};
|
|
32
|
+
var box = {
|
|
33
|
+
topLeft: "\u250C",
|
|
34
|
+
topRight: "\u2510",
|
|
35
|
+
bottomLeft: "\u2514",
|
|
36
|
+
bottomRight: "\u2518",
|
|
37
|
+
horizontal: "\u2500",
|
|
38
|
+
vertical: "\u2502",
|
|
39
|
+
leftT: "\u251C"};
|
|
40
|
+
var symbols = {
|
|
41
|
+
success: color.success("\u2713"),
|
|
42
|
+
error: color.error("\u2717"),
|
|
43
|
+
thinking: "\u25C6",
|
|
44
|
+
tool: "\u2699",
|
|
45
|
+
memory: "\u{1F4BE}",
|
|
46
|
+
subtask: "\u25C8",
|
|
47
|
+
agent: "\u25CF"
|
|
48
|
+
};
|
|
49
|
+
function formatDuration(ms) {
|
|
50
|
+
if (ms < 1e3) {
|
|
51
|
+
return `${ms}ms`;
|
|
52
|
+
}
|
|
53
|
+
if (ms < 6e4) {
|
|
54
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
55
|
+
}
|
|
56
|
+
return `${Math.floor(ms / 6e4)}m ${Math.floor(ms % 6e4 / 1e3)}s`;
|
|
57
|
+
}
|
|
58
|
+
function formatPath(path, maxLen = 40) {
|
|
59
|
+
if (path.length <= maxLen) {
|
|
60
|
+
return path;
|
|
61
|
+
}
|
|
62
|
+
const parts = path.split("/");
|
|
63
|
+
if (parts.length <= 2) {
|
|
64
|
+
return "..." + path.slice(-maxLen + 3);
|
|
65
|
+
}
|
|
66
|
+
return `.../${parts.slice(-2).join("/")}`;
|
|
67
|
+
}
|
|
68
|
+
function formatBudget(event) {
|
|
69
|
+
const data = event.data;
|
|
70
|
+
const used = typeof data.budgetUsedTokens === "number" ? data.budgetUsedTokens : null;
|
|
71
|
+
const remaining = typeof data.budgetRemainingTokens === "number" ? data.budgetRemainingTokens : null;
|
|
72
|
+
const total = typeof data.budgetTotalTokens === "number" ? data.budgetTotalTokens : null;
|
|
73
|
+
if (used === null && remaining === null && total === null) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const fmt = (value) => value === null ? "?" : value.toLocaleString("en-US");
|
|
77
|
+
return `Budget ${fmt(used)} used / ${fmt(total)} total (${fmt(remaining)} left)`;
|
|
78
|
+
}
|
|
79
|
+
function renderBoxTop(title, colorFn, width = 60) {
|
|
80
|
+
const titleLen = title.length + 2;
|
|
81
|
+
const leftPad = 2;
|
|
82
|
+
const rightPad = width - leftPad - titleLen - 2;
|
|
83
|
+
return colorFn(
|
|
84
|
+
`${box.topLeft}${box.horizontal.repeat(leftPad)} ${title} ${box.horizontal.repeat(Math.max(0, rightPad))}${box.topRight}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
function renderBoxBottom(colorFn, width = 60) {
|
|
88
|
+
return colorFn(`${box.bottomLeft}${box.horizontal.repeat(width - 2)}${box.bottomRight}`);
|
|
89
|
+
}
|
|
90
|
+
function renderBoxLine(content, colorFn) {
|
|
91
|
+
return `${colorFn(box.vertical)} ${content}`;
|
|
92
|
+
}
|
|
93
|
+
function createEventRenderer(options) {
|
|
94
|
+
const { verbose = true, showToolOutput = true, showLLMContent = false, showDebug = false } = options;
|
|
95
|
+
const state = {
|
|
96
|
+
currentSubtask: null,
|
|
97
|
+
agentActive: false,
|
|
98
|
+
indentLevel: 0
|
|
99
|
+
};
|
|
100
|
+
return (event) => {
|
|
101
|
+
switch (event.type) {
|
|
102
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
103
|
+
// SUBTASK LEVEL
|
|
104
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
105
|
+
case "subtask:start": {
|
|
106
|
+
state.currentSubtask = {
|
|
107
|
+
id: event.data.subtaskId,
|
|
108
|
+
index: event.data.index,
|
|
109
|
+
total: event.data.total
|
|
110
|
+
};
|
|
111
|
+
state.indentLevel = 1;
|
|
112
|
+
const subtaskNum = `${event.data.index + 1}/${event.data.total}`;
|
|
113
|
+
console.log(color.accent(box.vertical));
|
|
114
|
+
console.log(
|
|
115
|
+
color.accent(`${box.leftT}${box.horizontal}`) + renderBoxTop(`SUBTASK ${subtaskNum}`, color.secondary, 50)
|
|
116
|
+
);
|
|
117
|
+
console.log(
|
|
118
|
+
color.accent(box.vertical) + " " + renderBoxLine(
|
|
119
|
+
`${symbols.subtask} ${event.data.description.slice(0, 45)}${event.data.description.length > 45 ? "..." : ""}`,
|
|
120
|
+
color.secondary
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
console.log(color.accent(box.vertical) + " " + color.secondary(box.vertical));
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case "subtask:end": {
|
|
127
|
+
const status = event.data.success ? color.success(`${symbols.success} Done`) : color.error(`${symbols.error} Failed`);
|
|
128
|
+
console.log(color.accent(box.vertical) + " " + color.secondary(box.vertical));
|
|
129
|
+
console.log(
|
|
130
|
+
color.accent(box.vertical) + " " + renderBoxLine(status, color.secondary)
|
|
131
|
+
);
|
|
132
|
+
console.log(
|
|
133
|
+
color.accent(box.vertical) + " " + renderBoxBottom(color.secondary, 50)
|
|
134
|
+
);
|
|
135
|
+
state.currentSubtask = null;
|
|
136
|
+
state.indentLevel = 0;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
140
|
+
// AGENT LEVEL (nested under subtask or standalone)
|
|
141
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
142
|
+
case "agent:start": {
|
|
143
|
+
state.agentActive = true;
|
|
144
|
+
const linePrefix = state.currentSubtask ? color.accent(box.vertical) + " " + color.secondary(box.vertical) + " " : "";
|
|
145
|
+
console.log(linePrefix);
|
|
146
|
+
console.log(linePrefix + renderBoxTop(`AGENT [${event.data.tier}]`, color.primary, 45));
|
|
147
|
+
console.log(linePrefix + renderBoxLine(
|
|
148
|
+
`${symbols.agent} ${event.data.task.slice(0, 40)}${event.data.task.length > 40 ? "..." : ""}`,
|
|
149
|
+
color.primary
|
|
150
|
+
));
|
|
151
|
+
console.log(linePrefix + renderBoxLine(
|
|
152
|
+
color.dim(`Tools: ${event.data.toolCount} | Max iterations: ${event.data.maxIterations}`),
|
|
153
|
+
color.primary
|
|
154
|
+
));
|
|
155
|
+
state.indentLevel = state.currentSubtask ? 3 : 1;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case "agent:end": {
|
|
159
|
+
const linePrefix = state.currentSubtask ? color.accent(box.vertical) + " " + color.secondary(box.vertical) + " " : "";
|
|
160
|
+
const status = event.data.success ? color.success(`${symbols.success} Success`) : color.error(`${symbols.error} Failed`);
|
|
161
|
+
console.log(linePrefix + color.primary(box.vertical));
|
|
162
|
+
console.log(linePrefix + renderBoxLine(
|
|
163
|
+
`${status} ${color.dim(`(${formatDuration(event.data.durationMs)}, ${event.data.tokensUsed} tokens)`)}`,
|
|
164
|
+
color.primary
|
|
165
|
+
));
|
|
166
|
+
if (event.data.summary) {
|
|
167
|
+
console.log(linePrefix + color.primary(box.vertical));
|
|
168
|
+
console.log(linePrefix + renderBoxLine(
|
|
169
|
+
color.bold("\u{1F4CB} Result:"),
|
|
170
|
+
color.primary
|
|
171
|
+
));
|
|
172
|
+
const summaryLines = event.data.summary.split("\n");
|
|
173
|
+
for (const line of summaryLines) {
|
|
174
|
+
if (line.trim()) {
|
|
175
|
+
const words = line.split(" ");
|
|
176
|
+
let currentLine = "";
|
|
177
|
+
for (const word of words) {
|
|
178
|
+
if (currentLine.length + word.length > 75) {
|
|
179
|
+
if (currentLine) {
|
|
180
|
+
console.log(linePrefix + renderBoxLine(` ${currentLine}`, color.primary));
|
|
181
|
+
}
|
|
182
|
+
currentLine = word;
|
|
183
|
+
} else {
|
|
184
|
+
currentLine = currentLine ? `${currentLine} ${word}` : word;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (currentLine) {
|
|
188
|
+
console.log(linePrefix + renderBoxLine(` ${currentLine}`, color.primary));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (event.data.filesModified.length > 0 || event.data.filesCreated.length > 0) {
|
|
194
|
+
const files = [...event.data.filesCreated, ...event.data.filesModified];
|
|
195
|
+
console.log(linePrefix + renderBoxLine(
|
|
196
|
+
color.dim(`Files: ${files.slice(0, 3).map((f) => formatPath(f, 20)).join(", ")}${files.length > 3 ? ` +${files.length - 3}` : ""}`),
|
|
197
|
+
color.primary
|
|
198
|
+
));
|
|
199
|
+
}
|
|
200
|
+
console.log(linePrefix + renderBoxBottom(color.primary, 45));
|
|
201
|
+
state.agentActive = false;
|
|
202
|
+
state.indentLevel = state.currentSubtask ? 1 : 0;
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
case "agent:error": {
|
|
206
|
+
const linePrefix = getLinePrefix(state);
|
|
207
|
+
console.log(linePrefix + renderBoxLine(
|
|
208
|
+
`${symbols.error} ${color.error("Error:")} ${event.data.error.slice(0, 50)}`,
|
|
209
|
+
color.primary
|
|
210
|
+
));
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
214
|
+
// ITERATION & LLM (inside agent box)
|
|
215
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
216
|
+
case "iteration:start": {
|
|
217
|
+
const linePrefix = getLinePrefix(state);
|
|
218
|
+
if (verbose) {
|
|
219
|
+
console.log(linePrefix + color.primary(box.vertical));
|
|
220
|
+
console.log(linePrefix + renderBoxLine(
|
|
221
|
+
color.dim(`\u2500\u2500\u2500 Iteration ${event.data.iteration}/${event.data.maxIterations} \u2500\u2500\u2500`),
|
|
222
|
+
color.primary
|
|
223
|
+
));
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
case "llm:start": {
|
|
228
|
+
const linePrefix = getLinePrefix(state);
|
|
229
|
+
if (verbose) {
|
|
230
|
+
const iterLabel = event.data.iteration !== void 0 ? color.dim(` #${event.data.iteration}`) : "";
|
|
231
|
+
const msgLabel = showDebug ? color.dim(` [${event.data.messageCount} msgs, ${event.data.toolCount ?? 0} tools, ${event.data.systemPromptChars ?? 0} sys chars]`) : "";
|
|
232
|
+
process.stdout.write(linePrefix + renderBoxLine(
|
|
233
|
+
`${color.accent(symbols.thinking)} ${color.dim("Thinking...")}${iterLabel}${msgLabel}`,
|
|
234
|
+
color.primary
|
|
235
|
+
));
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
case "llm:end": {
|
|
240
|
+
if (verbose) {
|
|
241
|
+
process.stdout.write(`\r`);
|
|
242
|
+
const linePrefix = getLinePrefix(state);
|
|
243
|
+
const stopLabel = event.data.stopReason ? `, stop=${event.data.stopReason}` : "";
|
|
244
|
+
console.log(linePrefix + renderBoxLine(
|
|
245
|
+
`${color.accent(symbols.thinking)} Thought ${color.dim(`(${formatDuration(event.data.durationMs)}, ${event.data.tokensUsed} tok${stopLabel})`)}`,
|
|
246
|
+
color.primary
|
|
247
|
+
));
|
|
248
|
+
if (event.data.content) {
|
|
249
|
+
const maxLen = showDebug ? 2e3 : showLLMContent ? 500 : 150;
|
|
250
|
+
const content = event.data.content.slice(0, maxLen).replace(/\n/g, " ").trim();
|
|
251
|
+
if (content) {
|
|
252
|
+
console.log(linePrefix + renderBoxLine(
|
|
253
|
+
color.dim(` \u{1F4AD} "${content}${event.data.content.length > maxLen ? "..." : ""}"`),
|
|
254
|
+
color.primary
|
|
255
|
+
));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
262
|
+
// TOOL EXECUTION (inside agent, compact format)
|
|
263
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
264
|
+
case "tool:start": {
|
|
265
|
+
const linePrefix = getLinePrefix(state);
|
|
266
|
+
const toolName = event.data.toolName;
|
|
267
|
+
const meta = event.data.metadata;
|
|
268
|
+
let details = "";
|
|
269
|
+
if (showDebug) {
|
|
270
|
+
const inputObj = event.data.input;
|
|
271
|
+
if (inputObj && Object.keys(inputObj).length > 0) {
|
|
272
|
+
const raw = JSON.stringify(inputObj);
|
|
273
|
+
const maxLen = 200;
|
|
274
|
+
details = ` ${color.dim(raw.slice(0, maxLen) + (raw.length > maxLen ? "..." : ""))}`;
|
|
275
|
+
}
|
|
276
|
+
} else if (meta?.filePath) {
|
|
277
|
+
details = ` ${color.dim(formatPath(meta.filePath, 30))}`;
|
|
278
|
+
} else if (meta?.query) {
|
|
279
|
+
details = ` ${color.dim(`"${meta.query.slice(0, 25)}${meta.query.length > 25 ? "..." : ""}"`)}`;
|
|
280
|
+
} else if (meta?.command) {
|
|
281
|
+
details = ` ${color.dim(`$ ${meta.command.slice(0, 25)}`)}`;
|
|
282
|
+
}
|
|
283
|
+
process.stdout.write(linePrefix + renderBoxLine(
|
|
284
|
+
`${color.highlight(symbols.tool)} ${color.highlight(toolName)}${details}`,
|
|
285
|
+
color.primary
|
|
286
|
+
));
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case "tool:end": {
|
|
290
|
+
const status = event.data.success ? ` ${symbols.success}` : ` ${symbols.error}`;
|
|
291
|
+
process.stdout.write(`${status} ${color.dim(formatDuration(event.data.durationMs))}
|
|
292
|
+
`);
|
|
293
|
+
if (showToolOutput) {
|
|
294
|
+
const linePrefix = getLinePrefix(state);
|
|
295
|
+
const meta = event.data.metadata;
|
|
296
|
+
const output = event.data.output;
|
|
297
|
+
if (output && verbose) {
|
|
298
|
+
const maxOutputLen = showDebug ? 1e3 : 200;
|
|
299
|
+
if (showDebug) {
|
|
300
|
+
const truncated = output.slice(0, maxOutputLen);
|
|
301
|
+
const lines = truncated.split("\n");
|
|
302
|
+
for (const line of lines) {
|
|
303
|
+
if (line.trim()) {
|
|
304
|
+
console.log(linePrefix + renderBoxLine(
|
|
305
|
+
color.dim(` \u{1F4C4} ${line}`),
|
|
306
|
+
color.primary
|
|
307
|
+
));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (output.length > maxOutputLen) {
|
|
311
|
+
console.log(linePrefix + renderBoxLine(
|
|
312
|
+
color.dim(` \u{1F4C4} ... (${output.length - maxOutputLen} more chars)`),
|
|
313
|
+
color.primary
|
|
314
|
+
));
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
const cleanOutput = output.slice(0, maxOutputLen).replace(/\n/g, " ").replace(/\s+/g, " ").trim();
|
|
318
|
+
if (cleanOutput && cleanOutput.length > 10) {
|
|
319
|
+
console.log(linePrefix + renderBoxLine(
|
|
320
|
+
color.dim(` \u{1F4C4} ${cleanOutput}${output.length > maxOutputLen ? "..." : ""}`),
|
|
321
|
+
color.primary
|
|
322
|
+
));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (meta?.summary && !output) {
|
|
327
|
+
console.log(linePrefix + renderBoxLine(
|
|
328
|
+
color.dim(` \u2514\u2500 ${meta.summary.slice(0, 80)}`),
|
|
329
|
+
color.primary
|
|
330
|
+
));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
case "tool:error": {
|
|
336
|
+
process.stdout.write(` ${symbols.error}
|
|
337
|
+
`);
|
|
338
|
+
const linePrefix = getLinePrefix(state);
|
|
339
|
+
console.log(linePrefix + renderBoxLine(
|
|
340
|
+
color.error(` \u2514\u2500 ${event.data.error.slice(0, 50)}`),
|
|
341
|
+
color.primary
|
|
342
|
+
));
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
346
|
+
// MEMORY & PROGRESS (compact notifications)
|
|
347
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
348
|
+
case "memory:write": {
|
|
349
|
+
if (verbose) {
|
|
350
|
+
const linePrefix = getLinePrefix(state);
|
|
351
|
+
console.log(linePrefix + renderBoxLine(
|
|
352
|
+
color.dim(`${symbols.memory} Saved ${event.data.entryType} to ${event.data.target}`),
|
|
353
|
+
color.primary
|
|
354
|
+
));
|
|
355
|
+
}
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
case "progress:update": {
|
|
359
|
+
const budgetLine = formatBudget(event);
|
|
360
|
+
const phase = event.data.phase || "progress";
|
|
361
|
+
const progress = Math.max(0, Math.min(100, Math.round(event.data.progress || 0)));
|
|
362
|
+
const message = event.data.message || "";
|
|
363
|
+
if (verbose) {
|
|
364
|
+
const linePrefix = getLinePrefix(state);
|
|
365
|
+
const main = `[${phase}] ${progress}%${message ? ` - ${message}` : ""}`;
|
|
366
|
+
console.log(linePrefix + renderBoxLine(color.info(main), color.primary));
|
|
367
|
+
if (budgetLine) {
|
|
368
|
+
console.log(linePrefix + renderBoxLine(color.dim(` ${budgetLine}`), color.primary));
|
|
369
|
+
}
|
|
370
|
+
} else if (message && (phase === "plan" || phase === "spec") && (progress === 100 || progress === 5)) {
|
|
371
|
+
const budgetSuffix = budgetLine ? ` | ${budgetLine}` : "";
|
|
372
|
+
console.log(`${color.info(`[${phase}]`)} ${message}${budgetSuffix}`);
|
|
373
|
+
}
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
case "status:change": {
|
|
377
|
+
const budgetLine = formatBudget(event);
|
|
378
|
+
if (verbose && event.data.message) {
|
|
379
|
+
const linePrefix = getLinePrefix(state);
|
|
380
|
+
console.log(linePrefix + renderBoxLine(
|
|
381
|
+
color.info(`Status: ${event.data.status}${event.data.message ? ` - ${event.data.message}` : ""}`),
|
|
382
|
+
color.primary
|
|
383
|
+
));
|
|
384
|
+
if (budgetLine) {
|
|
385
|
+
console.log(linePrefix + renderBoxLine(color.dim(` ${budgetLine}`), color.primary));
|
|
386
|
+
}
|
|
387
|
+
if (event.data.status === "waiting" && event.sessionId) {
|
|
388
|
+
const sid = event.sessionId;
|
|
389
|
+
console.log(linePrefix + renderBoxLine(color.dim(` To approve: kb agent run --session-id=${sid} --approve`), color.primary));
|
|
390
|
+
console.log(linePrefix + renderBoxLine(color.dim(` To execute: kb agent run --session-id=${sid}`), color.primary));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (!verbose && (event.data.status === "done" || event.data.status === "error")) {
|
|
394
|
+
const budgetSuffix = budgetLine ? ` (${budgetLine})` : "";
|
|
395
|
+
console.log(
|
|
396
|
+
event.data.status === "done" ? `${symbols.success} ${event.data.message}${budgetSuffix}` : `${symbols.error} ${event.data.message}${budgetSuffix}`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
case "middleware:decision": {
|
|
402
|
+
if (verbose) {
|
|
403
|
+
const linePrefix = getLinePrefix(state);
|
|
404
|
+
const decisionIcons = {
|
|
405
|
+
soft_warning: "\u26A0",
|
|
406
|
+
hard_stop: "\u{1F6D1}",
|
|
407
|
+
trimmed: "\u2702",
|
|
408
|
+
loop_detected: "\u{1F501}",
|
|
409
|
+
stuck: "\u23F8",
|
|
410
|
+
summarized: "\u{1F4DD}"
|
|
411
|
+
};
|
|
412
|
+
const icon = decisionIcons[event.data.decision] ?? "\xB7";
|
|
413
|
+
console.log(linePrefix + renderBoxLine(
|
|
414
|
+
color.dim(` ${icon} [${event.data.middleware}] ${event.data.decision}`),
|
|
415
|
+
color.primary
|
|
416
|
+
));
|
|
417
|
+
}
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
case "llm:debug": {
|
|
421
|
+
if (!showDebug) {
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
const linePrefix = getLinePrefix(state);
|
|
425
|
+
const iterLabel = event.data.iteration !== void 0 ? ` (iter #${event.data.iteration})` : "";
|
|
426
|
+
console.log(linePrefix + renderBoxLine(
|
|
427
|
+
color.dim(` \u2500\u2500\u2500 System Prompt${iterLabel} \u2500\u2500\u2500`),
|
|
428
|
+
color.primary
|
|
429
|
+
));
|
|
430
|
+
for (const line of event.data.systemPrompt.split("\n")) {
|
|
431
|
+
console.log(linePrefix + renderBoxLine(color.dim(` ${line}`), color.primary));
|
|
432
|
+
}
|
|
433
|
+
console.log(linePrefix + renderBoxLine(color.dim(" \u2500\u2500\u2500 Messages \u2500\u2500\u2500"), color.primary));
|
|
434
|
+
for (const m of event.data.messages) {
|
|
435
|
+
const roleLabel = `[${m.role}]`;
|
|
436
|
+
const content = m.content;
|
|
437
|
+
const lines = content.split("\n");
|
|
438
|
+
const firstLine = `${roleLabel} ${lines[0] ?? ""}`;
|
|
439
|
+
console.log(linePrefix + renderBoxLine(color.dim(` ${firstLine}`), color.primary));
|
|
440
|
+
for (const line of lines.slice(1)) {
|
|
441
|
+
console.log(linePrefix + renderBoxLine(color.dim(` ${line}`), color.primary));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
console.log(linePrefix + renderBoxLine(color.dim(" \u2500\u2500\u2500 End Prompt \u2500\u2500\u2500"), color.primary));
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
function getLinePrefix(state2) {
|
|
450
|
+
if (state2.currentSubtask && state2.agentActive) {
|
|
451
|
+
return color.accent(box.vertical) + " " + color.secondary(box.vertical) + " ";
|
|
452
|
+
}
|
|
453
|
+
if (state2.currentSubtask) {
|
|
454
|
+
return color.accent(box.vertical) + " " + color.secondary(box.vertical) + " ";
|
|
455
|
+
}
|
|
456
|
+
if (state2.agentActive) {
|
|
457
|
+
return "";
|
|
458
|
+
}
|
|
459
|
+
return "";
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function createMinimalRenderer() {
|
|
463
|
+
return createEventRenderer({
|
|
464
|
+
verbose: false,
|
|
465
|
+
showToolOutput: false,
|
|
466
|
+
showLLMContent: false
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
function createDetailedRenderer() {
|
|
470
|
+
return createEventRenderer({
|
|
471
|
+
verbose: true,
|
|
472
|
+
showToolOutput: true,
|
|
473
|
+
showLLMContent: true
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
function createDebugRenderer() {
|
|
477
|
+
return createEventRenderer({
|
|
478
|
+
verbose: true,
|
|
479
|
+
showToolOutput: true,
|
|
480
|
+
showLLMContent: true,
|
|
481
|
+
showDebug: true
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// src/cli/commands/run.ts
|
|
486
|
+
bootstrapAgentSDK();
|
|
487
|
+
function parseBooleanFlag(value, defaultValue) {
|
|
488
|
+
if (typeof value === "boolean") {
|
|
489
|
+
return value;
|
|
490
|
+
}
|
|
491
|
+
if (typeof value === "string") {
|
|
492
|
+
const normalized = value.trim().toLowerCase();
|
|
493
|
+
if (["true", "1", "yes", "y", "on"].includes(normalized)) {
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
if (["false", "0", "no", "n", "off"].includes(normalized)) {
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (typeof value === "number") {
|
|
501
|
+
return value !== 0;
|
|
502
|
+
}
|
|
503
|
+
return defaultValue;
|
|
504
|
+
}
|
|
505
|
+
var run_default = defineCommand({
|
|
506
|
+
id: "agent:run",
|
|
507
|
+
description: "Execute a task with autonomous agent (orchestrator + child agents)",
|
|
508
|
+
handler: {
|
|
509
|
+
async execute(ctx, input) {
|
|
510
|
+
const flags = input.flags ?? input;
|
|
511
|
+
const {
|
|
512
|
+
task,
|
|
513
|
+
workingDir = ctx.cwd || process.cwd(),
|
|
514
|
+
maxIterations = 200,
|
|
515
|
+
temperature = 0.1,
|
|
516
|
+
verbose: verboseRaw = true,
|
|
517
|
+
quiet: quietRaw = false,
|
|
518
|
+
detailed: detailedRaw = false,
|
|
519
|
+
sessionId,
|
|
520
|
+
tier = "medium",
|
|
521
|
+
mode = "execute",
|
|
522
|
+
complexity,
|
|
523
|
+
files,
|
|
524
|
+
trace,
|
|
525
|
+
approve: approveRaw = false,
|
|
526
|
+
execute: executeRaw = false,
|
|
527
|
+
spec: specRaw = false,
|
|
528
|
+
"dry-run": dryRunRaw = false,
|
|
529
|
+
debug: debugRaw = false,
|
|
530
|
+
timeout: timeoutSeconds,
|
|
531
|
+
budget: budgetOverride,
|
|
532
|
+
json: jsonOutput = false
|
|
533
|
+
} = flags;
|
|
534
|
+
const verbose = parseBooleanFlag(verboseRaw, true);
|
|
535
|
+
const quiet = parseBooleanFlag(quietRaw, false);
|
|
536
|
+
const detailed = parseBooleanFlag(detailedRaw, false);
|
|
537
|
+
const approve = parseBooleanFlag(approveRaw, false);
|
|
538
|
+
const executeAfterPlan = parseBooleanFlag(executeRaw, false);
|
|
539
|
+
const spec = parseBooleanFlag(specRaw, false);
|
|
540
|
+
const dryRun = parseBooleanFlag(dryRunRaw, false);
|
|
541
|
+
const debug = parseBooleanFlag(debugRaw, false);
|
|
542
|
+
const timeoutSecs = typeof timeoutSeconds === "number" && timeoutSeconds > 0 ? timeoutSeconds : void 0;
|
|
543
|
+
const abortController = timeoutSecs !== void 0 ? new AbortController() : void 0;
|
|
544
|
+
let timeoutHandle;
|
|
545
|
+
if (abortController && timeoutSecs !== void 0) {
|
|
546
|
+
timeoutHandle = setTimeout(() => {
|
|
547
|
+
abortController.abort(
|
|
548
|
+
new Error(`Agent execution timed out after ${timeoutSecs}s (--timeout=${timeoutSecs})`)
|
|
549
|
+
);
|
|
550
|
+
}, timeoutSecs * 1e3);
|
|
551
|
+
timeoutHandle.unref?.();
|
|
552
|
+
}
|
|
553
|
+
const clearTimeout_ = () => {
|
|
554
|
+
if (timeoutHandle !== void 0) {
|
|
555
|
+
clearTimeout(timeoutHandle);
|
|
556
|
+
timeoutHandle = void 0;
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
if (!task) {
|
|
560
|
+
if (approve && sessionId) {
|
|
561
|
+
const sessionManager = new SessionManager(workingDir || ctx.cwd || process.cwd());
|
|
562
|
+
const planPath = sessionManager.getSessionPlanPath(sessionId);
|
|
563
|
+
try {
|
|
564
|
+
const raw = await promises.readFile(planPath, "utf-8");
|
|
565
|
+
const plan = JSON.parse(raw);
|
|
566
|
+
if (plan.status !== "draft") {
|
|
567
|
+
ctx.ui?.warn?.(`Plan is not in draft state (current: ${plan.status}). Nothing to approve.`);
|
|
568
|
+
clearTimeout_();
|
|
569
|
+
return { exitCode: 1 };
|
|
570
|
+
}
|
|
571
|
+
const approvedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
572
|
+
const approvedPlan = { ...plan, status: "approved", approvedAt, approvalComment: "Approved via CLI --approve", updatedAt: approvedAt };
|
|
573
|
+
await promises.writeFile(planPath, JSON.stringify(approvedPlan, null, 2), "utf-8");
|
|
574
|
+
const planDocumentService = new PlanDocumentService(workingDir || ctx.cwd || process.cwd());
|
|
575
|
+
const planDocPath = planDocumentService.getPlanPath(plan);
|
|
576
|
+
await planDocumentService.appendExecutionLog(planDocPath, `- ${approvedAt}: Plan approved via CLI (--approve).`).catch(() => {
|
|
577
|
+
});
|
|
578
|
+
ctx.ui?.success?.(`Plan approved: ${approvedPlan.id} (session: ${sessionId})`);
|
|
579
|
+
ctx.ui?.info?.(`Ready to execute: kb agent run --session-id=${sessionId}`);
|
|
580
|
+
clearTimeout_();
|
|
581
|
+
return { exitCode: 0, sessionId };
|
|
582
|
+
} catch {
|
|
583
|
+
ctx.ui?.error?.(`No plan found for session: ${sessionId}`);
|
|
584
|
+
clearTimeout_();
|
|
585
|
+
return { exitCode: 1 };
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
ctx.ui?.error?.("Error: --task is required");
|
|
589
|
+
clearTimeout_();
|
|
590
|
+
return { exitCode: 1 };
|
|
591
|
+
}
|
|
592
|
+
let modeConfig;
|
|
593
|
+
if (mode !== "execute") {
|
|
594
|
+
modeConfig = { mode };
|
|
595
|
+
if (mode === "plan") {
|
|
596
|
+
modeConfig.context = { mode: "plan", task, complexity };
|
|
597
|
+
} else if (mode === "edit") {
|
|
598
|
+
modeConfig.context = { mode: "edit", task, targetFiles: files || [], dryRun };
|
|
599
|
+
} else if (mode === "debug") {
|
|
600
|
+
modeConfig.context = { mode: "debug", task, traceFile: trace, relevantFiles: files || [] };
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
let eventRenderer;
|
|
604
|
+
if (jsonOutput) {
|
|
605
|
+
eventRenderer = () => {
|
|
606
|
+
};
|
|
607
|
+
} else if (quiet) {
|
|
608
|
+
eventRenderer = createMinimalRenderer();
|
|
609
|
+
} else if (debug) {
|
|
610
|
+
eventRenderer = createDebugRenderer();
|
|
611
|
+
} else if (detailed) {
|
|
612
|
+
eventRenderer = createDetailedRenderer();
|
|
613
|
+
} else {
|
|
614
|
+
eventRenderer = createEventRenderer({
|
|
615
|
+
verbose,
|
|
616
|
+
showToolOutput: true,
|
|
617
|
+
showLLMContent: false
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
try {
|
|
621
|
+
const runId = `run-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
622
|
+
const sessionManager = new SessionManager(workingDir);
|
|
623
|
+
let effectiveSessionId = sessionId;
|
|
624
|
+
if (!effectiveSessionId) {
|
|
625
|
+
const createdSession = await sessionManager.createSession({
|
|
626
|
+
mode,
|
|
627
|
+
task,
|
|
628
|
+
agentId: "cli-agent"
|
|
629
|
+
});
|
|
630
|
+
effectiveSessionId = createdSession.id;
|
|
631
|
+
} else {
|
|
632
|
+
const existing = await sessionManager.loadSession(effectiveSessionId);
|
|
633
|
+
if (!existing) {
|
|
634
|
+
const createdSession = await sessionManager.createSession({
|
|
635
|
+
mode,
|
|
636
|
+
task,
|
|
637
|
+
agentId: "cli-agent",
|
|
638
|
+
sessionId: effectiveSessionId
|
|
639
|
+
});
|
|
640
|
+
effectiveSessionId = createdSession.id;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
await sessionManager.createUserTurn(effectiveSessionId, task, runId);
|
|
644
|
+
const filesRead = /* @__PURE__ */ new Set();
|
|
645
|
+
const filesReadHash = /* @__PURE__ */ new Map();
|
|
646
|
+
const sessionMemory = createSessionMemoryBridge(workingDir, effectiveSessionId);
|
|
647
|
+
const responseRequirementsSelector = createDefaultResponseRequirementsSelector();
|
|
648
|
+
const toolRegistry = createToolRegistry({
|
|
649
|
+
workingDir,
|
|
650
|
+
currentTask: task,
|
|
651
|
+
sessionId: effectiveSessionId,
|
|
652
|
+
verbose: false,
|
|
653
|
+
// Disable tool registry verbose - we have event renderer
|
|
654
|
+
cache: useCache(),
|
|
655
|
+
filesRead,
|
|
656
|
+
filesReadHash,
|
|
657
|
+
sessionMemory,
|
|
658
|
+
responseRequirementsResolver: async ({ task: activeTask, kernel }) => responseRequirementsSelector.select({
|
|
659
|
+
state: kernel,
|
|
660
|
+
messages: [],
|
|
661
|
+
task: activeTask ?? task
|
|
662
|
+
})
|
|
663
|
+
});
|
|
664
|
+
const agentsConfig = await useConfig();
|
|
665
|
+
const effectiveBudget = typeof budgetOverride === "number" && budgetOverride > 0 ? { ...agentsConfig?.tokenBudget ?? {}, enabled: true, maxTokens: budgetOverride } : agentsConfig?.tokenBudget;
|
|
666
|
+
const analytics = useAnalytics() ?? null;
|
|
667
|
+
const taskId = `task-${Date.now()}`;
|
|
668
|
+
const tracer = new IncrementalTraceWriter(taskId);
|
|
669
|
+
if (spec && effectiveSessionId && sessionId) {
|
|
670
|
+
const planPath = sessionManager.getSessionPlanPath(effectiveSessionId);
|
|
671
|
+
try {
|
|
672
|
+
const planData = JSON.parse(await promises.readFile(planPath, "utf-8"));
|
|
673
|
+
if (planData.status === "approved" || planData.status === "spec_ready") {
|
|
674
|
+
ctx.ui?.info?.(`Found approved plan: ${planData.id} (${planData.phases.length} phases). Generating spec directly...`);
|
|
675
|
+
let pendingSessionWrite2 = Promise.resolve();
|
|
676
|
+
const specEventCallback = (event) => {
|
|
677
|
+
tracer.trace(event);
|
|
678
|
+
eventRenderer(event);
|
|
679
|
+
pendingSessionWrite2 = pendingSessionWrite2.then(async () => {
|
|
680
|
+
await sessionManager.addEvent(effectiveSessionId, {
|
|
681
|
+
...event,
|
|
682
|
+
sessionId: effectiveSessionId,
|
|
683
|
+
runId,
|
|
684
|
+
metadata: {
|
|
685
|
+
...event["metadata"],
|
|
686
|
+
sessionId: effectiveSessionId,
|
|
687
|
+
runId,
|
|
688
|
+
workingDir
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
}).catch((error) => {
|
|
692
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
693
|
+
console.warn(`[agent:run] Failed to persist spec event: ${message}`);
|
|
694
|
+
});
|
|
695
|
+
};
|
|
696
|
+
const specConfig = {
|
|
697
|
+
workingDir,
|
|
698
|
+
maxIterations: 40,
|
|
699
|
+
temperature: 0.1,
|
|
700
|
+
sessionId: effectiveSessionId,
|
|
701
|
+
tier,
|
|
702
|
+
analytics,
|
|
703
|
+
tokenBudget: effectiveBudget,
|
|
704
|
+
onEvent: specEventCallback,
|
|
705
|
+
abortSignal: abortController?.signal
|
|
706
|
+
};
|
|
707
|
+
const specHandler = new SpecModeHandler();
|
|
708
|
+
const specResult = await specHandler.execute(planData, specConfig, toolRegistry);
|
|
709
|
+
await pendingSessionWrite2;
|
|
710
|
+
await tracer.finalize();
|
|
711
|
+
const detailedTrace2 = tracer.getEntries();
|
|
712
|
+
if (detailedTrace2.length > 0) {
|
|
713
|
+
await sessionManager.storeTraceArtifacts(effectiveSessionId, runId, detailedTrace2);
|
|
714
|
+
}
|
|
715
|
+
if (specResult.success) {
|
|
716
|
+
ctx.ui?.success?.(`Spec generated: ${specResult.spec?.id} (${specResult.spec?.sections.length || 0} sections, ${specResult.spec?.sections.reduce((s, sec) => s + sec.changes.length, 0) || 0} changes)`);
|
|
717
|
+
} else {
|
|
718
|
+
ctx.ui?.warn?.(`Spec generation failed: ${specResult.summary}`);
|
|
719
|
+
}
|
|
720
|
+
const specSucceeded = specResult.success;
|
|
721
|
+
clearTimeout_();
|
|
722
|
+
return {
|
|
723
|
+
exitCode: specSucceeded ? 0 : 1,
|
|
724
|
+
sessionId: effectiveSessionId,
|
|
725
|
+
result: {
|
|
726
|
+
success: specSucceeded,
|
|
727
|
+
summary: specResult.summary,
|
|
728
|
+
filesCreated: specResult.filesCreated,
|
|
729
|
+
filesModified: specResult.filesModified,
|
|
730
|
+
filesRead: specResult.filesRead,
|
|
731
|
+
iterations: specResult.iterations,
|
|
732
|
+
tokensUsed: specResult.tokensUsed
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
} catch {
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
let pendingSessionWrite = Promise.resolve();
|
|
740
|
+
let persistedEventCount = 0;
|
|
741
|
+
const compositeEventCallback = (event) => {
|
|
742
|
+
tracer.trace(event);
|
|
743
|
+
eventRenderer(event);
|
|
744
|
+
pendingSessionWrite = pendingSessionWrite.then(async () => {
|
|
745
|
+
await sessionManager.addEvent(effectiveSessionId, {
|
|
746
|
+
...event,
|
|
747
|
+
sessionId: effectiveSessionId,
|
|
748
|
+
runId
|
|
749
|
+
});
|
|
750
|
+
persistedEventCount += 1;
|
|
751
|
+
}).catch((error) => {
|
|
752
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
753
|
+
console.warn(`[agent:run] Failed to persist event: ${message}`);
|
|
754
|
+
});
|
|
755
|
+
};
|
|
756
|
+
const config = {
|
|
757
|
+
workingDir,
|
|
758
|
+
maxIterations,
|
|
759
|
+
temperature,
|
|
760
|
+
sessionId: effectiveSessionId,
|
|
761
|
+
tier,
|
|
762
|
+
analytics,
|
|
763
|
+
tokenBudget: agentsConfig?.tokenBudget,
|
|
764
|
+
mode: modeConfig,
|
|
765
|
+
onEvent: compositeEventCallback,
|
|
766
|
+
debug,
|
|
767
|
+
abortSignal: abortController?.signal
|
|
768
|
+
};
|
|
769
|
+
if (timeoutSecs !== void 0 && !quiet) {
|
|
770
|
+
ctx.ui?.info?.(`\u23F1 Timeout active: agent will abort after ${timeoutSecs}s (--timeout=${timeoutSecs})`);
|
|
771
|
+
}
|
|
772
|
+
const sdk = new AgentSDK();
|
|
773
|
+
sdk.register(createCoreToolPack(toolRegistry));
|
|
774
|
+
const runner = sdk.createRunner(config);
|
|
775
|
+
let result = await runner.execute(task);
|
|
776
|
+
clearTimeout_();
|
|
777
|
+
await pendingSessionWrite;
|
|
778
|
+
if (persistedEventCount === 0 && result.summary?.trim()) {
|
|
779
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
780
|
+
const agentId = `agent-${runId}`;
|
|
781
|
+
const baseMetadata = { sessionId: effectiveSessionId, runId, workingDir };
|
|
782
|
+
await sessionManager.addEvent(effectiveSessionId, {
|
|
783
|
+
type: "agent:start",
|
|
784
|
+
timestamp: now,
|
|
785
|
+
sessionId: effectiveSessionId,
|
|
786
|
+
agentId,
|
|
787
|
+
runId,
|
|
788
|
+
data: { task, tier, maxIterations, toolCount: 0 },
|
|
789
|
+
metadata: baseMetadata
|
|
790
|
+
});
|
|
791
|
+
await sessionManager.addEvent(effectiveSessionId, {
|
|
792
|
+
type: "llm:end",
|
|
793
|
+
timestamp: now,
|
|
794
|
+
sessionId: effectiveSessionId,
|
|
795
|
+
agentId,
|
|
796
|
+
runId,
|
|
797
|
+
data: {
|
|
798
|
+
content: result.summary,
|
|
799
|
+
hasToolCalls: false,
|
|
800
|
+
tokensUsed: 0,
|
|
801
|
+
durationMs: 0,
|
|
802
|
+
stopReason: "no_tool_calls"
|
|
803
|
+
},
|
|
804
|
+
metadata: baseMetadata
|
|
805
|
+
});
|
|
806
|
+
await sessionManager.addEvent(effectiveSessionId, {
|
|
807
|
+
type: "agent:end",
|
|
808
|
+
timestamp: now,
|
|
809
|
+
sessionId: effectiveSessionId,
|
|
810
|
+
agentId,
|
|
811
|
+
runId,
|
|
812
|
+
data: {
|
|
813
|
+
success: result.success,
|
|
814
|
+
summary: result.summary,
|
|
815
|
+
iterations: result.iterations,
|
|
816
|
+
tokensUsed: result.tokensUsed,
|
|
817
|
+
durationMs: 0,
|
|
818
|
+
filesCreated: result.filesCreated,
|
|
819
|
+
filesModified: result.filesModified,
|
|
820
|
+
stopReason: result.success ? "report_complete" : "unknown"
|
|
821
|
+
},
|
|
822
|
+
metadata: baseMetadata
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
const detailedTrace = tracer.getEntries();
|
|
826
|
+
if (detailedTrace.length > 0) {
|
|
827
|
+
await sessionManager.storeTraceArtifacts(effectiveSessionId, runId, detailedTrace);
|
|
828
|
+
}
|
|
829
|
+
if (result.fileChanges && result.fileChanges.length > 0) {
|
|
830
|
+
await sessionManager.attachFileChangesToTurn(effectiveSessionId, runId, result.fileChanges);
|
|
831
|
+
}
|
|
832
|
+
if (approve) {
|
|
833
|
+
if (mode !== "plan") {
|
|
834
|
+
ctx.ui?.warn?.("--approve is currently supported only with --mode=plan");
|
|
835
|
+
} else if (!result.plan) {
|
|
836
|
+
ctx.ui?.warn?.("No plan produced by plan mode, nothing to approve");
|
|
837
|
+
} else {
|
|
838
|
+
const approvedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
839
|
+
const approvedPlan = {
|
|
840
|
+
...result.plan,
|
|
841
|
+
status: "approved",
|
|
842
|
+
approvedAt,
|
|
843
|
+
approvalComment: "Approved via CLI --approve",
|
|
844
|
+
updatedAt: approvedAt
|
|
845
|
+
};
|
|
846
|
+
const sessionPlanPath = sessionManager.getSessionPlanPath(effectiveSessionId);
|
|
847
|
+
await promises.writeFile(sessionPlanPath, JSON.stringify(approvedPlan, null, 2), "utf-8");
|
|
848
|
+
const planDocumentService = new PlanDocumentService(workingDir);
|
|
849
|
+
const planDocPath = planDocumentService.getPlanPath(result.plan);
|
|
850
|
+
await planDocumentService.appendExecutionLog(
|
|
851
|
+
planDocPath,
|
|
852
|
+
`- ${approvedAt}: Plan approved via CLI (--approve).`
|
|
853
|
+
);
|
|
854
|
+
ctx.ui?.success?.(`Plan approved: ${approvedPlan.id}`);
|
|
855
|
+
if (executeAfterPlan) {
|
|
856
|
+
ctx.ui?.info?.("Executing approved plan...");
|
|
857
|
+
const executeConfig = {
|
|
858
|
+
...config,
|
|
859
|
+
mode: { mode: "execute" }
|
|
860
|
+
};
|
|
861
|
+
const executeSdk = new AgentSDK();
|
|
862
|
+
executeSdk.register(createCoreToolPack(toolRegistry));
|
|
863
|
+
const executeRunner = executeSdk.createRunner(executeConfig);
|
|
864
|
+
result = await executeRunner.execute(task);
|
|
865
|
+
} else {
|
|
866
|
+
ctx.ui?.info?.(`Execute: kb agent run --session-id=${effectiveSessionId}`);
|
|
867
|
+
}
|
|
868
|
+
if (spec && approvedPlan) {
|
|
869
|
+
ctx.ui?.info?.("Generating detailed specification from approved plan...");
|
|
870
|
+
const specHandler = new SpecModeHandler();
|
|
871
|
+
const specResult = await specHandler.execute(approvedPlan, config, toolRegistry);
|
|
872
|
+
if (specResult.success) {
|
|
873
|
+
ctx.ui?.success?.(`Spec generated: ${specResult.spec?.id} (${specResult.spec?.sections.length || 0} sections)`);
|
|
874
|
+
} else {
|
|
875
|
+
ctx.ui?.warn?.(`Spec generation failed: ${specResult.summary}`);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
await tracer.finalize();
|
|
881
|
+
const runSucceeded = result.success;
|
|
882
|
+
const structuredResult = {
|
|
883
|
+
exitCode: runSucceeded ? 0 : 1,
|
|
884
|
+
sessionId: effectiveSessionId,
|
|
885
|
+
summary: result.summary,
|
|
886
|
+
data: {
|
|
887
|
+
sessionId: effectiveSessionId,
|
|
888
|
+
success: runSucceeded,
|
|
889
|
+
summary: result.summary,
|
|
890
|
+
filesCreated: result.filesCreated,
|
|
891
|
+
filesModified: result.filesModified,
|
|
892
|
+
filesRead: result.filesRead,
|
|
893
|
+
iterations: result.iterations,
|
|
894
|
+
tokensUsed: result.tokensUsed,
|
|
895
|
+
hasPlan: mode === "plan" && !!result.plan
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
if (jsonOutput) {
|
|
899
|
+
ctx.ui?.json?.(structuredResult);
|
|
900
|
+
}
|
|
901
|
+
return structuredResult;
|
|
902
|
+
} catch (error) {
|
|
903
|
+
clearTimeout_();
|
|
904
|
+
if (abortController?.signal.aborted) {
|
|
905
|
+
const reason = abortController.signal.reason instanceof Error ? abortController.signal.reason.message : `Agent execution timed out after ${timeoutSecs}s`;
|
|
906
|
+
console.error(`
|
|
907
|
+
\u23F1 ${reason}
|
|
908
|
+
`);
|
|
909
|
+
return { exitCode: 124 };
|
|
910
|
+
}
|
|
911
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
912
|
+
console.error(`
|
|
913
|
+
\u274C Agent execution failed: ${errorMessage}
|
|
914
|
+
`);
|
|
915
|
+
return { exitCode: 1 };
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
export { run_default as default };
|
|
922
|
+
//# sourceMappingURL=run.js.map
|
|
923
|
+
//# sourceMappingURL=run.js.map
|