@staff0rd/assist 0.170.2 → 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 +641 -294
  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.2",
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);
@@ -7996,7 +8322,7 @@ function isNameReferencedInSource(sourceFile, name) {
7996
8322
  }
7997
8323
  async function applyExtraction(functionName, sourceFile, destPath, plan2, project) {
7998
8324
  project.createSourceFile(destPath, plan2.destContent, { overwrite: false });
7999
- for (const fn of [plan2.target, ...plan2.dependencies]) {
8325
+ for (const fn of [plan2.target, ...plan2.functionsToRemove]) {
8000
8326
  fn.remove();
8001
8327
  }
8002
8328
  for (const stmt of plan2.statementsToRemove) {
@@ -8033,7 +8359,7 @@ async function applyExtraction(functionName, sourceFile, destPath, plan2, projec
8033
8359
 
8034
8360
  // src/commands/refactor/extract/collectDependencies.ts
8035
8361
  import {
8036
- SyntaxKind as SyntaxKind5
8362
+ SyntaxKind as SyntaxKind7
8037
8363
  } from "ts-morph";
8038
8364
 
8039
8365
  // src/commands/refactor/extract/collectPrivateFunctions.ts
@@ -8072,6 +8398,41 @@ function collectPrivateFunctions(target, fnMap) {
8072
8398
  });
8073
8399
  }
8074
8400
 
8401
+ // src/commands/refactor/extract/collectPrivateStatements.ts
8402
+ import { SyntaxKind as SyntaxKind5 } from "ts-morph";
8403
+ function getReferencedIdentifiers(fn) {
8404
+ const names = /* @__PURE__ */ new Set();
8405
+ for (const id of fn.getDescendantsOfKind(SyntaxKind5.Identifier)) {
8406
+ names.add(id.getText());
8407
+ }
8408
+ return names;
8409
+ }
8410
+ function collectPrivateStatements(functions, stmtMap) {
8411
+ const seen = /* @__PURE__ */ new Set();
8412
+ for (const fn of functions) {
8413
+ for (const name of getReferencedIdentifiers(fn)) {
8414
+ const stmt = stmtMap.get(name);
8415
+ if (stmt) seen.add(stmt);
8416
+ }
8417
+ }
8418
+ return [...seen];
8419
+ }
8420
+
8421
+ // src/commands/refactor/extract/getFunctionMap.ts
8422
+ import {
8423
+ SyntaxKind as SyntaxKind6
8424
+ } from "ts-morph";
8425
+ function getFunctionMap(sourceFile) {
8426
+ const map = /* @__PURE__ */ new Map();
8427
+ for (const fn of sourceFile.getDescendantsOfKind(
8428
+ SyntaxKind6.FunctionDeclaration
8429
+ )) {
8430
+ const name = fn.getName();
8431
+ if (name) map.set(name, fn);
8432
+ }
8433
+ return map;
8434
+ }
8435
+
8075
8436
  // src/commands/refactor/extract/getPrivateStatementMap.ts
8076
8437
  function getPrivateStatementMap(sourceFile) {
8077
8438
  const map = /* @__PURE__ */ new Map();
@@ -8089,73 +8450,61 @@ function getPrivateStatementMap(sourceFile) {
8089
8450
  }
8090
8451
 
8091
8452
  // src/commands/refactor/extract/collectDependencies.ts
8092
- function getReferencedIdentifiers(fn) {
8093
- const names = /* @__PURE__ */ new Set();
8094
- for (const id of fn.getDescendantsOfKind(SyntaxKind5.Identifier)) {
8095
- names.add(id.getText());
8096
- }
8097
- return names;
8098
- }
8099
- function getFunctionMap(sourceFile) {
8100
- const map = /* @__PURE__ */ new Map();
8101
- for (const fn of sourceFile.getDescendantsOfKind(
8102
- SyntaxKind5.FunctionDeclaration
8103
- )) {
8104
- const name = fn.getName();
8105
- if (name) map.set(name, fn);
8106
- }
8107
- return map;
8453
+ function getRemainingFunctions(sourceFile, extracted) {
8454
+ return sourceFile.getDescendantsOfKind(SyntaxKind7.FunctionDeclaration).filter((fn) => !extracted.has(fn));
8108
8455
  }
8109
- function collectPrivateStatements(functions, stmtMap) {
8110
- const seen = /* @__PURE__ */ new Set();
8111
- for (const fn of functions) {
8112
- for (const name of getReferencedIdentifiers(fn)) {
8113
- const stmt = stmtMap.get(name);
8114
- if (stmt) seen.add(stmt);
8456
+ function collectFnsUsedByRemaining(remaining, fnMap) {
8457
+ const used = /* @__PURE__ */ new Set();
8458
+ for (const fn of remaining) {
8459
+ for (const dep of collectPrivateFunctions(fn, fnMap)) {
8460
+ used.add(dep);
8115
8461
  }
8116
8462
  }
8117
- return [...seen];
8118
- }
8119
- function getRemainingFunctions(sourceFile, extracted) {
8120
- return sourceFile.getDescendantsOfKind(SyntaxKind5.FunctionDeclaration).filter((fn) => !extracted.has(fn));
8463
+ return used;
8121
8464
  }
8122
8465
  function collectDependencies(target, sourceFile) {
8123
8466
  const fnMap = getFunctionMap(sourceFile);
8124
8467
  const depFunctions = collectPrivateFunctions(target, fnMap);
8125
8468
  const allExtracted = [target, ...depFunctions];
8126
8469
  const stmtMap = getPrivateStatementMap(sourceFile);
8127
- const toCopy = collectPrivateStatements(allExtracted, stmtMap);
8128
- const extractedSet = new Set(allExtracted);
8129
- const remaining = getRemainingFunctions(sourceFile, extractedSet);
8130
- const usedByRemaining = new Set(collectPrivateStatements(remaining, stmtMap));
8131
- const toRemove = toCopy.filter((s) => !usedByRemaining.has(s));
8470
+ const stmtsToCopy = collectPrivateStatements(allExtracted, stmtMap);
8471
+ const remaining = getRemainingFunctions(sourceFile, new Set(allExtracted));
8472
+ const fnsUsedByRemaining = collectFnsUsedByRemaining(remaining, fnMap);
8473
+ const fnsToRemove = depFunctions.filter((fn) => !fnsUsedByRemaining.has(fn));
8474
+ const staysInSource = [
8475
+ ...remaining,
8476
+ ...depFunctions.filter((fn) => fnsUsedByRemaining.has(fn))
8477
+ ];
8478
+ const stmtsToRemove = stmtsToCopy.filter(
8479
+ (s) => !new Set(collectPrivateStatements(staysInSource, stmtMap)).has(s)
8480
+ );
8132
8481
  return {
8133
- functions: depFunctions,
8134
- statements: { toCopy, toRemove }
8482
+ functions: { toCopy: depFunctions, toRemove: fnsToRemove },
8483
+ statements: { toCopy: stmtsToCopy, toRemove: stmtsToRemove }
8135
8484
  };
8136
8485
  }
8137
8486
 
8138
8487
  // src/commands/refactor/extract/findFunction.ts
8139
8488
  import {
8140
- SyntaxKind as SyntaxKind6
8489
+ SyntaxKind as SyntaxKind8
8141
8490
  } from "ts-morph";
8142
8491
  function findFunction(sourceFile, functionName) {
8143
- return sourceFile.getDescendantsOfKind(SyntaxKind6.FunctionDeclaration).find((fn) => fn.getName() === functionName);
8492
+ return sourceFile.getDescendantsOfKind(SyntaxKind8.FunctionDeclaration).find((fn) => fn.getName() === functionName);
8144
8493
  }
8145
8494
 
8146
8495
  // src/commands/refactor/extract/getExportedDependencyNames.ts
8147
- import { SyntaxKind as SyntaxKind7 } from "ts-morph";
8496
+ import { SyntaxKind as SyntaxKind9 } from "ts-morph";
8148
8497
  function getExportedDependencyNames(target, sourceFile) {
8149
8498
  const calledNames = /* @__PURE__ */ new Set();
8150
- for (const call of target.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
8499
+ for (const call of target.getDescendantsOfKind(SyntaxKind9.CallExpression)) {
8151
8500
  const expr = call.getExpression();
8152
- if (expr.getKind() === SyntaxKind7.Identifier) {
8501
+ if (expr.getKind() === SyntaxKind9.Identifier) {
8153
8502
  calledNames.add(expr.getText());
8154
8503
  }
8155
8504
  }
8156
8505
  const exported = [];
8157
8506
  for (const fn of sourceFile.getDescendantsOfKind(
8158
- SyntaxKind7.FunctionDeclaration
8507
+ SyntaxKind9.FunctionDeclaration
8159
8508
  )) {
8160
8509
  const name = fn.getName();
8161
8510
  if (name && calledNames.has(name) && fn.isExported()) {
@@ -8166,9 +8515,9 @@ function getExportedDependencyNames(target, sourceFile) {
8166
8515
  }
8167
8516
 
8168
8517
  // src/commands/refactor/extract/getStatementNames.ts
8169
- import { SyntaxKind as SyntaxKind8 } from "ts-morph";
8518
+ import { SyntaxKind as SyntaxKind10 } from "ts-morph";
8170
8519
  function getStatementNames(node) {
8171
- if (node.getKind() === SyntaxKind8.VariableStatement) {
8520
+ if (node.getKind() === SyntaxKind10.VariableStatement) {
8172
8521
  const stmt = node;
8173
8522
  return stmt.getDeclarations().map((d) => d.getName());
8174
8523
  }
@@ -8178,7 +8527,7 @@ function getStatementNames(node) {
8178
8527
 
8179
8528
  // src/commands/refactor/extract/resolveImports.ts
8180
8529
  import {
8181
- SyntaxKind as SyntaxKind9
8530
+ SyntaxKind as SyntaxKind11
8182
8531
  } from "ts-morph";
8183
8532
 
8184
8533
  // src/commands/refactor/extract/matchImport.ts
@@ -8222,7 +8571,7 @@ function matchImport(importDecl, neededNames) {
8222
8571
  function getReferencedNames(nodes) {
8223
8572
  const names = /* @__PURE__ */ new Set();
8224
8573
  for (const node of nodes) {
8225
- for (const id of node.getDescendantsOfKind(SyntaxKind9.Identifier)) {
8574
+ for (const id of node.getDescendantsOfKind(SyntaxKind11.Identifier)) {
8226
8575
  names.add(id.getText());
8227
8576
  }
8228
8577
  }
@@ -8237,7 +8586,7 @@ function getLocallyDeclaredNames(functions) {
8237
8586
  names.add(param.getName());
8238
8587
  }
8239
8588
  for (const varDecl of fn.getDescendantsOfKind(
8240
- SyntaxKind9.VariableDeclaration
8589
+ SyntaxKind11.VariableDeclaration
8241
8590
  )) {
8242
8591
  names.add(varDecl.getName());
8243
8592
  }
@@ -8274,26 +8623,24 @@ function extractTexts(target, allFunctions, statements) {
8274
8623
  function analyseTarget(sourceFile, functionName) {
8275
8624
  const target = findFunction(sourceFile, functionName);
8276
8625
  if (!target) throw new Error(`Function "${functionName}" not found`);
8277
- const { functions: dependencies, statements } = collectDependencies(
8278
- target,
8279
- sourceFile
8280
- );
8281
- const all = [target, ...dependencies];
8626
+ const { functions, statements } = collectDependencies(target, sourceFile);
8627
+ const all = [target, ...functions.toCopy];
8282
8628
  return {
8283
8629
  target,
8284
- dependencies,
8630
+ dependencies: functions.toCopy,
8631
+ functionsToRemove: functions.toRemove,
8285
8632
  statementsToCopy: statements.toCopy,
8286
8633
  statementsToRemove: statements.toRemove,
8287
8634
  imports: resolveImports(
8288
8635
  target,
8289
- dependencies,
8636
+ functions.toCopy,
8290
8637
  sourceFile,
8291
8638
  statements.toCopy
8292
8639
  ),
8293
8640
  exportedDeps: getExportedDependencyNames(target, sourceFile),
8294
8641
  extractedNames: [
8295
8642
  ...statements.toRemove.flatMap(getStatementNames),
8296
- ...all.map((fn) => fn.getName()).filter(Boolean)
8643
+ ...[target, ...functions.toRemove].map((fn) => fn.getName()).filter(Boolean)
8297
8644
  ],
8298
8645
  functionTexts: extractTexts(target, all, statements.toCopy)
8299
8646
  };
@@ -8394,16 +8741,16 @@ function rewriteImportPaths(imports, sourcePath, destPath) {
8394
8741
  }
8395
8742
 
8396
8743
  // src/commands/refactor/extract/sourceReferencesName.ts
8397
- import { SyntaxKind as SyntaxKind10 } from "ts-morph";
8744
+ import { SyntaxKind as SyntaxKind12 } from "ts-morph";
8398
8745
  var DECLARATION_KINDS = /* @__PURE__ */ new Set([
8399
- SyntaxKind10.FunctionDeclaration,
8400
- SyntaxKind10.ImportSpecifier,
8401
- SyntaxKind10.ExportSpecifier
8746
+ SyntaxKind12.FunctionDeclaration,
8747
+ SyntaxKind12.ImportSpecifier,
8748
+ SyntaxKind12.ExportSpecifier
8402
8749
  ]);
8403
8750
  function isInsideExtractedFunction(node, extracted) {
8404
8751
  let current = node;
8405
8752
  while (current) {
8406
- if (current.getKind() !== SyntaxKind10.FunctionDeclaration) {
8753
+ if (current.getKind() !== SyntaxKind12.FunctionDeclaration) {
8407
8754
  current = current.getParent();
8408
8755
  continue;
8409
8756
  }
@@ -8415,7 +8762,7 @@ function isInsideExtractedFunction(node, extracted) {
8415
8762
  }
8416
8763
  function sourceReferencesName(sourceFile, functionName, extractedNames) {
8417
8764
  const extracted = new Set(extractedNames);
8418
- for (const id of sourceFile.getDescendantsOfKind(SyntaxKind10.Identifier)) {
8765
+ for (const id of sourceFile.getDescendantsOfKind(SyntaxKind12.Identifier)) {
8419
8766
  if (id.getText() !== functionName) continue;
8420
8767
  const parent = id.getParent();
8421
8768
  if (!parent || DECLARATION_KINDS.has(parent.getKind())) continue;
@@ -8620,24 +8967,24 @@ import chalk107 from "chalk";
8620
8967
  import { Project as Project3 } from "ts-morph";
8621
8968
 
8622
8969
  // src/commands/refactor/renameSymbol/findSymbol.ts
8623
- import { SyntaxKind as SyntaxKind11 } from "ts-morph";
8970
+ import { SyntaxKind as SyntaxKind13 } from "ts-morph";
8624
8971
  var declarationKinds = [
8625
- SyntaxKind11.VariableDeclaration,
8626
- SyntaxKind11.FunctionDeclaration,
8627
- SyntaxKind11.ClassDeclaration,
8628
- SyntaxKind11.InterfaceDeclaration,
8629
- SyntaxKind11.TypeAliasDeclaration,
8630
- SyntaxKind11.EnumDeclaration,
8631
- SyntaxKind11.PropertyDeclaration,
8632
- SyntaxKind11.MethodDeclaration,
8633
- SyntaxKind11.Parameter
8972
+ SyntaxKind13.VariableDeclaration,
8973
+ SyntaxKind13.FunctionDeclaration,
8974
+ SyntaxKind13.ClassDeclaration,
8975
+ SyntaxKind13.InterfaceDeclaration,
8976
+ SyntaxKind13.TypeAliasDeclaration,
8977
+ SyntaxKind13.EnumDeclaration,
8978
+ SyntaxKind13.PropertyDeclaration,
8979
+ SyntaxKind13.MethodDeclaration,
8980
+ SyntaxKind13.Parameter
8634
8981
  ];
8635
8982
  function isDeclaration(identifier) {
8636
8983
  const parent = identifier.getParent();
8637
8984
  return parent !== void 0 && declarationKinds.includes(parent.getKind());
8638
8985
  }
8639
8986
  function findSymbol(sourceFile, symbolName) {
8640
- for (const id of sourceFile.getDescendantsOfKind(SyntaxKind11.Identifier)) {
8987
+ for (const id of sourceFile.getDescendantsOfKind(SyntaxKind13.Identifier)) {
8641
8988
  if (id.getText() === symbolName && isDeclaration(id)) return id;
8642
8989
  }
8643
8990
  return void 0;
@@ -9475,8 +9822,8 @@ function registerSeq(program2) {
9475
9822
  }
9476
9823
 
9477
9824
  // src/commands/transcript/shared.ts
9478
- import { existsSync as existsSync32, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
9479
- 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";
9480
9827
  import * as readline2 from "readline";
9481
9828
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
9482
9829
  function getDatePrefix(daysOffset = 0) {
@@ -9494,8 +9841,8 @@ function collectFiles(dir, extension) {
9494
9841
  if (!existsSync32(dir)) return [];
9495
9842
  const results = [];
9496
9843
  for (const entry of readdirSync5(dir)) {
9497
- const fullPath = join26(dir, entry);
9498
- if (statSync2(fullPath).isDirectory()) {
9844
+ const fullPath = join29(dir, entry);
9845
+ if (statSync4(fullPath).isDirectory()) {
9499
9846
  results.push(...collectFiles(fullPath, extension));
9500
9847
  } else if (entry.endsWith(extension)) {
9501
9848
  results.push(fullPath);
@@ -9591,11 +9938,11 @@ async function configure() {
9591
9938
  import { existsSync as existsSync34 } from "fs";
9592
9939
 
9593
9940
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
9594
- import { dirname as dirname18, join as join28 } from "path";
9941
+ import { dirname as dirname18, join as join31 } from "path";
9595
9942
 
9596
9943
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
9597
- import { renameSync } from "fs";
9598
- import { join as join27 } from "path";
9944
+ import { renameSync as renameSync2 } from "fs";
9945
+ import { join as join30 } from "path";
9599
9946
  async function resolveDate(rl, choice) {
9600
9947
  if (choice === "1") return getDatePrefix(0);
9601
9948
  if (choice === "2") return getDatePrefix(-1);
@@ -9610,7 +9957,7 @@ async function resolveDate(rl, choice) {
9610
9957
  }
9611
9958
  function renameWithPrefix(vttDir, vttFile, prefix2) {
9612
9959
  const newFilename = `${prefix2}.${vttFile}`;
9613
- renameSync(join27(vttDir, vttFile), join27(vttDir, newFilename));
9960
+ renameSync2(join30(vttDir, vttFile), join30(vttDir, newFilename));
9614
9961
  console.log(`Renamed to: ${newFilename}`);
9615
9962
  return newFilename;
9616
9963
  }
@@ -9644,12 +9991,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
9644
9991
  const vttFileDir = dirname18(vttFile.absolutePath);
9645
9992
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
9646
9993
  if (newFilename) {
9647
- const newRelativePath = join28(
9994
+ const newRelativePath = join31(
9648
9995
  dirname18(vttFile.relativePath),
9649
9996
  newFilename
9650
9997
  );
9651
9998
  vttFiles[i] = {
9652
- absolutePath: join28(vttFileDir, newFilename),
9999
+ absolutePath: join31(vttFileDir, newFilename),
9653
10000
  relativePath: newRelativePath,
9654
10001
  filename: newFilename
9655
10002
  };
@@ -9662,8 +10009,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
9662
10009
  }
9663
10010
 
9664
10011
  // src/commands/transcript/format/processVttFile/index.ts
9665
- import { existsSync as existsSync33, mkdirSync as mkdirSync7, readFileSync as readFileSync26, writeFileSync as writeFileSync24 } from "fs";
9666
- 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";
9667
10014
 
9668
10015
  // src/commands/transcript/cleanText.ts
9669
10016
  function cleanText(text) {
@@ -9873,22 +10220,22 @@ function toMdFilename(vttFilename) {
9873
10220
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
9874
10221
  }
9875
10222
  function resolveOutputDir(relativeDir, transcriptsDir) {
9876
- return relativeDir === "." ? transcriptsDir : join29(transcriptsDir, relativeDir);
10223
+ return relativeDir === "." ? transcriptsDir : join32(transcriptsDir, relativeDir);
9877
10224
  }
9878
10225
  function buildOutputPaths(vttFile, transcriptsDir) {
9879
10226
  const mdFile = toMdFilename(vttFile.filename);
9880
10227
  const relativeDir = dirname19(vttFile.relativePath);
9881
10228
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
9882
- const outputPath = join29(outputDir, mdFile);
10229
+ const outputPath = join32(outputDir, mdFile);
9883
10230
  return { outputDir, outputPath, mdFile, relativeDir };
9884
10231
  }
9885
10232
  function logSkipped(relativeDir, mdFile) {
9886
- console.log(`Skipping (already exists): ${join29(relativeDir, mdFile)}`);
10233
+ console.log(`Skipping (already exists): ${join32(relativeDir, mdFile)}`);
9887
10234
  return "skipped";
9888
10235
  }
9889
10236
  function ensureDirectory(dir, label2) {
9890
10237
  if (!existsSync33(dir)) {
9891
- mkdirSync7(dir, { recursive: true });
10238
+ mkdirSync8(dir, { recursive: true });
9892
10239
  console.log(`Created ${label2}: ${dir}`);
9893
10240
  }
9894
10241
  }
@@ -9910,7 +10257,7 @@ function logReduction(cueCount, messageCount) {
9910
10257
  }
9911
10258
  function readAndParseCues(inputPath) {
9912
10259
  console.log(`Reading: ${inputPath}`);
9913
- return processCues(readFileSync26(inputPath, "utf-8"));
10260
+ return processCues(readFileSync27(inputPath, "utf-8"));
9914
10261
  }
9915
10262
  function writeFormatted(outputPath, content) {
9916
10263
  writeFileSync24(outputPath, content, "utf-8");
@@ -9982,17 +10329,17 @@ async function format() {
9982
10329
 
9983
10330
  // src/commands/transcript/summarise/index.ts
9984
10331
  import { existsSync as existsSync36 } from "fs";
9985
- 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";
9986
10333
 
9987
10334
  // src/commands/transcript/summarise/processStagedFile/index.ts
9988
10335
  import {
9989
10336
  existsSync as existsSync35,
9990
- mkdirSync as mkdirSync8,
9991
- readFileSync as readFileSync27,
9992
- renameSync as renameSync2,
10337
+ mkdirSync as mkdirSync9,
10338
+ readFileSync as readFileSync28,
10339
+ renameSync as renameSync3,
9993
10340
  rmSync
9994
10341
  } from "fs";
9995
- import { dirname as dirname20, join as join30 } from "path";
10342
+ import { dirname as dirname20, join as join33 } from "path";
9996
10343
 
9997
10344
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
9998
10345
  import chalk118 from "chalk";
@@ -10021,7 +10368,7 @@ function validateStagedContent(filename, content) {
10021
10368
  }
10022
10369
 
10023
10370
  // src/commands/transcript/summarise/processStagedFile/index.ts
10024
- var STAGING_DIR = join30(process.cwd(), ".assist", "transcript");
10371
+ var STAGING_DIR = join33(process.cwd(), ".assist", "transcript");
10025
10372
  function processStagedFile() {
10026
10373
  if (!existsSync35(STAGING_DIR)) {
10027
10374
  return false;
@@ -10032,7 +10379,7 @@ function processStagedFile() {
10032
10379
  }
10033
10380
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
10034
10381
  const stagedFile = stagedFiles[0];
10035
- const content = readFileSync27(stagedFile.absolutePath, "utf-8");
10382
+ const content = readFileSync28(stagedFile.absolutePath, "utf-8");
10036
10383
  validateStagedContent(stagedFile.filename, content);
10037
10384
  const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
10038
10385
  const transcriptFiles = findMdFilesRecursive(transcriptsDir);
@@ -10045,12 +10392,12 @@ function processStagedFile() {
10045
10392
  );
10046
10393
  process.exit(1);
10047
10394
  }
10048
- const destPath = join30(summaryDir, matchingTranscript.relativePath);
10395
+ const destPath = join33(summaryDir, matchingTranscript.relativePath);
10049
10396
  const destDir = dirname20(destPath);
10050
10397
  if (!existsSync35(destDir)) {
10051
- mkdirSync8(destDir, { recursive: true });
10398
+ mkdirSync9(destDir, { recursive: true });
10052
10399
  }
10053
- renameSync2(stagedFile.absolutePath, destPath);
10400
+ renameSync3(stagedFile.absolutePath, destPath);
10054
10401
  const remaining = findMdFilesRecursive(STAGING_DIR);
10055
10402
  if (remaining.length === 0) {
10056
10403
  rmSync(STAGING_DIR, { recursive: true });
@@ -10061,7 +10408,7 @@ function processStagedFile() {
10061
10408
  // src/commands/transcript/summarise/index.ts
10062
10409
  function buildRelativeKey(relativePath, baseName) {
10063
10410
  const relDir = dirname21(relativePath);
10064
- return relDir === "." ? baseName : join31(relDir, baseName);
10411
+ return relDir === "." ? baseName : join34(relDir, baseName);
10065
10412
  }
10066
10413
  function buildSummaryIndex(summaryDir) {
10067
10414
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -10095,8 +10442,8 @@ function summarise2() {
10095
10442
  }
10096
10443
  const next3 = missing[0];
10097
10444
  const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
10098
- const outputPath = join31(STAGING_DIR, outputFilename);
10099
- const summaryFileDir = join31(summaryDir, dirname21(next3.relativePath));
10445
+ const outputPath = join34(STAGING_DIR, outputFilename);
10446
+ const summaryFileDir = join34(summaryDir, dirname21(next3.relativePath));
10100
10447
  const relativeTranscriptPath = encodeURI(
10101
10448
  relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
10102
10449
  );
@@ -10142,50 +10489,50 @@ function registerVerify(program2) {
10142
10489
 
10143
10490
  // src/commands/voice/devices.ts
10144
10491
  import { spawnSync as spawnSync3 } from "child_process";
10145
- import { join as join33 } from "path";
10492
+ import { join as join36 } from "path";
10146
10493
 
10147
10494
  // src/commands/voice/shared.ts
10148
10495
  import { homedir as homedir7 } from "os";
10149
- import { dirname as dirname22, join as join32 } from "path";
10496
+ import { dirname as dirname22, join as join35 } from "path";
10150
10497
  import { fileURLToPath as fileURLToPath6 } from "url";
10151
10498
  var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
10152
- var VOICE_DIR = join32(homedir7(), ".assist", "voice");
10499
+ var VOICE_DIR = join35(homedir7(), ".assist", "voice");
10153
10500
  var voicePaths = {
10154
10501
  dir: VOICE_DIR,
10155
- pid: join32(VOICE_DIR, "voice.pid"),
10156
- log: join32(VOICE_DIR, "voice.log"),
10157
- venv: join32(VOICE_DIR, ".venv"),
10158
- 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")
10159
10506
  };
10160
10507
  function getPythonDir() {
10161
- return join32(__dirname6, "commands", "voice", "python");
10508
+ return join35(__dirname6, "commands", "voice", "python");
10162
10509
  }
10163
10510
  function getVenvPython() {
10164
- 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");
10165
10512
  }
10166
10513
  function getLockDir() {
10167
10514
  const config = loadConfig();
10168
10515
  return config.voice?.lockDir ?? VOICE_DIR;
10169
10516
  }
10170
10517
  function getLockFile() {
10171
- return join32(getLockDir(), "voice.lock");
10518
+ return join35(getLockDir(), "voice.lock");
10172
10519
  }
10173
10520
 
10174
10521
  // src/commands/voice/devices.ts
10175
10522
  function devices() {
10176
- const script = join33(getPythonDir(), "list_devices.py");
10523
+ const script = join36(getPythonDir(), "list_devices.py");
10177
10524
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
10178
10525
  }
10179
10526
 
10180
10527
  // src/commands/voice/logs.ts
10181
- import { existsSync as existsSync37, readFileSync as readFileSync28 } from "fs";
10528
+ import { existsSync as existsSync37, readFileSync as readFileSync29 } from "fs";
10182
10529
  function logs(options2) {
10183
10530
  if (!existsSync37(voicePaths.log)) {
10184
10531
  console.log("No voice log file found");
10185
10532
  return;
10186
10533
  }
10187
10534
  const count = Number.parseInt(options2.lines ?? "150", 10);
10188
- const content = readFileSync28(voicePaths.log, "utf-8").trim();
10535
+ const content = readFileSync29(voicePaths.log, "utf-8").trim();
10189
10536
  if (!content) {
10190
10537
  console.log("Voice log is empty");
10191
10538
  return;
@@ -10207,13 +10554,13 @@ function logs(options2) {
10207
10554
 
10208
10555
  // src/commands/voice/setup.ts
10209
10556
  import { spawnSync as spawnSync4 } from "child_process";
10210
- import { mkdirSync as mkdirSync10 } from "fs";
10211
- import { join as join35 } from "path";
10557
+ import { mkdirSync as mkdirSync11 } from "fs";
10558
+ import { join as join38 } from "path";
10212
10559
 
10213
10560
  // src/commands/voice/checkLockFile.ts
10214
10561
  import { execSync as execSync37 } from "child_process";
10215
- import { existsSync as existsSync38, mkdirSync as mkdirSync9, readFileSync as readFileSync29, writeFileSync as writeFileSync25 } from "fs";
10216
- 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";
10217
10564
  function isProcessAlive2(pid) {
10218
10565
  try {
10219
10566
  process.kill(pid, 0);
@@ -10226,7 +10573,7 @@ function checkLockFile() {
10226
10573
  const lockFile = getLockFile();
10227
10574
  if (!existsSync38(lockFile)) return;
10228
10575
  try {
10229
- const lock = JSON.parse(readFileSync29(lockFile, "utf-8"));
10576
+ const lock = JSON.parse(readFileSync30(lockFile, "utf-8"));
10230
10577
  if (lock.pid && isProcessAlive2(lock.pid)) {
10231
10578
  console.error(
10232
10579
  `Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
@@ -10250,7 +10597,7 @@ function bootstrapVenv() {
10250
10597
  }
10251
10598
  function writeLockFile(pid) {
10252
10599
  const lockFile = getLockFile();
10253
- mkdirSync9(join34(lockFile, ".."), { recursive: true });
10600
+ mkdirSync10(join37(lockFile, ".."), { recursive: true });
10254
10601
  writeFileSync25(
10255
10602
  lockFile,
10256
10603
  JSON.stringify({
@@ -10263,10 +10610,10 @@ function writeLockFile(pid) {
10263
10610
 
10264
10611
  // src/commands/voice/setup.ts
10265
10612
  function setup() {
10266
- mkdirSync10(voicePaths.dir, { recursive: true });
10613
+ mkdirSync11(voicePaths.dir, { recursive: true });
10267
10614
  bootstrapVenv();
10268
10615
  console.log("\nDownloading models...\n");
10269
- const script = join35(getPythonDir(), "setup_models.py");
10616
+ const script = join38(getPythonDir(), "setup_models.py");
10270
10617
  const result = spawnSync4(getVenvPython(), [script], {
10271
10618
  stdio: "inherit",
10272
10619
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -10279,8 +10626,8 @@ function setup() {
10279
10626
 
10280
10627
  // src/commands/voice/start.ts
10281
10628
  import { spawn as spawn5 } from "child_process";
10282
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync26 } from "fs";
10283
- import { join as join36 } from "path";
10629
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync26 } from "fs";
10630
+ import { join as join39 } from "path";
10284
10631
 
10285
10632
  // src/commands/voice/buildDaemonEnv.ts
10286
10633
  function buildDaemonEnv(options2) {
@@ -10313,12 +10660,12 @@ function spawnBackground(python, script, env) {
10313
10660
  console.log(`Voice daemon started (PID ${pid})`);
10314
10661
  }
10315
10662
  function start2(options2) {
10316
- mkdirSync11(voicePaths.dir, { recursive: true });
10663
+ mkdirSync12(voicePaths.dir, { recursive: true });
10317
10664
  checkLockFile();
10318
10665
  bootstrapVenv();
10319
10666
  const debug = options2.debug || options2.foreground || process.platform === "win32";
10320
10667
  const env = buildDaemonEnv({ debug });
10321
- const script = join36(getPythonDir(), "voice_daemon.py");
10668
+ const script = join39(getPythonDir(), "voice_daemon.py");
10322
10669
  const python = getVenvPython();
10323
10670
  if (options2.foreground) {
10324
10671
  spawnForeground(python, script, env);
@@ -10328,7 +10675,7 @@ function start2(options2) {
10328
10675
  }
10329
10676
 
10330
10677
  // src/commands/voice/status.ts
10331
- import { existsSync as existsSync39, readFileSync as readFileSync30 } from "fs";
10678
+ import { existsSync as existsSync39, readFileSync as readFileSync31 } from "fs";
10332
10679
  function isProcessAlive3(pid) {
10333
10680
  try {
10334
10681
  process.kill(pid, 0);
@@ -10339,7 +10686,7 @@ function isProcessAlive3(pid) {
10339
10686
  }
10340
10687
  function readRecentLogs(count) {
10341
10688
  if (!existsSync39(voicePaths.log)) return [];
10342
- const lines = readFileSync30(voicePaths.log, "utf-8").trim().split("\n");
10689
+ const lines = readFileSync31(voicePaths.log, "utf-8").trim().split("\n");
10343
10690
  return lines.slice(-count);
10344
10691
  }
10345
10692
  function status() {
@@ -10347,7 +10694,7 @@ function status() {
10347
10694
  console.log("Voice daemon: not running (no PID file)");
10348
10695
  return;
10349
10696
  }
10350
- const pid = Number.parseInt(readFileSync30(voicePaths.pid, "utf-8").trim(), 10);
10697
+ const pid = Number.parseInt(readFileSync31(voicePaths.pid, "utf-8").trim(), 10);
10351
10698
  const alive = isProcessAlive3(pid);
10352
10699
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
10353
10700
  const recent = readRecentLogs(5);
@@ -10366,13 +10713,13 @@ function status() {
10366
10713
  }
10367
10714
 
10368
10715
  // src/commands/voice/stop.ts
10369
- 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";
10370
10717
  function stop() {
10371
10718
  if (!existsSync40(voicePaths.pid)) {
10372
10719
  console.log("Voice daemon is not running (no PID file)");
10373
10720
  return;
10374
10721
  }
10375
- const pid = Number.parseInt(readFileSync31(voicePaths.pid, "utf-8").trim(), 10);
10722
+ const pid = Number.parseInt(readFileSync32(voicePaths.pid, "utf-8").trim(), 10);
10376
10723
  try {
10377
10724
  process.kill(pid, "SIGTERM");
10378
10725
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -10606,15 +10953,15 @@ async function auth() {
10606
10953
  }
10607
10954
 
10608
10955
  // src/commands/roam/showClaudeCodeIcon.ts
10609
- import { readFileSync as readFileSync32 } from "fs";
10610
- import { join as join37 } from "path";
10956
+ import { readFileSync as readFileSync33 } from "fs";
10957
+ import { join as join40 } from "path";
10611
10958
  async function showClaudeCodeIcon() {
10612
10959
  const appData = process.env.APPDATA;
10613
10960
  if (!appData) return;
10614
- const portFile = join37(appData, "Roam", "roam-local-api.port");
10961
+ const portFile = join40(appData, "Roam", "roam-local-api.port");
10615
10962
  let port;
10616
10963
  try {
10617
- port = readFileSync32(portFile, "utf-8").trim();
10964
+ port = readFileSync33(portFile, "utf-8").trim();
10618
10965
  } catch {
10619
10966
  return;
10620
10967
  }
@@ -10685,8 +11032,8 @@ Done in ${elapsed}`);
10685
11032
  }
10686
11033
 
10687
11034
  // src/commands/run/add.ts
10688
- import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync27 } from "fs";
10689
- import { join as join38 } from "path";
11035
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync27 } from "fs";
11036
+ import { join as join41 } from "path";
10690
11037
  function findAddIndex() {
10691
11038
  const addIndex = process.argv.indexOf("add");
10692
11039
  if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
@@ -10732,15 +11079,15 @@ function saveNewRunConfig(name, command, args) {
10732
11079
  saveConfig(config);
10733
11080
  }
10734
11081
  function createCommandFile(name) {
10735
- const dir = join38(".claude", "commands");
10736
- mkdirSync12(dir, { recursive: true });
11082
+ const dir = join41(".claude", "commands");
11083
+ mkdirSync13(dir, { recursive: true });
10737
11084
  const content = `---
10738
11085
  description: Run ${name}
10739
11086
  ---
10740
11087
 
10741
11088
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
10742
11089
  `;
10743
- const filePath = join38(dir, `${name}.md`);
11090
+ const filePath = join41(dir, `${name}.md`);
10744
11091
  writeFileSync27(filePath, content);
10745
11092
  console.log(`Created command file: ${filePath}`);
10746
11093
  }
@@ -10811,9 +11158,9 @@ function run3(name, args) {
10811
11158
 
10812
11159
  // src/commands/screenshot/index.ts
10813
11160
  import { execSync as execSync40 } from "child_process";
10814
- 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";
10815
11162
  import { tmpdir as tmpdir6 } from "os";
10816
- import { join as join39, resolve as resolve5 } from "path";
11163
+ import { join as join42, resolve as resolve5 } from "path";
10817
11164
  import chalk120 from "chalk";
10818
11165
 
10819
11166
  // src/commands/screenshot/captureWindowPs1.ts
@@ -10944,13 +11291,13 @@ Write-Output $OutputPath
10944
11291
  // src/commands/screenshot/index.ts
10945
11292
  function buildOutputPath(outputDir, processName) {
10946
11293
  if (!existsSync41(outputDir)) {
10947
- mkdirSync13(outputDir, { recursive: true });
11294
+ mkdirSync14(outputDir, { recursive: true });
10948
11295
  }
10949
11296
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
10950
11297
  return resolve5(outputDir, `${processName}-${timestamp}.png`);
10951
11298
  }
10952
11299
  function runPowerShellScript(processName, outputPath) {
10953
- const scriptPath = join39(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
11300
+ const scriptPath = join42(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
10954
11301
  writeFileSync28(scriptPath, captureWindowPs1, "utf-8");
10955
11302
  try {
10956
11303
  execSync40(