@staff0rd/assist 0.170.3 → 0.171.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +549 -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.0",
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,199 @@ 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/loadPlan.ts
132
+ function toPhase(db, itemId, p) {
133
+ const tasks = db.prepare(
134
+ "SELECT task, verify FROM plan_tasks WHERE item_id = ? AND phase_idx = ? ORDER BY idx"
135
+ ).all(itemId, p.idx);
136
+ const phase = {
137
+ name: p.name,
138
+ tasks: tasks.map((t) => ({
139
+ task: t.task,
140
+ ...t.verify != null ? { verify: t.verify } : {}
141
+ }))
142
+ };
143
+ if (p.manual_checks) {
144
+ phase.manualChecks = JSON.parse(p.manual_checks);
145
+ }
146
+ return phase;
147
+ }
148
+ function loadPlan(db, itemId) {
149
+ const phases = db.prepare(
150
+ "SELECT idx, name, manual_checks FROM plan_phases WHERE item_id = ? ORDER BY idx"
151
+ ).all(itemId);
152
+ if (phases.length === 0) return void 0;
153
+ return phases.map((p) => toPhase(db, itemId, p));
154
+ }
155
+
156
+ // src/commands/backlog/loadAllItems.ts
157
+ function loadComments(db, itemId) {
158
+ return db.prepare(
159
+ "SELECT text, phase, timestamp, type FROM comments WHERE item_id = ? ORDER BY idx"
160
+ ).all(itemId);
161
+ }
162
+ function loadLinks(db, itemId) {
163
+ return db.prepare("SELECT type, target_id as targetId FROM links WHERE item_id = ?").all(itemId);
164
+ }
165
+ function rowToItem(db, row) {
166
+ const comments2 = loadComments(db, row.id);
167
+ const links = loadLinks(db, row.id);
168
+ const plan2 = loadPlan(db, row.id);
169
+ const item = {
170
+ id: row.id,
171
+ type: row.type,
172
+ name: row.name,
173
+ acceptanceCriteria: JSON.parse(row.acceptance_criteria),
174
+ status: row.status
175
+ };
176
+ if (row.description != null) item.description = row.description;
177
+ if (row.current_phase != null) item.currentPhase = row.current_phase;
178
+ if (comments2.length > 0) item.comments = comments2;
179
+ if (links && links.length > 0) item.links = links;
180
+ if (plan2) item.plan = plan2;
181
+ return item;
182
+ }
183
+ function loadAllItems(db) {
184
+ const rows = db.prepare("SELECT * FROM items ORDER BY id").all();
185
+ return rows.map((row) => rowToItem(db, row));
186
+ }
187
+
188
+ // src/commands/backlog/exportToJsonl.ts
189
+ function getJsonlPath(dir) {
190
+ return join(dir, ".assist", "backlog.jsonl");
191
+ }
192
+ function exportToJsonl(db, dir) {
193
+ const jsonlPath = getJsonlPath(dir);
194
+ const items = loadAllItems(db);
195
+ const lines = items.map((item) => JSON.stringify(item));
196
+ writeFileSync(jsonlPath, lines.length > 0 ? `${lines.join("\n")}
197
+ ` : "");
198
+ const mtimeMs = statSync(jsonlPath).mtimeMs;
199
+ db.prepare(
200
+ "INSERT INTO metadata (key, value) VALUES ('jsonl_last_import_ms', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
201
+ ).run(String(mtimeMs));
202
+ }
203
+
204
+ // src/commands/backlog/importFromJsonlIfNeeded.ts
205
+ import { readFileSync, statSync as statSync2 } from "fs";
206
+
207
+ // src/commands/backlog/insertItemRelations.ts
208
+ function insertComments(db, item) {
209
+ if (!item.comments) return;
210
+ const stmt = db.prepare(
211
+ "INSERT INTO comments (item_id, idx, text, phase, timestamp, type) VALUES (?, ?, ?, ?, ?, ?)"
212
+ );
213
+ for (let i = 0; i < item.comments.length; i++) {
214
+ const c = item.comments[i];
215
+ stmt.run(item.id, i, c.text, c.phase ?? null, c.timestamp, c.type);
216
+ }
217
+ }
218
+ function insertLinks(db, item) {
219
+ if (!item.links) return;
220
+ const stmt = db.prepare(
221
+ "INSERT INTO links (item_id, type, target_id) VALUES (?, ?, ?)"
222
+ );
223
+ for (const l of item.links) {
224
+ stmt.run(item.id, l.type, l.targetId);
225
+ }
226
+ }
227
+ function insertPlan(db, item) {
228
+ if (!item.plan) return;
229
+ const phaseStmt = db.prepare(
230
+ "INSERT INTO plan_phases (item_id, idx, name, manual_checks) VALUES (?, ?, ?, ?)"
231
+ );
232
+ const taskStmt = db.prepare(
233
+ "INSERT INTO plan_tasks (item_id, phase_idx, idx, task, verify) VALUES (?, ?, ?, ?, ?)"
234
+ );
235
+ for (let pi = 0; pi < item.plan.length; pi++) {
236
+ const phase = item.plan[pi];
237
+ phaseStmt.run(
238
+ item.id,
239
+ pi,
240
+ phase.name,
241
+ phase.manualChecks ? JSON.stringify(phase.manualChecks) : null
242
+ );
243
+ for (let ti = 0; ti < phase.tasks.length; ti++) {
244
+ const task = phase.tasks[ti];
245
+ taskStmt.run(item.id, pi, ti, task.task, task.verify ?? null);
246
+ }
247
+ }
248
+ }
249
+ function insertItemRelations(db, item) {
250
+ insertComments(db, item);
251
+ insertLinks(db, item);
252
+ insertPlan(db, item);
253
+ }
254
+
255
+ // src/commands/backlog/saveAllItems.ts
256
+ function upsertItem(db, item) {
257
+ db.prepare(
258
+ `INSERT INTO items (id, type, name, description, acceptance_criteria, status, current_phase)
259
+ VALUES (?, ?, ?, ?, ?, ?, ?)
260
+ ON CONFLICT(id) DO UPDATE SET
261
+ type = excluded.type,
262
+ name = excluded.name,
263
+ description = excluded.description,
264
+ acceptance_criteria = excluded.acceptance_criteria,
265
+ status = excluded.status,
266
+ current_phase = excluded.current_phase`
267
+ ).run(
268
+ item.id,
269
+ item.type,
270
+ item.name,
271
+ item.description ?? null,
272
+ JSON.stringify(item.acceptanceCriteria),
273
+ item.status,
274
+ item.currentPhase ?? null
275
+ );
276
+ deleteItemRelations(db, item.id);
277
+ insertItemRelations(db, item);
278
+ }
279
+ function saveAllItems(db, items) {
280
+ const save = db.transaction(() => {
281
+ const existingIds = db.prepare("SELECT id FROM items").all();
282
+ const newIds = new Set(items.map((i) => i.id));
283
+ for (const { id } of existingIds) {
284
+ if (!newIds.has(id)) {
285
+ deleteItemRelations(db, id);
286
+ db.prepare("DELETE FROM items WHERE id = ?").run(id);
287
+ }
288
+ }
289
+ for (const item of items) {
290
+ upsertItem(db, item);
291
+ }
292
+ });
293
+ save();
294
+ }
108
295
 
109
296
  // src/commands/backlog/types.ts
110
297
  import { z } from "zod";
@@ -145,6 +332,143 @@ var backlogItemSchema = z.strictObject({
145
332
  });
146
333
  var backlogFileSchema = z.array(backlogItemSchema);
147
334
 
