@sean.holung/minicode 0.2.4 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/src/indexer/code-map.js +2 -1
  2. package/dist/src/indexer/plugins/typescript.js +63 -34
  3. package/dist/src/serve/agent-bridge.js +127 -4
  4. package/dist/src/serve/server.js +101 -3
  5. package/dist/src/session/session-store.js +3 -1
  6. package/dist/src/ui/cli-ink.js +1 -0
  7. package/dist/src/web/app.js +2037 -117
  8. package/dist/src/web/index.html +28 -9
  9. package/dist/src/web/style.css +503 -3
  10. package/dist/tests/benchmark-index.test.js +152 -0
  11. package/dist/tests/indexer.test.js +62 -0
  12. package/dist/tests/serve.integration.test.js +225 -0
  13. package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.d.ts +6 -1
  14. package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.d.ts.map +1 -1
  15. package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.js +35 -20
  16. package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.js.map +1 -1
  17. package/node_modules/@minicode/agent-sdk/dist/src/index.d.ts +2 -1
  18. package/node_modules/@minicode/agent-sdk/dist/src/index.d.ts.map +1 -1
  19. package/node_modules/@minicode/agent-sdk/dist/src/index.js.map +1 -1
  20. package/node_modules/@minicode/agent-sdk/dist/src/indexer/types.d.ts +68 -0
  21. package/node_modules/@minicode/agent-sdk/dist/src/indexer/types.d.ts.map +1 -0
  22. package/node_modules/@minicode/agent-sdk/dist/src/indexer/types.js +2 -0
  23. package/node_modules/@minicode/agent-sdk/dist/src/indexer/types.js.map +1 -0
  24. package/node_modules/@minicode/agent-sdk/dist/src/prompt/system-prompt.d.ts +1 -5
  25. package/node_modules/@minicode/agent-sdk/dist/src/prompt/system-prompt.d.ts.map +1 -1
  26. package/node_modules/@minicode/agent-sdk/dist/src/prompt/system-prompt.js.map +1 -1
  27. package/node_modules/@minicode/agent-sdk/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +7 -4
@@ -10,7 +10,8 @@ function formatSymbol(symbol, indent, isMethod) {
10
10
  return `${indent}${symbol.kind} ${symbol.qualifiedName}\n${indent} ${symbol.signature}`;
11
11
  }
12
12
  function isEntryPointFile(filePath) {
13
- return filePath === "src/index.ts" || filePath.endsWith("/index.ts");
13
+ const name = filePath.replace(/\\/g, "/");
14
+ return /(?:^|\/)index\.[jt]sx?$/.test(name);
14
15
  }
