@staff0rd/assist 0.220.2 → 0.222.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.220.2",
9
+ version: "0.222.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -3704,19 +3704,19 @@ function moveCaseInsensitive(absSource, absDest) {
3704
3704
  fs8.renameSync(absSource, tmp);
3705
3705
  fs8.renameSync(tmp, absDest);
3706
3706
  }
3707
- function applyMoves(project, moves, cwd, emit) {
3707
+ function applyMoves(project, moves, cwd, emit2) {
3708
3708
  for (const { sourcePath, destPath } of moves) {
3709
3709
  const start3 = performance.now();
3710
3710
  const absSource = path16.resolve(sourcePath);
3711
3711
  const absDest = path16.resolve(destPath);
3712
3712
  for (const r of renameExports(project, absSource, absDest)) {
3713
- emit(` Renamed export ${r} in ${sourcePath}`);
3713
+ emit2(` Renamed export ${r} in ${sourcePath}`);
3714
3714
  }
3715
3715
  const sourceFile = project.getSourceFile(absSource);
3716
3716
  if (sourceFile) sourceFile.move(absDest);
3717
3717
  const ms = (performance.now() - start3).toFixed(0);
3718
3718
  const rel = `${path16.relative(cwd, absSource)} \u2192 ${path16.relative(cwd, absDest)}`;
3719
- emit(` Renamed ${rel} (${ms}ms)`);
3719
+ emit2(` Renamed ${rel} (${ms}ms)`);
3720
3720
  }
3721
3721
  project.saveSync();
3722
3722
  for (const { sourcePath, destPath } of moves) {
@@ -8392,6 +8392,303 @@ function registerDotnet(program2) {
8392
8392
  cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
8393
8393
  }
8394
8394
 
8395
+ // src/commands/handover/archive.ts
8396
+ import { existsSync as existsSync30, mkdirSync as mkdirSync7, renameSync as renameSync2 } from "fs";
8397
+ import { join as join31 } from "path";
8398
+
8399
+ // src/commands/handover/formatArchiveTimestamp.ts
8400
+ function formatArchiveTimestamp(date = /* @__PURE__ */ new Date()) {
8401
+ const pad = (n) => n.toString().padStart(2, "0");
8402
+ const yyyy = date.getUTCFullYear().toString();
8403
+ const mm = pad(date.getUTCMonth() + 1);
8404
+ const dd = pad(date.getUTCDate());
8405
+ const hh = pad(date.getUTCHours());
8406
+ const mi = pad(date.getUTCMinutes());
8407
+ const ss = pad(date.getUTCSeconds());
8408
+ return `${yyyy}-${mm}-${dd}T${hh}${mi}${ss}Z`;
8409
+ }
8410
+
8411
+ // src/commands/handover/getHandoverArchiveDir.ts
8412
+ import { join as join29 } from "path";
8413
+ function getHandoverArchiveDir(cwd = process.cwd()) {
8414
+ return join29(cwd, ".assist", "handovers", "archive");
8415
+ }
8416
+
8417
+ // src/commands/handover/getHandoverPath.ts
8418
+ import { join as join30 } from "path";
8419
+ function getHandoverPath(cwd = process.cwd()) {
8420
+ return join30(cwd, ".assist", "HANDOVER.md");
8421
+ }
8422
+
8423
+ // src/commands/handover/archive.ts
8424
+ var MAX_COLLISION_SUFFIX = 99;
8425
+ function buildArchiveFilename(timestamp, suffix) {
8426
+ const base = suffix ? `${timestamp}-${suffix}` : timestamp;
8427
+ return `${base}.md`;
8428
+ }
8429
+ function resolveCollisionPath(archiveDir, timestamp, suffix) {
8430
+ const initial = join31(archiveDir, buildArchiveFilename(timestamp, suffix));
8431
+ if (!existsSync30(initial)) return initial;
8432
+ for (let i = 1; i <= MAX_COLLISION_SUFFIX; i++) {
8433
+ const collisionSuffix = suffix ? `${suffix}-${i}` : `${i}`;
8434
+ const candidate = join31(
8435
+ archiveDir,
8436
+ buildArchiveFilename(timestamp, collisionSuffix)
8437
+ );
8438
+ if (!existsSync30(candidate)) return candidate;
8439
+ }
8440
+ throw new Error(
8441
+ `Exhausted collision suffixes (1-${MAX_COLLISION_SUFFIX}) for ${timestamp}`
8442
+ );
8443
+ }
8444
+ function archive(options2 = {}) {
8445
+ const cwd = options2.cwd ?? process.cwd();
8446
+ const handoverPath = getHandoverPath(cwd);
8447
+ if (!existsSync30(handoverPath)) return void 0;
8448
+ const archiveDir = getHandoverArchiveDir(cwd);
8449
+ mkdirSync7(archiveDir, { recursive: true });
8450
+ const timestamp = formatArchiveTimestamp(options2.now);
8451
+ const destination = resolveCollisionPath(
8452
+ archiveDir,
8453
+ timestamp,
8454
+ options2.suffix
8455
+ );
8456
+ renameSync2(handoverPath, destination);
8457
+ return destination;
8458
+ }
8459
+
8460
+ // src/commands/handover/load.ts
8461
+ import { existsSync as existsSync31, readFileSync as readFileSync27 } from "fs";
8462
+
8463
+ // src/commands/handover/parseLoadInput.ts
8464
+ async function parseLoadInput(stdin) {
8465
+ try {
8466
+ const raw = await stdin();
8467
+ if (!raw.trim()) return {};
8468
+ return JSON.parse(raw);
8469
+ } catch {
8470
+ return {};
8471
+ }
8472
+ }
8473
+
8474
+ // src/commands/handover/findRecentSessionJsonl.ts
8475
+ import { readdirSync as readdirSync5, statSync as statSync4 } from "fs";
8476
+ import { homedir as homedir8 } from "os";
8477
+ import { join as join32 } from "path";
8478
+
8479
+ // src/commands/handover/encodeCwdForProjects.ts
8480
+ function encodeCwdForProjects(cwd) {
8481
+ return cwd.replace(/[\\/.]/g, "-");
8482
+ }
8483
+
8484
+ // src/commands/sessions/summarise/iterateUserEntries.ts
8485
+ import * as fs17 from "fs";
8486
+
8487
+ // src/commands/sessions/summarise/parseUserLine.ts
8488
+ function parseUserLine(line) {
8489
+ let entry;
8490
+ try {
8491
+ entry = JSON.parse(line);
8492
+ } catch {
8493
+ return void 0;
8494
+ }
8495
+ if (entry.type !== "user") return void 0;
8496
+ const msg = entry.message;
8497
+ const c = msg?.content;
8498
+ let text;
8499
+ if (typeof c === "string") {
8500
+ text = c;
8501
+ } else if (Array.isArray(c)) {
8502
+ const collected = c.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n");
8503
+ text = collected || void 0;
8504
+ }
8505
+ if (!text) return void 0;
8506
+ return {
8507
+ text,
8508
+ entrypoint: typeof entry.entrypoint === "string" ? entry.entrypoint : void 0
8509
+ };
8510
+ }
8511
+
8512
+ // src/commands/sessions/summarise/iterateUserEntries.ts
8513
+ function* iterateUserEntries(filePath) {
8514
+ let content;
8515
+ try {
8516
+ content = fs17.readFileSync(filePath, "utf8");
8517
+ } catch {
8518
+ return;
8519
+ }
8520
+ for (const line of content.split("\n")) {
8521
+ if (!line) continue;
8522
+ const entry = parseUserLine(line);
8523
+ if (entry) yield entry;
8524
+ }
8525
+ }
8526
+
8527
+ // src/commands/handover/isSdkCliOnly.ts
8528
+ function isSdkCliOnly(jsonlPath) {
8529
+ for (const entry of iterateUserEntries(jsonlPath)) {
8530
+ if (entry.entrypoint !== "sdk-cli") return false;
8531
+ }
8532
+ return true;
8533
+ }
8534
+
8535
+ // src/commands/handover/findRecentSessionJsonl.ts
8536
+ function getProjectDir(cwd) {
8537
+ return join32(homedir8(), ".claude", "projects", encodeCwdForProjects(cwd));
8538
+ }
8539
+ function findRecentSessionJsonl(cwd, options2 = {}) {
8540
+ const projectDir = options2.projectDir ?? getProjectDir(cwd);
8541
+ let entries;
8542
+ try {
8543
+ entries = readdirSync5(projectDir);
8544
+ } catch {
8545
+ return void 0;
8546
+ }
8547
+ const jsonls = entries.filter((f) => f.endsWith(".jsonl")).map((name) => {
8548
+ const path52 = join32(projectDir, name);
8549
+ let mtime = 0;
8550
+ try {
8551
+ mtime = statSync4(path52).mtimeMs;
8552
+ } catch {
8553
+ return void 0;
8554
+ }
8555
+ return { path: path52, name, mtime };
8556
+ }).filter((x) => !!x).sort((a, b) => b.mtime - a.mtime);
8557
+ for (const { path: path52, name } of jsonls) {
8558
+ const sessionId = name.replace(/\.jsonl$/, "");
8559
+ if (options2.excludeSessionId && sessionId === options2.excludeSessionId)
8560
+ continue;
8561
+ if (isSdkCliOnly(path52)) continue;
8562
+ return path52;
8563
+ }
8564
+ return void 0;
8565
+ }
8566
+
8567
+ // src/commands/handover/summarise.ts
8568
+ import { execFileSync as execFileSync4 } from "child_process";
8569
+ var SUMMARISE_RECURSION_GUARD = "_CLAUDE_HOOK_SUMMARISE_RUNNING";
8570
+ var MAX_TURNS = 15;
8571
+ var MAX_PAYLOAD_BYTES = 8 * 1024;
8572
+ var PROMPT_TEMPLATE = [
8573
+ "Summarise what the user has been working on in this Claude Code session in ONE short sentence (under 100 chars).",
8574
+ "Return ONLY the summary, no quotes, prefix, or explanation.",
8575
+ "",
8576
+ "Last user turns (most recent last):"
8577
+ ].join("\n");
8578
+ function summarise(jsonlPath) {
8579
+ const entries = [...iterateUserEntries(jsonlPath)];
8580
+ const humanEntries = entries.filter((e) => e.entrypoint !== "sdk-cli");
8581
+ if (humanEntries.length === 0) return "";
8582
+ const turns = humanEntries.map((e) => stripPreludes(e.text)).filter((t) => t.length > 0).slice(-MAX_TURNS);
8583
+ if (turns.length === 0) return "";
8584
+ const payload = capPayload(turns.join("\n---\n"), MAX_PAYLOAD_BYTES);
8585
+ const prompt = `${PROMPT_TEMPLATE}
8586
+ ${payload}`;
8587
+ try {
8588
+ const output = execFileSync4("claude", ["-p", "--model", "haiku", prompt], {
8589
+ encoding: "utf8",
8590
+ timeout: 3e4,
8591
+ stdio: ["ignore", "pipe", "ignore"],
8592
+ env: { ...process.env, [SUMMARISE_RECURSION_GUARD]: "1" }
8593
+ });
8594
+ return normaliseOutput(output);
8595
+ } catch {
8596
+ return "";
8597
+ }
8598
+ }
8599
+ function stripPreludes(text) {
8600
+ return text.replace(/<command-name>[\s\S]*?<\/command-name>/g, "").replace(/<command-message>[\s\S]*?<\/command-message>/g, "").replace(/<command-args>[\s\S]*?<\/command-args>/g, "").replace(/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/g, "").replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
8601
+ }
8602
+ function capPayload(text, maxBytes) {
8603
+ const buf = Buffer.from(text, "utf8");
8604
+ if (buf.length <= maxBytes) return text;
8605
+ return buf.subarray(buf.length - maxBytes).toString("utf8");
8606
+ }
8607
+ function normaliseOutput(raw) {
8608
+ const firstLine = raw.trim().split("\n")[0] ?? "";
8609
+ return firstLine.replace(/^["']|["']$/g, "").trim();
8610
+ }
8611
+
8612
+ // src/commands/handover/resolveLoadOptions.ts
8613
+ function resolveLoadOptions(options2) {
8614
+ return {
8615
+ stdin: options2.stdin ?? readStdin,
8616
+ env: options2.env ?? process.env,
8617
+ cwdFallback: options2.cwdFallback ?? process.cwd(),
8618
+ summariseFn: options2.summariseFn ?? summarise,
8619
+ findRecentFn: options2.findRecentFn ?? ((cwd, sid) => findRecentSessionJsonl(cwd, { excludeSessionId: sid }))
8620
+ };
8621
+ }
8622
+
8623
+ // src/commands/handover/load.ts
8624
+ function loadFromHandover(cwd) {
8625
+ const handoverPath = getHandoverPath(cwd);
8626
+ if (!existsSync31(handoverPath)) return void 0;
8627
+ const content = readFileSync27(handoverPath, "utf-8");
8628
+ archive({ cwd });
8629
+ return {
8630
+ additionalContext: content,
8631
+ systemMessage: "Loaded handover from previous session"
8632
+ };
8633
+ }
8634
+ function loadFromPriorTranscript(cwd, sessionId, findRecent, summariseJsonl) {
8635
+ const jsonlPath = findRecent(cwd, sessionId);
8636
+ if (!jsonlPath) return void 0;
8637
+ const summary = summariseJsonl(jsonlPath);
8638
+ if (!summary) return void 0;
8639
+ const message = `Previous session: ${summary}`;
8640
+ return { additionalContext: message, systemMessage: message };
8641
+ }
8642
+ function emit(context) {
8643
+ const json = JSON.stringify({
8644
+ hookSpecificOutput: {
8645
+ hookEventName: "SessionStart",
8646
+ additionalContext: context.additionalContext
8647
+ },
8648
+ systemMessage: context.systemMessage
8649
+ });
8650
+ console.log(json);
8651
+ return json;
8652
+ }
8653
+ async function load(options2 = {}) {
8654
+ const opts = resolveLoadOptions(options2);
8655
+ if (opts.env[SUMMARISE_RECURSION_GUARD]) return null;
8656
+ const input = await parseLoadInput(opts.stdin);
8657
+ const cwd = input.cwd ?? opts.cwdFallback;
8658
+ const context = loadFromHandover(cwd) ?? loadFromPriorTranscript(
8659
+ cwd,
8660
+ input.session_id,
8661
+ opts.findRecentFn,
8662
+ opts.summariseFn
8663
+ );
8664
+ return context ? emit(context) : null;
8665
+ }
8666
+
8667
+ // src/commands/registerHandover.ts
8668
+ function registerHandover(program2) {
8669
+ const cmd = program2.command("handover").description("Session handover utilities");
8670
+ cmd.command("archive").description(
8671
+ "Archive the current .assist/HANDOVER.md to .assist/handovers/archive/"
8672
+ ).option(
8673
+ "--suffix <suffix>",
8674
+ "Optional suffix appended to the archive filename"
8675
+ ).action((options2) => {
8676
+ const dest = archive({ suffix: options2.suffix });
8677
+ if (dest) console.log(dest);
8678
+ });
8679
+ cmd.command("summarise").description(
8680
+ "Print a one-line summary of a session JSONL via claude -p --model haiku"
8681
+ ).argument("<jsonl>", "Path to a session JSONL file").action((jsonl) => {
8682
+ const line = summarise(jsonl);
8683
+ if (line) console.log(line);
8684
+ });
8685
+ cmd.command("load").description(
8686
+ "SessionStart hook: archive prior handover and emit additionalContext (or fall back to prior-session summary)"
8687
+ ).action(async () => {
8688
+ await load();
8689
+ });
8690
+ }
8691
+
8395
8692
  // src/commands/jira/acceptanceCriteria.ts
8396
8693
  import chalk97 from "chalk";
8397
8694
 
@@ -8507,20 +8804,20 @@ function acceptanceCriteria(issueKey) {
8507
8804
  import { execSync as execSync25 } from "child_process";
8508
8805
 
8509
8806
  // src/shared/loadJson.ts
8510
- import { existsSync as existsSync30, mkdirSync as mkdirSync7, readFileSync as readFileSync26, writeFileSync as writeFileSync20 } from "fs";
8511
- import { homedir as homedir8 } from "os";
8512
- import { join as join29 } from "path";
8807
+ import { existsSync as existsSync32, mkdirSync as mkdirSync8, readFileSync as readFileSync28, writeFileSync as writeFileSync20 } from "fs";
8808
+ import { homedir as homedir9 } from "os";
8809
+ import { join as join33 } from "path";
8513
8810
  function getStoreDir() {
8514
- return join29(homedir8(), ".assist");
8811
+ return join33(homedir9(), ".assist");
8515
8812
  }
8516
8813
  function getStorePath(filename) {
8517
- return join29(getStoreDir(), filename);
8814
+ return join33(getStoreDir(), filename);
8518
8815
  }
8519
8816
  function loadJson(filename) {
8520
8817
  const path52 = getStorePath(filename);
8521
- if (existsSync30(path52)) {
8818
+ if (existsSync32(path52)) {
8522
8819
  try {
8523
- return JSON.parse(readFileSync26(path52, "utf-8"));
8820
+ return JSON.parse(readFileSync28(path52, "utf-8"));
8524
8821
  } catch {
8525
8822
  return {};
8526
8823
  }
@@ -8529,8 +8826,8 @@ function loadJson(filename) {
8529
8826
  }
8530
8827
  function saveJson(filename, data) {
8531
8828
  const dir = getStoreDir();
8532
- if (!existsSync30(dir)) {
8533
- mkdirSync7(dir, { recursive: true });
8829
+ if (!existsSync32(dir)) {
8830
+ mkdirSync8(dir, { recursive: true });
8534
8831
  }
8535
8832
  writeFileSync20(getStorePath(filename), JSON.stringify(data, null, 2));
8536
8833
  }
@@ -8619,12 +8916,12 @@ function registerJira(program2) {
8619
8916
  }
8620
8917
 
8621
8918
  // src/commands/mermaid/index.ts
8622
- import { mkdirSync as mkdirSync8, readdirSync as readdirSync5 } from "fs";
8919
+ import { mkdirSync as mkdirSync9, readdirSync as readdirSync6 } from "fs";
8623
8920
  import { resolve as resolve10 } from "path";
8624
8921
  import chalk101 from "chalk";
8625
8922
 
8626
8923
  // src/commands/mermaid/exportFile.ts
8627
- import { readFileSync as readFileSync27, writeFileSync as writeFileSync21 } from "fs";
8924
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync21 } from "fs";
8628
8925
  import { basename as basename7, extname, resolve as resolve9 } from "path";
8629
8926
  import chalk100 from "chalk";
8630
8927
 
@@ -8650,7 +8947,7 @@ async function renderBlock(krokiUrl, source) {
8650
8947
 
8651
8948
  // src/commands/mermaid/exportFile.ts
8652
8949
  async function exportFile(file, outDir, krokiUrl, onlyIndex) {
8653
- const content = readFileSync27(file, "utf8");
8950
+ const content = readFileSync29(file, "utf8");
8654
8951
  const blocks = extractMermaidBlocks(content);
8655
8952
  const stem = basename7(file, extname(file));
8656
8953
  if (onlyIndex !== void 0) {
@@ -8688,7 +8985,7 @@ function extractMermaidBlocks(markdown) {
8688
8985
  async function mermaidExport(file, options2 = {}) {
8689
8986
  const { mermaid } = loadConfig();
8690
8987
  const outDir = resolve10(process.cwd(), options2.out ?? ".");
8691
- mkdirSync8(outDir, { recursive: true });
8988
+ mkdirSync9(outDir, { recursive: true });
8692
8989
  if (options2.index !== void 0) {
8693
8990
  if (!Number.isInteger(options2.index) || options2.index < 1) {
8694
8991
  console.error(
@@ -8701,7 +8998,7 @@ async function mermaidExport(file, options2 = {}) {
8701
8998
  process.exit(1);
8702
8999
  }
8703
9000
  }
8704
- const files = file ? [file] : readdirSync5(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
9001
+ const files = file ? [file] : readdirSync6(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
8705
9002
  if (files.length === 0) {
8706
9003
  console.log(chalk101.gray("No markdown files found in current directory."));
8707
9004
  return;
@@ -9007,7 +9304,7 @@ function registerPrompts(program2) {
9007
9304
  import { spawnSync as spawnSync2 } from "child_process";
9008
9305
  import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
9009
9306
  import { tmpdir as tmpdir4 } from "os";
9010
- import { join as join30 } from "path";
9307
+ import { join as join34 } from "path";
9011
9308
  function buildArgs2(queryFile, vars) {
9012
9309
  const args = ["api", "graphql", "-F", `query=@${queryFile}`];
9013
9310
  for (const [key, value] of Object.entries(vars)) {
@@ -9017,7 +9314,7 @@ function buildArgs2(queryFile, vars) {
9017
9314
  return args;
9018
9315
  }
9019
9316
  function runGhGraphql(mutation, vars) {
9020
- const queryFile = join30(tmpdir4(), `gh-query-${Date.now()}.graphql`);
9317
+ const queryFile = join34(tmpdir4(), `gh-query-${Date.now()}.graphql`);
9021
9318
  writeFileSync22(queryFile, mutation);
9022
9319
  try {
9023
9320
  const result = spawnSync2("gh", buildArgs2(queryFile, vars), {
@@ -9211,26 +9508,26 @@ import { execSync as execSync29 } from "child_process";
9211
9508
  import { execSync as execSync28 } from "child_process";
9212
9509
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync23 } from "fs";
9213
9510
  import { tmpdir as tmpdir5 } from "os";
9214
- import { join as join32 } from "path";
9511
+ import { join as join36 } from "path";
9215
9512
 
9216
9513
  // src/commands/prs/loadCommentsCache.ts
9217
- import { existsSync as existsSync31, readFileSync as readFileSync28, unlinkSync as unlinkSync7 } from "fs";
9218
- import { join as join31 } from "path";
9514
+ import { existsSync as existsSync33, readFileSync as readFileSync30, unlinkSync as unlinkSync7 } from "fs";
9515
+ import { join as join35 } from "path";
9219
9516
  import { parse as parse2 } from "yaml";
9220
9517
  function getCachePath(prNumber) {
9221
- return join31(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
9518
+ return join35(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
9222
9519
  }
9223
9520
  function loadCommentsCache(prNumber) {
9224
9521
  const cachePath = getCachePath(prNumber);
9225
- if (!existsSync31(cachePath)) {
9522
+ if (!existsSync33(cachePath)) {
9226
9523
  return null;
9227
9524
  }
9228
- const content = readFileSync28(cachePath, "utf-8");
9525
+ const content = readFileSync30(cachePath, "utf-8");
9229
9526
  return parse2(content);
9230
9527
  }
9231
9528
  function deleteCommentsCache(prNumber) {
9232
9529
  const cachePath = getCachePath(prNumber);
9233
- if (existsSync31(cachePath)) {
9530
+ if (existsSync33(cachePath)) {
9234
9531
  unlinkSync7(cachePath);
9235
9532
  console.log("No more unresolved line comments. Cache dropped.");
9236
9533
  }
@@ -9245,7 +9542,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
9245
9542
  }
9246
9543
  function resolveThread(threadId) {
9247
9544
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
9248
- const queryFile = join32(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
9545
+ const queryFile = join36(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
9249
9546
  writeFileSync23(queryFile, mutation);
9250
9547
  try {
9251
9548
  execSync28(
@@ -9327,18 +9624,18 @@ function fixed(commentId, sha) {
9327
9624
  }
9328
9625
 
9329
9626
  // src/commands/prs/listComments/index.ts
9330
- import { existsSync as existsSync32, mkdirSync as mkdirSync9, writeFileSync as writeFileSync25 } from "fs";
9331
- import { join as join34 } from "path";
9627
+ import { existsSync as existsSync34, mkdirSync as mkdirSync10, writeFileSync as writeFileSync25 } from "fs";
9628
+ import { join as join38 } from "path";
9332
9629
  import { stringify } from "yaml";
9333
9630
 
9334
9631
  // src/commands/prs/fetchThreadIds.ts
9335
9632
  import { execSync as execSync30 } from "child_process";
9336
9633
  import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync24 } from "fs";
9337
9634
  import { tmpdir as tmpdir6 } from "os";
9338
- import { join as join33 } from "path";
9635
+ import { join as join37 } from "path";
9339
9636
  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 } } } } } } }`;
9340
9637
  function fetchThreadIds(org, repo, prNumber) {
9341
- const queryFile = join33(tmpdir6(), `gh-query-${Date.now()}.graphql`);
9638
+ const queryFile = join37(tmpdir6(), `gh-query-${Date.now()}.graphql`);
9342
9639
  writeFileSync24(queryFile, THREAD_QUERY);
9343
9640
  try {
9344
9641
  const result = execSync30(
@@ -9425,7 +9722,7 @@ function formatForHuman(comment3) {
9425
9722
  ""
9426
9723
  ].join("\n");
9427
9724
  }
9428
- function summarise(comments2) {
9725
+ function summarise2(comments2) {
9429
9726
  const lineCount = comments2.filter((c) => c.type === "line").length;
9430
9727
  const reviewCount = comments2.filter((c) => c.type === "review").length;
9431
9728
  const parts = [];
@@ -9444,7 +9741,7 @@ function printComments2(result) {
9444
9741
  console.log(formatForHuman(comment3));
9445
9742
  }
9446
9743
  }
9447
- console.log(summarise(comments2));
9744
+ console.log(summarise2(comments2));
9448
9745
  if (cachePath) {
9449
9746
  console.log(`Saved to ${cachePath}`);
9450
9747
  }
@@ -9452,16 +9749,16 @@ function printComments2(result) {
9452
9749
 
9453
9750
  // src/commands/prs/listComments/index.ts
9454
9751
  function writeCommentsCache(prNumber, comments2) {
9455
- const assistDir = join34(process.cwd(), ".assist");
9456
- if (!existsSync32(assistDir)) {
9457
- mkdirSync9(assistDir, { recursive: true });
9752
+ const assistDir = join38(process.cwd(), ".assist");
9753
+ if (!existsSync34(assistDir)) {
9754
+ mkdirSync10(assistDir, { recursive: true });
9458
9755
  }
9459
9756
  const cacheData = {
9460
9757
  prNumber,
9461
9758
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
9462
9759
  comments: comments2
9463
9760
  };
9464
- const cachePath = join34(assistDir, `pr-${prNumber}-comments.yaml`);
9761
+ const cachePath = join38(assistDir, `pr-${prNumber}-comments.yaml`);
9465
9762
  writeFileSync25(cachePath, stringify(cacheData));
9466
9763
  }
9467
9764
  function handleKnownErrors(error) {
@@ -9494,7 +9791,7 @@ async function listComments() {
9494
9791
  ];
9495
9792
  updateCache(prNumber, allComments);
9496
9793
  const hasLineComments = allComments.some((c) => c.type === "line");
9497
- const cachePath = hasLineComments ? join34(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
9794
+ const cachePath = hasLineComments ? join38(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
9498
9795
  return { comments: allComments, cachePath };
9499
9796
  } catch (error) {
9500
9797
  const handled = handleKnownErrors(error);
@@ -10178,17 +10475,17 @@ Refactor check failed:
10178
10475
 
10179
10476
  // src/commands/refactor/check/getViolations/index.ts
10180
10477
  import { execSync as execSync36 } from "child_process";
10181
- import fs18 from "fs";
10478
+ import fs19 from "fs";
10182
10479
  import { minimatch as minimatch4 } from "minimatch";
10183
10480
 
10184
10481
  // src/commands/refactor/check/getViolations/getIgnoredFiles.ts
10185
- import fs17 from "fs";
10482
+ import fs18 from "fs";
10186
10483
  var REFACTOR_YML_PATH = "refactor.yml";
10187
10484
  function parseRefactorYml() {
10188
- if (!fs17.existsSync(REFACTOR_YML_PATH)) {
10485
+ if (!fs18.existsSync(REFACTOR_YML_PATH)) {
10189
10486
  return [];
10190
10487
  }
10191
- const content = fs17.readFileSync(REFACTOR_YML_PATH, "utf-8");
10488
+ const content = fs18.readFileSync(REFACTOR_YML_PATH, "utf-8");
10192
10489
  const entries = [];
10193
10490
  const lines = content.split("\n");
10194
10491
  let currentEntry = {};
@@ -10218,7 +10515,7 @@ function getIgnoredFiles() {
10218
10515
 
10219
10516
  // src/commands/refactor/check/getViolations/index.ts
10220
10517
  function countLines(filePath) {
10221
- const content = fs18.readFileSync(filePath, "utf-8");
10518
+ const content = fs19.readFileSync(filePath, "utf-8");
10222
10519
  return content.split("\n").length;
10223
10520
  }
10224
10521
  function getGitFiles(options2) {
@@ -10924,12 +11221,12 @@ import chalk121 from "chalk";
10924
11221
  import { Project as Project3 } from "ts-morph";
10925
11222
 
10926
11223
  // src/commands/refactor/extract/findTsConfig.ts
10927
- import fs19 from "fs";
11224
+ import fs20 from "fs";
10928
11225
  import path34 from "path";
10929
11226
  import { Project as Project2 } from "ts-morph";
10930
11227
  function findTsConfig(sourcePath) {
10931
11228
  const rootConfig = path34.resolve("tsconfig.json");
10932
- if (!fs19.existsSync(rootConfig)) return rootConfig;
11229
+ if (!fs20.existsSync(rootConfig)) return rootConfig;
10933
11230
  const tried = /* @__PURE__ */ new Set();
10934
11231
  const candidates = [rootConfig, ...readReferences(rootConfig)];
10935
11232
  for (const candidate of candidates) {
@@ -10937,7 +11234,7 @@ function findTsConfig(sourcePath) {
10937
11234
  tried.add(candidate);
10938
11235
  if (projectIncludes(candidate, sourcePath)) return candidate;
10939
11236
  }
10940
- const siblings = fs19.readdirSync(path34.dirname(rootConfig)).filter((f) => /^tsconfig.*\.json$/.test(f)).map((f) => path34.resolve(path34.dirname(rootConfig), f));
11237
+ const siblings = fs20.readdirSync(path34.dirname(rootConfig)).filter((f) => /^tsconfig.*\.json$/.test(f)).map((f) => path34.resolve(path34.dirname(rootConfig), f));
10941
11238
  for (const sibling of siblings) {
10942
11239
  if (tried.has(sibling)) continue;
10943
11240
  tried.add(sibling);
@@ -10946,8 +11243,8 @@ function findTsConfig(sourcePath) {
10946
11243
  return rootConfig;
10947
11244
  }
10948
11245
  function readReferences(configPath) {
10949
- if (!fs19.existsSync(configPath)) return [];
10950
- const raw = fs19.readFileSync(configPath, "utf-8");
11246
+ if (!fs20.existsSync(configPath)) return [];
11247
+ const raw = fs20.readFileSync(configPath, "utf-8");
10951
11248
  const stripped = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
10952
11249
  let parsed;
10953
11250
  try {
@@ -10959,8 +11256,8 @@ function readReferences(configPath) {
10959
11256
  const cwd = path34.dirname(configPath);
10960
11257
  return parsed.references.map((ref) => {
10961
11258
  const refPath = path34.resolve(cwd, ref.path);
10962
- return fs19.statSync(refPath, { throwIfNoEntry: false })?.isDirectory() ? path34.join(refPath, "tsconfig.json") : refPath;
10963
- }).filter((p) => fs19.existsSync(p));
11259
+ return fs20.statSync(refPath, { throwIfNoEntry: false })?.isDirectory() ? path34.join(refPath, "tsconfig.json") : refPath;
11260
+ }).filter((p) => fs20.existsSync(p));
10964
11261
  }
10965
11262
  function projectIncludes(configPath, sourcePath) {
10966
11263
  try {
@@ -11010,25 +11307,25 @@ async function extract(file, functionName, destination, options2 = {}) {
11010
11307
  }
11011
11308
 
11012
11309
  // src/commands/refactor/ignore.ts
11013
- import fs20 from "fs";
11310
+ import fs21 from "fs";
11014
11311
  import chalk123 from "chalk";
11015
11312
  var REFACTOR_YML_PATH2 = "refactor.yml";
11016
11313
  function ignore(file) {
11017
- if (!fs20.existsSync(file)) {
11314
+ if (!fs21.existsSync(file)) {
11018
11315
  console.error(chalk123.red(`Error: File does not exist: ${file}`));
11019
11316
  process.exit(1);
11020
11317
  }
11021
- const content = fs20.readFileSync(file, "utf-8");
11318
+ const content = fs21.readFileSync(file, "utf-8");
11022
11319
  const lineCount = content.split("\n").length;
11023
11320
  const maxLines = lineCount + 10;
11024
11321
  const entry = `- file: ${file}
11025
11322
  maxLines: ${maxLines}
11026
11323
  `;
11027
- if (fs20.existsSync(REFACTOR_YML_PATH2)) {
11028
- const existing = fs20.readFileSync(REFACTOR_YML_PATH2, "utf-8");
11029
- fs20.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
11324
+ if (fs21.existsSync(REFACTOR_YML_PATH2)) {
11325
+ const existing = fs21.readFileSync(REFACTOR_YML_PATH2, "utf-8");
11326
+ fs21.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
11030
11327
  } else {
11031
- fs20.writeFileSync(REFACTOR_YML_PATH2, entry);
11328
+ fs21.writeFileSync(REFACTOR_YML_PATH2, entry);
11032
11329
  }
11033
11330
  console.log(
11034
11331
  chalk123.green(
@@ -11276,7 +11573,7 @@ function clusterFiles(graph) {
11276
11573
  import path42 from "path";
11277
11574
 
11278
11575
  // src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
11279
- import fs21 from "fs";
11576
+ import fs22 from "fs";
11280
11577
  function getOrCreateList(map, key) {
11281
11578
  const list4 = map.get(key) ?? [];
11282
11579
  if (!map.has(key)) map.set(key, list4);
@@ -11295,7 +11592,7 @@ function rewriteSpecifier(content, oldSpecifier, newSpecifier) {
11295
11592
  return content.replace(pattern2, `$1${newSpecifier}$2`);
11296
11593
  }
11297
11594
  function applyFileRewrites(file, fileRewrites) {
11298
- let content = fs21.readFileSync(file, "utf-8");
11595
+ let content = fs22.readFileSync(file, "utf-8");
11299
11596
  for (const { oldSpecifier, newSpecifier } of fileRewrites) {
11300
11597
  content = rewriteSpecifier(content, oldSpecifier, newSpecifier);
11301
11598
  }
@@ -11423,27 +11720,27 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
11423
11720
  }
11424
11721
 
11425
11722
  // src/commands/refactor/restructure/executePlan.ts
11426
- import fs22 from "fs";
11723
+ import fs23 from "fs";
11427
11724
  import path44 from "path";
11428
11725
  import chalk127 from "chalk";
11429
11726
  function executePlan(plan2) {
11430
11727
  const updatedContents = applyRewrites(plan2.rewrites);
11431
11728
  for (const [file, content] of updatedContents) {
11432
- fs22.writeFileSync(file, content, "utf-8");
11729
+ fs23.writeFileSync(file, content, "utf-8");
11433
11730
  console.log(
11434
11731
  chalk127.cyan(` Rewrote imports in ${path44.relative(process.cwd(), file)}`)
11435
11732
  );
11436
11733
  }
11437
11734
  for (const dir of plan2.newDirectories) {
11438
- fs22.mkdirSync(dir, { recursive: true });
11735
+ fs23.mkdirSync(dir, { recursive: true });
11439
11736
  console.log(chalk127.green(` Created ${path44.relative(process.cwd(), dir)}/`));
11440
11737
  }
11441
11738
  for (const move of plan2.moves) {
11442
11739
  const targetDir = path44.dirname(move.to);
11443
- if (!fs22.existsSync(targetDir)) {
11444
- fs22.mkdirSync(targetDir, { recursive: true });
11740
+ if (!fs23.existsSync(targetDir)) {
11741
+ fs23.mkdirSync(targetDir, { recursive: true });
11445
11742
  }
11446
- fs22.renameSync(move.from, move.to);
11743
+ fs23.renameSync(move.from, move.to);
11447
11744
  console.log(
11448
11745
  chalk127.white(
11449
11746
  ` Moved ${path44.relative(process.cwd(), move.from)} \u2192 ${path44.relative(process.cwd(), move.to)}`
@@ -11455,10 +11752,10 @@ function executePlan(plan2) {
11455
11752
  function removeEmptyDirectories(dirs) {
11456
11753
  const unique = [...new Set(dirs)];
11457
11754
  for (const dir of unique) {
11458
- if (!fs22.existsSync(dir)) continue;
11459
- const entries = fs22.readdirSync(dir);
11755
+ if (!fs23.existsSync(dir)) continue;
11756
+ const entries = fs23.readdirSync(dir);
11460
11757
  if (entries.length === 0) {
11461
- fs22.rmdirSync(dir);
11758
+ fs23.rmdirSync(dir);
11462
11759
  console.log(
11463
11760
  chalk127.dim(
11464
11761
  ` Removed empty directory ${path44.relative(process.cwd(), dir)}`
@@ -11472,18 +11769,18 @@ function removeEmptyDirectories(dirs) {
11472
11769
  import path46 from "path";
11473
11770
 
11474
11771
  // src/commands/refactor/restructure/planFileMoves/shared.ts
11475
- import fs23 from "fs";
11772
+ import fs24 from "fs";
11476
11773
  function emptyResult() {
11477
11774
  return { moves: [], directories: [], warnings: [] };
11478
11775
  }
11479
11776
  function checkDirConflict(result, label2, dir) {
11480
- if (!fs23.existsSync(dir)) return false;
11777
+ if (!fs24.existsSync(dir)) return false;
11481
11778
  result.warnings.push(`Skipping ${label2}: directory ${dir} already exists`);
11482
11779
  return true;
11483
11780
  }
11484
11781
 
11485
11782
  // src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
11486
- import fs24 from "fs";
11783
+ import fs25 from "fs";
11487
11784
  import path45 from "path";
11488
11785
  function collectEntry(results, dir, entry) {
11489
11786
  const full = path45.join(dir, entry.name);
@@ -11491,9 +11788,9 @@ function collectEntry(results, dir, entry) {
11491
11788
  results.push(...items);
11492
11789
  }
11493
11790
  function listFilesRecursive(dir) {
11494
- if (!fs24.existsSync(dir)) return [];
11791
+ if (!fs25.existsSync(dir)) return [];
11495
11792
  const results = [];
11496
- for (const entry of fs24.readdirSync(dir, { withFileTypes: true })) {
11793
+ for (const entry of fs25.readdirSync(dir, { withFileTypes: true })) {
11497
11794
  collectEntry(results, dir, entry);
11498
11795
  }
11499
11796
  return results;
@@ -11744,15 +12041,15 @@ ${context.diff.trimEnd()}
11744
12041
  }
11745
12042
 
11746
12043
  // src/commands/review/buildReviewPaths.ts
11747
- import { join as join35 } from "path";
12044
+ import { join as join39 } from "path";
11748
12045
  function buildReviewPaths(repoRoot, key) {
11749
- const reviewDir = join35(repoRoot, ".assist", "reviews", key);
12046
+ const reviewDir = join39(repoRoot, ".assist", "reviews", key);
11750
12047
  return {
11751
12048
  reviewDir,
11752
- requestPath: join35(reviewDir, "request.md"),
11753
- claudePath: join35(reviewDir, "claude.md"),
11754
- codexPath: join35(reviewDir, "codex.md"),
11755
- synthesisPath: join35(reviewDir, "synthesis.md")
12049
+ requestPath: join39(reviewDir, "request.md"),
12050
+ claudePath: join39(reviewDir, "claude.md"),
12051
+ codexPath: join39(reviewDir, "codex.md"),
12052
+ synthesisPath: join39(reviewDir, "synthesis.md")
11756
12053
  };
11757
12054
  }
11758
12055
 
@@ -11870,7 +12167,7 @@ function gatherContext() {
11870
12167
  }
11871
12168
 
11872
12169
  // src/commands/review/postReviewToPr.ts
11873
- import { readFileSync as readFileSync29 } from "fs";
12170
+ import { readFileSync as readFileSync31 } from "fs";
11874
12171
 
11875
12172
  // src/commands/review/parseFindings.ts
11876
12173
  var SEVERITIES = ["blocker", "major", "minor", "nit"];
@@ -12100,7 +12397,7 @@ async function postReviewToPr(synthesisPath, options2) {
12100
12397
  console.log("No PR found for current branch; nothing posted.");
12101
12398
  return;
12102
12399
  }
12103
- const markdown = readFileSync29(synthesisPath, "utf-8");
12400
+ const markdown = readFileSync31(synthesisPath, "utf-8");
12104
12401
  const findings = parseFindings(markdown);
12105
12402
  if (findings.length === 0) {
12106
12403
  console.log("Synthesis contains no findings; nothing to post.");
@@ -12177,14 +12474,14 @@ async function handlePostSynthesis(synthesisPath, options2) {
12177
12474
  }
12178
12475
 
12179
12476
  // src/commands/review/prepareReviewDir.ts
12180
- import { existsSync as existsSync33, mkdirSync as mkdirSync10, unlinkSync as unlinkSync10, writeFileSync as writeFileSync26 } from "fs";
12477
+ import { existsSync as existsSync35, mkdirSync as mkdirSync11, unlinkSync as unlinkSync10, writeFileSync as writeFileSync26 } from "fs";
12181
12478
  function clearReviewFiles(paths) {
12182
12479
  for (const path52 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
12183
- if (existsSync33(path52)) unlinkSync10(path52);
12480
+ if (existsSync35(path52)) unlinkSync10(path52);
12184
12481
  }
12185
12482
  }
12186
12483
  function prepareReviewDir(paths, requestBody, force) {
12187
- mkdirSync10(paths.reviewDir, { recursive: true });
12484
+ mkdirSync11(paths.reviewDir, { recursive: true });
12188
12485
  if (force) clearReviewFiles(paths);
12189
12486
  writeFileSync26(paths.requestPath, requestBody);
12190
12487
  }
@@ -12225,11 +12522,11 @@ async function runApplySession(synthesisPath) {
12225
12522
  }
12226
12523
 
12227
12524
  // src/commands/review/cachedReviewerResult.ts
12228
- import { statSync as statSync4 } from "fs";
12525
+ import { statSync as statSync5 } from "fs";
12229
12526
  function cachedReviewerResult(name, outputPath) {
12230
12527
  let size;
12231
12528
  try {
12232
- size = statSync4(outputPath).size;
12529
+ size = statSync5(outputPath).size;
12233
12530
  } catch {
12234
12531
  return null;
12235
12532
  }
@@ -12442,7 +12739,7 @@ function printReviewerFailures(results) {
12442
12739
  }
12443
12740
 
12444
12741
  // src/commands/review/runAndSynthesise.ts
12445
- import { existsSync as existsSync35, unlinkSync as unlinkSync12 } from "fs";
12742
+ import { existsSync as existsSync37, unlinkSync as unlinkSync12 } from "fs";
12446
12743
 
12447
12744
  // src/commands/review/buildReviewerStdin.ts
12448
12745
  var REVIEW_PROMPT = `You are acting as a reviewer for a proposed code change made by another engineer. The full review request \u2014 branch, base, changed files, and unified diff \u2014 is in request.md in the current working directory.
@@ -12860,7 +13157,7 @@ function resolveClaude(args) {
12860
13157
  }
12861
13158
 
12862
13159
  // src/commands/review/runCodexReviewer.ts
12863
- import { existsSync as existsSync34, unlinkSync as unlinkSync11 } from "fs";
13160
+ import { existsSync as existsSync36, unlinkSync as unlinkSync11 } from "fs";
12864
13161
 
12865
13162
  // src/commands/review/parseCodexEvent.ts
12866
13163
  function isItemStarted(value) {
@@ -12914,7 +13211,7 @@ async function runCodexReviewer(spec) {
12914
13211
  reportReviewerToolUse(spec.name, event, spinner);
12915
13212
  }
12916
13213
  });
12917
- if (result.exitCode !== 0 && existsSync34(spec.outputPath)) {
13214
+ if (result.exitCode !== 0 && existsSync36(spec.outputPath)) {
12918
13215
  unlinkSync11(spec.outputPath);
12919
13216
  }
12920
13217
  return finaliseReviewerRun({ ...spec, command }, spinner, result);
@@ -12958,7 +13255,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
12958
13255
  }
12959
13256
 
12960
13257
  // src/commands/review/synthesise.ts
12961
- import { readFileSync as readFileSync30 } from "fs";
13258
+ import { readFileSync as readFileSync32 } from "fs";
12962
13259
 
12963
13260
  // src/commands/review/buildSynthesisStdin.ts
12964
13261
  var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
@@ -13014,7 +13311,7 @@ Files:
13014
13311
 
13015
13312
  // src/commands/review/synthesise.ts
13016
13313
  function printSummary(synthesisPath) {
13017
- const markdown = readFileSync30(synthesisPath, "utf-8");
13314
+ const markdown = readFileSync32(synthesisPath, "utf-8");
13018
13315
  console.log("");
13019
13316
  console.log(buildReviewSummary(markdown));
13020
13317
  console.log("");
@@ -13062,7 +13359,7 @@ async function runAndSynthesise(args) {
13062
13359
  console.error("Both reviewers failed; skipping synthesis.");
13063
13360
  return { ok: false, failures };
13064
13361
  }
13065
- if (anyFresh && existsSync35(paths.synthesisPath)) {
13362
+ if (anyFresh && existsSync37(paths.synthesisPath)) {
13066
13363
  unlinkSync12(paths.synthesisPath);
13067
13364
  }
13068
13365
  const synthesisResult = await synthesise(paths, { multi });
@@ -13879,8 +14176,8 @@ function registerSql(program2) {
13879
14176
  }
13880
14177
 
13881
14178
  // src/commands/transcript/shared.ts
13882
- import { existsSync as existsSync36, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
13883
- import { basename as basename8, join as join36, relative as relative2 } from "path";
14179
+ import { existsSync as existsSync38, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
14180
+ import { basename as basename8, join as join40, relative as relative2 } from "path";
13884
14181
  import * as readline2 from "readline";
13885
14182
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
13886
14183
  function getDatePrefix(daysOffset = 0) {
@@ -13895,11 +14192,11 @@ function isValidDatePrefix(filename) {
13895
14192
  return DATE_PREFIX_REGEX.test(filename);
13896
14193
  }
13897
14194
  function collectFiles(dir, extension) {
13898
- if (!existsSync36(dir)) return [];
14195
+ if (!existsSync38(dir)) return [];
13899
14196
  const results = [];
13900
- for (const entry of readdirSync6(dir)) {
13901
- const fullPath = join36(dir, entry);
13902
- if (statSync5(fullPath).isDirectory()) {
14197
+ for (const entry of readdirSync7(dir)) {
14198
+ const fullPath = join40(dir, entry);
14199
+ if (statSync6(fullPath).isDirectory()) {
13903
14200
  results.push(...collectFiles(fullPath, extension));
13904
14201
  } else if (entry.endsWith(extension)) {
13905
14202
  results.push(fullPath);
@@ -13992,14 +14289,14 @@ async function configure() {
13992
14289
  }
13993
14290
 
13994
14291
  // src/commands/transcript/format/index.ts
13995
- import { existsSync as existsSync38 } from "fs";
14292
+ import { existsSync as existsSync40 } from "fs";
13996
14293
 
13997
14294
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
13998
- import { dirname as dirname20, join as join38 } from "path";
14295
+ import { dirname as dirname20, join as join42 } from "path";
13999
14296
 
14000
14297
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
14001
- import { renameSync as renameSync2 } from "fs";
14002
- import { join as join37 } from "path";
14298
+ import { renameSync as renameSync3 } from "fs";
14299
+ import { join as join41 } from "path";
14003
14300
  async function resolveDate(rl, choice) {
14004
14301
  if (choice === "1") return getDatePrefix(0);
14005
14302
  if (choice === "2") return getDatePrefix(-1);
@@ -14014,7 +14311,7 @@ async function resolveDate(rl, choice) {
14014
14311
  }
14015
14312
  function renameWithPrefix(vttDir, vttFile, prefix2) {
14016
14313
  const newFilename = `${prefix2}.${vttFile}`;
14017
- renameSync2(join37(vttDir, vttFile), join37(vttDir, newFilename));
14314
+ renameSync3(join41(vttDir, vttFile), join41(vttDir, newFilename));
14018
14315
  console.log(`Renamed to: ${newFilename}`);
14019
14316
  return newFilename;
14020
14317
  }
@@ -14048,12 +14345,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
14048
14345
  const vttFileDir = dirname20(vttFile.absolutePath);
14049
14346
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
14050
14347
  if (newFilename) {
14051
- const newRelativePath = join38(
14348
+ const newRelativePath = join42(
14052
14349
  dirname20(vttFile.relativePath),
14053
14350
  newFilename
14054
14351
  );
14055
14352
  vttFiles[i] = {
14056
- absolutePath: join38(vttFileDir, newFilename),
14353
+ absolutePath: join42(vttFileDir, newFilename),
14057
14354
  relativePath: newRelativePath,
14058
14355
  filename: newFilename
14059
14356
  };
@@ -14066,8 +14363,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
14066
14363
  }
14067
14364
 
14068
14365
  // src/commands/transcript/format/processVttFile/index.ts
14069
- import { existsSync as existsSync37, mkdirSync as mkdirSync11, readFileSync as readFileSync31, writeFileSync as writeFileSync28 } from "fs";
14070
- import { basename as basename9, dirname as dirname21, join as join39 } from "path";
14366
+ import { existsSync as existsSync39, mkdirSync as mkdirSync12, readFileSync as readFileSync33, writeFileSync as writeFileSync28 } from "fs";
14367
+ import { basename as basename9, dirname as dirname21, join as join43 } from "path";
14071
14368
 
14072
14369
  // src/commands/transcript/cleanText.ts
14073
14370
  function cleanText(text) {
@@ -14277,22 +14574,22 @@ function toMdFilename(vttFilename) {
14277
14574
  return `${basename9(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
14278
14575
  }
14279
14576
  function resolveOutputDir(relativeDir, transcriptsDir) {
14280
- return relativeDir === "." ? transcriptsDir : join39(transcriptsDir, relativeDir);
14577
+ return relativeDir === "." ? transcriptsDir : join43(transcriptsDir, relativeDir);
14281
14578
  }
14282
14579
  function buildOutputPaths(vttFile, transcriptsDir) {
14283
14580
  const mdFile = toMdFilename(vttFile.filename);
14284
14581
  const relativeDir = dirname21(vttFile.relativePath);
14285
14582
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
14286
- const outputPath = join39(outputDir, mdFile);
14583
+ const outputPath = join43(outputDir, mdFile);
14287
14584
  return { outputDir, outputPath, mdFile, relativeDir };
14288
14585
  }
14289
14586
  function logSkipped(relativeDir, mdFile) {
14290
- console.log(`Skipping (already exists): ${join39(relativeDir, mdFile)}`);
14587
+ console.log(`Skipping (already exists): ${join43(relativeDir, mdFile)}`);
14291
14588
  return "skipped";
14292
14589
  }
14293
14590
  function ensureDirectory(dir, label2) {
14294
- if (!existsSync37(dir)) {
14295
- mkdirSync11(dir, { recursive: true });
14591
+ if (!existsSync39(dir)) {
14592
+ mkdirSync12(dir, { recursive: true });
14296
14593
  console.log(`Created ${label2}: ${dir}`);
14297
14594
  }
14298
14595
  }
@@ -14314,7 +14611,7 @@ function logReduction(cueCount, messageCount) {
14314
14611
  }
14315
14612
  function readAndParseCues(inputPath) {
14316
14613
  console.log(`Reading: ${inputPath}`);
14317
- return processCues(readFileSync31(inputPath, "utf-8"));
14614
+ return processCues(readFileSync33(inputPath, "utf-8"));
14318
14615
  }
14319
14616
  function writeFormatted(outputPath, content) {
14320
14617
  writeFileSync28(outputPath, content, "utf-8");
@@ -14327,7 +14624,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
14327
14624
  logReduction(cues.length, chatMessages.length);
14328
14625
  }
14329
14626
  function tryProcessVtt(vttFile, paths) {
14330
- if (existsSync37(paths.outputPath))
14627
+ if (existsSync39(paths.outputPath))
14331
14628
  return logSkipped(paths.relativeDir, paths.mdFile);
14332
14629
  convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
14333
14630
  return "processed";
@@ -14353,7 +14650,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
14353
14650
  logSummary(counts);
14354
14651
  }
14355
14652
  function requireVttDir(vttDir) {
14356
- if (!existsSync38(vttDir)) {
14653
+ if (!existsSync40(vttDir)) {
14357
14654
  console.error(`VTT directory not found: ${vttDir}`);
14358
14655
  process.exit(1);
14359
14656
  }
@@ -14385,18 +14682,18 @@ async function format() {
14385
14682
  }
14386
14683
 
14387
14684
  // src/commands/transcript/summarise/index.ts
14388
- import { existsSync as existsSync40 } from "fs";
14389
- import { basename as basename10, dirname as dirname23, join as join41, relative as relative3 } from "path";
14685
+ import { existsSync as existsSync42 } from "fs";
14686
+ import { basename as basename10, dirname as dirname23, join as join45, relative as relative3 } from "path";
14390
14687
 
14391
14688
  // src/commands/transcript/summarise/processStagedFile/index.ts
14392
14689
  import {
14393
- existsSync as existsSync39,
14394
- mkdirSync as mkdirSync12,
14395
- readFileSync as readFileSync32,
14396
- renameSync as renameSync3,
14690
+ existsSync as existsSync41,
14691
+ mkdirSync as mkdirSync13,
14692
+ readFileSync as readFileSync34,
14693
+ renameSync as renameSync4,
14397
14694
  rmSync
14398
14695
  } from "fs";
14399
- import { dirname as dirname22, join as join40 } from "path";
14696
+ import { dirname as dirname22, join as join44 } from "path";
14400
14697
 
14401
14698
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
14402
14699
  import chalk142 from "chalk";
@@ -14425,9 +14722,9 @@ function validateStagedContent(filename, content) {
14425
14722
  }
14426
14723
 
14427
14724
  // src/commands/transcript/summarise/processStagedFile/index.ts
14428
- var STAGING_DIR = join40(process.cwd(), ".assist", "transcript");
14725
+ var STAGING_DIR = join44(process.cwd(), ".assist", "transcript");
14429
14726
  function processStagedFile() {
14430
- if (!existsSync39(STAGING_DIR)) {
14727
+ if (!existsSync41(STAGING_DIR)) {
14431
14728
  return false;
14432
14729
  }
14433
14730
  const stagedFiles = findMdFilesRecursive(STAGING_DIR);
@@ -14436,7 +14733,7 @@ function processStagedFile() {
14436
14733
  }
14437
14734
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
14438
14735
  const stagedFile = stagedFiles[0];
14439
- const content = readFileSync32(stagedFile.absolutePath, "utf-8");
14736
+ const content = readFileSync34(stagedFile.absolutePath, "utf-8");
14440
14737
  validateStagedContent(stagedFile.filename, content);
14441
14738
  const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
14442
14739
  const transcriptFiles = findMdFilesRecursive(transcriptsDir);
@@ -14449,12 +14746,12 @@ function processStagedFile() {
14449
14746
  );
14450
14747
  process.exit(1);
14451
14748
  }
14452
- const destPath = join40(summaryDir, matchingTranscript.relativePath);
14749
+ const destPath = join44(summaryDir, matchingTranscript.relativePath);
14453
14750
  const destDir = dirname22(destPath);
14454
- if (!existsSync39(destDir)) {
14455
- mkdirSync12(destDir, { recursive: true });
14751
+ if (!existsSync41(destDir)) {
14752
+ mkdirSync13(destDir, { recursive: true });
14456
14753
  }
14457
- renameSync3(stagedFile.absolutePath, destPath);
14754
+ renameSync4(stagedFile.absolutePath, destPath);
14458
14755
  const remaining = findMdFilesRecursive(STAGING_DIR);
14459
14756
  if (remaining.length === 0) {
14460
14757
  rmSync(STAGING_DIR, { recursive: true });
@@ -14465,7 +14762,7 @@ function processStagedFile() {
14465
14762
  // src/commands/transcript/summarise/index.ts
14466
14763
  function buildRelativeKey(relativePath, baseName) {
14467
14764
  const relDir = dirname23(relativePath);
14468
- return relDir === "." ? baseName : join41(relDir, baseName);
14765
+ return relDir === "." ? baseName : join45(relDir, baseName);
14469
14766
  }
14470
14767
  function buildSummaryIndex(summaryDir) {
14471
14768
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -14475,10 +14772,10 @@ function buildSummaryIndex(summaryDir) {
14475
14772
  )
14476
14773
  );
14477
14774
  }
14478
- function summarise2() {
14775
+ function summarise3() {
14479
14776
  processStagedFile();
14480
14777
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
14481
- if (!existsSync40(transcriptsDir)) {
14778
+ if (!existsSync42(transcriptsDir)) {
14482
14779
  console.log("No transcripts directory found.");
14483
14780
  return;
14484
14781
  }
@@ -14499,8 +14796,8 @@ function summarise2() {
14499
14796
  }
14500
14797
  const next3 = missing[0];
14501
14798
  const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
14502
- const outputPath = join41(STAGING_DIR, outputFilename);
14503
- const summaryFileDir = join41(summaryDir, dirname23(next3.relativePath));
14799
+ const outputPath = join45(STAGING_DIR, outputFilename);
14800
+ const summaryFileDir = join45(summaryDir, dirname23(next3.relativePath));
14504
14801
  const relativeTranscriptPath = encodeURI(
14505
14802
  relative3(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
14506
14803
  );
@@ -14521,7 +14818,7 @@ function registerTranscript(program2) {
14521
14818
  const transcriptCommand = program2.command("transcript").description("Meeting transcript utilities");
14522
14819
  transcriptCommand.command("configure").description("Configure transcript directories").action(configure);
14523
14820
  transcriptCommand.command("format").description("Convert VTT files to formatted markdown transcripts").action(format);
14524
- transcriptCommand.command("summarise").description("List transcripts that do not have summaries").action(summarise2);
14821
+ transcriptCommand.command("summarise").description("List transcripts that do not have summaries").action(summarise3);
14525
14822
  }
14526
14823
 
14527
14824
  // src/commands/registerVerify.ts
@@ -14549,50 +14846,50 @@ function registerVerify(program2) {
14549
14846
 
14550
14847
  // src/commands/voice/devices.ts
14551
14848
  import { spawnSync as spawnSync4 } from "child_process";
14552
- import { join as join43 } from "path";
14849
+ import { join as join47 } from "path";
14553
14850
 
14554
14851
  // src/commands/voice/shared.ts
14555
- import { homedir as homedir9 } from "os";
14556
- import { dirname as dirname24, join as join42 } from "path";
14852
+ import { homedir as homedir10 } from "os";
14853
+ import { dirname as dirname24, join as join46 } from "path";
14557
14854
  import { fileURLToPath as fileURLToPath6 } from "url";
14558
14855
  var __dirname6 = dirname24(fileURLToPath6(import.meta.url));
14559
- var VOICE_DIR = join42(homedir9(), ".assist", "voice");
14856
+ var VOICE_DIR = join46(homedir10(), ".assist", "voice");
14560
14857
  var voicePaths = {
14561
14858
  dir: VOICE_DIR,
14562
- pid: join42(VOICE_DIR, "voice.pid"),
14563
- log: join42(VOICE_DIR, "voice.log"),
14564
- venv: join42(VOICE_DIR, ".venv"),
14565
- lock: join42(VOICE_DIR, "voice.lock")
14859
+ pid: join46(VOICE_DIR, "voice.pid"),
14860
+ log: join46(VOICE_DIR, "voice.log"),
14861
+ venv: join46(VOICE_DIR, ".venv"),
14862
+ lock: join46(VOICE_DIR, "voice.lock")
14566
14863
  };
14567
14864
  function getPythonDir() {
14568
- return join42(__dirname6, "commands", "voice", "python");
14865
+ return join46(__dirname6, "commands", "voice", "python");
14569
14866
  }
14570
14867
  function getVenvPython() {
14571
- return process.platform === "win32" ? join42(voicePaths.venv, "Scripts", "python.exe") : join42(voicePaths.venv, "bin", "python");
14868
+ return process.platform === "win32" ? join46(voicePaths.venv, "Scripts", "python.exe") : join46(voicePaths.venv, "bin", "python");
14572
14869
  }
14573
14870
  function getLockDir() {
14574
14871
  const config = loadConfig();
14575
14872
  return config.voice?.lockDir ?? VOICE_DIR;
14576
14873
  }
14577
14874
  function getLockFile() {
14578
- return join42(getLockDir(), "voice.lock");
14875
+ return join46(getLockDir(), "voice.lock");
14579
14876
  }
14580
14877
 
14581
14878
  // src/commands/voice/devices.ts
14582
14879
  function devices() {
14583
- const script = join43(getPythonDir(), "list_devices.py");
14880
+ const script = join47(getPythonDir(), "list_devices.py");
14584
14881
  spawnSync4(getVenvPython(), [script], { stdio: "inherit" });
14585
14882
  }
14586
14883
 
14587
14884
  // src/commands/voice/logs.ts
14588
- import { existsSync as existsSync41, readFileSync as readFileSync33 } from "fs";
14885
+ import { existsSync as existsSync43, readFileSync as readFileSync35 } from "fs";
14589
14886
  function logs(options2) {
14590
- if (!existsSync41(voicePaths.log)) {
14887
+ if (!existsSync43(voicePaths.log)) {
14591
14888
  console.log("No voice log file found");
14592
14889
  return;
14593
14890
  }
14594
14891
  const count = Number.parseInt(options2.lines ?? "150", 10);
14595
- const content = readFileSync33(voicePaths.log, "utf-8").trim();
14892
+ const content = readFileSync35(voicePaths.log, "utf-8").trim();
14596
14893
  if (!content) {
14597
14894
  console.log("Voice log is empty");
14598
14895
  return;
@@ -14614,13 +14911,13 @@ function logs(options2) {
14614
14911
 
14615
14912
  // src/commands/voice/setup.ts
14616
14913
  import { spawnSync as spawnSync5 } from "child_process";
14617
- import { mkdirSync as mkdirSync14 } from "fs";
14618
- import { join as join45 } from "path";
14914
+ import { mkdirSync as mkdirSync15 } from "fs";
14915
+ import { join as join49 } from "path";
14619
14916
 
14620
14917
  // src/commands/voice/checkLockFile.ts
14621
14918
  import { execSync as execSync41 } from "child_process";
14622
- import { existsSync as existsSync42, mkdirSync as mkdirSync13, readFileSync as readFileSync34, writeFileSync as writeFileSync29 } from "fs";
14623
- import { join as join44 } from "path";
14919
+ import { existsSync as existsSync44, mkdirSync as mkdirSync14, readFileSync as readFileSync36, writeFileSync as writeFileSync29 } from "fs";
14920
+ import { join as join48 } from "path";
14624
14921
  function isProcessAlive2(pid) {
14625
14922
  try {
14626
14923
  process.kill(pid, 0);
@@ -14631,9 +14928,9 @@ function isProcessAlive2(pid) {
14631
14928
  }
14632
14929
  function checkLockFile() {
14633
14930
  const lockFile = getLockFile();
14634
- if (!existsSync42(lockFile)) return;
14931
+ if (!existsSync44(lockFile)) return;
14635
14932
  try {
14636
- const lock = JSON.parse(readFileSync34(lockFile, "utf-8"));
14933
+ const lock = JSON.parse(readFileSync36(lockFile, "utf-8"));
14637
14934
  if (lock.pid && isProcessAlive2(lock.pid)) {
14638
14935
  console.error(
14639
14936
  `Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
@@ -14644,7 +14941,7 @@ function checkLockFile() {
14644
14941
  }
14645
14942
  }
14646
14943
  function bootstrapVenv() {
14647
- if (existsSync42(getVenvPython())) return;
14944
+ if (existsSync44(getVenvPython())) return;
14648
14945
  console.log("Setting up Python environment...");
14649
14946
  const pythonDir = getPythonDir();
14650
14947
  execSync41(
@@ -14657,7 +14954,7 @@ function bootstrapVenv() {
14657
14954
  }
14658
14955
  function writeLockFile(pid) {
14659
14956
  const lockFile = getLockFile();
14660
- mkdirSync13(join44(lockFile, ".."), { recursive: true });
14957
+ mkdirSync14(join48(lockFile, ".."), { recursive: true });
14661
14958
  writeFileSync29(
14662
14959
  lockFile,
14663
14960
  JSON.stringify({
@@ -14670,10 +14967,10 @@ function writeLockFile(pid) {
14670
14967
 
14671
14968
  // src/commands/voice/setup.ts
14672
14969
  function setup() {
14673
- mkdirSync14(voicePaths.dir, { recursive: true });
14970
+ mkdirSync15(voicePaths.dir, { recursive: true });
14674
14971
  bootstrapVenv();
14675
14972
  console.log("\nDownloading models...\n");
14676
- const script = join45(getPythonDir(), "setup_models.py");
14973
+ const script = join49(getPythonDir(), "setup_models.py");
14677
14974
  const result = spawnSync5(getVenvPython(), [script], {
14678
14975
  stdio: "inherit",
14679
14976
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -14686,8 +14983,8 @@ function setup() {
14686
14983
 
14687
14984
  // src/commands/voice/start.ts
14688
14985
  import { spawn as spawn7 } from "child_process";
14689
- import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync30 } from "fs";
14690
- import { join as join46 } from "path";
14986
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync30 } from "fs";
14987
+ import { join as join50 } from "path";
14691
14988
 
14692
14989
  // src/commands/voice/buildDaemonEnv.ts
14693
14990
  function buildDaemonEnv(options2) {
@@ -14720,12 +15017,12 @@ function spawnBackground(python, script, env) {
14720
15017
  console.log(`Voice daemon started (PID ${pid})`);
14721
15018
  }
14722
15019
  function start2(options2) {
14723
- mkdirSync15(voicePaths.dir, { recursive: true });
15020
+ mkdirSync16(voicePaths.dir, { recursive: true });
14724
15021
  checkLockFile();
14725
15022
  bootstrapVenv();
14726
15023
  const debug = options2.debug || options2.foreground || process.platform === "win32";
14727
15024
  const env = buildDaemonEnv({ debug });
14728
- const script = join46(getPythonDir(), "voice_daemon.py");
15025
+ const script = join50(getPythonDir(), "voice_daemon.py");
14729
15026
  const python = getVenvPython();
14730
15027
  if (options2.foreground) {
14731
15028
  spawnForeground(python, script, env);
@@ -14735,7 +15032,7 @@ function start2(options2) {
14735
15032
  }
14736
15033
 
14737
15034
  // src/commands/voice/status.ts
14738
- import { existsSync as existsSync43, readFileSync as readFileSync35 } from "fs";
15035
+ import { existsSync as existsSync45, readFileSync as readFileSync37 } from "fs";
14739
15036
  function isProcessAlive3(pid) {
14740
15037
  try {
14741
15038
  process.kill(pid, 0);
@@ -14745,16 +15042,16 @@ function isProcessAlive3(pid) {
14745
15042
  }
14746
15043
  }
14747
15044
  function readRecentLogs(count) {
14748
- if (!existsSync43(voicePaths.log)) return [];
14749
- const lines = readFileSync35(voicePaths.log, "utf-8").trim().split("\n");
15045
+ if (!existsSync45(voicePaths.log)) return [];
15046
+ const lines = readFileSync37(voicePaths.log, "utf-8").trim().split("\n");
14750
15047
  return lines.slice(-count);
14751
15048
  }
14752
15049
  function status() {
14753
- if (!existsSync43(voicePaths.pid)) {
15050
+ if (!existsSync45(voicePaths.pid)) {
14754
15051
  console.log("Voice daemon: not running (no PID file)");
14755
15052
  return;
14756
15053
  }
14757
- const pid = Number.parseInt(readFileSync35(voicePaths.pid, "utf-8").trim(), 10);
15054
+ const pid = Number.parseInt(readFileSync37(voicePaths.pid, "utf-8").trim(), 10);
14758
15055
  const alive = isProcessAlive3(pid);
14759
15056
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
14760
15057
  const recent = readRecentLogs(5);
@@ -14773,13 +15070,13 @@ function status() {
14773
15070
  }
14774
15071
 
14775
15072
  // src/commands/voice/stop.ts
14776
- import { existsSync as existsSync44, readFileSync as readFileSync36, unlinkSync as unlinkSync13 } from "fs";
15073
+ import { existsSync as existsSync46, readFileSync as readFileSync38, unlinkSync as unlinkSync13 } from "fs";
14777
15074
  function stop2() {
14778
- if (!existsSync44(voicePaths.pid)) {
15075
+ if (!existsSync46(voicePaths.pid)) {
14779
15076
  console.log("Voice daemon is not running (no PID file)");
14780
15077
  return;
14781
15078
  }
14782
- const pid = Number.parseInt(readFileSync36(voicePaths.pid, "utf-8").trim(), 10);
15079
+ const pid = Number.parseInt(readFileSync38(voicePaths.pid, "utf-8").trim(), 10);
14783
15080
  try {
14784
15081
  process.kill(pid, "SIGTERM");
14785
15082
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -14792,7 +15089,7 @@ function stop2() {
14792
15089
  }
14793
15090
  try {
14794
15091
  const lockFile = getLockFile();
14795
- if (existsSync44(lockFile)) unlinkSync13(lockFile);
15092
+ if (existsSync46(lockFile)) unlinkSync13(lockFile);
14796
15093
  } catch {
14797
15094
  }
14798
15095
  console.log("Voice daemon stopped");
@@ -15013,20 +15310,20 @@ async function auth() {
15013
15310
  }
15014
15311
 
15015
15312
  // src/commands/roam/postRoamActivity.ts
15016
- import { execFileSync as execFileSync4 } from "child_process";
15017
- import { readdirSync as readdirSync7, readFileSync as readFileSync37, statSync as statSync6 } from "fs";
15018
- import { join as join47 } from "path";
15313
+ import { execFileSync as execFileSync5 } from "child_process";
15314
+ import { readdirSync as readdirSync8, readFileSync as readFileSync39, statSync as statSync7 } from "fs";
15315
+ import { join as join51 } from "path";
15019
15316
  function findPortFile(roamDir) {
15020
15317
  let entries;
15021
15318
  try {
15022
- entries = readdirSync7(roamDir);
15319
+ entries = readdirSync8(roamDir);
15023
15320
  } catch {
15024
15321
  return void 0;
15025
15322
  }
15026
15323
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
15027
- const path52 = join47(roamDir, name);
15324
+ const path52 = join51(roamDir, name);
15028
15325
  try {
15029
- return { path: path52, mtimeMs: statSync6(path52).mtimeMs };
15326
+ return { path: path52, mtimeMs: statSync7(path52).mtimeMs };
15030
15327
  } catch {
15031
15328
  return void 0;
15032
15329
  }
@@ -15036,17 +15333,17 @@ function findPortFile(roamDir) {
15036
15333
  function postRoamActivity(app, event) {
15037
15334
  const appData = process.env.APPDATA;
15038
15335
  if (!appData) return;
15039
- const portFile = findPortFile(join47(appData, "Roam"));
15336
+ const portFile = findPortFile(join51(appData, "Roam"));
15040
15337
  if (!portFile) return;
15041
15338
  let port;
15042
15339
  try {
15043
- port = readFileSync37(portFile, "utf-8").trim();
15340
+ port = readFileSync39(portFile, "utf-8").trim();
15044
15341
  } catch {
15045
15342
  return;
15046
15343
  }
15047
15344
  const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${app === "codex" ? 99998 : 99999}`;
15048
15345
  try {
15049
- execFileSync4("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
15346
+ execFileSync5("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
15050
15347
  stdio: "ignore"
15051
15348
  });
15052
15349
  } catch {
@@ -15173,16 +15470,16 @@ function runPreCommands(pre, cwd) {
15173
15470
  }
15174
15471
 
15175
15472
  // src/commands/run/spawnRunCommand.ts
15176
- import { execFileSync as execFileSync5, spawn as spawn8 } from "child_process";
15177
- import { existsSync as existsSync45 } from "fs";
15178
- import { dirname as dirname25, join as join48, resolve as resolve11 } from "path";
15473
+ import { execFileSync as execFileSync6, spawn as spawn8 } from "child_process";
15474
+ import { existsSync as existsSync47 } from "fs";
15475
+ import { dirname as dirname25, join as join52, resolve as resolve11 } from "path";
15179
15476
  function resolveCommand2(command) {
15180
15477
  if (process.platform !== "win32" || command !== "bash") return command;
15181
15478
  try {
15182
- const gitPath = execFileSync5("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
15479
+ const gitPath = execFileSync6("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
15183
15480
  const gitRoot = resolve11(dirname25(gitPath), "..");
15184
- const gitBash = join48(gitRoot, "bin", "bash.exe");
15185
- if (existsSync45(gitBash)) return gitBash;
15481
+ const gitBash = join52(gitRoot, "bin", "bash.exe");
15482
+ if (existsSync47(gitBash)) return gitBash;
15186
15483
  } catch {
15187
15484
  }
15188
15485
  return command;
@@ -15249,8 +15546,8 @@ function run3(name, args) {
15249
15546
  }
15250
15547
 
15251
15548
  // src/commands/run/add.ts
15252
- import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync31 } from "fs";
15253
- import { join as join49 } from "path";
15549
+ import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync31 } from "fs";
15550
+ import { join as join53 } from "path";
15254
15551
 
15255
15552
  // src/commands/run/extractOption.ts
15256
15553
  function extractOption(args, flag) {
@@ -15311,15 +15608,15 @@ function saveNewRunConfig(name, command, args, cwd) {
15311
15608
  saveConfig(config);
15312
15609
  }
15313
15610
  function createCommandFile(name) {
15314
- const dir = join49(".claude", "commands");
15315
- mkdirSync16(dir, { recursive: true });
15611
+ const dir = join53(".claude", "commands");
15612
+ mkdirSync17(dir, { recursive: true });
15316
15613
  const content = `---
15317
15614
  description: Run ${name}
15318
15615
  ---
15319
15616
 
15320
15617
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
15321
15618
  `;
15322
- const filePath = join49(dir, `${name}.md`);
15619
+ const filePath = join53(dir, `${name}.md`);
15323
15620
  writeFileSync31(filePath, content);
15324
15621
  console.log(`Created command file: ${filePath}`);
15325
15622
  }
@@ -15375,8 +15672,8 @@ function link2() {
15375
15672
  }
15376
15673
 
15377
15674
  // src/commands/run/remove.ts
15378
- import { existsSync as existsSync46, unlinkSync as unlinkSync14 } from "fs";
15379
- import { join as join50 } from "path";
15675
+ import { existsSync as existsSync48, unlinkSync as unlinkSync14 } from "fs";
15676
+ import { join as join54 } from "path";
15380
15677
  function findRemoveIndex() {
15381
15678
  const idx = process.argv.indexOf("remove");
15382
15679
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -15391,8 +15688,8 @@ function parseRemoveName() {
15391
15688
  return process.argv[idx + 1];
15392
15689
  }
15393
15690
  function deleteCommandFile(name) {
15394
- const filePath = join50(".claude", "commands", `${name}.md`);
15395
- if (existsSync46(filePath)) {
15691
+ const filePath = join54(".claude", "commands", `${name}.md`);
15692
+ if (existsSync48(filePath)) {
15396
15693
  unlinkSync14(filePath);
15397
15694
  console.log(`Deleted command file: ${filePath}`);
15398
15695
  }
@@ -15428,9 +15725,9 @@ function registerRun(program2) {
15428
15725
 
15429
15726
  // src/commands/screenshot/index.ts
15430
15727
  import { execSync as execSync44 } from "child_process";
15431
- import { existsSync as existsSync47, mkdirSync as mkdirSync17, unlinkSync as unlinkSync15, writeFileSync as writeFileSync32 } from "fs";
15728
+ import { existsSync as existsSync49, mkdirSync as mkdirSync18, unlinkSync as unlinkSync15, writeFileSync as writeFileSync32 } from "fs";
15432
15729
  import { tmpdir as tmpdir7 } from "os";
15433
- import { join as join51, resolve as resolve13 } from "path";
15730
+ import { join as join55, resolve as resolve13 } from "path";
15434
15731
  import chalk144 from "chalk";
15435
15732
 
15436
15733
  // src/commands/screenshot/captureWindowPs1.ts
@@ -15560,14 +15857,14 @@ Write-Output $OutputPath
15560
15857
 
15561
15858
  // src/commands/screenshot/index.ts
15562
15859
  function buildOutputPath(outputDir, processName) {
15563
- if (!existsSync47(outputDir)) {
15564
- mkdirSync17(outputDir, { recursive: true });
15860
+ if (!existsSync49(outputDir)) {
15861
+ mkdirSync18(outputDir, { recursive: true });
15565
15862
  }
15566
15863
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
15567
15864
  return resolve13(outputDir, `${processName}-${timestamp}.png`);
15568
15865
  }
15569
15866
  function runPowerShellScript(processName, outputPath) {
15570
- const scriptPath = join51(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
15867
+ const scriptPath = join55(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
15571
15868
  writeFileSync32(scriptPath, captureWindowPs1, "utf-8");
15572
15869
  try {
15573
15870
  execSync44(
@@ -15594,58 +15891,45 @@ function screenshot(processName) {
15594
15891
  }
15595
15892
 
15596
15893
  // src/commands/sessions/summarise/index.ts
15597
- import * as fs27 from "fs";
15894
+ import * as fs28 from "fs";
15598
15895
  import chalk145 from "chalk";
15599
15896
 
15600
15897
  // src/commands/sessions/summarise/shared.ts
15601
- import * as fs25 from "fs";
15898
+ import * as fs26 from "fs";
15602
15899
  function writeSummary(jsonlPath, summary) {
15603
- fs25.writeFileSync(summaryPathFor(jsonlPath), `${summary.trim()}
15900
+ fs26.writeFileSync(summaryPathFor(jsonlPath), `${summary.trim()}
15604
15901
  `, "utf8");
15605
15902
  }
15606
15903
  function hasSummary(jsonlPath) {
15607
- return fs25.existsSync(summaryPathFor(jsonlPath));
15904
+ return fs26.existsSync(summaryPathFor(jsonlPath));
15608
15905
  }
15609
15906
  function summaryPathFor(jsonlPath) {
15610
15907
  return jsonlPath.replace(/\.jsonl$/, ".summary");
15611
15908
  }
15612
15909
 
15613
15910
  // src/commands/sessions/summarise/summariseSession.ts
15614
- import { execFileSync as execFileSync6 } from "child_process";
15911
+ import { execFileSync as execFileSync7 } from "child_process";
15615
15912
 
15616
15913
  // src/commands/sessions/summarise/iterateUserMessages.ts
15617
- import * as fs26 from "fs";
15914
+ import * as fs27 from "fs";
15618
15915
  function* iterateUserMessages(filePath, maxBytes = 65536) {
15619
15916
  let content;
15620
15917
  try {
15621
- const fd = fs26.openSync(filePath, "r");
15918
+ const fd = fs27.openSync(filePath, "r");
15622
15919
  try {
15623
15920
  const buf = Buffer.alloc(maxBytes);
15624
- const bytesRead = fs26.readSync(fd, buf, 0, buf.length, 0);
15921
+ const bytesRead = fs27.readSync(fd, buf, 0, buf.length, 0);
15625
15922
  content = buf.toString("utf8", 0, bytesRead);
15626
15923
  } finally {
15627
- fs26.closeSync(fd);
15924
+ fs27.closeSync(fd);
15628
15925
  }
15629
15926
  } catch {
15630
15927
  return;
15631
15928
  }
15632
15929
  for (const line of content.split("\n")) {
15633
15930
  if (!line) continue;
15634
- let entry;
15635
- try {
15636
- entry = JSON.parse(line);
15637
- } catch {
15638
- continue;
15639
- }
15640
- if (entry.type !== "user") continue;
15641
- const msg = entry.message;
15642
- const c = msg?.content;
15643
- if (typeof c === "string") {
15644
- yield c;
15645
- } else if (Array.isArray(c)) {
15646
- const text = c.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n");
15647
- if (text) yield text;
15648
- }
15931
+ const entry = parseUserLine(line);
15932
+ if (entry) yield entry.text;
15649
15933
  }
15650
15934
  }
15651
15935
 
@@ -15701,7 +15985,7 @@ function summariseSession(jsonlPath) {
15701
15985
  }
15702
15986
  const prompt = buildPrompt2(firstMessage, backlogIds);
15703
15987
  try {
15704
- const output = execFileSync6("claude", ["-p", "--model", "haiku", prompt], {
15988
+ const output = execFileSync7("claude", ["-p", "--model", "haiku", prompt], {
15705
15989
  encoding: "utf8",
15706
15990
  timeout: 3e4,
15707
15991
  stdio: ["ignore", "pipe", "ignore"]
@@ -15732,7 +16016,7 @@ ${firstMessage}`);
15732
16016
  }
15733
16017
 
15734
16018
  // src/commands/sessions/summarise/index.ts
15735
- async function summarise3(options2) {
16019
+ async function summarise4(options2) {
15736
16020
  const files = await discoverSessionJsonlPaths();
15737
16021
  if (files.length === 0) {
15738
16022
  console.log(chalk145.yellow("No sessions found."));
@@ -15757,7 +16041,7 @@ function selectCandidates(files, options2) {
15757
16041
  const candidates = options2.force ? files : files.filter((f) => !hasSummary(f));
15758
16042
  candidates.sort((a, b) => {
15759
16043
  try {
15760
- return fs27.statSync(b).mtimeMs - fs27.statSync(a).mtimeMs;
16044
+ return fs28.statSync(b).mtimeMs - fs28.statSync(a).mtimeMs;
15761
16045
  } catch {
15762
16046
  return 0;
15763
16047
  }
@@ -15790,7 +16074,7 @@ function processSessions(files) {
15790
16074
  function registerSessions(program2) {
15791
16075
  const cmd = program2.command("sessions").description("Web dashboard for Claude Code sessions").action(() => web({ port: "3100" }));
15792
16076
  cmd.command("web").description("Start the sessions web dashboard").option("-p, --port <number>", "Port to listen on", "3100").action(web);
15793
- cmd.command("summarise").description("Generate one-line summaries for Claude sessions").option("-f, --force", "Re-generate all summaries, even existing ones").option("-n, --limit <count>", "Maximum number of sessions to summarise").action(summarise3);
16077
+ cmd.command("summarise").description("Generate one-line summaries for Claude sessions").option("-f, --force", "Re-generate all summaries, even existing ones").option("-n, --limit <count>", "Maximum number of sessions to summarise").action(summarise4);
15794
16078
  }
15795
16079
 
15796
16080
  // src/commands/statusLine.ts
@@ -15871,21 +16155,21 @@ async function statusLine() {
15871
16155
  }
15872
16156
 
15873
16157
  // src/commands/sync.ts
15874
- import * as fs30 from "fs";
16158
+ import * as fs31 from "fs";
15875
16159
  import * as os2 from "os";
15876
16160
  import * as path50 from "path";
15877
16161
  import { fileURLToPath as fileURLToPath7 } from "url";
15878
16162
 
15879
16163
  // src/commands/sync/syncClaudeMd.ts
15880
- import * as fs28 from "fs";
16164
+ import * as fs29 from "fs";
15881
16165
  import * as path48 from "path";
15882
16166
  import chalk148 from "chalk";
15883
16167
  async function syncClaudeMd(claudeDir, targetBase, options2) {
15884
16168
  const source = path48.join(claudeDir, "CLAUDE.md");
15885
16169
  const target = path48.join(targetBase, "CLAUDE.md");
15886
- const sourceContent = fs28.readFileSync(source, "utf-8");
15887
- if (fs28.existsSync(target)) {
15888
- const targetContent = fs28.readFileSync(target, "utf-8");
16170
+ const sourceContent = fs29.readFileSync(source, "utf-8");
16171
+ if (fs29.existsSync(target)) {
16172
+ const targetContent = fs29.readFileSync(target, "utf-8");
15889
16173
  if (sourceContent !== targetContent) {
15890
16174
  console.log(
15891
16175
  chalk148.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
@@ -15902,21 +16186,21 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
15902
16186
  }
15903
16187
  }
15904
16188
  }
15905
- fs28.copyFileSync(source, target);
16189
+ fs29.copyFileSync(source, target);
15906
16190
  console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
15907
16191
  }
15908
16192
 
15909
16193
  // src/commands/sync/syncSettings.ts
15910
- import * as fs29 from "fs";
16194
+ import * as fs30 from "fs";
15911
16195
  import * as path49 from "path";
15912
16196
  import chalk149 from "chalk";
15913
16197
  async function syncSettings(claudeDir, targetBase, options2) {
15914
16198
  const source = path49.join(claudeDir, "settings.json");
15915
16199
  const target = path49.join(targetBase, "settings.json");
15916
- const sourceContent = fs29.readFileSync(source, "utf-8");
16200
+ const sourceContent = fs30.readFileSync(source, "utf-8");
15917
16201
  const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
15918
- if (fs29.existsSync(target)) {
15919
- const targetContent = fs29.readFileSync(target, "utf-8");
16202
+ if (fs30.existsSync(target)) {
16203
+ const targetContent = fs30.readFileSync(target, "utf-8");
15920
16204
  const normalizedTarget = JSON.stringify(
15921
16205
  JSON.parse(targetContent),
15922
16206
  null,
@@ -15942,7 +16226,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
15942
16226
  }
15943
16227
  }
15944
16228
  }
15945
- fs29.writeFileSync(target, mergedContent);
16229
+ fs30.writeFileSync(target, mergedContent);
15946
16230
  console.log("Copied settings.json to ~/.claude/settings.json");
15947
16231
  }
15948
16232
 
@@ -15961,10 +16245,10 @@ async function sync(options2) {
15961
16245
  function syncCommands(claudeDir, targetBase) {
15962
16246
  const sourceDir = path50.join(claudeDir, "commands");
15963
16247
  const targetDir = path50.join(targetBase, "commands");
15964
- fs30.mkdirSync(targetDir, { recursive: true });
15965
- const files = fs30.readdirSync(sourceDir);
16248
+ fs31.mkdirSync(targetDir, { recursive: true });
16249
+ const files = fs31.readdirSync(sourceDir);
15966
16250
  for (const file of files) {
15967
- fs30.copyFileSync(path50.join(sourceDir, file), path50.join(targetDir, file));
16251
+ fs31.copyFileSync(path50.join(sourceDir, file), path50.join(targetDir, file));
15968
16252
  console.log(`Copied ${file} to ${targetDir}`);
15969
16253
  }
15970
16254
  console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
@@ -16032,6 +16316,7 @@ program.command("coverage").description("Print global statement coverage percent
16032
16316
  program.command("screenshot").description("Capture a screenshot of a running application window").argument("<process>", "Name of the running process (e.g. notepad, code)").action(screenshot);
16033
16317
  registerActivity(program);
16034
16318
  registerCliHook(program);
16319
+ registerHandover(program);
16035
16320
  registerJira(program);
16036
16321
  registerMermaid(program);
16037
16322
  registerPrs(program);