335
+ // src/commands/backlog/importFromJsonlIfNeeded.ts
336
+ function getLastImportMs(db) {
337
+ const row = db.prepare("SELECT value FROM metadata WHERE key = 'jsonl_last_import_ms'").get();
338
+ return row ? Number(row.value) : 0;
339
+ }
340
+ function setLastImportMs(db, ms) {
341
+ db.prepare(
342
+ "INSERT INTO metadata (key, value) VALUES ('jsonl_last_import_ms', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
343
+ ).run(String(ms));
344
+ }
345
+ function importFromJsonlIfNeeded(db, dir) {
346
+ const jsonlPath = getJsonlPath(dir);
347
+ let stat;
348
+ try {
349
+ stat = statSync2(jsonlPath);
350
+ } catch {
351
+ return;
352
+ }
353
+ const fileMtimeMs = stat.mtimeMs;
354
+ const lastImportMs = getLastImportMs(db);
355
+ if (fileMtimeMs <= lastImportMs) return;
356
+ const content = readFileSync(jsonlPath, "utf-8").trim();
357
+ if (content.length === 0) {
358
+ setLastImportMs(db, fileMtimeMs);
359
+ return;
360
+ }
361
+ const items = content.split("\n").map((line) => {
362
+ const parsed = JSON.parse(line);
363
+ return backlogItemSchema.parse(parsed);
364
+ });
365
+ saveAllItems(db, items);
366
+ setLastImportMs(db, fileMtimeMs);
367
+ }
368
+
369
+ // src/commands/backlog/migrateYamlIfNeeded.ts
370
+ import { existsSync, readFileSync as readFileSync2, renameSync } from "fs";
371
+ import { parse as parseYaml } from "yaml";
372
+ function migrateYamlIfNeeded(db, yamlPath) {
373
+ if (!existsSync(yamlPath)) return false;
374
+ const existing = db.prepare("SELECT COUNT(*) as count FROM items").get();
375
+ if (existing.count > 0) return false;
376
+ const content = readFileSync2(yamlPath, "utf-8");
377
+ const raw = parseYaml(content) || [];
378
+ const items = backlogFileSchema.parse(raw);
379
+ if (items.length > 0) {
380
+ saveAllItems(db, items);
381
+ renameSync(yamlPath, `${yamlPath}.bak`);
382
+ return true;
383
+ }
384
+ return false;
385
+ }
386
+
387
+ // src/commands/backlog/openDb.ts
388
+ import { mkdirSync } from "fs";
389
+ import { join as join2 } from "path";
390
+ import Database from "better-sqlite3";
391
+ var _db;
392
+ function getDbPath(dir) {
393
+ return join2(dir, ".assist", "backlog.db");
394
+ }
395
+ function initSchema(db) {
396
+ db.exec(`
397
+ CREATE TABLE IF NOT EXISTS items (
398
+ id INTEGER PRIMARY KEY,
399
+ type TEXT NOT NULL DEFAULT 'story',
400
+ name TEXT NOT NULL,
401
+ description TEXT,
402
+ acceptance_criteria TEXT NOT NULL DEFAULT '[]',
403
+ status TEXT NOT NULL DEFAULT 'todo',
404
+ current_phase INTEGER
405
+ );
406
+
407
+ CREATE TABLE IF NOT EXISTS comments (
408
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
409
+ idx INTEGER NOT NULL,
410
+ text TEXT NOT NULL,
411
+ phase INTEGER,
412
+ timestamp TEXT NOT NULL,
413
+ type TEXT NOT NULL DEFAULT 'comment',
414
+ PRIMARY KEY (item_id, idx)
415
+ );
416
+
417
+ CREATE TABLE IF NOT EXISTS links (
418
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
419
+ type TEXT NOT NULL,
420
+ target_id INTEGER NOT NULL,
421
+ PRIMARY KEY (item_id, type, target_id)
422
+ );
423
+
424
+ CREATE TABLE IF NOT EXISTS plan_phases (
425
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
426
+ idx INTEGER NOT NULL,
427
+ name TEXT NOT NULL,
428
+ manual_checks TEXT,
429
+ PRIMARY KEY (item_id, idx)
430
+ );
431
+
432
+ CREATE TABLE IF NOT EXISTS plan_tasks (
433
+ item_id INTEGER NOT NULL REFERENCES items(id) ON DELETE CASCADE,
434
+ phase_idx INTEGER NOT NULL,
435
+ idx INTEGER NOT NULL,
436
+ task TEXT NOT NULL,
437
+ verify TEXT,
438
+ PRIMARY KEY (item_id, phase_idx, idx),
439
+ FOREIGN KEY (item_id, phase_idx) REFERENCES plan_phases(item_id, idx) ON DELETE CASCADE
440
+ );
441
+
442
+ CREATE TABLE IF NOT EXISTS metadata (
443
+ key TEXT PRIMARY KEY,
444
+ value TEXT NOT NULL
445
+ );
446
+ `);
447
+ }
448
+ function openDb(dir) {
449
+ if (_db) return _db;
450
+ const dbPath = getDbPath(dir);
451
+ mkdirSync(join2(dir, ".assist"), { recursive: true });
452
+ const db = new Database(dbPath);
453
+ db.pragma("journal_mode = WAL");
454
+ db.pragma("foreign_keys = ON");
455
+ initSchema(db);
456
+ _db = db;
457
+ return db;
458
+ }
459
+
460
+ // src/commands/backlog/updateCurrentPhase.ts
461
+ function updateCurrentPhase(db, id, phase) {
462
+ const result = db.prepare("UPDATE items SET current_phase = ? WHERE id = ?").run(phase, id);
463
+ return result.changes > 0;
464
+ }
465
+
466
+ // src/commands/backlog/updateStatus.ts
467
+ function updateStatus(db, id, status2) {
468
+ const result = db.prepare("UPDATE items SET status = ? WHERE id = ?").run(status2, id);
469
+ return result.changes > 0;
470
+ }
471
+
148
472
  // src/commands/backlog/shared.ts
149
473
  var _backlogDir;
150
474
  function setBacklogDir(dir) {
@@ -154,33 +478,29 @@ function getBacklogDir() {
154
478
  return _backlogDir ?? process.cwd();
155
479
  }
156
480
  function getBacklogPath() {
157
- return join(getBacklogDir(), "assist.backlog.yml");
481
+ return join3(getBacklogDir(), "assist.backlog.yml");
482
+ }
483
+ function getDb() {
484
+ const dir = getBacklogDir();
485
+ const db = openDb(dir);
486
+ const migrated = migrateYamlIfNeeded(db, getBacklogPath());
487
+ if (migrated) exportToJsonl(db, dir);
488
+ return db;
158
489
  }
159
490
  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);
491
+ const db = getDb();
492
+ importFromJsonlIfNeeded(db, getBacklogDir());
493
+ return loadAllItems(db);
167
494
  }
168
495
  function saveBacklog(items) {
169
- const backlogPath = getBacklogPath();
170
- writeFileSync(backlogPath, stringifyYaml(items, { lineWidth: 0 }));
496
+ const db = getDb();
497
+ saveAllItems(db, items);
498
+ exportToJsonl(db, getBacklogDir());
171
499
  }
172
500
  function findItem(items, id) {
173
501
  return items.find((item) => item.id === id);
174
502
  }
175
503
  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
504
  const items = loadBacklog();
185
505
  const item = findItem(items, Number.parseInt(id, 10));
