@staff0rd/assist 0.170.3 → 0.171.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 (2) hide show
  1. package/dist/index.js +560 -223
  2. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.170.3",
9
+ version: "0.171.1",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -38,6 +38,7 @@ var package_default = {
38
38
  url: "https://github.com/staff0rd/assist"
39
39
  },
40
40
  dependencies: {
41
+ "better-sqlite3": "^12.8.0",
41
42
  chalk: "^5.6.2",
42
43
  commander: "^14.0.2",
43
44
  diff: "^8.0.2",
@@ -59,6 +60,7 @@ var package_default = {
59
60
  "@semantic-release/changelog": "^6.0.3",
60
61
  "@semantic-release/exec": "^7.1.0",
61
62
  "@semantic-release/git": "^10.0.1",
63
+ "@types/better-sqlite3": "^7.6.13",
62
64
  "@types/node": "^24.10.1",
63
65
  "@types/node-notifier": "^8.0.5",
64
66
  "@types/react": "^19.2.14",
@@ -97,14 +99,210 @@ async function exitOnCancel(promise) {
97
99
  }
98
100
 
99
101
  // src/commands/backlog/acquireLock.ts
100
- import { existsSync as existsSync2, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
101
- import { join as join2 } from "path";
102
+ import { existsSync as existsSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
103
+ import { join as join4 } from "path";
102
104
 
103
105
  // src/commands/backlog/shared.ts
104
- import { existsSync, readFileSync, writeFileSync } from "fs";
105
- import { join } from "path";
106
+ import { join as join3 } from "path";
106
107
  import chalk from "chalk";
107
- import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
108
+
109
+ // src/commands/backlog/deleteItemRelations.ts
110
+ function deleteItemRelations(db, itemId) {
111
+ db.prepare("DELETE FROM plan_tasks WHERE item_id = ?").run(itemId);
112
+ db.prepare("DELETE FROM plan_phases WHERE item_id = ?").run(itemId);
113
+ db.prepare("DELETE FROM comments WHERE item_id = ?").run(itemId);
114
+ db.prepare("DELETE FROM links WHERE item_id = ?").run(itemId);
115
+ }
116
+
117
+ // src/commands/backlog/deleteItem.ts
118
+ function deleteItem(db, id) {
119
+ const del2 = db.transaction(() => {
120
+ deleteItemRelations(db, id);
121
+ const result = db.prepare("DELETE FROM items WHERE id = ?").run(id);
122
+ return result.changes > 0;
123
+ });
124
+ return del2();
125
+ }
126
+
127
+ // src/commands/backlog/exportToJsonl.ts
128
+ import { statSync, writeFileSync } from "fs";
129
+ import { join } from "path";
130
+
131
+ // src/commands/backlog/loadComments.ts
132
+ function loadComments(db, itemId) {
133
+ const rows = db.prepare(
134
+ "SELECT text, phase, timestamp, type FROM comments WHERE item_id = ? ORDER BY idx"
135
+ ).all(itemId);
136
+ return rows.map((r) => {
137
+ const c = {
138
+ text: r.text,
139
+ timestamp: r.timestamp,
140
+ type: r.type
141
+ };
142
+ if (r.phase != null) c.phase = r.phase;
143
+ return c;
144
+ });
145
+ }
146
+
147
+ // src/commands/backlog/loadPlan.ts
148
+ function toPhase(db, itemId, p) {
149
+ const tasks = db.prepare(
150
+ "SELECT task, verify FROM plan_tasks WHERE item_id = ? AND phase_idx = ? ORDER BY idx"
151
+ ).all(itemId, p.idx);
152
+ const phase = {
153
+ name: p.name,
154
+ tasks: tasks.map((t) => ({
155
+ task: t.task,
156
+ ...t.verify != null ? { verify: t.verify } : {}
157
+ }))
158
+ };
159
+ if (p.manual_checks) {
160
+ phase.manualChecks = JSON.parse(p.manual_checks);
161
+ }
162
+ return phase;
163
+ }
164
+ function loadPlan(db, itemId) {
165
+ const phases = db.prepare(
166
+ "SELECT idx, name, manual_checks FROM plan_phases WHERE item_id = ? ORDER BY idx"
167
+ ).all(itemId);
168
+ if (phases.length === 0) return void 0;
169
+ return phases.map((p) => toPhase(db, itemId, p));
170
+ }
171
+
172
+ // src/commands/backlog/loadAllItems.ts
173
+ function loadLinks(db, itemId) {
174
+ return db.prepare("SELECT type, target_id as targetId FROM links WHERE item_id = ?").all(itemId);
175
+ }
176
+ function rowToItem(db, row) {
177
+ const comments2 = loadComments(db, row.id);
178
+ const links = loadLinks(db, row.id);
179
+ const plan2 = loadPlan(db, row.id);
180
+ const item = {
181
+ id: row.id,
182
+ type: row.type,
183
+ name: row.name,
184
+ acceptanceCriteria: JSON.parse(row.acceptance_criteria),
185
+ status: row.status
186
+ };
187
+ if (row.description != null) item.description = row.description;
188
+ if (row.current_phase != null) item.currentPhase = row.current_phase;
189
+ if (comments2.length > 0) item.comments = comments2;
190
+ if (links && links.length > 0) item.links = links;
191
+ if (plan2) item.plan = plan2;
192
+ return item;
193
+ }
194
+ function loadAllItems(db) {
195
+ const rows = db.prepare("SELECT * FROM items ORDER BY id").all();
196
+ return rows.map((row) => rowToItem(db, row));
197
+ }
198
+
199
+ // src/commands/backlog/exportToJsonl.ts
200
+ function getJsonlPath(dir) {
201
+ return join(dir, ".assist", "backlog.jsonl");
202
+ }
203
+ function exportToJsonl(db, dir) {
204
+ const jsonlPath = getJsonlPath(dir);
205
+ const items = loadAllItems(db);
206
+ const lines = items.map((item) => JSON.stringify(item));
207
+ writeFileSync(jsonlPath, lines.length > 0 ? `${lines.join("\n")}
208
+ ` : "");
209
+ const mtimeMs = statSync(jsonlPath).mtimeMs;
210
+ db.prepare(
211
+ "INSERT INTO metadata (key, value) VALUES ('jsonl_last_import_ms', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
212
+ ).run(String(mtimeMs));
213
+ }
214
+
215
+ // src/commands/backlog/importFromJsonlIfNeeded.ts
216
+ import { readFileSync, statSync as statSync2 } from "fs";
217
+
218
+ // src/commands/backlog/insertItemRelations.ts
219
+ function insertComments(db, item) {
220
+ if (!item.comments) return;
221
+ const stmt = db.prepare(
222
+ "INSERT INTO comments (item_id, idx, text, phase, timestamp, type) VALUES (?, ?, ?, ?, ?, ?)"
223
+ );
224
+ for (let i = 0; i < item.comments.length; i++) {
225
+ const c = item.comments[i];
226
+ stmt.run(item.id, i, c.text, c.phase ?? null, c.timestamp, c.type);
227
+ }
228
+ }
229
+ function insertLinks(db, item) {
230
+ if (!item.links) return;
231
+ const stmt = db.prepare(
232
+ "INSERT INTO links (item_id, type, target_id) VALUES (?, ?, ?)"
233
+ );
234
+ for (const l of item.links) {
235
+ stmt.run(item.id, l.type, l.targetId);
236
+ }
237
+ }
238
+ function insertPlan(db, item) {
239
+ if (!item.plan) return;
240
+ const phaseStmt = db.prepare(
241
+ "INSERT INTO plan_phases (item_id, idx, name, manual_checks) VALUES (?, ?, ?, ?)"
242
+ );
243
+ const taskStmt = db.prepare(
244
+ "INSERT INTO plan_tasks (item_id, phase_idx, idx, task, verify) VALUES (?, ?, ?, ?, ?)"
245
+ );
246
+ for (let pi = 0; pi < item.plan.length; pi++) {
247
+ const phase = item.plan[pi];
248
+ phaseStmt.run(
249
+ item.id,
250
+ pi,
251
+ phase.name,
252
+ phase.manualChecks ? JSON.stringify(phase.manualChecks) : null
253
+ );
254
+ for (let ti = 0; ti < phase.tasks.length; ti++) {
255
+ const task = phase.tasks[ti];
256
+ taskStmt.run(item.id, pi, ti, task.task, task.verify ?? null);
257
+ }
258
+ }
259
+ }
260
+ function insertItemRelations(db, item) {
261
+ insertComments(db, item);
262
+ insertLinks(db, item);
263
+ insertPlan(db, item);
264
+ }
265
+
266
+ // src/commands/backlog/saveAllItems.ts
267
+ function upsertItem(db, item) {
268
+ db.prepare(
269
+ `INSERT INTO items (id, type, name, description, acceptance_criteria, status, current_phase)
270
+ VALUES (?, ?, ?, ?, ?, ?, ?)
271
+ ON CONFLICT(id) DO UPDATE SET
272
+ type = excluded.type,
273
+ name = excluded.name,
274
+ description = excluded.description,
275
+ acceptance_criteria = excluded.acceptance_criteria,
276
+ status = excluded.status,
277
+ current_phase = excluded.current_phase`
278
+ ).run(
279
+ item.id,
280
+ item.type,
281
+ item.name,
282
+ item.description ?? null,
283
+ JSON.stringify(item.acceptanceCriteria),
284
+ item.status,
285
+ item.currentPhase ?? null
286
+ );
287
+ deleteItemRelations(db, item.id);
288
+ insertItemRelations(db, item);
289
+ }
290
+ function saveAllItems(db, items) {
291
+ const save = db.transaction(() => {
292
+ const existingIds = db.prepare("SELECT id FROM items").all();
293
+ const newIds = new Set(items.map((i) => i.id));
294
+ for (const { id } of existingIds) {
295
+ if (!newIds.has(id)) {
296
+ deleteItemRelations(db, id);
297
+ db.prepare("DELETE FROM items WHERE id = ?").run(id);
298
+ }
299
+ }
300
+ for (const item of items) {
301
+ upsertItem(db, item);
302
+ }
303
+ });
304
+ save();
305
+ }
108
306
 
109
307
  // src/commands/backlog/types.ts
110
308
  import { z } from "zod";
@@ -145,6 +343,143 @@ var backlogItemSchema = z.strictObject({
145
343
  });
146
344
  var backlogFileSchema = z.array(backlogItemSchema);
147
345
 
346
+ // src/commands/backlog/importFromJsonlIfNeeded.ts
347
+ function getLastImportMs(db) {
348
+ const row = db.prepare("SELECT value FROM metadata WHERE key = 'jsonl_last_import_ms'").get();
349
+ return row ? Number(row.value) : 0;
350
+ }
351
+ function setLastImportMs(db, ms) {
352
+ db.prepare(
353
+ "INSERT INTO metadata (key, value) VALUES ('jsonl_last_import_ms', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
354
+ ).run(String(ms));
355
+ }
356
+ function importFromJsonlIfNeeded(db, dir) {
357
+ const jsonlPath = getJsonlPath(dir);
358
+ let stat;
359
+ try {
360
+ stat = statSync2(jsonlPath);
361
+ } catch {
362
+ return;
363
+ }
364
+ const fileMtimeMs = stat.mtimeMs;
365
+ const lastImportMs = getLastImportMs(db);
366
+ if (fileMtimeMs <= lastImportMs) return;
367
+ const content = readFileSync(jsonlPath, "utf-8").trim();
368
+ if (content.length === 0) {
369
+ setLastImportMs(db, fileMtimeMs);
370
+ return;
371
+ }
372
+ const items = content.split("\n").map((line) => {
373
+ const parsed = JSON.parse(line);
374
+ return backlogItemSchema.parse(parsed);
375
+ });
376
+ saveAllItems(db, items);
377
+ setLastImportMs(db, fileMtimeMs);
378
+ }
379
+
380
+ // src/commands/backlog/migrateYamlIfNeeded.ts
381
+ import { existsSync, readFileSync as readFileSync2, renameSync } from "fs";
382
+ import { parse as parseYaml } from "yaml";
383
+ function migrateYamlIfNeeded(db, yamlPath) {
384
+ if (!existsSync(yamlPath)) return false;
385
+ const existing = db.prepare("SELECT COUNT(*) as count FROM items").get();
386
+ if (existing.count > 0) return false;
387
+ const content = readFileSync2(yamlPath, "utf-8");
388
+ const raw = parseYaml(content) || [];
389
+ const items = backlogFileSchema.parse(raw);
390
+ if (items.length > 0) {
391
+ saveAllItems(db, items);
392
+ renameSync(yamlPath, `${yamlPath}.bak`);
393
+ return true;
394
+ }
395
+ return false;
396
+ }
397
+
398
+ // src/commands/backlog/openDb.ts
399
+ import { mkdirSync } from "fs";
400
+ import { join as join2 } from "path";
401
+ import Database from "better-sqlite3";
402
+ var _db;
403
+ function getDbPath(dir) {
404
+ return join2(dir, ".assist", "backlog.db");
405
+ }
406
+ function initSchema(db) {
407
+ db.exec(`
408
+ CREATE TABLE IF NOT EXISTS items (
409
+ id INTEGER PRIMARY KEY,
410
+ type TEXT NOT NULL DEFAULT 'story',
411
+ name TEXT NOT NULL,
412
+ description TEXT,
413
+ acceptance_criteria TEXT NOT NULL DEFAULT '[]',
414
+ status TEXT NOT NULL DEFAULT 'todo',
415
+ current_phase INTEGER
416
+ );
417
+
418
+ CREATE TABLE IF NOT EXISTS comments (
419
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
420
+ idx INTEGER NOT NULL,
421
+ text TEXT NOT NULL,
422
+ phase INTEGER,
423
+ timestamp TEXT NOT NULL,
424
+ type TEXT NOT NULL DEFAULT 'comment',
425
+ PRIMARY KEY (item_id, idx)
426
+ );
427
+
428
+ CREATE TABLE IF NOT EXISTS links (
429
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
430
+ type TEXT NOT NULL,
431
+ target_id INTEGER NOT NULL,
432
+ PRIMARY KEY (item_id, type, target_id)
433
+ );
434
+
435
+ CREATE TABLE IF NOT EXISTS plan_phases (
436
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
437
+ idx INTEGER NOT NULL,
438
+ name TEXT NOT NULL,
439
+ manual_checks TEXT,
440
+ PRIMARY KEY (item_id, idx)
441
+ );
442
+
443
+ CREATE TABLE IF NOT EXISTS plan_tasks (
444
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
445
+ phase_idx INTEGER NOT NULL,
446
+ idx INTEGER NOT NULL,
447
+ task TEXT NOT NULL,
448
+ verify TEXT,
449
+ PRIMARY KEY (item_id, phase_idx, idx),
450
+ FOREIGN KEY (item_id, phase_idx) REFERENCES plan_phases(item_id, idx) ON DELETE CASCADE
451
+ );
452
+
453
+ CREATE TABLE IF NOT EXISTS metadata (
454
+ key TEXT PRIMARY KEY,
455
+ value TEXT NOT NULL
456
+ );
457
+ `);
458
+ }
459
+ function openDb(dir) {
460
+ if (_db) return _db;
461
+ const dbPath = getDbPath(dir);
462
+ mkdirSync(join2(dir, ".assist"), { recursive: true });
463
+ const db = new Database(dbPath);
464
+ db.pragma("journal_mode = WAL");
465
+ db.pragma("foreign_keys = ON");
466
+ initSchema(db);
467
+ _db = db;
468
+ return db;
469
+ }
470
+
471
+ // src/commands/backlog/updateCurrentPhase.ts
472
+ function updateCurrentPhase(db, id, phase) {
473
+ const result = db.prepare("UPDATE items SET current_phase = ? WHERE id = ?").run(phase, id);
474
+ return result.changes > 0;
475
+ }
476
+
477
+ // src/commands/backlog/updateStatus.ts
478
+ function updateStatus(db, id, status2) {
479
+ const result = db.prepare("UPDATE items SET status = ? WHERE id = ?").run(status2, id);
480
+ return result.changes > 0;
481
+ }
482
+
148
483
  // src/commands/backlog/shared.ts
149
484
  var _backlogDir;
150
485
  function setBacklogDir(dir) {
@@ -154,33 +489,29 @@ function getBacklogDir() {
154
489
  return _backlogDir ?? process.cwd();
155
490
  }
156
491
  function getBacklogPath() {
157
- return join(getBacklogDir(), "assist.backlog.yml");
492
+ return join3(getBacklogDir(), "assist.backlog.yml");
493
+ }
494
+ function getDb() {
495
+ const dir = getBacklogDir();
496
+ const db = openDb(dir);
497
+ const migrated = migrateYamlIfNeeded(db, getBacklogPath());
498
+ if (migrated) exportToJsonl(db, dir);
499
+ return db;
158
500
  }
159
501
  function loadBacklog() {
160
- const backlogPath = getBacklogPath();
161
- if (!existsSync(backlogPath)) {
162
- return [];
163
- }
164
- const content = readFileSync(backlogPath, "utf-8");
165
- const raw = parseYaml(content) || [];
166
- return backlogFileSchema.parse(raw);
502
+ const db = getDb();
503
+ importFromJsonlIfNeeded(db, getBacklogDir());
504
+ return loadAllItems(db);
167
505
  }
168
506
  function saveBacklog(items) {
169
- const backlogPath = getBacklogPath();
170
- writeFileSync(backlogPath, stringifyYaml(items, { lineWidth: 0 }));
507
+ const db = getDb();
508
+ saveAllItems(db, items);
509
+ exportToJsonl(db, getBacklogDir());
171
510
  }
172
511
  function findItem(items, id) {
173
512
  return items.find((item) => item.id === id);
174
513
  }
175
514
  function loadAndFindItem(id) {
176
- if (!existsSync(getBacklogPath())) {
177
- console.log(
178
- chalk.yellow(
179
- "No backlog found. Run 'assist backlog init' to create one."
180
- )
181
- );
182
- return void 0;
183
- }
184
515
  const items = loadBacklog();
185
516
  const item = findItem(items, Number.parseInt(id, 10));
186
517
  if (!item) {
@@ -192,20 +523,24 @@ function loadAndFindItem(id) {
192
523
  function setStatus(id, status2) {
193
524
  const result = loadAndFindItem(id);
194
525
  if (!result) return void 0;
195
- result.item.status = status2;
196
- saveBacklog(result.items);
526
+ const db = getDb();
527
+ updateStatus(db, result.item.id, status2);
528
+ exportToJsonl(db, getBacklogDir());
197
529
  return result.item.name;
198
530
  }
199
531
  function setCurrentPhase(id, phase) {
200
532
  const result = loadAndFindItem(id);
201
533
  if (!result) return;
202
- result.item.currentPhase = phase;
203
- saveBacklog(result.items);
534
+ const db = getDb();
535
+ updateCurrentPhase(db, result.item.id, phase);
536
+ exportToJsonl(db, getBacklogDir());
204
537
  }
205
538
  function removeItem(id) {
206
539
  const result = loadAndFindItem(id);
207
540
  if (!result) return void 0;
208
- saveBacklog(result.items.filter((i) => i.id !== result.item.id));
541
+ const db = getDb();
542
+ deleteItem(db, result.item.id);
543
+ exportToJsonl(db, getBacklogDir());
209
544
  return result.item.name;
210
545
  }
211
546
  function getNextId(items) {
@@ -215,7 +550,7 @@ function getNextId(items) {
215
550
 
216
551
  // src/commands/backlog/acquireLock.ts
217
552
  function getLockPath(itemId) {
218
- return join2(getBacklogDir(), `.assist-lock-${itemId}.json`);
553
+ return join4(getBacklogDir(), `.assist-lock-${itemId}.json`);
219
554
  }
220
555
  function isProcessAlive(pid) {
221
556
  try {
@@ -229,7 +564,7 @@ function isLockedByOther(itemId) {
229
564
  const lockPath = getLockPath(itemId);
230
565
  if (!existsSync2(lockPath)) return false;
231
566
  try {
232
- const lock = JSON.parse(readFileSync2(lockPath, "utf-8"));
567
+ const lock = JSON.parse(readFileSync3(lockPath, "utf-8"));
233
568
  if (lock.pid === process.pid) return false;
234
569
  return isProcessAlive(lock.pid);
235
570
  } catch {
@@ -438,10 +773,10 @@ async function handleIncompletePhase() {
438
773
 
439
774
  // src/commands/backlog/writeSignal.ts
440
775
  import { writeFileSync as writeFileSync3 } from "fs";
441
- import { join as join3 } from "path";
776
+ import { join as join5 } from "path";
442
777
  var SIGNAL_FILE = ".assist-signal.json";
443
778
  function getSignalPath() {
444
- return join3(getBacklogDir(), SIGNAL_FILE);
779
+ return join5(getBacklogDir(), SIGNAL_FILE);
445
780
  }
446
781
  function writeSignal(event, data) {
447
782
  const sessionId = process.env.ASSIST_SESSION_ID;
@@ -489,12 +824,12 @@ function spawnClaude(prompt, options2 = {}) {
489
824
  import { existsSync as existsSync5, unwatchFile, watchFile } from "fs";
490
825
 
491
826
  // src/commands/backlog/readSignal.ts
492
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
827
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
493
828
  function readSignal() {
494
829
  const path50 = getSignalPath();
495
830
  if (!existsSync4(path50)) return void 0;
496
831
  try {
497
- return JSON.parse(readFileSync3(path50, "utf-8"));
832
+ return JSON.parse(readFileSync4(path50, "utf-8"));
498
833
  } catch {
499
834
  return void 0;
500
835
  }
@@ -862,11 +1197,11 @@ function printComments(item) {
862
1197
 
863
1198
  // src/shared/web.ts
864
1199
  import { exec } from "child_process";
865
- import { readFileSync as readFileSync4 } from "fs";
1200
+ import { readFileSync as readFileSync5 } from "fs";
866
1201
  import {
867
1202
  createServer
868
1203
  } from "http";
869
- import { dirname, join as join4 } from "path";
1204
+ import { dirname, join as join6 } from "path";
870
1205
  import { fileURLToPath } from "url";
871
1206
  import chalk14 from "chalk";
872
1207
  function respondJson(res, status2, data) {
@@ -878,7 +1213,7 @@ function createBundleHandler(importMetaUrl, bundlePath) {
878
1213
  let cache;
879
1214
  return (_req, res) => {
880
1215
  if (!cache) {
881
- cache = readFileSync4(join4(dir, bundlePath), "utf-8");
1216
+ cache = readFileSync5(join6(dir, bundlePath), "utf-8");
882
1217
  }
883
1218
  res.writeHead(200, { "Content-Type": "application/javascript" });
884
1219
  res.end(cache);
@@ -991,7 +1326,7 @@ async function createItem(req, res) {
991
1326
  saveBacklog(items);
992
1327
  respondJson(res, 201, newItem);
993
1328
  }
994
- function deleteItem(res, id) {
1329
+ function deleteItem2(res, id) {
995
1330
  const result = findItemOr404(res, id);
996
1331
  if (!result) return;
997
1332
  saveBacklog(result.items.filter((i) => i.id !== id));
@@ -1033,7 +1368,7 @@ var itemRoutes = {
1033
1368
  GET: (_req, res, id) => getItemById(res, id),
1034
1369
  PUT: (req, res, id) => updateItem(req, res, id),
1035
1370
  PATCH: (req, res, id) => patchItemStatus(req, res, id),
1036
- DELETE: (_req, res, id) => deleteItem(res, id)
1371
+ DELETE: (_req, res, id) => deleteItem2(res, id)
1037
1372
  };
1038
1373
  var baseHandler = createRouteHandler(routes);
1039
1374
  async function handleRequest(req, res, port) {
@@ -1080,19 +1415,19 @@ async function launchMode(slashCommand) {
1080
1415
  import { execSync } from "child_process";
1081
1416
 
1082
1417
  // src/shared/loadConfig.ts
1083
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
1418
+ import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
1084
1419
  import { homedir } from "os";
1085
- import { basename, dirname as dirname2, join as join5 } from "path";
1420
+ import { basename, dirname as dirname2, join as join7 } from "path";
1086
1421
  import chalk16 from "chalk";
1087
- import { stringify as stringifyYaml2 } from "yaml";
1422
+ import { stringify as stringifyYaml } from "yaml";
1088
1423
 
1089
1424
  // src/shared/loadRawYaml.ts
1090
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1425
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
1091
1426
  import { parse as parseYaml2 } from "yaml";
1092
1427
  function loadRawYaml(path50) {
1093
1428
  if (!existsSync6(path50)) return {};
1094
1429
  try {
1095
- const content = readFileSync5(path50, "utf-8");
1430
+ const content = readFileSync6(path50, "utf-8");
1096
1431
  return parseYaml2(content) || {};
1097
1432
  } catch {
1098
1433
  return {};
@@ -1222,9 +1557,9 @@ var assistConfigSchema = z2.strictObject({
1222
1557
  function findConfigUp(startDir) {
1223
1558
  let current = startDir;
1224
1559
  while (current !== dirname2(current)) {
1225
- const claudePath = join5(current, ".claude", "assist.yml");
1560
+ const claudePath = join7(current, ".claude", "assist.yml");
1226
1561
  if (existsSync7(claudePath)) return claudePath;
1227
- const rootPath = join5(current, "assist.yml");
1562
+ const rootPath = join7(current, "assist.yml");
1228
1563
  if (existsSync7(rootPath)) return rootPath;
1229
1564
  current = dirname2(current);
1230
1565
  }
@@ -1233,10 +1568,10 @@ function findConfigUp(startDir) {
1233
1568
  function getConfigPath() {
1234
1569
  const found = findConfigUp(process.cwd());
1235
1570
  if (found) return found;
1236
- return join5(process.cwd(), "assist.yml");
1571
+ return join7(process.cwd(), "assist.yml");
1237
1572
  }
1238
1573
  function getGlobalConfigPath() {
1239
- return join5(homedir(), ".assist.yml");
1574
+ return join7(homedir(), ".assist.yml");
1240
1575
  }
1241
1576
  function loadConfig() {
1242
1577
  const globalRaw = loadRawYaml(getGlobalConfigPath());
@@ -1251,21 +1586,21 @@ function loadGlobalConfigRaw() {
1251
1586
  return loadRawYaml(getGlobalConfigPath());
1252
1587
  }
1253
1588
  function saveGlobalConfig(config) {
1254
- writeFileSync4(getGlobalConfigPath(), stringifyYaml2(config, { lineWidth: 0 }));
1589
+ writeFileSync4(getGlobalConfigPath(), stringifyYaml(config, { lineWidth: 0 }));
1255
1590
  }
1256
1591
  function saveConfig(config) {
1257
1592
  const configPath = getConfigPath();
1258
- writeFileSync4(configPath, stringifyYaml2(config, { lineWidth: 0 }));
1593
+ writeFileSync4(configPath, stringifyYaml(config, { lineWidth: 0 }));
1259
1594
  }
1260
1595
  function getRepoName() {
1261
1596
  const config = loadConfig();
1262
1597
  if (config.devlog?.name) {
1263
1598
  return config.devlog.name;
1264
1599
  }
1265
- const packageJsonPath = join5(process.cwd(), "package.json");
1600
+ const packageJsonPath = join7(process.cwd(), "package.json");
1266
1601
  if (existsSync7(packageJsonPath)) {
1267
1602
  try {
1268
- const content = readFileSync6(packageJsonPath, "utf-8");
1603
+ const content = readFileSync7(packageJsonPath, "utf-8");
1269
1604
  const pkg = JSON.parse(content);
1270
1605
  if (pkg.name) {
1271
1606
  return pkg.name;
@@ -1369,7 +1704,7 @@ function commit(args) {
1369
1704
 
1370
1705
  // src/commands/config/index.ts
1371
1706
  import chalk17 from "chalk";
1372
- import { stringify as stringifyYaml3 } from "yaml";
1707
+ import { stringify as stringifyYaml2 } from "yaml";
1373
1708
 
1374
1709
  // src/commands/config/setNestedValue.ts
1375
1710
  function isPlainObject(val) {
@@ -1476,7 +1811,7 @@ function configSet(key, value, options2 = {}) {
1476
1811
  }
1477
1812
  function configList() {
1478
1813
  const config = loadConfig();
1479
- console.log(stringifyYaml3(config, { lineWidth: 0 }).trimEnd());
1814
+ console.log(stringifyYaml2(config, { lineWidth: 0 }).trimEnd());
1480
1815
  }
1481
1816
 
1482
1817
  // src/commands/config/configGet.ts
@@ -1714,17 +2049,17 @@ import * as path3 from "path";
1714
2049
  import chalk25 from "chalk";
1715
2050
 
1716
2051
  // src/commands/verify/addToKnipIgnoreBinaries.ts
1717
- import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
1718
- import { join as join7 } from "path";
2052
+ import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
2053
+ import { join as join9 } from "path";
1719
2054
  import chalk24 from "chalk";
1720
2055
  function loadKnipConfig(knipJsonPath) {
1721
2056
  if (existsSync9(knipJsonPath)) {
1722
- return JSON.parse(readFileSync8(knipJsonPath, "utf-8"));
2057
+ return JSON.parse(readFileSync9(knipJsonPath, "utf-8"));
1723
2058
  }
1724
2059
  return { $schema: "https://unpkg.com/knip@5/schema.json" };
1725
2060
  }
1726
2061
  function addToKnipIgnoreBinaries(cwd, binary) {
1727
- const knipJsonPath = join7(cwd, "knip.json");
2062
+ const knipJsonPath = join9(cwd, "knip.json");
1728
2063
  try {
1729
2064
  const knipConfig = loadKnipConfig(knipJsonPath);
1730
2065
  const ignoreBinaries = knipConfig.ignoreBinaries ?? [];
@@ -1772,8 +2107,8 @@ import chalk29 from "chalk";
1772
2107
 
1773
2108
  // src/commands/lint/init.ts
1774
2109
  import { execSync as execSync5 } from "child_process";
1775
- import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
1776
- import { dirname as dirname7, join as join8 } from "path";
2110
+ import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
2111
+ import { dirname as dirname7, join as join10 } from "path";
1777
2112
  import { fileURLToPath as fileURLToPath2 } from "url";
1778
2113
  import chalk28 from "chalk";
1779
2114
 
@@ -1798,7 +2133,7 @@ async function promptConfirm(message, initial = true) {
1798
2133
 
1799
2134
  // src/shared/removeEslint/index.ts
1800
2135
  import { execSync as execSync4 } from "child_process";
1801
- import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
2136
+ import { existsSync as existsSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
1802
2137
 
1803
2138
  // src/shared/removeEslint/removeEslintConfigFiles.ts
1804
2139
  import { existsSync as existsSync10, unlinkSync as unlinkSync3 } from "fs";
@@ -1842,7 +2177,7 @@ function removeEslintFromPackageJson(options2) {
1842
2177
  if (!existsSync11(packageJsonPath)) {
1843
2178
  return false;
1844
2179
  }
1845
- const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
2180
+ const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
1846
2181
  let modified = false;
1847
2182
  modified = removeEslintDeps(packageJson.dependencies) || modified;
1848
2183
  modified = removeEslintDeps(packageJson.devDependencies) || modified;
@@ -1920,9 +2255,9 @@ async function init() {
1920
2255
  console.log("No biome.json found, skipping linter config");
1921
2256
  return;
1922
2257
  }
1923
- const linterConfigPath = join8(__dirname2, "commands/lint/biome.linter.json");
1924
- const linterConfig = JSON.parse(readFileSync10(linterConfigPath, "utf-8"));
1925
- const biomeConfig = JSON.parse(readFileSync10(biomeConfigPath, "utf-8"));
2258
+ const linterConfigPath = join10(__dirname2, "commands/lint/biome.linter.json");
2259
+ const linterConfig = JSON.parse(readFileSync11(linterConfigPath, "utf-8"));
2260
+ const biomeConfig = JSON.parse(readFileSync11(biomeConfigPath, "utf-8"));
1926
2261
  const oldContent = `${JSON.stringify(biomeConfig, null, 2)}
1927
2262
  `;
1928
2263
  biomeConfig.linter = linterConfig.linter;
@@ -2980,7 +3315,7 @@ function initPackageJson(name) {
2980
3315
  }
2981
3316
 
2982
3317
  // src/commands/new/registerNew/newCli/writeCliTemplate.ts
2983
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync11 } from "fs";
3318
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync11 } from "fs";
2984
3319
  function writeCliTemplate(name) {
2985
3320
  console.log("Writing tsconfig.json...");
2986
3321
  writeFileSync11(
@@ -3021,7 +3356,7 @@ export default defineConfig({
3021
3356
  `
3022
3357
  );
3023
3358
  console.log("Writing src/index.ts...");
3024
- mkdirSync2("src", { recursive: true });
3359
+ mkdirSync3("src", { recursive: true });
3025
3360
  writeFileSync11(
3026
3361
  "src/index.ts",
3027
3362
  `#!/usr/bin/env node
@@ -3050,7 +3385,7 @@ async function newCli() {
3050
3385
 
3051
3386
  // src/commands/new/registerNew/newProject.ts
3052
3387
  import { execSync as execSync13 } from "child_process";
3053
- import { existsSync as existsSync16, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
3388
+ import { existsSync as existsSync16, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "fs";
3054
3389
 
3055
3390
  // src/commands/deploy/init/index.ts
3056
3391
  import { execSync as execSync12 } from "child_process";
@@ -3058,8 +3393,8 @@ import chalk40 from "chalk";
3058
3393
  import enquirer5 from "enquirer";
3059
3394
 
3060
3395
  // src/commands/deploy/init/updateWorkflow.ts
3061
- import { existsSync as existsSync15, mkdirSync as mkdirSync3, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "fs";
3062
- import { dirname as dirname13, join as join11 } from "path";
3396
+ import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
3397
+ import { dirname as dirname13, join as join13 } from "path";
3063
3398
  import { fileURLToPath as fileURLToPath3 } from "url";
3064
3399
  import chalk39 from "chalk";
3065
3400
  var WORKFLOW_PATH = ".github/workflows/build.yml";
@@ -3068,23 +3403,23 @@ function getExistingSiteId() {
3068
3403
  if (!existsSync15(WORKFLOW_PATH)) {
3069
3404
  return null;
3070
3405
  }
3071
- const content = readFileSync12(WORKFLOW_PATH, "utf-8");
3406
+ const content = readFileSync13(WORKFLOW_PATH, "utf-8");
3072
3407
  const match = content.match(/-s\s+([a-f0-9-]{36})/);
3073
3408
  return match ? match[1] : null;
3074
3409
  }
3075
3410
  function getTemplateContent(siteId) {
3076
- const templatePath = join11(__dirname3, "commands/deploy/build.yml");
3077
- const template = readFileSync12(templatePath, "utf-8");
3411
+ const templatePath = join13(__dirname3, "commands/deploy/build.yml");
3412
+ const template = readFileSync13(templatePath, "utf-8");
3078
3413
  return template.replace("{{NETLIFY_SITE_ID}}", siteId);
3079
3414
  }
3080
3415
  async function updateWorkflow(siteId) {
3081
3416
  const newContent = getTemplateContent(siteId);
3082
3417
  const workflowDir = ".github/workflows";
3083
3418
  if (!existsSync15(workflowDir)) {
3084
- mkdirSync3(workflowDir, { recursive: true });
3419
+ mkdirSync4(workflowDir, { recursive: true });
3085
3420
  }
3086
3421
  if (existsSync15(WORKFLOW_PATH)) {
3087
- const oldContent = readFileSync12(WORKFLOW_PATH, "utf-8");
3422
+ const oldContent = readFileSync13(WORKFLOW_PATH, "utf-8");
3088
3423
  if (oldContent === newContent) {
3089
3424
  console.log(chalk39.green("build.yml is already up to date"));
3090
3425
  return;
@@ -3182,7 +3517,7 @@ function addViteBaseConfig() {
3182
3517
  console.log("No vite.config.ts found, skipping base config");
3183
3518
  return;
3184
3519
  }
3185
- const content = readFileSync13(viteConfigPath, "utf-8");
3520
+ const content = readFileSync14(viteConfigPath, "utf-8");
3186
3521
  if (content.includes("base:")) {
3187
3522
  console.log("vite.config.ts already has base config");
3188
3523
  return;
@@ -3365,12 +3700,13 @@ import chalk45 from "chalk";
3365
3700
 
3366
3701
  // src/commands/backlog/commitBacklog.ts
3367
3702
  import { execSync as execSync14 } from "child_process";
3703
+ import { join as join14 } from "path";
3368
3704
  import chalk43 from "chalk";
3369
3705
  function commitBacklog(id, name) {
3370
3706
  try {
3371
- const backlogPath = getBacklogPath();
3707
+ const jsonlPath = join14(getBacklogDir(), ".assist", "backlog.jsonl");
3372
3708
  const message = `chore: add backlog item #${id} \u2014 ${name}`;
3373
- execSync14(`git add ${shellQuote(backlogPath)}`, { stdio: "ignore" });
3709
+ execSync14(`git add ${shellQuote(jsonlPath)}`, { stdio: "ignore" });
3374
3710
  execSync14(`git commit -m ${shellQuote(message)}`, { stdio: "ignore" });
3375
3711
  } catch {
3376
3712
  console.log(chalk43.yellow("Warning: could not auto-commit backlog file."));
@@ -3378,7 +3714,7 @@ function commitBacklog(id, name) {
3378
3714
  }
3379
3715
 
3380
3716
  // src/commands/backlog/add/parseItemFile.ts
3381
- import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
3717
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
3382
3718
  import chalk44 from "chalk";
3383
3719
  import { ZodError } from "zod";
3384
3720
  var addItemSchema = backlogItemSchema.omit({ id: true, status: true });
@@ -3390,7 +3726,7 @@ function readJsonFile(filePath) {
3390
3726
  }
3391
3727
  let raw;
3392
3728
  try {
3393
- raw = readFileSync14(filePath, "utf-8");
3729
+ raw = readFileSync15(filePath, "utf-8");
3394
3730
  } catch {
3395
3731
  console.log(chalk44.red(`Failed to read file: ${filePath}`));
3396
3732
  process.exitCode = 1;
@@ -3428,9 +3764,9 @@ function parseItemFile(filePath) {
3428
3764
 
3429
3765
  // src/commands/backlog/add/shared.ts
3430
3766
  import { spawnSync } from "child_process";
3431
- import { mkdtempSync, readFileSync as readFileSync15, unlinkSync as unlinkSync4, writeFileSync as writeFileSync14 } from "fs";
3767
+ import { mkdtempSync, readFileSync as readFileSync16, unlinkSync as unlinkSync4, writeFileSync as writeFileSync14 } from "fs";
3432
3768
  import { tmpdir } from "os";
3433
- import { join as join12 } from "path";
3769
+ import { join as join15 } from "path";
3434
3770
  import enquirer6 from "enquirer";
3435
3771
  async function promptType() {
3436
3772
  const { type } = await enquirer6.prompt({
@@ -3470,15 +3806,15 @@ async function promptDescription() {
3470
3806
  }
3471
3807
  function openEditor() {
3472
3808
  const editor = process.env.EDITOR || process.env.VISUAL || "vi";
3473
- const dir = mkdtempSync(join12(tmpdir(), "assist-"));
3474
- const filePath = join12(dir, "description.md");
3809
+ const dir = mkdtempSync(join15(tmpdir(), "assist-"));
3810
+ const filePath = join15(dir, "description.md");
3475
3811
  writeFileSync14(filePath, "");
3476
3812
  const result = spawnSync(editor, [filePath], { stdio: "inherit" });
3477
3813
  if (result.status !== 0) {
3478
3814
  unlinkSync4(filePath);
3479
3815
  return void 0;
3480
3816
  }
3481
- const content = readFileSync15(filePath, "utf-8").trim();
3817
+ const content = readFileSync16(filePath, "utf-8").trim();
3482
3818
  unlinkSync4(filePath);
3483
3819
  return content || void 0;
3484
3820
  }
@@ -3870,7 +4206,7 @@ function extractGraphqlQuery(args) {
3870
4206
  }
3871
4207
 
3872
4208
  // src/shared/loadCliReads.ts
3873
- import { existsSync as existsSync21, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
4209
+ import { existsSync as existsSync21, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
3874
4210
  import { dirname as dirname14, resolve as resolve2 } from "path";
3875
4211
  import { fileURLToPath as fileURLToPath4 } from "url";
3876
4212
  var __filename2 = fileURLToPath4(import.meta.url);
@@ -3880,7 +4216,7 @@ function packageRoot() {
3880
4216
  }
3881
4217
  function readLines(path50) {
3882
4218
  if (!existsSync21(path50)) return [];
3883
- return readFileSync16(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
4219
+ return readFileSync17(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
3884
4220
  }
3885
4221
  var cachedReads;
3886
4222
  var cachedWrites;
@@ -3926,14 +4262,14 @@ function findCliWrite(command) {
3926
4262
  }
3927
4263
 
3928
4264
  // src/shared/readSettingsPerms.ts
3929
- import { existsSync as existsSync22, readFileSync as readFileSync17 } from "fs";
4265
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "fs";
3930
4266
  import { homedir as homedir3 } from "os";
3931
- import { join as join13 } from "path";
4267
+ import { join as join16 } from "path";
3932
4268
  function readSettingsPerms(key) {
3933
4269
  const paths = [
3934
- join13(homedir3(), ".claude", "settings.json"),
3935
- join13(process.cwd(), ".claude", "settings.json"),
3936
- join13(process.cwd(), ".claude", "settings.local.json")
4270
+ join16(homedir3(), ".claude", "settings.json"),
4271
+ join16(process.cwd(), ".claude", "settings.json"),
4272
+ join16(process.cwd(), ".claude", "settings.local.json")
3937
4273
  ];
3938
4274
  const entries = [];
3939
4275
  for (const p of paths) {
@@ -3944,7 +4280,7 @@ function readSettingsPerms(key) {
3944
4280
  function readPermissionArray(filePath, key) {
3945
4281
  if (!existsSync22(filePath)) return [];
3946
4282
  try {
3947
- const data = JSON.parse(readFileSync17(filePath, "utf-8"));
4283
+ const data = JSON.parse(readFileSync18(filePath, "utf-8"));
3948
4284
  const arr = data?.permissions?.[key];
3949
4285
  return Array.isArray(arr) ? arr.filter((e) => typeof e === "string") : [];
3950
4286
  } catch {
@@ -4229,9 +4565,9 @@ function denyRemove(pattern2) {
4229
4565
  }
4230
4566
 
4231
4567
  // src/commands/permitCliReads/index.ts
4232
- import { existsSync as existsSync23, mkdirSync as mkdirSync4, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
4568
+ import { existsSync as existsSync23, mkdirSync as mkdirSync5, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "fs";
4233
4569
  import { homedir as homedir4 } from "os";
4234
- import { join as join14 } from "path";
4570
+ import { join as join17 } from "path";
4235
4571
 
4236
4572
  // src/shared/getInstallDir.ts
4237
4573
  import { execSync as execSync15 } from "child_process";
@@ -4533,16 +4869,16 @@ function updateSettings(cli, commands) {
4533
4869
  // src/commands/permitCliReads/index.ts
4534
4870
  function logPath(cli) {
4535
4871
  const safeName = cli.replace(/\s+/g, "-");
4536
- return join14(homedir4(), ".assist", `cli-discover-${safeName}.log`);
4872
+ return join17(homedir4(), ".assist", `cli-discover-${safeName}.log`);
4537
4873
  }
4538
4874
  function readCache(cli) {
4539
4875
  const path50 = logPath(cli);
4540
4876
  if (!existsSync23(path50)) return void 0;
4541
- return readFileSync18(path50, "utf-8");
4877
+ return readFileSync19(path50, "utf-8");
4542
4878
  }
4543
4879
  function writeCache(cli, output) {
4544
- const dir = join14(homedir4(), ".assist");
4545
- mkdirSync4(dir, { recursive: true });
4880
+ const dir = join17(homedir4(), ".assist");
4881
+ mkdirSync5(dir, { recursive: true });
4546
4882
  writeFileSync16(logPath(cli), output);
4547
4883
  }
4548
4884
  async function permitCliReads(cli, options2 = { noCache: false }) {
@@ -5090,7 +5426,7 @@ function registerComplexity(program2) {
5090
5426
  }
5091
5427
 
5092
5428
  // src/commands/deploy/redirect.ts
5093
- import { existsSync as existsSync24, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "fs";
5429
+ import { existsSync as existsSync24, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "fs";
5094
5430
  import chalk64 from "chalk";
5095
5431
  var TRAILING_SLASH_SCRIPT = ` <script>
5096
5432
  if (!window.location.pathname.endsWith('/')) {
@@ -5103,7 +5439,7 @@ function redirect() {
5103
5439
  console.log(chalk64.yellow("No index.html found"));
5104
5440
  return;
5105
5441
  }
5106
- const content = readFileSync19(indexPath, "utf-8");
5442
+ const content = readFileSync20(indexPath, "utf-8");
5107
5443
  if (content.includes("window.location.pathname.endsWith('/')")) {
5108
5444
  console.log(chalk64.dim("Trailing slash script already present"));
5109
5445
  return;
@@ -5131,10 +5467,10 @@ import { basename as basename3 } from "path";
5131
5467
 
5132
5468
  // src/commands/devlog/loadBlogSkipDays.ts
5133
5469
  import { homedir as homedir5 } from "os";
5134
- import { join as join15 } from "path";
5135
- var BLOG_REPO_ROOT = join15(homedir5(), "git/blog");
5470
+ import { join as join18 } from "path";
5471
+ var BLOG_REPO_ROOT = join18(homedir5(), "git/blog");
5136
5472
  function loadBlogSkipDays(repoName) {
5137
- const config = loadRawYaml(join15(BLOG_REPO_ROOT, "assist.yml"));
5473
+ const config = loadRawYaml(join18(BLOG_REPO_ROOT, "assist.yml"));
5138
5474
  const devlog = config.devlog;
5139
5475
  const skip2 = devlog?.skip;
5140
5476
  return new Set(skip2?.[repoName] ?? []);
@@ -5145,9 +5481,9 @@ import { execSync as execSync17 } from "child_process";
5145
5481
  import chalk65 from "chalk";
5146
5482
 
5147
5483
  // src/commands/devlog/loadDevlogEntries.ts
5148
- import { readdirSync, readFileSync as readFileSync20 } from "fs";
5149
- import { join as join16 } from "path";
5150
- var DEVLOG_DIR = join16(BLOG_REPO_ROOT, "src/content/devlog");
5484
+ import { readdirSync, readFileSync as readFileSync21 } from "fs";
5485
+ import { join as join19 } from "path";
5486
+ var DEVLOG_DIR = join19(BLOG_REPO_ROOT, "src/content/devlog");
5151
5487
  function extractFrontmatter(content) {
5152
5488
  const fm = content.match(/^---\n([\s\S]*?)\n---/);
5153
5489
  return fm?.[1] ?? null;
@@ -5175,7 +5511,7 @@ function readDevlogFiles(callback) {
5175
5511
  try {
5176
5512
  const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
5177
5513
  for (const file of files) {
5178
- const content = readFileSync20(join16(DEVLOG_DIR, file), "utf-8");
5514
+ const content = readFileSync21(join19(DEVLOG_DIR, file), "utf-8");
5179
5515
  const parsed = parseFrontmatter(content, file);
5180
5516
  if (parsed) callback(parsed);
5181
5517
  }
@@ -5354,7 +5690,8 @@ function getLastVersionInfo(repoName, config) {
5354
5690
  const gitInfo = getLastVersionInfoFromGit();
5355
5691
  if (gitInfo) return { date: lastDate, version: gitInfo.version };
5356
5692
  }
5357
- const lastVersion = entries.get(lastDate)?.[0]?.version;
5693
+ const dayEntries = entries.get(lastDate);
5694
+ const lastVersion = dayEntries?.[dayEntries.length - 1]?.version;
5358
5695
  return lastVersion ? { date: lastDate, version: lastVersion } : null;
5359
5696
  }
5360
5697
  function cleanVersion(version2) {
@@ -5561,11 +5898,11 @@ function repos(options2) {
5561
5898
 
5562
5899
  // src/commands/devlog/skip.ts
5563
5900
  import { writeFileSync as writeFileSync18 } from "fs";
5564
- import { join as join17 } from "path";
5901
+ import { join as join20 } from "path";
5565
5902
  import chalk70 from "chalk";
5566
- import { stringify as stringifyYaml4 } from "yaml";
5903
+ import { stringify as stringifyYaml3 } from "yaml";
5567
5904
  function getBlogConfigPath() {
5568
- return join17(BLOG_REPO_ROOT, "assist.yml");
5905
+ return join20(BLOG_REPO_ROOT, "assist.yml");
5569
5906
  }
5570
5907
  function skip(date) {
5571
5908
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
@@ -5589,7 +5926,7 @@ function skip(date) {
5589
5926
  skip2[repoName] = skipDays;
5590
5927
  devlog.skip = skip2;
5591
5928
  config.devlog = devlog;
5592
- writeFileSync18(configPath, stringifyYaml4(config, { lineWidth: 0 }));
5929
+ writeFileSync18(configPath, stringifyYaml3(config, { lineWidth: 0 }));
5593
5930
  console.log(chalk70.green(`Added ${date} to skip list for ${repoName}`));
5594
5931
  }
5595
5932
 
@@ -5626,7 +5963,7 @@ function registerDevlog(program2) {
5626
5963
 
5627
5964
  // src/commands/dotnet/checkBuildLocks.ts
5628
5965
  import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
5629
- import { join as join18 } from "path";
5966
+ import { join as join21 } from "path";
5630
5967
  import chalk72 from "chalk";
5631
5968
 
5632
5969
  // src/shared/findRepoRoot.ts
@@ -5654,7 +5991,7 @@ function isLockedDll(debugDir) {
5654
5991
  }
5655
5992
  for (const file of files) {
5656
5993
  if (!file.toLowerCase().endsWith(".dll")) continue;
5657
- const dllPath = join18(debugDir, file);
5994
+ const dllPath = join21(debugDir, file);
5658
5995
  try {
5659
5996
  const fd = openSync(dllPath, "r+");
5660
5997
  closeSync(fd);
@@ -5672,13 +6009,13 @@ function findFirstLockedDll(dir) {
5672
6009
  return null;
5673
6010
  }
5674
6011
  if (entries.includes("bin")) {
5675
- const locked = isLockedDll(join18(dir, "bin", "Debug"));
6012
+ const locked = isLockedDll(join21(dir, "bin", "Debug"));
5676
6013
  if (locked) return locked;
5677
6014
  }
5678
6015
  for (const entry of entries) {
5679
6016
  if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
5680
6017
  continue;
5681
- const found = findFirstLockedDll(join18(dir, entry));
6018
+ const found = findFirstLockedDll(join21(dir, entry));
5682
6019
  if (found) return found;
5683
6020
  }
5684
6021
  return null;
@@ -5701,11 +6038,11 @@ async function checkBuildLocksCommand() {
5701
6038
  }
5702
6039
 
5703
6040
  // src/commands/dotnet/buildTree.ts
5704
- import { readFileSync as readFileSync21 } from "fs";
6041
+ import { readFileSync as readFileSync22 } from "fs";
5705
6042
  import path22 from "path";
5706
6043
  var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
5707
6044
  function getProjectRefs(csprojPath) {
5708
- const content = readFileSync21(csprojPath, "utf-8");
6045
+ const content = readFileSync22(csprojPath, "utf-8");
5709
6046
  const refs = [];
5710
6047
  for (const match of content.matchAll(PROJECT_REF_RE)) {
5711
6048
  refs.push(match[1].replace(/\\/g, "/"));
@@ -5722,7 +6059,7 @@ function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
5722
6059
  for (const ref of getProjectRefs(abs)) {
5723
6060
  const childAbs = path22.resolve(dir, ref);
5724
6061
  try {
5725
- readFileSync21(childAbs);
6062
+ readFileSync22(childAbs);
5726
6063
  node.children.push(buildTree(childAbs, repoRoot, visited));
5727
6064
  } catch {
5728
6065
  node.children.push({
@@ -5747,7 +6084,7 @@ function collectAllDeps(node) {
5747
6084
  }
5748
6085
 
5749
6086
  // src/commands/dotnet/findContainingSolutions.ts
5750
- import { readdirSync as readdirSync3, readFileSync as readFileSync22, statSync } from "fs";
6087
+ import { readdirSync as readdirSync3, readFileSync as readFileSync23, statSync as statSync3 } from "fs";
5751
6088
  import path23 from "path";
5752
6089
  function findSlnFiles(dir, maxDepth, depth = 0) {
5753
6090
  if (depth > maxDepth) return [];
@@ -5763,7 +6100,7 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
5763
6100
  continue;
5764
6101
  const full = path23.join(dir, entry);
5765
6102
  try {
5766
- const stat = statSync(full);
6103
+ const stat = statSync3(full);
5767
6104
  if (stat.isFile() && entry.endsWith(".sln")) {
5768
6105
  results.push(full);
5769
6106
  } else if (stat.isDirectory()) {
@@ -5782,7 +6119,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
5782
6119
  const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
5783
6120
  for (const sln of slnFiles) {
5784
6121
  try {
5785
- const content = readFileSync22(sln, "utf-8");
6122
+ const content = readFileSync23(sln, "utf-8");
5786
6123
  if (pattern2.test(content)) {
5787
6124
  matches.push(path23.relative(repoRoot, sln));
5788
6125
  }
@@ -6025,11 +6362,11 @@ import chalk78 from "chalk";
6025
6362
 
6026
6363
  // src/commands/dotnet/findSolution.ts
6027
6364
  import { readdirSync as readdirSync4 } from "fs";
6028
- import { dirname as dirname16, join as join19 } from "path";
6365
+ import { dirname as dirname16, join as join22 } from "path";
6029
6366
  import chalk77 from "chalk";
6030
6367
  function findSlnInDir(dir) {
6031
6368
  try {
6032
- return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join19(dir, f));
6369
+ return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join22(dir, f));
6033
6370
  } catch {
6034
6371
  return [];
6035
6372
  }
@@ -6100,7 +6437,7 @@ function parseInspectReport(json) {
6100
6437
 
6101
6438
  // src/commands/dotnet/runInspectCode.ts
6102
6439
  import { execSync as execSync23 } from "child_process";
6103
- import { existsSync as existsSync28, readFileSync as readFileSync23, unlinkSync as unlinkSync5 } from "fs";
6440
+ import { existsSync as existsSync28, readFileSync as readFileSync24, unlinkSync as unlinkSync5 } from "fs";
6104
6441
  import { tmpdir as tmpdir2 } from "os";
6105
6442
  import path26 from "path";
6106
6443
  import chalk79 from "chalk";
@@ -6135,7 +6472,7 @@ function runInspectCode(slnPath, include, swea) {
6135
6472
  console.error(chalk79.red("Report file not generated"));
6136
6473
  process.exit(1);
6137
6474
  }
6138
- const xml = readFileSync23(reportPath, "utf-8");
6475
+ const xml = readFileSync24(reportPath, "utf-8");
6139
6476
  unlinkSync5(reportPath);
6140
6477
  return xml;
6141
6478
  }
@@ -6363,20 +6700,20 @@ function acceptanceCriteria(issueKey) {
6363
6700
  import { execSync as execSync26 } from "child_process";
6364
6701
 
6365
6702
  // src/shared/loadJson.ts
6366
- import { existsSync as existsSync29, mkdirSync as mkdirSync5, readFileSync as readFileSync24, writeFileSync as writeFileSync19 } from "fs";
6703
+ import { existsSync as existsSync29, mkdirSync as mkdirSync6, readFileSync as readFileSync25, writeFileSync as writeFileSync19 } from "fs";
6367
6704
  import { homedir as homedir6 } from "os";
6368
- import { join as join20 } from "path";
6705
+ import { join as join23 } from "path";
6369
6706
  function getStoreDir() {
6370
- return join20(homedir6(), ".assist");
6707
+ return join23(homedir6(), ".assist");
6371
6708
  }
6372
6709
  function getStorePath(filename) {
6373
- return join20(getStoreDir(), filename);
6710
+ return join23(getStoreDir(), filename);
6374
6711
  }
6375
6712
  function loadJson(filename) {
6376
6713
  const path50 = getStorePath(filename);
6377
6714
  if (existsSync29(path50)) {
6378
6715
  try {
6379
- return JSON.parse(readFileSync24(path50, "utf-8"));
6716
+ return JSON.parse(readFileSync25(path50, "utf-8"));
6380
6717
  } catch {
6381
6718
  return {};
6382
6719
  }
@@ -6386,7 +6723,7 @@ function loadJson(filename) {
6386
6723
  function saveJson(filename, data) {
6387
6724
  const dir = getStoreDir();
6388
6725
  if (!existsSync29(dir)) {
6389
- mkdirSync5(dir, { recursive: true });
6726
+ mkdirSync6(dir, { recursive: true });
6390
6727
  }
6391
6728
  writeFileSync19(getStorePath(filename), JSON.stringify(data, null, 2));
6392
6729
  }
@@ -6702,7 +7039,7 @@ function registerNews(program2) {
6702
7039
  import { spawnSync as spawnSync2 } from "child_process";
6703
7040
  import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync20 } from "fs";
6704
7041
  import { tmpdir as tmpdir3 } from "os";
6705
- import { join as join21 } from "path";
7042
+ import { join as join24 } from "path";
6706
7043
 
6707
7044
  // src/commands/prs/shared.ts
6708
7045
  import { execSync as execSync27 } from "child_process";
@@ -6774,7 +7111,7 @@ function comment2(path50, line, body) {
6774
7111
  validateLine(line);
6775
7112
  try {
6776
7113
  const prId = getCurrentPrNodeId();
6777
- const queryFile = join21(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7114
+ const queryFile = join24(tmpdir3(), `gh-query-${Date.now()}.graphql`);
6778
7115
  writeFileSync20(queryFile, MUTATION);
6779
7116
  try {
6780
7117
  const result = spawnSync2(
@@ -6819,21 +7156,21 @@ import { execSync as execSync29 } from "child_process";
6819
7156
  import { execSync as execSync28 } from "child_process";
6820
7157
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync21 } from "fs";
6821
7158
  import { tmpdir as tmpdir4 } from "os";
6822
- import { join as join23 } from "path";
7159
+ import { join as join26 } from "path";
6823
7160
 
6824
7161
  // src/commands/prs/loadCommentsCache.ts
6825
- import { existsSync as existsSync30, readFileSync as readFileSync25, unlinkSync as unlinkSync7 } from "fs";
6826
- import { join as join22 } from "path";
7162
+ import { existsSync as existsSync30, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
7163
+ import { join as join25 } from "path";
6827
7164
  import { parse as parse2 } from "yaml";
6828
7165
  function getCachePath(prNumber) {
6829
- return join22(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
7166
+ return join25(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
6830
7167
  }
6831
7168
  function loadCommentsCache(prNumber) {
6832
7169
  const cachePath = getCachePath(prNumber);
6833
7170
  if (!existsSync30(cachePath)) {
6834
7171
  return null;
6835
7172
  }
6836
- const content = readFileSync25(cachePath, "utf-8");
7173
+ const content = readFileSync26(cachePath, "utf-8");
6837
7174
  return parse2(content);
6838
7175
  }
6839
7176
  function deleteCommentsCache(prNumber) {
@@ -6853,7 +7190,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
6853
7190
  }
6854
7191
  function resolveThread(threadId) {
6855
7192
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
6856
- const queryFile = join23(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
7193
+ const queryFile = join26(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
6857
7194
  writeFileSync21(queryFile, mutation);
6858
7195
  try {
6859
7196
  execSync28(
@@ -6935,18 +7272,18 @@ function fixed(commentId, sha) {
6935
7272
  }
6936
7273
 
6937
7274
  // src/commands/prs/listComments/index.ts
6938
- import { existsSync as existsSync31, mkdirSync as mkdirSync6, writeFileSync as writeFileSync23 } from "fs";
6939
- import { join as join25 } from "path";
7275
+ import { existsSync as existsSync31, mkdirSync as mkdirSync7, writeFileSync as writeFileSync23 } from "fs";
7276
+ import { join as join28 } from "path";
6940
7277
  import { stringify } from "yaml";
6941
7278
 
6942
7279
  // src/commands/prs/fetchThreadIds.ts
6943
7280
  import { execSync as execSync30 } from "child_process";
6944
7281
  import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync22 } from "fs";
6945
7282
  import { tmpdir as tmpdir5 } from "os";
6946
- import { join as join24 } from "path";
7283
+ import { join as join27 } from "path";
6947
7284
  var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
6948
7285
  function fetchThreadIds(org, repo, prNumber) {
6949
- const queryFile = join24(tmpdir5(), `gh-query-${Date.now()}.graphql`);
7286
+ const queryFile = join27(tmpdir5(), `gh-query-${Date.now()}.graphql`);
6950
7287
  writeFileSync22(queryFile, THREAD_QUERY);
6951
7288
  try {
6952
7289
  const result = execSync30(
@@ -7060,16 +7397,16 @@ function printComments2(result) {
7060
7397
 
7061
7398
  // src/commands/prs/listComments/index.ts
7062
7399
  function writeCommentsCache(prNumber, comments2) {
7063
- const assistDir = join25(process.cwd(), ".assist");
7400
+ const assistDir = join28(process.cwd(), ".assist");
7064
7401
  if (!existsSync31(assistDir)) {
7065
- mkdirSync6(assistDir, { recursive: true });
7402
+ mkdirSync7(assistDir, { recursive: true });
7066
7403
  }
7067
7404
  const cacheData = {
7068
7405
  prNumber,
7069
7406
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
7070
7407
  comments: comments2
7071
7408
  };
7072
- const cachePath = join25(assistDir, `pr-${prNumber}-comments.yaml`);
7409
+ const cachePath = join28(assistDir, `pr-${prNumber}-comments.yaml`);
7073
7410
  writeFileSync23(cachePath, stringify(cacheData));
7074
7411
  }
7075
7412
  function handleKnownErrors(error) {
@@ -7102,7 +7439,7 @@ async function listComments() {
7102
7439
  ];
7103
7440
  updateCache(prNumber, allComments);
7104
7441
  const hasLineComments = allComments.some((c) => c.type === "line");
7105
- const cachePath = hasLineComments ? join25(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
7442
+ const cachePath = hasLineComments ? join28(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
7106
7443
  return { comments: allComments, cachePath };
7107
7444
  } catch (error) {
7108
7445
  const handled = handleKnownErrors(error);
@@ -9496,8 +9833,8 @@ function registerSeq(program2) {
9496
9833
  }
9497
9834
 
9498
9835
  // src/commands/transcript/shared.ts
9499
- import { existsSync as existsSync32, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
9500
- import { basename as basename4, join as join26, relative } from "path";
9836
+ import { existsSync as existsSync32, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
9837
+ import { basename as basename4, join as join29, relative } from "path";
9501
9838
  import * as readline2 from "readline";
9502
9839
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
9503
9840
  function getDatePrefix(daysOffset = 0) {
@@ -9515,8 +9852,8 @@ function collectFiles(dir, extension) {
9515
9852
  if (!existsSync32(dir)) return [];
9516
9853
  const results = [];
9517
9854
  for (const entry of readdirSync5(dir)) {
9518
- const fullPath = join26(dir, entry);
9519
- if (statSync2(fullPath).isDirectory()) {
9855
+ const fullPath = join29(dir, entry);
9856
+ if (statSync4(fullPath).isDirectory()) {
9520
9857
  results.push(...collectFiles(fullPath, extension));
9521
9858
  } else if (entry.endsWith(extension)) {
9522
9859
  results.push(fullPath);
@@ -9612,11 +9949,11 @@ async function configure() {
9612
9949
  import { existsSync as existsSync34 } from "fs";
9613
9950
 
9614
9951
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
9615
- import { dirname as dirname18, join as join28 } from "path";
9952
+ import { dirname as dirname18, join as join31 } from "path";
9616
9953
 
9617
9954
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
9618
- import { renameSync } from "fs";
9619
- import { join as join27 } from "path";
9955
+ import { renameSync as renameSync2 } from "fs";
9956
+ import { join as join30 } from "path";
9620
9957
  async function resolveDate(rl, choice) {
9621
9958
  if (choice === "1") return getDatePrefix(0);
9622
9959
  if (choice === "2") return getDatePrefix(-1);
@@ -9631,7 +9968,7 @@ async function resolveDate(rl, choice) {
9631
9968
  }
9632
9969
  function renameWithPrefix(vttDir, vttFile, prefix2) {
9633
9970
  const newFilename = `${prefix2}.${vttFile}`;
9634
- renameSync(join27(vttDir, vttFile), join27(vttDir, newFilename));
9971
+ renameSync2(join30(vttDir, vttFile), join30(vttDir, newFilename));
9635
9972
  console.log(`Renamed to: ${newFilename}`);
9636
9973
  return newFilename;
9637
9974
  }
@@ -9665,12 +10002,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
9665
10002
  const vttFileDir = dirname18(vttFile.absolutePath);
9666
10003
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
9667
10004
  if (newFilename) {
9668
- const newRelativePath = join28(
10005
+ const newRelativePath = join31(
9669
10006
  dirname18(vttFile.relativePath),
9670
10007
  newFilename
9671
10008
  );
9672
10009
  vttFiles[i] = {
9673
- absolutePath: join28(vttFileDir, newFilename),
10010
+ absolutePath: join31(vttFileDir, newFilename),
9674
10011
  relativePath: newRelativePath,
9675
10012
  filename: newFilename
9676
10013
  };
@@ -9683,8 +10020,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
9683
10020
  }
9684
10021
 
9685
10022
  // src/commands/transcript/format/processVttFile/index.ts
9686
- import { existsSync as existsSync33, mkdirSync as mkdirSync7, readFileSync as readFileSync26, writeFileSync as writeFileSync24 } from "fs";
9687
- import { basename as basename5, dirname as dirname19, join as join29 } from "path";
10023
+ import { existsSync as existsSync33, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync24 } from "fs";
10024
+ import { basename as basename5, dirname as dirname19, join as join32 } from "path";
9688
10025
 
9689
10026
  // src/commands/transcript/cleanText.ts
9690
10027
  function cleanText(text) {
@@ -9894,22 +10231,22 @@ function toMdFilename(vttFilename) {
9894
10231
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
9895
10232
  }
9896
10233
  function resolveOutputDir(relativeDir, transcriptsDir) {
9897
- return relativeDir === "." ? transcriptsDir : join29(transcriptsDir, relativeDir);
10234
+ return relativeDir === "." ? transcriptsDir : join32(transcriptsDir, relativeDir);
9898
10235
  }
9899
10236
  function buildOutputPaths(vttFile, transcriptsDir) {
9900
10237
  const mdFile = toMdFilename(vttFile.filename);
9901
10238
  const relativeDir = dirname19(vttFile.relativePath);
9902
10239
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
9903
- const outputPath = join29(outputDir, mdFile);
10240
+ const outputPath = join32(outputDir, mdFile);
9904
10241
  return { outputDir, outputPath, mdFile, relativeDir };
9905
10242
  }
9906
10243
  function logSkipped(relativeDir, mdFile) {
9907
- console.log(`Skipping (already exists): ${join29(relativeDir, mdFile)}`);
10244
+ console.log(`Skipping (already exists): ${join32(relativeDir, mdFile)}`);
9908
10245
  return "skipped";
9909
10246
  }
9910
10247
  function ensureDirectory(dir, label2) {
9911
10248
  if (!existsSync33(dir)) {
9912
- mkdirSync7(dir, { recursive: true });
10249
+ mkdirSync8(dir, { recursive: true });
9913
10250
  console.log(`Created ${label2}: ${dir}`);
9914
10251
  }
9915
10252
  }
@@ -9931,7 +10268,7 @@ function logReduction(cueCount, messageCount) {
9931
10268
  }
9932
10269
  function readAndParseCues(inputPath) {
9933
10270
  console.log(`Reading: ${inputPath}`);
9934
- return processCues(readFileSync26(inputPath, "utf-8"));
10271
+ return processCues(readFileSync27(inputPath, "utf-8"));
9935
10272
  }
9936
10273
  function writeFormatted(outputPath, content) {
9937
10274
  writeFileSync24(outputPath, content, "utf-8");
@@ -10003,17 +10340,17 @@ async function format() {
10003
10340
 
10004
10341
  // src/commands/transcript/summarise/index.ts
10005
10342
  import { existsSync as existsSync36 } from "fs";
10006
- import { basename as basename6, dirname as dirname21, join as join31, relative as relative2 } from "path";
10343
+ import { basename as basename6, dirname as dirname21, join as join34, relative as relative2 } from "path";
10007
10344
 
10008
10345
  // src/commands/transcript/summarise/processStagedFile/index.ts
10009
10346
  import {
10010
10347
  existsSync as existsSync35,
10011
- mkdirSync as mkdirSync8,
10012
- readFileSync as readFileSync27,
10013
- renameSync as renameSync2,
10348
+ mkdirSync as mkdirSync9,
10349
+ readFileSync as readFileSync28,
10350
+ renameSync as renameSync3,
10014
10351
  rmSync
10015
10352
  } from "fs";
10016
- import { dirname as dirname20, join as join30 } from "path";
10353
+ import { dirname as dirname20, join as join33 } from "path";
10017
10354
 
10018
10355
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
10019
10356
  import chalk118 from "chalk";
@@ -10042,7 +10379,7 @@ function validateStagedContent(filename, content) {
10042
10379
  }
10043
10380
 
10044
10381
  // src/commands/transcript/summarise/processStagedFile/index.ts
10045
- var STAGING_DIR = join30(process.cwd(), ".assist", "transcript");
10382
+ var STAGING_DIR = join33(process.cwd(), ".assist", "transcript");
10046
10383
  function processStagedFile() {
10047
10384
  if (!existsSync35(STAGING_DIR)) {
10048
10385
  return false;
@@ -10053,7 +10390,7 @@ function processStagedFile() {
10053
10390
  }
10054
10391
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
10055
10392
  const stagedFile = stagedFiles[0];
10056
- const content = readFileSync27(stagedFile.absolutePath, "utf-8");
10393
+ const content = readFileSync28(stagedFile.absolutePath, "utf-8");
10057
10394
  validateStagedContent(stagedFile.filename, content);
10058
10395
  const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
10059
10396
  const transcriptFiles = findMdFilesRecursive(transcriptsDir);
@@ -10066,12 +10403,12 @@ function processStagedFile() {
10066
10403
  );
10067
10404
  process.exit(1);
10068
10405
  }
10069
- const destPath = join30(summaryDir, matchingTranscript.relativePath);
10406
+ const destPath = join33(summaryDir, matchingTranscript.relativePath);
10070
10407
  const destDir = dirname20(destPath);
10071
10408
  if (!existsSync35(destDir)) {
10072
- mkdirSync8(destDir, { recursive: true });
10409
+ mkdirSync9(destDir, { recursive: true });
10073
10410
  }
10074
- renameSync2(stagedFile.absolutePath, destPath);
10411
+ renameSync3(stagedFile.absolutePath, destPath);
10075
10412
  const remaining = findMdFilesRecursive(STAGING_DIR);
10076
10413
  if (remaining.length === 0) {
10077
10414
  rmSync(STAGING_DIR, { recursive: true });
@@ -10082,7 +10419,7 @@ function processStagedFile() {
10082
10419
  // src/commands/transcript/summarise/index.ts
10083
10420
  function buildRelativeKey(relativePath, baseName) {
10084
10421
  const relDir = dirname21(relativePath);
10085
- return relDir === "." ? baseName : join31(relDir, baseName);
10422
+ return relDir === "." ? baseName : join34(relDir, baseName);
10086
10423
  }
10087
10424
  function buildSummaryIndex(summaryDir) {
10088
10425
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -10116,8 +10453,8 @@ function summarise2() {
10116
10453
  }
10117
10454
  const next3 = missing[0];
10118
10455
  const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
10119
- const outputPath = join31(STAGING_DIR, outputFilename);
10120
- const summaryFileDir = join31(summaryDir, dirname21(next3.relativePath));
10456
+ const outputPath = join34(STAGING_DIR, outputFilename);
10457
+ const summaryFileDir = join34(summaryDir, dirname21(next3.relativePath));
10121
10458
  const relativeTranscriptPath = encodeURI(
10122
10459
  relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
10123
10460
  );
@@ -10163,50 +10500,50 @@ function registerVerify(program2) {
10163
10500
 
10164
10501
  // src/commands/voice/devices.ts
10165
10502
  import { spawnSync as spawnSync3 } from "child_process";
10166
- import { join as join33 } from "path";
10503
+ import { join as join36 } from "path";
10167
10504
 
10168
10505
  // src/commands/voice/shared.ts
10169
10506
  import { homedir as homedir7 } from "os";
10170
- import { dirname as dirname22, join as join32 } from "path";
10507
+ import { dirname as dirname22, join as join35 } from "path";
10171
10508
  import { fileURLToPath as fileURLToPath6 } from "url";
10172
10509
  var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
10173
- var VOICE_DIR = join32(homedir7(), ".assist", "voice");
10510
+ var VOICE_DIR = join35(homedir7(), ".assist", "voice");
10174
10511
  var voicePaths = {
10175
10512
  dir: VOICE_DIR,
10176
- pid: join32(VOICE_DIR, "voice.pid"),
10177
- log: join32(VOICE_DIR, "voice.log"),
10178
- venv: join32(VOICE_DIR, ".venv"),
10179
- lock: join32(VOICE_DIR, "voice.lock")
10513
+ pid: join35(VOICE_DIR, "voice.pid"),
10514
+ log: join35(VOICE_DIR, "voice.log"),
10515
+ venv: join35(VOICE_DIR, ".venv"),
10516
+ lock: join35(VOICE_DIR, "voice.lock")
10180
10517
  };
10181
10518
  function getPythonDir() {
10182
- return join32(__dirname6, "commands", "voice", "python");
10519
+ return join35(__dirname6, "commands", "voice", "python");
10183
10520
  }
10184
10521
  function getVenvPython() {
10185
- return process.platform === "win32" ? join32(voicePaths.venv, "Scripts", "python.exe") : join32(voicePaths.venv, "bin", "python");
10522
+ return process.platform === "win32" ? join35(voicePaths.venv, "Scripts", "python.exe") : join35(voicePaths.venv, "bin", "python");
10186
10523
  }
10187
10524
  function getLockDir() {
10188
10525
  const config = loadConfig();
10189
10526
  return config.voice?.lockDir ?? VOICE_DIR;
10190
10527
  }
10191
10528
  function getLockFile() {
10192
- return join32(getLockDir(), "voice.lock");
10529
+ return join35(getLockDir(), "voice.lock");
10193
10530
  }
10194
10531
 
10195
10532
  // src/commands/voice/devices.ts
10196
10533
  function devices() {
10197
- const script = join33(getPythonDir(), "list_devices.py");
10534
+ const script = join36(getPythonDir(), "list_devices.py");
10198
10535
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
10199
10536
  }
10200
10537
 
10201
10538
  // src/commands/voice/logs.ts
10202
- import { existsSync as existsSync37, readFileSync as readFileSync28 } from "fs";
10539
+ import { existsSync as existsSync37, readFileSync as readFileSync29 } from "fs";
10203
10540
  function logs(options2) {
10204
10541
  if (!existsSync37(voicePaths.log)) {
10205
10542
  console.log("No voice log file found");
10206
10543
  return;
10207
10544
  }
10208
10545
  const count = Number.parseInt(options2.lines ?? "150", 10);
10209
- const content = readFileSync28(voicePaths.log, "utf-8").trim();
10546
+ const content = readFileSync29(voicePaths.log, "utf-8").trim();
10210
10547
  if (!content) {
10211
10548
  console.log("Voice log is empty");
10212
10549
  return;
@@ -10228,13 +10565,13 @@ function logs(options2) {
10228
10565
 
10229
10566
  // src/commands/voice/setup.ts
10230
10567
  import { spawnSync as spawnSync4 } from "child_process";
10231
- import { mkdirSync as mkdirSync10 } from "fs";
10232
- import { join as join35 } from "path";
10568
+ import { mkdirSync as mkdirSync11 } from "fs";
10569
+ import { join as join38 } from "path";
10233
10570
 
10234
10571
  // src/commands/voice/checkLockFile.ts
10235
10572
  import { execSync as execSync37 } from "child_process";
10236
- import { existsSync as existsSync38, mkdirSync as mkdirSync9, readFileSync as readFileSync29, writeFileSync as writeFileSync25 } from "fs";
10237
- import { join as join34 } from "path";
10573
+ import { existsSync as existsSync38, mkdirSync as mkdirSync10, readFileSync as readFileSync30, writeFileSync as writeFileSync25 } from "fs";
10574
+ import { join as join37 } from "path";
10238
10575
  function isProcessAlive2(pid) {
10239
10576
  try {
10240
10577
  process.kill(pid, 0);
@@ -10247,7 +10584,7 @@ function checkLockFile() {
10247
10584
  const lockFile = getLockFile();
10248
10585
  if (!existsSync38(lockFile)) return;
10249
10586
  try {
10250
- const lock = JSON.parse(readFileSync29(lockFile, "utf-8"));
10587
+ const lock = JSON.parse(readFileSync30(lockFile, "utf-8"));
10251
10588
  if (lock.pid && isProcessAlive2(lock.pid)) {
10252
10589
  console.error(
10253
10590
  `Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
@@ -10271,7 +10608,7 @@ function bootstrapVenv() {
10271
10608
  }
10272
10609
  function writeLockFile(pid) {
10273
10610
  const lockFile = getLockFile();
10274
- mkdirSync9(join34(lockFile, ".."), { recursive: true });
10611
+ mkdirSync10(join37(lockFile, ".."), { recursive: true });
10275
10612
  writeFileSync25(
10276
10613
  lockFile,
10277
10614
  JSON.stringify({
@@ -10284,10 +10621,10 @@ function writeLockFile(pid) {
10284
10621
 
10285
10622
  // src/commands/voice/setup.ts
10286
10623
  function setup() {
10287
- mkdirSync10(voicePaths.dir, { recursive: true });
10624
+ mkdirSync11(voicePaths.dir, { recursive: true });
10288
10625
  bootstrapVenv();
10289
10626
  console.log("\nDownloading models...\n");
10290
- const script = join35(getPythonDir(), "setup_models.py");
10627
+ const script = join38(getPythonDir(), "setup_models.py");
10291
10628
  const result = spawnSync4(getVenvPython(), [script], {
10292
10629
  stdio: "inherit",
10293
10630
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -10300,8 +10637,8 @@ function setup() {
10300
10637
 
10301
10638
  // src/commands/voice/start.ts
10302
10639
  import { spawn as spawn5 } from "child_process";
10303
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync26 } from "fs";
10304
- import { join as join36 } from "path";
10640
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync26 } from "fs";
10641
+ import { join as join39 } from "path";
10305
10642
 
10306
10643
  // src/commands/voice/buildDaemonEnv.ts
10307
10644
  function buildDaemonEnv(options2) {
@@ -10334,12 +10671,12 @@ function spawnBackground(python, script, env) {
10334
10671
  console.log(`Voice daemon started (PID ${pid})`);
10335
10672
  }
10336
10673
  function start2(options2) {
10337
- mkdirSync11(voicePaths.dir, { recursive: true });
10674
+ mkdirSync12(voicePaths.dir, { recursive: true });
10338
10675
  checkLockFile();
10339
10676
  bootstrapVenv();
10340
10677
  const debug = options2.debug || options2.foreground || process.platform === "win32";
10341
10678
  const env = buildDaemonEnv({ debug });
10342
- const script = join36(getPythonDir(), "voice_daemon.py");
10679
+ const script = join39(getPythonDir(), "voice_daemon.py");
10343
10680
  const python = getVenvPython();
10344
10681
  if (options2.foreground) {
10345
10682
  spawnForeground(python, script, env);
@@ -10349,7 +10686,7 @@ function start2(options2) {
10349
10686
  }
10350
10687
 
10351
10688
  // src/commands/voice/status.ts
10352
- import { existsSync as existsSync39, readFileSync as readFileSync30 } from "fs";
10689
+ import { existsSync as existsSync39, readFileSync as readFileSync31 } from "fs";
10353
10690
  function isProcessAlive3(pid) {
10354
10691
  try {
10355
10692
  process.kill(pid, 0);
@@ -10360,7 +10697,7 @@ function isProcessAlive3(pid) {
10360
10697
  }
10361
10698
  function readRecentLogs(count) {
10362
10699
  if (!existsSync39(voicePaths.log)) return [];
10363
- const lines = readFileSync30(voicePaths.log, "utf-8").trim().split("\n");
10700
+ const lines = readFileSync31(voicePaths.log, "utf-8").trim().split("\n");
10364
10701
  return lines.slice(-count);
10365
10702
  }
10366
10703
  function status() {
@@ -10368,7 +10705,7 @@ function status() {
10368
10705
  console.log("Voice daemon: not running (no PID file)");
10369
10706
  return;
10370
10707
  }
10371
- const pid = Number.parseInt(readFileSync30(voicePaths.pid, "utf-8").trim(), 10);
10708
+ const pid = Number.parseInt(readFileSync31(voicePaths.pid, "utf-8").trim(), 10);
10372
10709
  const alive = isProcessAlive3(pid);
10373
10710
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
10374
10711
  const recent = readRecentLogs(5);
@@ -10387,13 +10724,13 @@ function status() {
10387
10724
  }
10388
10725
 
10389
10726
  // src/commands/voice/stop.ts
10390
- import { existsSync as existsSync40, readFileSync as readFileSync31, unlinkSync as unlinkSync10 } from "fs";
10727
+ import { existsSync as existsSync40, readFileSync as readFileSync32, unlinkSync as unlinkSync10 } from "fs";
10391
10728
  function stop() {
10392
10729
  if (!existsSync40(voicePaths.pid)) {
10393
10730
  console.log("Voice daemon is not running (no PID file)");
10394
10731
  return;
10395
10732
  }
10396
- const pid = Number.parseInt(readFileSync31(voicePaths.pid, "utf-8").trim(), 10);
10733
+ const pid = Number.parseInt(readFileSync32(voicePaths.pid, "utf-8").trim(), 10);
10397
10734
  try {
10398
10735
  process.kill(pid, "SIGTERM");
10399
10736
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -10627,15 +10964,15 @@ async function auth() {
10627
10964
  }
10628
10965
 
10629
10966
  // src/commands/roam/showClaudeCodeIcon.ts
10630
- import { readFileSync as readFileSync32 } from "fs";
10631
- import { join as join37 } from "path";
10967
+ import { readFileSync as readFileSync33 } from "fs";
10968
+ import { join as join40 } from "path";
10632
10969
  async function showClaudeCodeIcon() {
10633
10970
  const appData = process.env.APPDATA;
10634
10971
  if (!appData) return;
10635
- const portFile = join37(appData, "Roam", "roam-local-api.port");
10972
+ const portFile = join40(appData, "Roam", "roam-local-api.port");
10636
10973
  let port;
10637
10974
  try {
10638
- port = readFileSync32(portFile, "utf-8").trim();
10975
+ port = readFileSync33(portFile, "utf-8").trim();
10639
10976
  } catch {
10640
10977
  return;
10641
10978
  }
@@ -10706,8 +11043,8 @@ Done in ${elapsed}`);
10706
11043
  }
10707
11044
 
10708
11045
  // src/commands/run/add.ts
10709
- import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync27 } from "fs";
10710
- import { join as join38 } from "path";
11046
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync27 } from "fs";
11047
+ import { join as join41 } from "path";
10711
11048
  function findAddIndex() {
10712
11049
  const addIndex = process.argv.indexOf("add");
10713
11050
  if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
@@ -10753,15 +11090,15 @@ function saveNewRunConfig(name, command, args) {
10753
11090
  saveConfig(config);
10754
11091
  }
10755
11092
  function createCommandFile(name) {
10756
- const dir = join38(".claude", "commands");
10757
- mkdirSync12(dir, { recursive: true });
11093
+ const dir = join41(".claude", "commands");
11094
+ mkdirSync13(dir, { recursive: true });
10758
11095
  const content = `---
10759
11096
  description: Run ${name}
10760
11097
  ---
10761
11098
 
10762
11099
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
10763
11100
  `;
10764
- const filePath = join38(dir, `${name}.md`);
11101
+ const filePath = join41(dir, `${name}.md`);
10765
11102
  writeFileSync27(filePath, content);
10766
11103
  console.log(`Created command file: ${filePath}`);
10767
11104
  }
@@ -10832,9 +11169,9 @@ function run3(name, args) {
10832
11169
 
10833
11170
  // src/commands/screenshot/index.ts
10834
11171
  import { execSync as execSync40 } from "child_process";
10835
- import { existsSync as existsSync41, mkdirSync as mkdirSync13, unlinkSync as unlinkSync11, writeFileSync as writeFileSync28 } from "fs";
11172
+ import { existsSync as existsSync41, mkdirSync as mkdirSync14, unlinkSync as unlinkSync11, writeFileSync as writeFileSync28 } from "fs";
10836
11173
  import { tmpdir as tmpdir6 } from "os";
10837
- import { join as join39, resolve as resolve5 } from "path";
11174
+ import { join as join42, resolve as resolve5 } from "path";
10838
11175
  import chalk120 from "chalk";
10839
11176
 
10840
11177
  // src/commands/screenshot/captureWindowPs1.ts
@@ -10965,13 +11302,13 @@ Write-Output $OutputPath
10965
11302
  // src/commands/screenshot/index.ts
10966
11303
  function buildOutputPath(outputDir, processName) {
10967
11304
  if (!existsSync41(outputDir)) {
10968
- mkdirSync13(outputDir, { recursive: true });
11305
+ mkdirSync14(outputDir, { recursive: true });
10969
11306
  }
10970
11307
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
10971
11308
  return resolve5(outputDir, `${processName}-${timestamp}.png`);
10972
11309
  }
10973
11310
  function runPowerShellScript(processName, outputPath) {
10974
- const scriptPath = join39(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
11311
+ const scriptPath = join42(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
10975
11312
  writeFileSync28(scriptPath, captureWindowPs1, "utf-8");
10976
11313
  try {
10977
11314
  execSync40(