15
16
  /**
16
17
  * Build the set of symbols related to focus symbols via dependency edges.
@@ -17,7 +17,7 @@ function extractSignature(node, sourceFile) {
17
17
  if (ts.isArrowFunction(node) && ts.isBlock(node.body)) {
18
18
  return node.body.getStart(sourceFile);
19
19
  }
20
- if (ts.isClassDeclaration(node)) {
20
+ if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
21
21
  const text = sourceText.slice(node.getStart(), node.getEnd());
22
22
  const braceIdx = text.indexOf("{");
23
23
  return braceIdx >= 0 ? node.getStart() + braceIdx : null;
@@ -84,7 +84,8 @@ function createPlugin() {
84
84
  });
85
85
  return;
86
86
  }
87
- if (ts.isClassDeclaration(node) && node.name) {
87
+ if ((ts.isClassDeclaration(node) || ts.isClassExpression(node)) &&
88
+ node.name) {
88
89
  const name = node.name.getText(sourceFile);
89
90
  const prevClass = currentClass;
90
91
  currentClass = name;
@@ -97,7 +98,7 @@ function createPlugin() {
97
98
  startLine: getLine(sourceFile, node.getStart(sourceFile)),
98
99
  endLine: getLine(sourceFile, node.getEnd()),
99
100
  signature: extractSignature(node, sourceFile),
100
- exported: isExported(node),
101
+ exported: ts.isClassDeclaration(node) ? isExported(node) : false,
101
102
  dependencies: [],
102
103
  ...(doc && { docComment: doc }),
103
104
  });
@@ -183,9 +184,9 @@ function createPlugin() {
183
184
  const doc = extractJSDoc(node, sourceFile);
184
185
  for (const decl of node.declarationList.declarations) {
185
186
  const init = decl.initializer;
186
- if (ts.isIdentifier(decl.name) &&
187
- init &&
188
- (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
187
+ if (!ts.isIdentifier(decl.name) || !init)
188
+ continue;
189
+ if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) {
189
190
  const name = decl.name.getText(sourceFile);
190
191
  symbols.push({
191
192
  name,
@@ -200,6 +201,25 @@ function createPlugin() {
200
201
  ...(doc && { docComment: doc }),
201
202
  });
202
203
  }
204
+ else if (ts.isClassExpression(init)) {
205
+ const name = decl.name.getText(sourceFile);
206
+ const prevClass = currentClass;
207
+ currentClass = name;
208
+ symbols.push({
209
+ name,
210
+ qualifiedName: name,
211
+ kind: "class",
212
+ filePath,
213
+ startLine: getLine(sourceFile, decl.getStart(sourceFile)),
214
+ endLine: getLine(sourceFile, decl.getEnd()),
215
+ signature: extractSignature(init, sourceFile),
216
+ exported,
217
+ dependencies: [],
218
+ ...(doc && { docComment: doc }),
219
+ });
220
+ ts.forEachChild(init, visit);
221
+ currentClass = prevClass;
222
+ }
203
223
  }
204
224
  return;
205
225
  }
@@ -236,10 +256,11 @@ function createPlugin() {
236
256
  if (ts.isIdentifier(expr)) {
237
257
  addEdge(from, expr.getText(), "calls");
238
258
  }
239
- else if (ts.isNewExpression(expr) && expr.expression) {
240
- if (ts.isIdentifier(expr.expression)) {
241
- addEdge(from, expr.expression.getText(), "calls");
242
- }
259
+ }
260
+ if (ts.isNewExpression(node)) {
261
+ const expr = node.expression;
262
+ if (ts.isIdentifier(expr)) {
263
+ addEdge(from, expr.getText(), "calls");
243
264
  }
244
265
  }
245
266
  ts.forEachChild(node, (n) => collectCalls(n, from));
@@ -248,29 +269,33 @@ function createPlugin() {
248
269
  const fullPath = path.join(rootDir, filePath);
249
270
  const sourceFile = ts.createSourceFile(fullPath, content, ts.ScriptTarget.Latest, true);
250
271
  let currentClass = null;
251
- function visit(node) {
252
- if (ts.isClassDeclaration(node) && node.name) {
253
- const name = node.name.getText(sourceFile);
254
- const prevClass = currentClass;
255
- currentClass = name;
256
- if (symbolSet.has(name)) {
257
- for (const clause of node.heritageClauses ?? []) {
258
- for (const type of clause.types) {
259
- const expr = type.expression;
260
- const target = ts.isIdentifier(expr)
261
- ? expr.getText()
262
- : ts.isPropertyAccessExpression(expr)
263
- ? expr.expression.getText()
264
- : expr.getText();
265
- const kind = clause.token === ts.SyntaxKind.ExtendsKeyword
266
- ? "extends"
267
- : "implements";
268
- addEdge(name, target, kind);
269
- }
272
+ function visitClassNode(node, name) {
273
+ const prevClass = currentClass;
274
+ currentClass = name;
275
+ if (symbolSet.has(name)) {
276
+ for (const clause of node.heritageClauses ?? []) {
277
+ for (const type of clause.types) {
278
+ const expr = type.expression;
279
+ const target = ts.isIdentifier(expr)
280
+ ? expr.getText()
281
+ : ts.isPropertyAccessExpression(expr)
282
+ ? expr.expression.getText()
283
+ : expr.getText();
284
+ const kind = clause.token === ts.SyntaxKind.ExtendsKeyword
285
+ ? "extends"
286
+ : "implements";
287
+ addEdge(name, target, kind);
270
288
  }
271
289
  }
272
- ts.forEachChild(node, visit);
273
- currentClass = prevClass;
290
+ }
291
+ ts.forEachChild(node, visit);
292
+ currentClass = prevClass;
293
+ }
294
+ function visit(node) {
295
+ if ((ts.isClassDeclaration(node) || ts.isClassExpression(node)) &&
296
+ node.name) {
297
+ const name = node.name.getText(sourceFile);
298
+ visitClassNode(node, name);
274
299
  return;
275
300
  }
276
301
  if (ts.isConstructorDeclaration(node)) {
@@ -304,15 +329,19 @@ function createPlugin() {
304
329
  if (ts.isVariableStatement(node)) {
305
330
  for (const decl of node.declarationList.declarations) {
306
331
  const init = decl.initializer;
307
- if (ts.isIdentifier(decl.name) &&
308
- init &&
309
- (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
332
+ if (!ts.isIdentifier(decl.name) || !init)
333
+ continue;
334
+ if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) {
310
335
  const name = decl.name.getText(sourceFile);
311
336
  if (symbolSet.has(name)) {
312
337
  collectTypeRefs(decl, name);
313
338
  collectCalls(decl, name);
314
339
  }
315
340
  }
341
+ else if (ts.isClassExpression(init)) {
342
+ const name = decl.name.getText(sourceFile);
343
+ visitClassNode(init, name);
344
+ }
316
345
  }
317
346
  return;
318
347
  }
@@ -15,6 +15,7 @@ export class AgentBridge {
15
15
  verbose;
16
16
  listeners = new Set();
17
17
  pinnedSymbols = new Set();
18
+ annotations = new Map();
18
19
  constructor(broadcast, verbose) {
19
20
  this.broadcast = broadcast;
20
21
  this.verbose = verbose;
@@ -51,9 +52,15 @@ export class AgentBridge {
51
52
  projectIndex = undefined;
52
53
  }
53
54
  const toolRegistry = createToolRegistry(config, projectIndex);
55
+ // Wrap tool registry execute to inject annotations into tool results
56
+ const originalExecute = toolRegistry.execute.bind(toolRegistry);
57
+ toolRegistry.execute = async (name, input) => {
58
+ const result = await originalExecute(name, input);
59
+ return this.appendAnnotationsToResult(name, input, result);
60
+ };
54
61
  this.config = config;
55
62
  this.projectIndex = projectIndex;
56
- this.buildAgent = (session) => {
63
+ this.buildAgent = (session, onUiUpdate) => {
57
64
  return new CodingAgent({
58
65
  config,
59
66
  modelClient,
@@ -63,9 +70,10 @@ export class AgentBridge {
63
70
  ...(projectIndex !== undefined
64
71
  ? { getCodeMap: (focusSymbols) => projectIndex.getCodeMap(undefined, focusSymbols) }
65
72
  : {}),
66
- onUiUpdate: (event) => {
73
+ onUiUpdate: onUiUpdate ?? ((event) => {
67
74
  this.emit(event);
68
- },
75
+ }),
76
+ getSystemPromptSuffix: () => this.buildAnnotationSuffix(),
69
77
  });
70
78
  };
71
79
  this.agent = this.buildAgent();
@@ -118,13 +126,23 @@ export class AgentBridge {
118
126
  }
119
127
  // Session operations
120
128
  async saveSess(label) {
121
- return saveSession(this.agent.getSession(), label);
129
+ const annotationsObj = this.annotations.size > 0
130
+ ? Object.fromEntries(this.annotations)
131
+ : undefined;
132
+ return saveSession(this.agent.getSession(), label, annotationsObj);
122
133
  }
123
134
  async loadSess(label) {
124
135
  const result = (await loadSessionByLabel(label)) ?? (await loadSession(label));
125
136
  if (!result)
126
137
  return null;
127
138
  this.agent = this.buildAgent(result.session);
139
+ // Restore annotations from saved session
140
+ this.annotations.clear();
141
+ if (result.annotations) {
142
+ for (const [name, notes] of Object.entries(result.annotations)) {
143
+ this.annotations.set(name, notes);
144
+ }
145
+ }
128
146
  return result;
129
147
  }
130
148
  async listSess() {
@@ -230,4 +248,109 @@ export class AgentBridge {
230
248
  this.pinnedSymbols.delete(sym.qualifiedName);
231
249
  return true;
232
250
  }
251
+ // ── Annotations ──
252
+ getAnnotations() {
253
+ this.evictStaleAnnotations();
254
+ return Object.fromEntries(this.annotations);
255
+ }
256
+ getAnnotationsForSymbol(name) {
257
+ return this.annotations.get(name) ?? [];
258
+ }
259
+ addAnnotation(name, text) {
260
+ if (!this.projectIndex)
261
+ return false;
262
+ const sym = this.projectIndex.getSymbol(name);
263
+ if (!sym)
264
+ return false;
265
+ const trimmed = text.slice(0, 500).trim();
266
+ if (trimmed.length === 0)
267
+ return false;
268
+ const key = sym.qualifiedName;
269
+ const existing = this.annotations.get(key) ?? [];
270
+ existing.push(trimmed);
271
+ this.annotations.set(key, existing);
272
+ return true;
273
+ }
274
+ removeAnnotation(name, index) {
275
+ const notes = this.annotations.get(name);
276
+ if (!notes || index < 0 || index >= notes.length)
277
+ return false;
278
+ notes.splice(index, 1);
279
+ if (notes.length === 0) {
280
+ this.annotations.delete(name);
281
+ }
282
+ return true;
283
+ }
284
+ clearAnnotations(name) {
285
+ this.annotations.delete(name);
286
+ }
287
+ evictStaleAnnotations() {
288
+ if (!this.projectIndex)
289
+ return;
290
+ for (const name of [...this.annotations.keys()]) {
291
+ if (!this.projectIndex.getSymbol(name)) {
292
+ this.annotations.delete(name);
293
+ }
294
+ }
295
+ }
296
+ buildAnnotationSuffix() {
297
+ this.evictStaleAnnotations();
298
+ if (this.annotations.size === 0)
299
+ return undefined;
300
+ return `[Annotated symbols: ${[...this.annotations.keys()].join(", ")}]`;
301
+ }
302
+ appendAnnotationsToResult(toolName, input, result) {
303
+ if (this.annotations.size === 0)
304
+ return result;
305
+ const inp = input;
306
+ if (toolName === "read_symbol" || toolName === "find_references" || toolName === "get_dependencies") {
307
+ const symName = (inp.name ?? inp.symbol ?? inp.query);
308
+ if (!symName)
309
+ return result;
310
+ // Try direct match, then resolve via index
311
+ let notes = this.annotations.get(symName);
312
+ if (!notes && this.projectIndex) {
313
+ const sym = this.projectIndex.getSymbol(symName);
314
+ if (sym)
315
+ notes = this.annotations.get(sym.qualifiedName);
316
+ }
317
+ if (notes && notes.length > 0) {
318
+ return result + `\n[User annotation: ${notes.join("; ")}]`;
319
+ }
320
+ }
321
+ if (toolName === "read_file") {
322
+ const filePath = inp.path;
323
+ if (!filePath)
324
+ return result;
325
+ const fileAnnotations = [];
326
+ for (const [name, notes] of this.annotations) {
327
+ if (!this.projectIndex)
328
+ continue;
329
+ const sym = this.projectIndex.getSymbol(name);
330
+ if (sym && (sym.filePath === filePath || filePath.endsWith(sym.filePath))) {
331
+ fileAnnotations.push(`- ${sym.name}: ${notes.join("; ")}`);
332
+ }
333
+ }
334
+ if (fileAnnotations.length > 0) {
335
+ return result + `\n[User annotations for symbols in this file:]\n${fileAnnotations.join("\n")}`;
336
+ }
337
+ }
338
+ return result;
339
+ }
340
+ // ── Explain ──
341
+ async explainSymbol(name, onEvent, signal) {
342
+ if (!this.projectIndex)
343
+ throw new Error("No project index");
344
+ const sym = this.projectIndex.getSymbol(name);
345
+ if (!sym)
346
+ throw new Error(`Symbol "${name}" not found`);
347
+ const explainAgent = this.buildAgent(undefined, onEvent);
348
+ const prompt = `Explain "${sym.name}" (${sym.kind} in ${sym.filePath}).
349
+ Use read_symbol, get_dependencies, find_references to gather context.
350
+ Explain what it does, how it works, what depends on it, and key design decisions.
351
+ Be concise but thorough.`;
352
+ const opts = signal ? { signal } : undefined;
353
+ const result = await explainAgent.runTurn(prompt, opts);
354
+ return result.text;
355
+ }
233
356
  }
@@ -7,10 +7,12 @@ import { createWebSocketServer } from "./websocket.js";
7
7
  import { handleChatCompletions, handleModels } from "./openai-compat.js";
8
8
  import { formatConfigForDisplay } from "../agent/config.js";
9
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
- // Resolve web dir: works in both dev (src/serve/) and dist (dist/src/serve/)
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
11
13
  const webDir = __dirname.includes(`${path.sep}dist${path.sep}`)
12
- ? path.resolve(__dirname, "../../src/web")
13
- : path.resolve(__dirname, "../web");
14
+ ? path.resolve(__dirname, "../web")
15
+ : path.resolve(__dirname, "../../dist/src/web");
14
16
  const MIME_TYPES = {
15
17
  ".html": "text/html",
16
18
  ".css": "text/css",
@@ -133,6 +135,26 @@ export function createRequestHandler(bridge) {
133
135
  sendJson(res, 200, { symbol: name, references: result });
134
136
  return;
135
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
+ }
136
158
  if (pathname === "/api/code-map" && method === "GET") {
137
159
  const budgetParam = url.searchParams.get("budget");
138
160
  const budget = budgetParam ? Number(budgetParam) : undefined;
@@ -180,6 +202,82 @@ export function createRequestHandler(bridge) {
180
202
  sendJson(res, 400, { error: `Unknown action "${body.action}". Use "pin" or "unpin".` });
181
203
  return;
182
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
+ }
183
281
  if (pathname === "/api/chat" && method === "POST") {
184
282
  const body = JSON.parse(await readBody(req));
185
283
  if (!body.message) {
@@ -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 {
@@ -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(),