186
506
  if (!item) {
@@ -192,20 +512,24 @@ function loadAndFindItem(id) {
192
512
  function setStatus(id, status2) {
193
513
  const result = loadAndFindItem(id);
194
514
  if (!result) return void 0;
195
- result.item.status = status2;
196
- saveBacklog(result.items);
515
+ const db = getDb();
516
+ updateStatus(db, result.item.id, status2);
517
+ exportToJsonl(db, getBacklogDir());
197
518
  return result.item.name;
198
519
  }
199
520
  function setCurrentPhase(id, phase) {
200
521
  const result = loadAndFindItem(id);
201
522
  if (!result) return;
202
- result.item.currentPhase = phase;
203
- saveBacklog(result.items);
523
+ const db = getDb();
524
+ updateCurrentPhase(db, result.item.id, phase);
525
+ exportToJsonl(db, getBacklogDir());
204
526
  }
205
527
  function removeItem(id) {
206
528
  const result = loadAndFindItem(id);
207
529
  if (!result) return void 0;
208
- saveBacklog(result.items.filter((i) => i.id !== result.item.id));
530
+ const db = getDb();
531
+ deleteItem(db, result.item.id);
532
+ exportToJsonl(db, getBacklogDir());
209
533
  return result.item.name;
210
534
  }
211
535
  function getNextId(items) {
@@ -215,7 +539,7 @@ function getNextId(items) {
215
539
 
216
540
  // src/commands/backlog/acquireLock.ts
217
541
  function getLockPath(itemId) {
218
- return join2(getBacklogDir(), `.assist-lock-${itemId}.json`);
542
+ return join4(getBacklogDir(), `.assist-lock-${itemId}.json`);
219
543
  }
220
544
  function isProcessAlive(pid) {
221
545
  try {
@@ -229,7 +553,7 @@ function isLockedByOther(itemId) {
229
553
  const lockPath = getLockPath(itemId);
230
554
  if (!existsSync2(lockPath)) return false;
231
555
  try {
232
- const lock = JSON.parse(readFileSync2(lockPath, "utf-8"));
556
+ const lock = JSON.parse(readFileSync3(lockPath, "utf-8"));
233
557
  if (lock.pid === process.pid) return false;
234
558
  return isProcessAlive(lock.pid);
235
559
  } catch {
@@ -438,10 +762,10 @@ async function handleIncompletePhase() {
438
762
 
439
763
  // src/commands/backlog/writeSignal.ts
440
764
  import { writeFileSync as writeFileSync3 } from "fs";
441
- import { join as join3 } from "path";
765
+ import { join as join5 } from "path";
442
766
  var SIGNAL_FILE = ".assist-signal.json";
443
767
  function getSignalPath() {
444
- return join3(getBacklogDir(), SIGNAL_FILE);
768
+ return join5(getBacklogDir(), SIGNAL_FILE);
445
769
  }
446
770
  function writeSignal(event, data) {
447
771
  const sessionId = process.env.ASSIST_SESSION_ID;
@@ -489,12 +813,12 @@ function spawnClaude(prompt, options2 = {}) {
489
813
  import { existsSync as existsSync5, unwatchFile, watchFile } from "fs";
490
814
 
491
815
  // src/commands/backlog/readSignal.ts
492
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
816
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
493
817
  function readSignal() {
494
818
  const path50 = getSignalPath();
495
819
  if (!existsSync4(path50)) return void 0;
496
820
  try {
497
- return JSON.parse(readFileSync3(path50, "utf-8"));
821
+ return JSON.parse(readFileSync4(path50, "utf-8"));
498
822
  } catch {
499
823
  return void 0;
500
824
  }
@@ -862,11 +1186,11 @@ function printComments(item) {
862
1186
 
863
1187
  // src/shared/web.ts
864
1188
  import { exec } from "child_process";
865
- import { readFileSync as readFileSync4 } from "fs";
1189
+ import { readFileSync as readFileSync5 } from "fs";
866
1190
  import {
867
1191
  createServer
868
1192
  } from "http";
869
- import { dirname, join as join4 } from "path";
1193
+ import { dirname, join as join6 } from "path";
870
1194
  import { fileURLToPath } from "url";
871
1195
  import chalk14 from "chalk";
872
1196
  function respondJson(res, status2, data) {
@@ -878,7 +1202,7 @@ function createBundleHandler(importMetaUrl, bundlePath) {
878
1202
  let cache;
879
1203
  return (_req, res) => {
880
1204
  if (!cache) {
881
- cache = readFileSync4(join4(dir, bundlePath), "utf-8");
1205
+ cache = readFileSync5(join6(dir, bundlePath), "utf-8");
882
1206
  }
883
1207
  res.writeHead(200, { "Content-Type": "application/javascript" });
884
1208
  res.end(cache);
@@ -991,7 +1315,7 @@ async function createItem(req, res) {
991
1315
  saveBacklog(items);
992
1316
  respondJson(res, 201, newItem);
993
1317
  }
994
- function deleteItem(res, id) {
1318
+ function deleteItem2(res, id) {
995
1319
  const result = findItemOr404(res, id);
996
1320
  if (!result) return;
997
1321
  saveBacklog(result.items.filter((i) => i.id !== id));
@@ -1033,7 +1357,7 @@ var itemRoutes = {
1033
1357
  GET: (_req, res, id) => getItemById(res, id),
1034
1358
  PUT: (req, res, id) => updateItem(req, res, id),
1035
1359
  PATCH: (req, res, id) => patchItemStatus(req, res, id),
1036
- DELETE: (_req, res, id) => deleteItem(res, id)
1360
+ DELETE: (_req, res, id) => deleteItem2(res, id)
1037
1361
  };
1038
1362
  var baseHandler = createRouteHandler(routes);
1039
1363
  async function handleRequest(req, res, port) {
@@ -1080,19 +1404,19 @@ async function launchMode(slashCommand) {
1080
1404
  import { execSync } from "child_process";
1081
1405
 
1082
1406
  // src/shared/loadConfig.ts
1083
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
1407
+ import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
1084
1408
  import { homedir } from "os";
1085
- import { basename, dirname as dirname2, join as join5 } from "path";
1409
+ import { basename, dirname as dirname2, join as join7 } from "path";
1086
1410
  import chalk16 from "chalk";
1087
- import { stringify as stringifyYaml2 } from "yaml";
1411
+ import { stringify as stringifyYaml } from "yaml";
1088
1412
 
1089
1413
  // src/shared/loadRawYaml.ts
1090
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1414
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
1091
1415
  import { parse as parseYaml2 } from "yaml";
1092
1416
  function loadRawYaml(path50) {
1093
1417
  if (!existsSync6(path50)) return {};
1094
1418
  try {
1095
- const content = readFileSync5(path50, "utf-8");
1419
+ const content = readFileSync6(path50, "utf-8");
1096
1420
  return parseYaml2(content) || {};
1097
1421
  } catch {
1098
1422
  return {};
@@ -1222,9 +1546,9 @@ var assistConfigSchema = z2.strictObject({
1222
1546
  function findConfigUp(startDir) {
1223
1547
  let current = startDir;
1224
1548
  while (current !== dirname2(current)) {
1225
- const claudePath = join5(current, ".claude", "assist.yml");
1549
+ const claudePath = join7(current, ".claude", "assist.yml");
1226
1550
  if (existsSync7(claudePath)) return claudePath;
1227
- const rootPath = join5(current, "assist.yml");
1551
+ const rootPath = join7(current, "assist.yml");
1228
1552
  if (existsSync7(rootPath)) return rootPath;
1229
1553
  current = dirname2(current);
1230
1554
  }
@@ -1233,10 +1557,10 @@ function findConfigUp(startDir) {
1233
1557
  function getConfigPath() {
1234
1558
  const found = findConfigUp(process.cwd());
1235
1559
  if (found) return found;
1236
- return join5(process.cwd(), "assist.yml");
1560
+ return join7(process.cwd(), "assist.yml");
1237
1561
  }
1238
1562
  function getGlobalConfigPath() {
1239
- return join5(homedir(), ".assist.yml");
1563
+ return join7(homedir(), ".assist.yml");
1240
1564
  }
1241
1565
  function loadConfig() {
1242
1566
  const globalRaw = loadRawYaml(getGlobalConfigPath());
@@ -1251,21 +1575,21 @@ function loadGlobalConfigRaw() {
1251
1575
  return loadRawYaml(getGlobalConfigPath());
1252
1576
  }
1253
1577
  function saveGlobalConfig(config) {
1254
- writeFileSync4(getGlobalConfigPath(), stringifyYaml2(config, { lineWidth: 0 }));
1578
+ writeFileSync4(getGlobalConfigPath(), stringifyYaml(config, { lineWidth: 0 }));
1255
1579
  }
1256
1580
  function saveConfig(config) {
1257
1581
  const configPath = getConfigPath();
1258
- writeFileSync4(configPath, stringifyYaml2(config, { lineWidth: 0 }));
1582
+ writeFileSync4(configPath, stringifyYaml(config, { lineWidth: 0 }));
1259
1583
  }
1260
1584
  function getRepoName() {
1261
1585
  const config = loadConfig();
1262
1586
  if (config.devlog?.name) {
1263
1587
  return config.devlog.name;
1264
1588
  }
1265
- const packageJsonPath = join5(process.cwd(), "package.json");
1589
+ const packageJsonPath = join7(process.cwd(), "package.json");
1266
1590
  if (existsSync7(packageJsonPath)) {
1267
1591
  try {
1268
- const content = readFileSync6(packageJsonPath, "utf-8");
1592
+ const content = readFileSync7(packageJsonPath, "utf-8");
1269
1593
  const pkg = JSON.parse(content);
1270
1594
  if (pkg.name) {
1271
1595
  return pkg.name;
@@ -1369,7 +1693,7 @@ function commit(args) {
1369
1693
 
1370
1694
  // src/commands/config/index.ts
1371
1695
  import chalk17 from "chalk";
1372
- import { stringify as stringifyYaml3 } from "yaml";
1696
+ import { stringify as stringifyYaml2 } from "yaml";
1373
1697
 
1374
1698
  // src/commands/config/setNestedValue.ts
1375
1699
  function isPlainObject(val) {
@@ -1476,7 +1800,7 @@ function configSet(key, value, options2 = {}) {
1476
1800
  }
1477
1801
  function configList() {
1478
1802
  const config = loadConfig();
1479
- console.log(stringifyYaml3(config, { lineWidth: 0 }).trimEnd());
1803
+ console.log(stringifyYaml2(config, { lineWidth: 0 }).trimEnd());
1480
1804
  }
1481
1805
 
1482
1806
  // src/commands/config/configGet.ts
@@ -1714,17 +2038,17 @@ import * as path3 from "path";
1714
2038
  import chalk25 from "chalk";
1715
2039
 
1716
2040
  // 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";
2041
+ import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
2042
+ import { join as join9 } from "path";
1719
2043
  import chalk24 from "chalk";
1720
2044
  function loadKnipConfig(knipJsonPath) {
1721
2045
  if (existsSync9(knipJsonPath)) {
1722
- return JSON.parse(readFileSync8(knipJsonPath, "utf-8"));
2046
+ return JSON.parse(readFileSync9(knipJsonPath, "utf-8"));
1723
2047
  }
1724
2048
  return { $schema: "https://unpkg.com/knip@5/schema.json" };
1725
2049
  }
1726
2050
  function addToKnipIgnoreBinaries(cwd, binary) {
1727
- const knipJsonPath = join7(cwd, "knip.json");
2051
+ const knipJsonPath = join9(cwd, "knip.json");
1728
2052
  try {
1729
2053
  const knipConfig = loadKnipConfig(knipJsonPath);
1730
2054
  const ignoreBinaries = knipConfig.ignoreBinaries ?? [];
@@ -1772,8 +2096,8 @@ import chalk29 from "chalk";
1772
2096
 
1773
2097
  // src/commands/lint/init.ts
1774
2098
  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";
2099
+ import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
2100
+ import { dirname as dirname7, join as join10 } from "path";
1777
2101
  import { fileURLToPath as fileURLToPath2 } from "url";
1778
2102
  import chalk28 from "chalk";
1779
2103
 
@@ -1798,7 +2122,7 @@ async function promptConfirm(message, initial = true) {
1798
2122
 
1799
2123
  // src/shared/removeEslint/index.ts
1800
2124
  import { execSync as execSync4 } from "child_process";
1801
- import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
2125
+ import { existsSync as existsSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
1802
2126
 
1803
2127
  // src/shared/removeEslint/removeEslintConfigFiles.ts
1804
2128
  import { existsSync as existsSync10, unlinkSync as unlinkSync3 } from "fs";
@@ -1842,7 +2166,7 @@ function removeEslintFromPackageJson(options2) {
1842
2166
  if (!existsSync11(packageJsonPath)) {
1843
2167
  return false;
1844
2168
  }
1845
- const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
2169
+ const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
1846
2170
  let modified = false;
1847
2171
  modified = removeEslintDeps(packageJson.dependencies) || modified;
1848
2172
  modified = removeEslintDeps(packageJson.devDependencies) || modified;
@@ -1920,9 +2244,9 @@ async function init() {
1920
2244
  console.log("No biome.json found, skipping linter config");
1921
2245
  return;
1922
2246
  }
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"));
2247
+ const linterConfigPath = join10(__dirname2, "commands/lint/biome.linter.json");
2248
+ const linterConfig = JSON.parse(readFileSync11(linterConfigPath, "utf-8"));
2249
+ const biomeConfig = JSON.parse(readFileSync11(biomeConfigPath, "utf-8"));
1926
2250
  const oldContent = `${JSON.stringify(biomeConfig, null, 2)}
1927
2251
  `;
1928
2252
  biomeConfig.linter = linterConfig.linter;
@@ -2980,7 +3304,7 @@ function initPackageJson(name) {
2980
3304
  }
2981
3305
 
2982
3306
  // src/commands/new/registerNew/newCli/writeCliTemplate.ts
2983
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync11 } from "fs";
3307
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync11 } from "fs";
2984
3308
  function writeCliTemplate(name) {
2985
3309
  console.log("Writing tsconfig.json...");
2986
3310
  writeFileSync11(
@@ -3021,7 +3345,7 @@ export default defineConfig({
3021
3345
  `
3022
3346
  );
3023
3347
  console.log("Writing src/index.ts...");
3024
- mkdirSync2("src", { recursive: true });
3348
+ mkdirSync3("src", { recursive: true });
3025
3349
  writeFileSync11(
3026
3350
  "src/index.ts",
3027
3351
  `#!/usr/bin/env node
@@ -3050,7 +3374,7 @@ async function newCli() {
3050
3374
 
3051
3375
  // src/commands/new/registerNew/newProject.ts
3052
3376
  import { execSync as execSync13 } from "child_process";
3053
- import { existsSync as existsSync16, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
3377
+ import { existsSync as existsSync16, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "fs";
3054
3378
 
3055
3379
  // src/commands/deploy/init/index.ts
3056
3380
  import { execSync as execSync12 } from "child_process";
@@ -3058,8 +3382,8 @@ import chalk40 from "chalk";
3058
3382
  import enquirer5 from "enquirer";
3059
3383
 
3060
3384
  // 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";
3385
+ import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
3386
+ import { dirname as dirname13, join as join13 } from "path";
3063
3387
  import { fileURLToPath as fileURLToPath3 } from "url";
3064
3388
  import chalk39 from "chalk";
3065
3389
  var WORKFLOW_PATH = ".github/workflows/build.yml";
@@ -3068,23 +3392,23 @@ function getExistingSiteId() {
3068
3392
  if (!existsSync15(WORKFLOW_PATH)) {
3069
3393
  return null;
3070
3394
  }
3071
- const content = readFileSync12(WORKFLOW_PATH, "utf-8");
3395
+ const content = readFileSync13(WORKFLOW_PATH, "utf-8");
3072
3396
  const match = content.match(/-s\s+([a-f0-9-]{36})/);
3073
3397
  return match ? match[1] : null;
3074
3398
  }
3075
3399
  function getTemplateContent(siteId) {
3076
- const templatePath = join11(__dirname3, "commands/deploy/build.yml");
3077
- const template = readFileSync12(templatePath, "utf-8");
3400
+ const templatePath = join13(__dirname3, "commands/deploy/build.yml");
3401
+ const template = readFileSync13(templatePath, "utf-8");
3078
3402
  return template.replace("{{NETLIFY_SITE_ID}}", siteId);
3079
3403
  }
3080
3404
  async function updateWorkflow(siteId) {
3081
3405
  const newContent = getTemplateContent(siteId);
3082
3406
  const workflowDir = ".github/workflows";
3083
3407
  if (!existsSync15(workflowDir)) {
3084
- mkdirSync3(workflowDir, { recursive: true });
3408
+ mkdirSync4(workflowDir, { recursive: true });
3085
3409
  }
3086
3410
  if (existsSync15(WORKFLOW_PATH)) {
3087
- const oldContent = readFileSync12(WORKFLOW_PATH, "utf-8");
3411
+ const oldContent = readFileSync13(WORKFLOW_PATH, "utf-8");
3088
3412
  if (oldContent === newContent) {
3089
3413
  console.log(chalk39.green("build.yml is already up to date"));
3090
3414
  return;
@@ -3182,7 +3506,7 @@ function addViteBaseConfig() {
3182
3506
  console.log("No vite.config.ts found, skipping base config");
3183
3507
  return;
3184
3508
  }
3185
- const content = readFileSync13(viteConfigPath, "utf-8");
3509
+ const content = readFileSync14(viteConfigPath, "utf-8");
3186
3510
  if (content.includes("base:")) {
3187
3511
  console.log("vite.config.ts already has base config");
3188
3512
  return;
@@ -3365,12 +3689,13 @@ import chalk45 from "chalk";
3365
3689
 
3366
3690
  // src/commands/backlog/commitBacklog.ts
3367
3691
  import { execSync as execSync14 } from "child_process";
3692
+ import { join as join14 } from "path";
3368
3693
  import chalk43 from "chalk";
3369
3694
  function commitBacklog(id, name) {
3370
3695
  try {
3371
- const backlogPath = getBacklogPath();
3696
+ const jsonlPath = join14(getBacklogDir(), ".assist", "backlog.jsonl");
3372
3697
  const message = `chore: add backlog item #${id} \u2014 ${name}`;
3373
- execSync14(`git add ${shellQuote(backlogPath)}`, { stdio: "ignore" });
3698
+ execSync14(`git add ${shellQuote(jsonlPath)}`, { stdio: "ignore" });
3374
3699
  execSync14(`git commit -m ${shellQuote(message)}`, { stdio: "ignore" });
3375
3700
  } catch {
3376
3701
  console.log(chalk43.yellow("Warning: could not auto-commit backlog file."));
@@ -3378,7 +3703,7 @@ function commitBacklog(id, name) {
3378
3703
  }
3379
3704
 
3380
3705
  // src/commands/backlog/add/parseItemFile.ts
3381
- import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
3706
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
3382
3707
  import chalk44 from "chalk";
3383
3708
  import { ZodError } from "zod";
3384
3709
  var addItemSchema = backlogItemSchema.omit({ id: true, status: true });
@@ -3390,7 +3715,7 @@ function readJsonFile(filePath) {
3390
3715
  }
3391
3716
  let raw;
3392
3717
  try {
3393
- raw = readFileSync14(filePath, "utf-8");
3718
+ raw = readFileSync15(filePath, "utf-8");
3394
3719
  } catch {
3395
3720
  console.log(chalk44.red(`Failed to read file: ${filePath}`));
3396
3721
  process.exitCode = 1;
@@ -3428,9 +3753,9 @@ function parseItemFile(filePath) {
3428
3753
 
3429
3754
  // src/commands/backlog/add/shared.ts
3430
3755
  import { spawnSync } from "child_process";
3431
- import { mkdtempSync, readFileSync as readFileSync15, unlinkSync as unlinkSync4, writeFileSync as writeFileSync14 } from "fs";
3756
+ import { mkdtempSync, readFileSync as readFileSync16, unlinkSync as unlinkSync4, writeFileSync as writeFileSync14 } from "fs";
3432
3757
  import { tmpdir } from "os";
3433
- import { join as join12 } from "path";
3758
+ import { join as join15 } from "path";
3434
3759
  import enquirer6 from "enquirer";
3435
3760
  async function promptType() {
3436
3761
  const { type } = await enquirer6.prompt({
@@ -3470,15 +3795,15 @@ async function promptDescription() {
3470
3795
  }
3471
3796
  function openEditor() {
3472
3797
  const editor = process.env.EDITOR || process.env.VISUAL || "vi";
3473
- const dir = mkdtempSync(join12(tmpdir(), "assist-"));
3474
- const filePath = join12(dir, "description.md");
3798
+ const dir = mkdtempSync(join15(tmpdir(), "assist-"));
3799
+ const filePath = join15(dir, "description.md");
3475
3800
  writeFileSync14(filePath, "");
3476
3801
  const result = spawnSync(editor, [filePath], { stdio: "inherit" });
3477
3802
  if (result.status !== 0) {
3478
3803
  unlinkSync4(filePath);
3479
3804
  return void 0;
3480
3805
  }
3481
- const content = readFileSync15(filePath, "utf-8").trim();
3806
+ const content = readFileSync16(filePath, "utf-8").trim();
3482
3807
  unlinkSync4(filePath);
3483
3808
  return content || void 0;
3484
3809
  }
@@ -3870,7 +4195,7 @@ function extractGraphqlQuery(args) {
3870
4195
  }
3871
4196
 
3872
4197
  // src/shared/loadCliReads.ts
3873
- import { existsSync as existsSync21, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
4198
+ import { existsSync as existsSync21, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
3874
4199
  import { dirname as dirname14, resolve as resolve2 } from "path";
3875
4200
  import { fileURLToPath as fileURLToPath4 } from "url";
3876
4201
  var __filename2 = fileURLToPath4(import.meta.url);
@@ -3880,7 +4205,7 @@ function packageRoot() {
3880
4205
  }
3881
4206
  function readLines(path50) {
3882
4207
  if (!existsSync21(path50)) return [];
3883
- return readFileSync16(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
4208
+ return readFileSync17(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
3884
4209
  }
3885
4210
  var cachedReads;
3886
4211
  var cachedWrites;
@@ -3926,14 +4251,14 @@ function findCliWrite(command) {
3926
4251
  }
3927
4252
 
3928
4253
  // src/shared/readSettingsPerms.ts
3929
- import { existsSync as existsSync22, readFileSync as readFileSync17 } from "fs";
4254
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "fs";
3930
4255
  import { homedir as homedir3 } from "os";
3931
- import { join as join13 } from "path";
4256
+ import { join as join16 } from "path";
3932
4257
  function readSettingsPerms(key) {
3933
4258
  const paths = [
3934
- join13(homedir3(), ".claude", "settings.json"),
3935
- join13(process.cwd(), ".claude", "settings.json"),
3936
- join13(process.cwd(), ".claude", "settings.local.json")
4259
+ join16(homedir3(), ".claude", "settings.json"),
4260
+ join16(process.cwd(), ".claude", "settings.json"),
4261
+ join16(process.cwd(), ".claude", "settings.local.json")
3937
4262
  ];
3938
4263
  const entries = [];
3939
4264
  for (const p of paths) {
@@ -3944,7 +4269,7 @@ function readSettingsPerms(key) {
3944
4269
  function readPermissionArray(filePath, key) {
3945
4270
  if (!existsSync22(filePath)) return [];
3946
4271
  try {
3947
- const data = JSON.parse(readFileSync17(filePath, "utf-8"));
4272
+ const data = JSON.parse(readFileSync18(filePath, "utf-8"));
3948
4273
  const arr = data?.permissions?.[key];
3949
4274
  return Array.isArray(arr) ? arr.filter((e) => typeof e === "string") : [];
3950
4275
  } catch {
@@ -4229,9 +4554,9 @@ function denyRemove(pattern2) {
4229
4554
  }
4230
4555
 
4231
4556
  // src/commands/permitCliReads/index.ts
4232
- import { existsSync as existsSync23, mkdirSync as mkdirSync4, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
4557
+ import { existsSync as existsSync23, mkdirSync as mkdirSync5, readFileSync as readFileSync19, writeFileSync as writeFileSync16 } from "fs";
4233
4558
  import { homedir as homedir4 } from "os";
4234
- import { join as join14 } from "path";
4559
+ import { join as join17 } from "path";
4235
4560
 
4236
4561
  // src/shared/getInstallDir.ts
4237
4562
  import { execSync as execSync15 } from "child_process";
@@ -4533,16 +4858,16 @@ function updateSettings(cli, commands) {
4533
4858
  // src/commands/permitCliReads/index.ts
4534
4859
  function logPath(cli) {
4535
4860
  const safeName = cli.replace(/\s+/g, "-");
4536
- return join14(homedir4(), ".assist", `cli-discover-${safeName}.log`);
4861
+ return join17(homedir4(), ".assist", `cli-discover-${safeName}.log`);
4537
4862
  }
4538
4863
  function readCache(cli) {
4539
4864
  const path50 = logPath(cli);
4540
4865
  if (!existsSync23(path50)) return void 0;
4541
- return readFileSync18(path50, "utf-8");
4866
+ return readFileSync19(path50, "utf-8");
4542
4867
  }
4543
4868
  function writeCache(cli, output) {
4544
- const dir = join14(homedir4(), ".assist");
4545
- mkdirSync4(dir, { recursive: true });
4869
+ const dir = join17(homedir4(), ".assist");
4870
+ mkdirSync5(dir, { recursive: true });
4546
4871
  writeFileSync16(logPath(cli), output);
4547
4872
  }
4548
4873
  async function permitCliReads(cli, options2 = { noCache: false }) {
@@ -5090,7 +5415,7 @@ function registerComplexity(program2) {
5090
5415
  }
5091
5416
 
5092
5417
  // src/commands/deploy/redirect.ts
5093
- import { existsSync as existsSync24, readFileSync as readFileSync19, writeFileSync as writeFileSync17 } from "fs";
5418
+ import { existsSync as existsSync24, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "fs";
5094
5419
  import chalk64 from "chalk";
5095
5420
  var TRAILING_SLASH_SCRIPT = ` <script>
5096
5421
  if (!window.location.pathname.endsWith('/')) {
@@ -5103,7 +5428,7 @@ function redirect() {
5103
5428
  console.log(chalk64.yellow("No index.html found"));
5104
5429
  return;
5105
5430
  }
5106
- const content = readFileSync19(indexPath, "utf-8");
5431
+ const content = readFileSync20(indexPath, "utf-8");
5107
5432
  if (content.includes("window.location.pathname.endsWith('/')")) {
5108
5433
  console.log(chalk64.dim("Trailing slash script already present"));
5109
5434
  return;
@@ -5131,10 +5456,10 @@ import { basename as basename3 } from "path";
5131
5456
 
5132
5457
  // src/commands/devlog/loadBlogSkipDays.ts
5133
5458
  import { homedir as homedir5 } from "os";
5134
- import { join as join15 } from "path";
5135
- var BLOG_REPO_ROOT = join15(homedir5(), "git/blog");
5459
+ import { join as join18 } from "path";
5460
+ var BLOG_REPO_ROOT = join18(homedir5(), "git/blog");
5136
5461
  function loadBlogSkipDays(repoName) {
5137
- const config = loadRawYaml(join15(BLOG_REPO_ROOT, "assist.yml"));
5462
+ const config = loadRawYaml(join18(BLOG_REPO_ROOT, "assist.yml"));
5138
5463
  const devlog = config.devlog;
5139
5464
  const skip2 = devlog?.skip;
5140
5465
  return new Set(skip2?.[repoName] ?? []);
@@ -5145,9 +5470,9 @@ import { execSync as execSync17 } from "child_process";
5145
5470
  import chalk65 from "chalk";
5146
5471
 
5147
5472
  // 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");
5473
+ import { readdirSync, readFileSync as readFileSync21 } from "fs";
5474
+ import { join as join19 } from "path";
5475
+ var DEVLOG_DIR = join19(BLOG_REPO_ROOT, "src/content/devlog");
5151
5476
  function extractFrontmatter(content) {
5152
5477
  const fm = content.match(/^---\n([\s\S]*?)\n---/);
5153
5478
  return fm?.[1] ?? null;
@@ -5175,7 +5500,7 @@ function readDevlogFiles(callback) {
5175
5500
  try {
5176
5501
  const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
5177
5502
  for (const file of files) {
5178
- const content = readFileSync20(join16(DEVLOG_DIR, file), "utf-8");
5503
+ const content = readFileSync21(join19(DEVLOG_DIR, file), "utf-8");
5179
5504
  const parsed = parseFrontmatter(content, file);
5180
5505
  if (parsed) callback(parsed);
5181
5506
  }
@@ -5354,7 +5679,8 @@ function getLastVersionInfo(repoName, config) {
5354
5679
  const gitInfo = getLastVersionInfoFromGit();
5355
5680
  if (gitInfo) return { date: lastDate, version: gitInfo.version };
5356
5681
  }
5357
- const lastVersion = entries.get(lastDate)?.[0]?.version;
5682
+ const dayEntries = entries.get(lastDate);
5683
+ const lastVersion = dayEntries?.[dayEntries.length - 1]?.version;
5358
5684
  return lastVersion ? { date: lastDate, version: lastVersion } : null;
5359
5685
  }
5360
5686
  function cleanVersion(version2) {
@@ -5561,11 +5887,11 @@ function repos(options2) {
5561
5887
 
5562
5888
  // src/commands/devlog/skip.ts
5563
5889
  import { writeFileSync as writeFileSync18 } from "fs";
5564
- import { join as join17 } from "path";
5890
+ import { join as join20 } from "path";
5565
5891
  import chalk70 from "chalk";
5566
- import { stringify as stringifyYaml4 } from "yaml";
5892
+ import { stringify as stringifyYaml3 } from "yaml";
5567
5893
  function getBlogConfigPath() {
5568
- return join17(BLOG_REPO_ROOT, "assist.yml");
5894
+ return join20(BLOG_REPO_ROOT, "assist.yml");
5569
5895
  }
5570
5896
  function skip(date) {
5571
5897
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
@@ -5589,7 +5915,7 @@ function skip(date) {
5589
5915
  skip2[repoName] = skipDays;
5590
5916
  devlog.skip = skip2;
5591
5917
  config.devlog = devlog;
5592
- writeFileSync18(configPath, stringifyYaml4(config, { lineWidth: 0 }));
5918
+ writeFileSync18(configPath, stringifyYaml3(config, { lineWidth: 0 }));
5593
5919
  console.log(chalk70.green(`Added ${date} to skip list for ${repoName}`));
5594
5920
  }
5595
5921
 
@@ -5626,7 +5952,7 @@ function registerDevlog(program2) {
5626
5952
 
5627
5953
  // src/commands/dotnet/checkBuildLocks.ts
5628
5954
  import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
5629
- import { join as join18 } from "path";
5955
+ import { join as join21 } from "path";
5630
5956
  import chalk72 from "chalk";
5631
5957
 
5632
5958
  // src/shared/findRepoRoot.ts
@@ -5654,7 +5980,7 @@ function isLockedDll(debugDir) {
5654
5980
  }
5655
5981
  for (const file of files) {
5656
5982
  if (!file.toLowerCase().endsWith(".dll")) continue;
5657
- const dllPath = join18(debugDir, file);
5983
+ const dllPath = join21(debugDir, file);
5658
5984
  try {
5659
5985
  const fd = openSync(dllPath, "r+");
5660
5986
  closeSync(fd);
@@ -5672,13 +5998,13 @@ function findFirstLockedDll(dir) {
5672
5998
  return null;
5673
5999
  }
5674
6000
  if (entries.includes("bin")) {
5675
- const locked = isLockedDll(join18(dir, "bin", "Debug"));
6001
+ const locked = isLockedDll(join21(dir, "bin", "Debug"));
5676
6002
  if (locked) return locked;
5677
6003
  }
5678
6004
  for (const entry of entries) {
5679
6005
  if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
5680
6006
  continue;
5681
- const found = findFirstLockedDll(join18(dir, entry));
6007
+ const found = findFirstLockedDll(join21(dir, entry));
5682
6008
  if (found) return found;
5683
6009
  }
5684
6010
  return null;
@@ -5701,11 +6027,11 @@ async function checkBuildLocksCommand() {
5701
6027
  }
5702
6028
 
5703
6029
  // src/commands/dotnet/buildTree.ts
5704
- import { readFileSync as readFileSync21 } from "fs";
6030
+ import { readFileSync as readFileSync22 } from "fs";
5705
6031
  import path22 from "path";
5706
6032
  var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
5707
6033
  function getProjectRefs(csprojPath) {
5708
- const content = readFileSync21(csprojPath, "utf-8");
6034
+ const content = readFileSync22(csprojPath, "utf-8");
5709
6035
  const refs = [];
5710
6036
  for (const match of content.matchAll(PROJECT_REF_RE)) {
5711
6037
  refs.push(match[1].replace(/\\/g, "/"));
@@ -5722,7 +6048,7 @@ function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
5722
6048
  for (const ref of getProjectRefs(abs)) {
5723
6049
  const childAbs = path22.resolve(dir, ref);
5724
6050
  try {
5725
- readFileSync21(childAbs);
6051
+ readFileSync22(childAbs);
5726
6052
  node.children.push(buildTree(childAbs, repoRoot, visited));
5727
6053
  } catch {
5728
6054
  node.children.push({
@@ -5747,7 +6073,7 @@ function collectAllDeps(node) {
5747
6073
  }
5748
6074
 
5749
6075
  // src/commands/dotnet/findContainingSolutions.ts
5750
- import { readdirSync as readdirSync3, readFileSync as readFileSync22, statSync } from "fs";
6076
+ import { readdirSync as readdirSync3, readFileSync as readFileSync23, statSync as statSync3 } from "fs";
5751
6077
  import path23 from "path";
5752
6078
  function findSlnFiles(dir, maxDepth, depth = 0) {
5753
6079
  if (depth > maxDepth) return [];
@@ -5763,7 +6089,7 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
5763
6089
  continue;
5764
6090
  const full = path23.join(dir, entry);
5765
6091
  try {
5766
- const stat = statSync(full);
6092
+ const stat = statSync3(full);
5767
6093
  if (stat.isFile() && entry.endsWith(".sln")) {
5768
6094
  results.push(full);
5769
6095
  } else if (stat.isDirectory()) {
@@ -5782,7 +6108,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
5782
6108
  const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
5783
6109
  for (const sln of slnFiles) {
5784
6110
  try {
5785
- const content = readFileSync22(sln, "utf-8");
6111
+ const content = readFileSync23(sln, "utf-8");
5786
6112
  if (pattern2.test(content)) {
5787
6113
  matches.push(path23.relative(repoRoot, sln));
5788
6114
  }
@@ -6025,11 +6351,11 @@ import chalk78 from "chalk";
6025
6351
 
6026
6352
  // src/commands/dotnet/findSolution.ts
6027
6353
  import { readdirSync as readdirSync4 } from "fs";
6028
- import { dirname as dirname16, join as join19 } from "path";
6354
+ import { dirname as dirname16, join as join22 } from "path";
6029
6355
  import chalk77 from "chalk";
6030
6356
  function findSlnInDir(dir) {
6031
6357
  try {
6032
- return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join19(dir, f));
6358
+ return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join22(dir, f));
6033
6359
  } catch {
6034
6360
  return [];
6035
6361
  }
@@ -6100,7 +6426,7 @@ function parseInspectReport(json) {
6100
6426
 
6101
6427
  // src/commands/dotnet/runInspectCode.ts
6102
6428
  import { execSync as execSync23 } from "child_process";
6103
- import { existsSync as existsSync28, readFileSync as readFileSync23, unlinkSync as unlinkSync5 } from "fs";
6429
+ import { existsSync as existsSync28, readFileSync as readFileSync24, unlinkSync as unlinkSync5 } from "fs";
6104
6430
  import { tmpdir as tmpdir2 } from "os";
6105
6431
  import path26 from "path";
6106
6432
  import chalk79 from "chalk";
@@ -6135,7 +6461,7 @@ function runInspectCode(slnPath, include, swea) {
6135
6461
  console.error(chalk79.red("Report file not generated"));
6136
6462
  process.exit(1);
6137
6463
  }
6138
- const xml = readFileSync23(reportPath, "utf-8");
6464
+ const xml = readFileSync24(reportPath, "utf-8");
6139
6465
  unlinkSync5(reportPath);
6140
6466
  return xml;
6141
6467
  }
@@ -6363,20 +6689,20 @@ function acceptanceCriteria(issueKey) {
6363
6689
  import { execSync as execSync26 } from "child_process";
6364
6690
 
6365
6691
  // src/shared/loadJson.ts
6366
- import { existsSync as existsSync29, mkdirSync as mkdirSync5, readFileSync as readFileSync24, writeFileSync as writeFileSync19 } from "fs";
6692
+ import { existsSync as existsSync29, mkdirSync as mkdirSync6, readFileSync as readFileSync25, writeFileSync as writeFileSync19 } from "fs";
6367
6693
  import { homedir as homedir6 } from "os";
6368
- import { join as join20 } from "path";
6694
+ import { join as join23 } from "path";
6369
6695
  function getStoreDir() {
6370
- return join20(homedir6(), ".assist");
6696
+ return join23(homedir6(), ".assist");
6371
6697
  }
6372
6698
  function getStorePath(filename) {
6373
- return join20(getStoreDir(), filename);
6699
+ return join23(getStoreDir(), filename);
6374
6700
  }
6375
6701
  function loadJson(filename) {
6376
6702
  const path50 = getStorePath(filename);
6377
6703
  if (existsSync29(path50)) {
6378
6704
  try {
6379
- return JSON.parse(readFileSync24(path50, "utf-8"));
6705
+ return JSON.parse(readFileSync25(path50, "utf-8"));
6380
6706
  } catch {
6381
6707
  return {};
6382
6708
  }
@@ -6386,7 +6712,7 @@ function loadJson(filename) {
6386
6712
  function saveJson(filename, data) {
6387
6713
  const dir = getStoreDir();
6388
6714
  if (!existsSync29(dir)) {
6389
- mkdirSync5(dir, { recursive: true });
6715
+ mkdirSync6(dir, { recursive: true });
6390
6716
  }
6391
6717
  writeFileSync19(getStorePath(filename), JSON.stringify(data, null, 2));
6392
6718
  }
@@ -6702,7 +7028,7 @@ function registerNews(program2) {
6702
7028
  import { spawnSync as spawnSync2 } from "child_process";
6703
7029
  import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync20 } from "fs";
6704
7030
  import { tmpdir as tmpdir3 } from "os";
6705
- import { join as join21 } from "path";
7031
+ import { join as join24 } from "path";
6706
7032
 
6707
7033
  // src/commands/prs/shared.ts
6708
7034
  import { execSync as execSync27 } from "child_process";
@@ -6774,7 +7100,7 @@ function comment2(path50, line, body) {
6774
7100
  validateLine(line);
6775
7101
  try {
6776
7102
  const prId = getCurrentPrNodeId();
6777
- const queryFile = join21(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7103
+ const queryFile = join24(tmpdir3(), `gh-query-${Date.now()}.graphql`);
6778
7104
  writeFileSync20(queryFile, MUTATION);
6779
7105
  try {
6780
7106
  const result = spawnSync2(
@@ -6819,21 +7145,21 @@ import { execSync as execSync29 } from "child_process";
6819
7145
  import { execSync as execSync28 } from "child_process";
6820
7146
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync21 } from "fs";
6821
7147
  import { tmpdir as tmpdir4 } from "os";
6822
- import { join as join23 } from "path";
7148
+ import { join as join26 } from "path";
6823
7149
 
6824
7150
  // 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";
7151
+ import { existsSync as existsSync30, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
7152
+ import { join as join25 } from "path";
6827
7153
  import { parse as parse2 } from "yaml";
6828
7154
  function getCachePath(prNumber) {
6829
- return join22(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
7155
+ return join25(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
6830
7156
  }
6831
7157
  function loadCommentsCache(prNumber) {
6832
7158
  const cachePath = getCachePath(prNumber);
6833
7159
  if (!existsSync30(cachePath)) {
6834
7160
  return null;
6835
7161
  }
6836
- const content = readFileSync25(cachePath, "utf-8");
7162
+ const content = readFileSync26(cachePath, "utf-8");
6837
7163
  return parse2(content);
6838
7164
  }
6839
7165
  function deleteCommentsCache(prNumber) {
@@ -6853,7 +7179,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
6853
7179
  }
6854
7180
  function resolveThread(threadId) {
6855
7181
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
6856
- const queryFile = join23(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
7182
+ const queryFile = join26(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
6857
7183
  writeFileSync21(queryFile, mutation);
6858
7184
  try {
6859
7185
  execSync28(
@@ -6935,18 +7261,18 @@ function fixed(commentId, sha) {
6935
7261
  }
6936
7262
 
6937
7263
  // 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";
7264
+ import { existsSync as existsSync31, mkdirSync as mkdirSync7, writeFileSync as writeFileSync23 } from "fs";
7265
+ import { join as join28 } from "path";
6940
7266
  import { stringify } from "yaml";
6941
7267
 
6942
7268
  // src/commands/prs/fetchThreadIds.ts
6943
7269
  import { execSync as execSync30 } from "child_process";
6944
7270
  import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync22 } from "fs";
6945
7271
  import { tmpdir as tmpdir5 } from "os";
6946
- import { join as join24 } from "path";
7272
+ import { join as join27 } from "path";
6947
7273
  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
7274
  function fetchThreadIds(org, repo, prNumber) {
6949
- const queryFile = join24(tmpdir5(), `gh-query-${Date.now()}.graphql`);
7275
+ const queryFile = join27(tmpdir5(), `gh-query-${Date.now()}.graphql`);
6950
7276
  writeFileSync22(queryFile, THREAD_QUERY);
6951
7277
  try {
6952
7278
  const result = execSync30(
@@ -7060,16 +7386,16 @@ function printComments2(result) {
7060
7386
 
7061
7387
  // src/commands/prs/listComments/index.ts
7062
7388
  function writeCommentsCache(prNumber, comments2) {
7063
- const assistDir = join25(process.cwd(), ".assist");
7389
+ const assistDir = join28(process.cwd(), ".assist");
7064
7390
  if (!existsSync31(assistDir)) {
7065
- mkdirSync6(assistDir, { recursive: true });
7391
+ mkdirSync7(assistDir, { recursive: true });
7066
7392
  }
7067
7393
  const cacheData = {
7068
7394
  prNumber,
7069
7395
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
7070
7396
  comments: comments2
7071
7397
  };
7072
- const cachePath = join25(assistDir, `pr-${prNumber}-comments.yaml`);
7398
+ const cachePath = join28(assistDir, `pr-${prNumber}-comments.yaml`);
7073
7399
  writeFileSync23(cachePath, stringify(cacheData));
7074
7400
  }
7075
7401
  function handleKnownErrors(error) {
@@ -7102,7 +7428,7 @@ async function listComments() {
7102
7428
  ];
7103
7429
  updateCache(prNumber, allComments);
7104
7430
  const hasLineComments = allComments.some((c) => c.type === "line");
7105
- const cachePath = hasLineComments ? join25(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
7431
+ const cachePath = hasLineComments ? join28(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
7106
7432
  return { comments: allComments, cachePath };
7107
7433
  } catch (error) {
7108
7434
  const handled = handleKnownErrors(error);
@@ -9496,8 +9822,8 @@ function registerSeq(program2) {
9496
9822
  }
9497
9823
 
9498
9824
  // 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";
9825
+ import { existsSync as existsSync32, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
9826
+ import { basename as basename4, join as join29, relative } from "path";
9501
9827
  import * as readline2 from "readline";
9502
9828
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
9503
9829
  function getDatePrefix(daysOffset = 0) {
@@ -9515,8 +9841,8 @@ function collectFiles(dir, extension) {
9515
9841
  if (!existsSync32(dir)) return [];
9516
9842
  const results = [];
9517
9843
  for (const entry of readdirSync5(dir)) {
9518
- const fullPath = join26(dir, entry);
9519
- if (statSync2(fullPath).isDirectory()) {
9844
+ const fullPath = join29(dir, entry);
9845
+ if (statSync4(fullPath).isDirectory()) {
9520
9846
  results.push(...collectFiles(fullPath, extension));
9521
9847
  } else if (entry.endsWith(extension)) {
9522
9848
  results.push(fullPath);
@@ -9612,11 +9938,11 @@ async function configure() {
9612
9938
  import { existsSync as existsSync34 } from "fs";
9613
9939
 
9614
9940
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
9615
- import { dirname as dirname18, join as join28 } from "path";
9941
+ import { dirname as dirname18, join as join31 } from "path";
9616
9942
 
9617
9943
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
9618
- import { renameSync } from "fs";
9619
- import { join as join27 } from "path";
9944
+ import { renameSync as renameSync2 } from "fs";
9945
+ import { join as join30 } from "path";
9620
9946
  async function resolveDate(rl, choice) {
9621
9947
  if (choice === "1") return getDatePrefix(0);
9622
9948
  if (choice === "2") return getDatePrefix(-1);
@@ -9631,7 +9957,7 @@ async function resolveDate(rl, choice) {
9631
9957
  }
9632
9958
  function renameWithPrefix(vttDir, vttFile, prefix2) {
9633
9959
  const newFilename = `${prefix2}.${vttFile}`;
9634
- renameSync(join27(vttDir, vttFile), join27(vttDir, newFilename));
9960
+ renameSync2(join30(vttDir, vttFile), join30(vttDir, newFilename));
9635
9961
  console.log(`Renamed to: ${newFilename}`);
9636
9962
  return newFilename;
9637
9963
  }
@@ -9665,12 +9991,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
9665
9991
  const vttFileDir = dirname18(vttFile.absolutePath);
9666
9992
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
9667
9993
  if (newFilename) {
9668
- const newRelativePath = join28(
9994
+ const newRelativePath = join31(
9669
9995
  dirname18(vttFile.relativePath),
9670
9996
  newFilename
9671
9997
  );
9672
9998
  vttFiles[i] = {
9673
- absolutePath: join28(vttFileDir, newFilename),
9999
+ absolutePath: join31(vttFileDir, newFilename),
9674
10000
  relativePath: newRelativePath,
9675
10001
  filename: newFilename
9676
10002
  };
@@ -9683,8 +10009,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
9683
10009
  }
9684
10010
 
9685
10011
  // 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";
10012
+ import { existsSync as existsSync33, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync24 } from "fs";
10013
+ import { basename as basename5, dirname as dirname19, join as join32 } from "path";
9688
10014
 
9689
10015
  // src/commands/transcript/cleanText.ts
9690
10016
  function cleanText(text) {
@@ -9894,22 +10220,22 @@ function toMdFilename(vttFilename) {
9894
10220
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
9895
10221
  }
9896
10222
  function resolveOutputDir(relativeDir, transcriptsDir) {
9897
- return relativeDir === "." ? transcriptsDir : join29(transcriptsDir, relativeDir);
10223
+ return relativeDir === "." ? transcriptsDir : join32(transcriptsDir, relativeDir);
9898
10224
  }
9899
10225
  function buildOutputPaths(vttFile, transcriptsDir) {
9900
10226
  const mdFile = toMdFilename(vttFile.filename);
9901
10227
  const relativeDir = dirname19(vttFile.relativePath);
9902
10228
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
9903
- const outputPath = join29(outputDir, mdFile);
10229
+ const outputPath = join32(outputDir, mdFile);
9904
10230
  return { outputDir, outputPath, mdFile, relativeDir };
9905
10231
  }
9906
10232
  function logSkipped(relativeDir, mdFile) {
9907
- console.log(`Skipping (already exists): ${join29(relativeDir, mdFile)}`);
10233
+ console.log(`Skipping (already exists): ${join32(relativeDir, mdFile)}`);
9908
10234
  return "skipped";
9909
10235
  }
9910
10236
  function ensureDirectory(dir, label2) {
9911
10237
  if (!existsSync33(dir)) {
9912
- mkdirSync7(dir, { recursive: true });
10238
+ mkdirSync8(dir, { recursive: true });
9913
10239
  console.log(`Created ${label2}: ${dir}`);
9914
10240
  }
9915
10241
  }
@@ -9931,7 +10257,7 @@ function logReduction(cueCount, messageCount) {
9931
10257
  }
9932
10258
  function readAndParseCues(inputPath) {
9933
10259
  console.log(`Reading: ${inputPath}`);
9934
- return processCues(readFileSync26(inputPath, "utf-8"));
10260
+ return processCues(readFileSync27(inputPath, "utf-8"));
9935
10261
  }
9936
10262
  function writeFormatted(outputPath, content) {
9937
10263
  writeFileSync24(outputPath, content, "utf-8");
@@ -10003,17 +10329,17 @@ async function format() {
10003
10329
 
10004
10330
  // src/commands/transcript/summarise/index.ts
10005
10331
  import { existsSync as existsSync36 } from "fs";
10006
- import { basename as basename6, dirname as dirname21, join as join31, relative as relative2 } from "path";
10332
+ import { basename as basename6, dirname as dirname21, join as join34, relative as relative2 } from "path";
10007
10333
 
10008
10334
  // src/commands/transcript/summarise/processStagedFile/index.ts
10009
10335
  import {
10010
10336
  existsSync as existsSync35,
10011
- mkdirSync as mkdirSync8,
10012
- readFileSync as readFileSync27,
10013
- renameSync as renameSync2,
10337
+ mkdirSync as mkdirSync9,
10338
+ readFileSync as readFileSync28,
10339
+ renameSync as renameSync3,
10014
10340
  rmSync
10015
10341
  } from "fs";
10016
- import { dirname as dirname20, join as join30 } from "path";
10342
+ import { dirname as dirname20, join as join33 } from "path";
10017
10343
 
10018
10344
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
10019
10345
  import chalk118 from "chalk";
@@ -10042,7 +10368,7 @@ function validateStagedContent(filename, content) {
10042
10368
  }
10043
10369
 
10044
10370
  // src/commands/transcript/summarise/processStagedFile/index.ts
10045
- var STAGING_DIR = join30(process.cwd(), ".assist", "transcript");
10371
+ var STAGING_DIR = join33(process.cwd(), ".assist", "transcript");
10046
10372
  function processStagedFile() {
10047
10373
  if (!existsSync35(STAGING_DIR)) {
10048
10374
  return false;
@@ -10053,7 +10379,7 @@ function processStagedFile() {
10053
10379
  }
10054
10380
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
10055
10381
  const stagedFile = stagedFiles[0];
10056
- const content = readFileSync27(stagedFile.absolutePath, "utf-8");
10382
+ const content = readFileSync28(stagedFile.absolutePath, "utf-8");
10057
10383
  validateStagedContent(stagedFile.filename, content);
10058
10384
  const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
10059
10385
  const transcriptFiles = findMdFilesRecursive(transcriptsDir);
@@ -10066,12 +10392,12 @@ function processStagedFile() {
10066
10392
  );
10067
10393
  process.exit(1);
10068
10394
  }
10069
- const destPath = join30(summaryDir, matchingTranscript.relativePath);
10395
+ const destPath = join33(summaryDir, matchingTranscript.relativePath);
10070
10396
  const destDir = dirname20(destPath);
10071
10397
  if (!existsSync35(destDir)) {
10072
- mkdirSync8(destDir, { recursive: true });
10398
+ mkdirSync9(destDir, { recursive: true });
10073
10399
  }
10074
- renameSync2(stagedFile.absolutePath, destPath);
10400
+ renameSync3(stagedFile.absolutePath, destPath);
10075
10401
  const remaining = findMdFilesRecursive(STAGING_DIR);
10076
10402
  if (remaining.length === 0) {
10077
10403
  rmSync(STAGING_DIR, { recursive: true });
@@ -10082,7 +10408,7 @@ function processStagedFile() {
10082
10408
  // src/commands/transcript/summarise/index.ts
10083
10409
  function buildRelativeKey(relativePath, baseName) {
10084
10410
  const relDir = dirname21(relativePath);
10085
- return relDir === "." ? baseName : join31(relDir, baseName);
10411
+ return relDir === "." ? baseName : join34(relDir, baseName);
10086
10412
  }
10087
10413
  function buildSummaryIndex(summaryDir) {
10088
10414
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -10116,8 +10442,8 @@ function summarise2() {
10116
10442
  }
10117
10443
  const next3 = missing[0];
10118
10444
  const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
10119
- const outputPath = join31(STAGING_DIR, outputFilename);
10120
- const summaryFileDir = join31(summaryDir, dirname21(next3.relativePath));
10445
+ const outputPath = join34(STAGING_DIR, outputFilename);
10446
+ const summaryFileDir = join34(summaryDir, dirname21(next3.relativePath));
10121
10447
  const relativeTranscriptPath = encodeURI(
10122
10448
  relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
10123
10449
  );
@@ -10163,50 +10489,50 @@ function registerVerify(program2) {
10163
10489
 
10164
10490
  // src/commands/voice/devices.ts
10165
10491
  import { spawnSync as spawnSync3 } from "child_process";
10166
- import { join as join33 } from "path";
10492
+ import { join as join36 } from "path";
10167
10493
 
10168
10494
  // src/commands/voice/shared.ts
10169
10495
  import { homedir as homedir7 } from "os";
10170
- import { dirname as dirname22, join as join32 } from "path";
10496
+ import { dirname as dirname22, join as join35 } from "path";
10171
10497
  import { fileURLToPath as fileURLToPath6 } from "url";
10172
10498
  var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
10173
- var VOICE_DIR = join32(homedir7(), ".assist", "voice");
10499
+ var VOICE_DIR = join35(homedir7(), ".assist", "voice");
10174
10500
  var voicePaths = {
10175
10501
  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")
10502
+ pid: join35(VOICE_DIR, "voice.pid"),
10503
+ log: join35(VOICE_DIR, "voice.log"),
10504
+ venv: join35(VOICE_DIR, ".venv"),
10505
+ lock: join35(VOICE_DIR, "voice.lock")
10180
10506
  };
10181
10507
  function getPythonDir() {
10182
- return join32(__dirname6, "commands", "voice", "python");
10508
+ return join35(__dirname6, "commands", "voice", "python");
10183
10509
  }
10184
10510
  function getVenvPython() {
10185
- return process.platform === "win32" ? join32(voicePaths.venv, "Scripts", "python.exe") : join32(voicePaths.venv, "bin", "python");
10511
+ return process.platform === "win32" ? join35(voicePaths.venv, "Scripts", "python.exe") : join35(voicePaths.venv, "bin", "python");
10186
10512
  }
10187
10513
  function getLockDir() {
10188
10514
  const config = loadConfig();
10189
10515
  return config.voice?.lockDir ?? VOICE_DIR;
10190
10516
  }
10191
10517
  function getLockFile() {
10192
- return join32(getLockDir(), "voice.lock");
10518
+ return join35(getLockDir(), "voice.lock");
10193
10519
  }
10194
10520
 
10195
10521
  // src/commands/voice/devices.ts
10196
10522
  function devices() {
10197
- const script = join33(getPythonDir(), "list_devices.py");
10523
+ const script = join36(getPythonDir(), "list_devices.py");
10198
10524
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
10199
10525
  }
10200
10526
 
10201
10527
  // src/commands/voice/logs.ts
10202
- import { existsSync as existsSync37, readFileSync as readFileSync28 } from "fs";
10528
+ import { existsSync as existsSync37, readFileSync as readFileSync29 } from "fs";
10203
10529
  function logs(options2) {
10204
10530
  if (!existsSync37(voicePaths.log)) {
10205
10531
  console.log("No voice log file found");
10206
10532
  return;
10207
10533
  }
10208
10534
  const count = Number.parseInt(options2.lines ?? "150", 10);
10209
- const content = readFileSync28(voicePaths.log, "utf-8").trim();
10535
+ const content = readFileSync29(voicePaths.log, "utf-8").trim();
10210
10536
  if (!content) {
10211
10537
  console.log("Voice log is empty");
10212
10538
  return;
@@ -10228,13 +10554,13 @@ function logs(options2) {
10228
10554
 
10229
10555
  // src/commands/voice/setup.ts
10230
10556
  import { spawnSync as spawnSync4 } from "child_process";
10231
- import { mkdirSync as mkdirSync10 } from "fs";
10232
- import { join as join35 } from "path";
10557
+ import { mkdirSync as mkdirSync11 } from "fs";
10558
+ import { join as join38 } from "path";
10233
10559
 
10234
10560
  // src/commands/voice/checkLockFile.ts
10235
10561
  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";
10562
+ import { existsSync as existsSync38, mkdirSync as mkdirSync10, readFileSync as readFileSync30, writeFileSync as writeFileSync25 } from "fs";
10563
+ import { join as join37 } from "path";
10238
10564
  function isProcessAlive2(pid) {
10239
10565
  try {
10240
10566
  process.kill(pid, 0);
@@ -10247,7 +10573,7 @@ function checkLockFile() {
10247
10573
  const lockFile = getLockFile();
10248
10574
  if (!existsSync38(lockFile)) return;
10249
10575
  try {
10250
- const lock = JSON.parse(readFileSync29(lockFile, "utf-8"));
10576
+ const lock = JSON.parse(readFileSync30(lockFile, "utf-8"));
10251
10577
  if (lock.pid && isProcessAlive2(lock.pid)) {
10252
10578
  console.error(
10253
10579
  `Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
@@ -10271,7 +10597,7 @@ function bootstrapVenv() {
10271
10597
  }
10272
10598
  function writeLockFile(pid) {
10273
10599
  const lockFile = getLockFile();
10274
- mkdirSync9(join34(lockFile, ".."), { recursive: true });
10600
+ mkdirSync10(join37(lockFile, ".."), { recursive: true });
10275
10601
  writeFileSync25(
10276
10602
  lockFile,
10277
10603
  JSON.stringify({
@@ -10284,10 +10610,10 @@ function writeLockFile(pid) {
10284
10610
 
10285
10611
  // src/commands/voice/setup.ts
10286
10612
  function setup() {
10287
- mkdirSync10(voicePaths.dir, { recursive: true });
10613
+ mkdirSync11(voicePaths.dir, { recursive: true });
10288
10614
  bootstrapVenv();
10289
10615
  console.log("\nDownloading models...\n");
10290
- const script = join35(getPythonDir(), "setup_models.py");
10616
+ const script = join38(getPythonDir(), "setup_models.py");
10291
10617
  const result = spawnSync4(getVenvPython(), [script], {
10292
10618
  stdio: "inherit",
10293
10619
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -10300,8 +10626,8 @@ function setup() {
10300
10626
 
10301
10627
  // src/commands/voice/start.ts
10302
10628
  import { spawn as spawn5 } from "child_process";
10303
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync26 } from "fs";
10304
- import { join as join36 } from "path";
10629
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync26 } from "fs";
10630
+ import { join as join39 } from "path";
10305
10631
 
10306
10632
  // src/commands/voice/buildDaemonEnv.ts
10307
10633
  function buildDaemonEnv(options2) {
@@ -10334,12 +10660,12 @@ function spawnBackground(python, script, env) {
10334
10660
  console.log(`Voice daemon started (PID ${pid})`);
10335
10661
  }
10336
10662
  function start2(options2) {
10337
- mkdirSync11(voicePaths.dir, { recursive: true });
10663
+ mkdirSync12(voicePaths.dir, { recursive: true });
10338
10664
  checkLockFile();
10339
10665
  bootstrapVenv();
10340
10666
  const debug = options2.debug || options2.foreground || process.platform === "win32";
10341
10667
  const env = buildDaemonEnv({ debug });
10342
- const script = join36(getPythonDir(), "voice_daemon.py");
10668
+ const script = join39(getPythonDir(), "voice_daemon.py");
10343
10669
  const python = getVenvPython();
10344
10670
  if (options2.foreground) {
10345
10671
  spawnForeground(python, script, env);
@@ -10349,7 +10675,7 @@ function start2(options2) {
10349
10675
  }
10350
10676
 
10351
10677
  // src/commands/voice/status.ts
10352
- import { existsSync as existsSync39, readFileSync as readFileSync30 } from "fs";
10678
+ import { existsSync as existsSync39, readFileSync as readFileSync31 } from "fs";
10353
10679
  function isProcessAlive3(pid) {
10354
10680
  try {
10355
10681
  process.kill(pid, 0);
@@ -10360,7 +10686,7 @@ function isProcessAlive3(pid) {
10360
10686
  }
10361
10687
  function readRecentLogs(count) {
10362
10688
  if (!existsSync39(voicePaths.log)) return [];
10363
- const lines = readFileSync30(voicePaths.log, "utf-8").trim().split("\n");
10689
+ const lines = readFileSync31(voicePaths.log, "utf-8").trim().split("\n");
10364
10690
  return lines.slice(-count);
10365
10691
  }
10366
10692
  function status() {
@@ -10368,7 +10694,7 @@ function status() {
10368
10694
  console.log("Voice daemon: not running (no PID file)");
10369
10695
  return;
10370
10696
  }
10371
- const pid = Number.parseInt(readFileSync30(voicePaths.pid, "utf-8").trim(), 10);
10697
+ const pid = Number.parseInt(readFileSync31(voicePaths.pid, "utf-8").trim(), 10);
10372
10698
  const alive = isProcessAlive3(pid);
10373
10699
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
10374
10700
  const recent = readRecentLogs(5);
@@ -10387,13 +10713,13 @@ function status() {
10387
10713
  }
10388
10714
 
10389
10715
  // src/commands/voice/stop.ts
10390
- import { existsSync as existsSync40, readFileSync as readFileSync31, unlinkSync as unlinkSync10 } from "fs";
10716
+ import { existsSync as existsSync40, readFileSync as readFileSync32, unlinkSync as unlinkSync10 } from "fs";
10391
10717
  function stop() {
10392
10718
  if (!existsSync40(voicePaths.pid)) {
10393
10719
  console.log("Voice daemon is not running (no PID file)");
10394
10720
  return;
10395
10721
  }
10396
- const pid = Number.parseInt(readFileSync31(voicePaths.pid, "utf-8").trim(), 10);
10722
+ const pid = Number.parseInt(readFileSync32(voicePaths.pid, "utf-8").trim(), 10);
10397
10723
  try {
10398
10724
  process.kill(pid, "SIGTERM");
10399
10725
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -10627,15 +10953,15 @@ async function auth() {
10627
10953
  }
10628
10954
 
10629
10955
  // src/commands/roam/showClaudeCodeIcon.ts
10630
- import { readFileSync as readFileSync32 } from "fs";
10631
- import { join as join37 } from "path";
10956
+ import { readFileSync as readFileSync33 } from "fs";
10957
+ import { join as join40 } from "path";
10632
10958
  async function showClaudeCodeIcon() {
10633
10959
  const appData = process.env.APPDATA;
10634
10960
  if (!appData) return;
10635
- const portFile = join37(appData, "Roam", "roam-local-api.port");
10961
+ const portFile = join40(appData, "Roam", "roam-local-api.port");
10636
10962
  let port;
10637
10963
  try {
10638
- port = readFileSync32(portFile, "utf-8").trim();
10964
+ port = readFileSync33(portFile, "utf-8").trim();
10639
10965
  } catch {
10640
10966
  return;
10641
10967
  }
@@ -10706,8 +11032,8 @@ Done in ${elapsed}`);
10706
11032
  }
10707
11033
 
10708
11034
  // src/commands/run/add.ts
10709
- import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync27 } from "fs";
10710
- import { join as join38 } from "path";
11035
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync27 } from "fs";
11036
+ import { join as join41 } from "path";
10711
11037
  function findAddIndex() {
10712
11038
  const addIndex = process.argv.indexOf("add");
10713
11039
  if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
@@ -10753,15 +11079,15 @@ function saveNewRunConfig(name, command, args) {
10753
11079
  saveConfig(config);
10754
11080
  }
10755
11081
  function createCommandFile(name) {
10756
- const dir = join38(".claude", "commands");
10757
- mkdirSync12(dir, { recursive: true });
11082
+ const dir = join41(".claude", "commands");
11083
+ mkdirSync13(dir, { recursive: true });
10758
11084
  const content = `---
10759
11085
  description: Run ${name}
10760
11086
  ---
10761
11087
 
10762
11088
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
10763
11089
  `;
10764
- const filePath = join38(dir, `${name}.md`);
11090
+ const filePath = join41(dir, `${name}.md`);
10765
11091
  writeFileSync27(filePath, content);
10766
11092
  console.log(`Created command file: ${filePath}`);
10767
11093
  }
@@ -10832,9 +11158,9 @@ function run3(name, args) {
10832
11158
 
10833
11159
  // src/commands/screenshot/index.ts
10834
11160
  import { execSync as execSync40 } from "child_process";
10835
- import { existsSync as existsSync41, mkdirSync as mkdirSync13, unlinkSync as unlinkSync11, writeFileSync as writeFileSync28 } from "fs";
11161
+ import { existsSync as existsSync41, mkdirSync as mkdirSync14, unlinkSync as unlinkSync11, writeFileSync as writeFileSync28 } from "fs";
10836
11162
  import { tmpdir as tmpdir6 } from "os";
10837
- import { join as join39, resolve as resolve5 } from "path";
11163
+ import { join as join42, resolve as resolve5 } from "path";
10838
11164
  import chalk120 from "chalk";
10839
11165
 
10840
11166
  // src/commands/screenshot/captureWindowPs1.ts
@@ -10965,13 +11291,13 @@ Write-Output $OutputPath
10965
11291
  // src/commands/screenshot/index.ts
10966
11292
  function buildOutputPath(outputDir, processName) {
10967
11293
  if (!existsSync41(outputDir)) {
10968
- mkdirSync13(outputDir, { recursive: true });
11294
+ mkdirSync14(outputDir, { recursive: true });
10969
11295
  }
10970
11296
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
10971
11297
  return resolve5(outputDir, `${processName}-${timestamp}.png`);
10972
11298
  }
10973
11299
  function runPowerShellScript(processName, outputPath) {
10974
- const scriptPath = join39(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
11300
+ const scriptPath = join42(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
10975
11301
  writeFileSync28(scriptPath, captureWindowPs1, "utf-8");
10976
11302
  try {
10977
11303
  execSync40(