@sean.holung/minicode 0.2.3 → 0.3.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 +13 -8
- package/dist/src/cli/args.js +31 -0
- package/dist/src/index.js +5 -0
- package/dist/src/serve/agent-bridge.js +356 -0
- package/dist/src/serve/openai-compat.js +144 -0
- package/dist/src/serve/server.js +349 -0
- package/dist/src/serve/types.js +2 -0
- package/dist/src/serve/websocket.js +28 -0
- package/dist/src/session/session-store.js +3 -1
- package/dist/src/ui/cli-ink.js +1 -0
- package/dist/src/web/app.js +2270 -0
- package/dist/src/web/index.html +68 -0
- package/dist/src/web/style.css +922 -0
- package/dist/tests/cli-args.test.js +4 -2
- package/dist/tests/serve.integration.test.js +759 -0
- package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.d.ts +5 -0
- package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.js +35 -20
- package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/model/client.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/model/client.js +2 -0
- package/node_modules/@minicode/agent-sdk/dist/src/model/client.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -5
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { AgentBridge } from "./agent-bridge.js";
|
|
6
|
+
import { createWebSocketServer } from "./websocket.js";
|
|
7
|
+
import { handleChatCompletions, handleModels } from "./openai-compat.js";
|
|
8
|
+
import { formatConfigForDisplay } from "../agent/config.js";
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
// Resolve web dir: always serve from dist/src/web (built by scripts/build-web.mjs)
|
|
11
|
+
// In dev (tsx): __dirname = src/serve → go up to project root, then dist/src/web
|
|
12
|
+
// In prod (dist): __dirname = dist/src/serve → sibling dir dist/src/web
|
|
13
|
+
const webDir = __dirname.includes(`${path.sep}dist${path.sep}`)
|
|
14
|
+
? path.resolve(__dirname, "../web")
|
|
15
|
+
: path.resolve(__dirname, "../../dist/src/web");
|
|
16
|
+
const MIME_TYPES = {
|
|
17
|
+
".html": "text/html",
|
|
18
|
+
".css": "text/css",
|
|
19
|
+
".js": "application/javascript",
|
|
20
|
+
".json": "application/json",
|
|
21
|
+
};
|
|
22
|
+
function sendJson(res, status, body) {
|
|
23
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
24
|
+
res.end(JSON.stringify(body));
|
|
25
|
+
}
|
|
26
|
+
function readBody(req) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const chunks = [];
|
|
29
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
30
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
31
|
+
req.on("error", reject);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function serveStatic(res, urlPath) {
|
|
35
|
+
const fileName = urlPath === "/" ? "index.html" : urlPath.slice(1);
|
|
36
|
+
const filePath = path.join(webDir, fileName);
|
|
37
|
+
// Prevent path traversal
|
|
38
|
+
if (!filePath.startsWith(webDir)) {
|
|
39
|
+
res.writeHead(403);
|
|
40
|
+
res.end("Forbidden");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const content = await readFile(filePath);
|
|
45
|
+
const ext = path.extname(filePath);
|
|
46
|
+
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
47
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
48
|
+
res.end(content);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
res.writeHead(404);
|
|
52
|
+
res.end("Not Found");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Create the HTTP request handler. Exported for testing. */
|
|
56
|
+
export function createRequestHandler(bridge) {
|
|
57
|
+
const config = bridge.getConfig();
|
|
58
|
+
return (req, res) => {
|
|
59
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
60
|
+
const method = req.method ?? "GET";
|
|
61
|
+
const pathname = url.pathname;
|
|
62
|
+
const handle = async () => {
|
|
63
|
+
// OpenAI-compatible routes
|
|
64
|
+
if (pathname === "/v1/models" && method === "GET") {
|
|
65
|
+
handleModels(req, res);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (pathname === "/v1/chat/completions" && method === "POST") {
|
|
69
|
+
await handleChatCompletions(req, res, bridge);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Minicode REST API
|
|
73
|
+
if (pathname === "/api/status" && method === "GET") {
|
|
74
|
+
sendJson(res, 200, {
|
|
75
|
+
status: bridge.isBusy() ? "busy" : "ready",
|
|
76
|
+
workspace: config.workspaceRoot,
|
|
77
|
+
model: config.model,
|
|
78
|
+
provider: config.modelProvider,
|
|
79
|
+
});
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (pathname === "/api/config" && method === "GET") {
|
|
83
|
+
sendJson(res, 200, { config: formatConfigForDisplay(config) });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (pathname === "/api/sessions" && method === "GET") {
|
|
87
|
+
const sessions = await bridge.listSess();
|
|
88
|
+
sendJson(res, 200, { sessions });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (pathname === "/api/sessions/save" && method === "POST") {
|
|
92
|
+
const body = JSON.parse(await readBody(req));
|
|
93
|
+
const meta = await bridge.saveSess(body.label);
|
|
94
|
+
sendJson(res, 200, meta);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (pathname === "/api/sessions/load" && method === "POST") {
|
|
98
|
+
const body = JSON.parse(await readBody(req));
|
|
99
|
+
const result = await bridge.loadSess(body.label);
|
|
100
|
+
if (!result) {
|
|
101
|
+
sendJson(res, 404, { error: "Session not found" });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
sendJson(res, 200, { label: result.label });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// ── Graph / Index API ──
|
|
108
|
+
if (pathname === "/api/symbols" && method === "GET") {
|
|
109
|
+
if (!bridge.hasIndex()) {
|
|
110
|
+
sendJson(res, 404, { error: "No project index available" });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
sendJson(res, 200, { symbols: bridge.getSymbols() });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (pathname.startsWith("/api/symbols/") && pathname.endsWith("/dependencies") && method === "GET") {
|
|
117
|
+
const name = decodeURIComponent(pathname.slice("/api/symbols/".length, -"/dependencies".length));
|
|
118
|
+
const depthParam = url.searchParams.get("depth");
|
|
119
|
+
const depth = depthParam ? Number(depthParam) : undefined;
|
|
120
|
+
const result = bridge.getDependencies(name, depth);
|
|
121
|
+
if (!result) {
|
|
122
|
+
sendJson(res, 404, { error: `Symbol "${name}" not found` });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
sendJson(res, 200, { symbol: name, dependencies: result });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (pathname.startsWith("/api/symbols/") && pathname.endsWith("/references") && method === "GET") {
|
|
129
|
+
const name = decodeURIComponent(pathname.slice("/api/symbols/".length, -"/references".length));
|
|
130
|
+
const result = bridge.getReferences(name);
|
|
131
|
+
if (!result) {
|
|
132
|
+
sendJson(res, 404, { error: `Symbol "${name}" not found` });
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
sendJson(res, 200, { symbol: name, references: result });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (pathname.startsWith("/api/symbols/") && pathname.endsWith("/source") && method === "GET") {
|
|
139
|
+
const name = decodeURIComponent(pathname.slice("/api/symbols/".length, -"/source".length));
|
|
140
|
+
const sym = bridge.getSymbol(name);
|
|
141
|
+
if (!sym) {
|
|
142
|
+
sendJson(res, 404, { error: `Symbol "${name}" not found` });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const fileContent = await readFile(path.resolve(config.workspaceRoot, sym.filePath), "utf8");
|
|
147
|
+
const lines = fileContent.split(/\r?\n/);
|
|
148
|
+
const start = Math.max(0, sym.startLine - 1);
|
|
149
|
+
const end = Math.min(lines.length, sym.endLine);
|
|
150
|
+
const source = lines.slice(start, end).join("\n");
|
|
151
|
+
sendJson(res, 200, { symbol: name, filePath: sym.filePath, startLine: sym.startLine, endLine: sym.endLine, source });
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
sendJson(res, 500, { error: `Could not read file: ${sym.filePath}` });
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (pathname === "/api/code-map" && method === "GET") {
|
|
159
|
+
const budgetParam = url.searchParams.get("budget");
|
|
160
|
+
const budget = budgetParam ? Number(budgetParam) : undefined;
|
|
161
|
+
const result = bridge.getCodeMap(budget);
|
|
162
|
+
if (!result) {
|
|
163
|
+
sendJson(res, 404, { error: "No project index available" });
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
sendJson(res, 200, result);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (pathname === "/api/graph" && method === "GET") {
|
|
170
|
+
const result = bridge.getGraph();
|
|
171
|
+
if (!result) {
|
|
172
|
+
sendJson(res, 404, { error: "No project index available" });
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
sendJson(res, 200, result);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (pathname === "/api/focus" && method === "GET") {
|
|
179
|
+
sendJson(res, 200, { pinned: bridge.getPinnedSymbols() });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (pathname === "/api/focus" && method === "POST") {
|
|
183
|
+
const body = JSON.parse(await readBody(req));
|
|
184
|
+
if (!body.symbol || !body.action) {
|
|
185
|
+
sendJson(res, 400, { error: "action and symbol are required" });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (body.action === "pin") {
|
|
189
|
+
const ok = bridge.pinSymbol(body.symbol);
|
|
190
|
+
if (!ok) {
|
|
191
|
+
sendJson(res, 404, { error: `Symbol "${body.symbol}" not found` });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
sendJson(res, 200, { pinned: bridge.getPinnedSymbols() });
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (body.action === "unpin") {
|
|
198
|
+
bridge.unpinSymbol(body.symbol);
|
|
199
|
+
sendJson(res, 200, { pinned: bridge.getPinnedSymbols() });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
sendJson(res, 400, { error: `Unknown action "${body.action}". Use "pin" or "unpin".` });
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// ── Annotations API ──
|
|
206
|
+
if (pathname === "/api/annotations" && method === "GET") {
|
|
207
|
+
sendJson(res, 200, { annotations: bridge.getAnnotations() });
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (pathname.startsWith("/api/symbols/") && pathname.endsWith("/annotations") && method === "GET") {
|
|
211
|
+
const name = decodeURIComponent(pathname.slice("/api/symbols/".length, -"/annotations".length));
|
|
212
|
+
const notes = bridge.getAnnotationsForSymbol(name);
|
|
213
|
+
sendJson(res, 200, { symbol: name, annotations: notes });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (pathname.startsWith("/api/symbols/") && pathname.endsWith("/annotations") && method === "POST") {
|
|
217
|
+
const name = decodeURIComponent(pathname.slice("/api/symbols/".length, -"/annotations".length));
|
|
218
|
+
const body = JSON.parse(await readBody(req));
|
|
219
|
+
if (!body.text) {
|
|
220
|
+
sendJson(res, 400, { error: "text is required" });
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const ok = bridge.addAnnotation(name, body.text);
|
|
224
|
+
if (!ok) {
|
|
225
|
+
sendJson(res, 404, { error: `Symbol "${name}" not found or text empty` });
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
sendJson(res, 200, { symbol: name, annotations: bridge.getAnnotationsForSymbol(name) });
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
// DELETE /api/symbols/:name/annotations/:index
|
|
232
|
+
{
|
|
233
|
+
const annoDeleteMatch = pathname.match(/^\/api\/symbols\/(.+)\/annotations\/(\d+)$/);
|
|
234
|
+
if (annoDeleteMatch && method === "DELETE") {
|
|
235
|
+
const name = decodeURIComponent(annoDeleteMatch[1]);
|
|
236
|
+
const index = Number(annoDeleteMatch[2]);
|
|
237
|
+
const ok = bridge.removeAnnotation(name, index);
|
|
238
|
+
if (!ok) {
|
|
239
|
+
sendJson(res, 404, { error: "Annotation not found" });
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
sendJson(res, 200, { symbol: name, annotations: bridge.getAnnotationsForSymbol(name) });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (pathname.startsWith("/api/symbols/") && pathname.endsWith("/annotations") && method === "DELETE") {
|
|
247
|
+
const name = decodeURIComponent(pathname.slice("/api/symbols/".length, -"/annotations".length));
|
|
248
|
+
bridge.clearAnnotations(name);
|
|
249
|
+
sendJson(res, 200, { symbol: name, annotations: [] });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// ── Explain SSE ──
|
|
253
|
+
if (pathname.startsWith("/api/symbols/") && pathname.endsWith("/explain") && method === "GET") {
|
|
254
|
+
const name = decodeURIComponent(pathname.slice("/api/symbols/".length, -"/explain".length));
|
|
255
|
+
res.writeHead(200, {
|
|
256
|
+
"Content-Type": "text/event-stream",
|
|
257
|
+
"Cache-Control": "no-cache",
|
|
258
|
+
Connection: "keep-alive",
|
|
259
|
+
});
|
|
260
|
+
const abortController = new AbortController();
|
|
261
|
+
req.on("close", () => abortController.abort());
|
|
262
|
+
try {
|
|
263
|
+
await bridge.explainSymbol(name, (event) => {
|
|
264
|
+
if (!res.writableEnded) {
|
|
265
|
+
res.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
266
|
+
}
|
|
267
|
+
}, abortController.signal);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
if (!res.writableEnded) {
|
|
271
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
272
|
+
res.write(`data: ${JSON.stringify({ type: "error", message: msg })}\n\n`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (!res.writableEnded) {
|
|
276
|
+
res.write("data: [DONE]\n\n");
|
|
277
|
+
res.end();
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (pathname === "/api/chat" && method === "POST") {
|
|
282
|
+
const body = JSON.parse(await readBody(req));
|
|
283
|
+
if (!body.message) {
|
|
284
|
+
sendJson(res, 400, { error: "message is required" });
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (bridge.isBusy()) {
|
|
288
|
+
sendJson(res, 429, { error: "Agent is busy" });
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
const result = await bridge.runTurn(body.message);
|
|
293
|
+
sendJson(res, 200, { text: result.text, usage: result.usage });
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
297
|
+
sendJson(res, 500, { error: msg });
|
|
298
|
+
}
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
// Static files
|
|
302
|
+
await serveStatic(res, pathname);
|
|
303
|
+
};
|
|
304
|
+
handle().catch((error) => {
|
|
305
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
306
|
+
sendJson(res, 500, { error: msg });
|
|
307
|
+
});
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
export async function runServe(verbose, port) {
|
|
311
|
+
console.log("Initializing agent...");
|
|
312
|
+
// Set up broadcast plumbing
|
|
313
|
+
let broadcastFn = () => { };
|
|
314
|
+
const bridge = new AgentBridge((msg) => broadcastFn(msg), verbose);
|
|
315
|
+
await bridge.init();
|
|
316
|
+
const config = bridge.getConfig();
|
|
317
|
+
const handler = createRequestHandler(bridge);
|
|
318
|
+
const server = createServer(handler);
|
|
319
|
+
// WebSocket server — captures the real broadcast function
|
|
320
|
+
const wss = createWebSocketServer(server, bridge);
|
|
321
|
+
// Wire up the broadcast: WS clients receive all agent events
|
|
322
|
+
const { WebSocket } = await import("ws");
|
|
323
|
+
broadcastFn = (msg) => {
|
|
324
|
+
const data = JSON.stringify(msg);
|
|
325
|
+
for (const client of wss.clients) {
|
|
326
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
327
|
+
client.send(data);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
// Graceful shutdown
|
|
332
|
+
process.on("SIGINT", () => {
|
|
333
|
+
console.log("\nShutting down...");
|
|
334
|
+
wss.close();
|
|
335
|
+
server.close(() => {
|
|
336
|
+
process.exit(0);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
server.listen(port, "127.0.0.1", () => {
|
|
340
|
+
console.log(`\nminicode serve`);
|
|
341
|
+
console.log(` Workspace: ${config.workspaceRoot}`);
|
|
342
|
+
console.log(` Model: ${config.model} (${config.modelProvider})`);
|
|
343
|
+
console.log(` Web UI: http://localhost:${port}`);
|
|
344
|
+
console.log(` OpenAI: http://localhost:${port}/v1`);
|
|
345
|
+
console.log(`\nPress Ctrl+C to stop.\n`);
|
|
346
|
+
});
|
|
347
|
+
// Keep alive
|
|
348
|
+
await new Promise(() => { });
|
|
349
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { WebSocketServer } from "ws";
|
|
2
|
+
export function createWebSocketServer(httpServer, bridge) {
|
|
3
|
+
const wss = new WebSocketServer({ server: httpServer });
|
|
4
|
+
wss.on("connection", (ws) => {
|
|
5
|
+
ws.on("message", (raw) => {
|
|
6
|
+
let msg;
|
|
7
|
+
try {
|
|
8
|
+
msg = JSON.parse(String(raw));
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (msg.type === "chat") {
|
|
14
|
+
if (bridge.isBusy()) {
|
|
15
|
+
ws.send(JSON.stringify({ type: "busy" }));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
bridge.runTurn(msg.message).catch(() => {
|
|
19
|
+
// errors already broadcast via agent-bridge
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
else if (msg.type === "cancel") {
|
|
23
|
+
bridge.cancel();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
return wss;
|
|
28
|
+
}
|
|
@@ -7,7 +7,7 @@ let sessionsDir = path.join(os.homedir(), ".minicode", "sessions");
|
|
|
7
7
|
export function setSessionsDir(dir) {
|
|
8
8
|
sessionsDir = dir;
|
|
9
9
|
}
|
|
10
|
-
export async function saveSession(session, label) {
|
|
10
|
+
export async function saveSession(session, label, annotations) {
|
|
11
11
|
await mkdir(sessionsDir, { recursive: true });
|
|
12
12
|
const savedAt = new Date().toISOString();
|
|
13
13
|
const snapshot = session.toJSON();
|
|
@@ -18,6 +18,7 @@ export async function saveSession(session, label) {
|
|
|
18
18
|
label: resolvedLabel,
|
|
19
19
|
savedAt,
|
|
20
20
|
session: snapshot,
|
|
21
|
+
...(annotations && Object.keys(annotations).length > 0 ? { annotations } : {}),
|
|
21
22
|
};
|
|
22
23
|
const filePath = path.join(sessionsDir, `${snapshot.id}.json`);
|
|
23
24
|
await writeFile(filePath, JSON.stringify(data, null, 2), "utf8");
|
|
@@ -67,6 +68,7 @@ export async function loadSession(sessionId) {
|
|
|
67
68
|
return {
|
|
68
69
|
session: Session.fromJSON(data.session),
|
|
69
70
|
label: data.label,
|
|
71
|
+
...(data.annotations ? { annotations: data.annotations } : {}),
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
74
|
catch {
|
package/dist/src/ui/cli-ink.js
CHANGED
|
@@ -90,6 +90,7 @@ export async function runInkCli(verbose, initialTask) {
|
|
|
90
90
|
...(verbose
|
|
91
91
|
? {
|
|
92
92
|
onProgress: (msg) => store.addItem({ type: "system", content: msg }),
|
|
93
|
+
onVerbose: (msg) => store.addItem({ type: "system", content: msg }),
|
|
93
94
|
}
|
|
94
95
|
: {}),
|
|
95
96
|
onUiUpdate: createUiUpdateHandler(),
|