@staff0rd/assist 0.643.5 → 0.644.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.643.5",
9
+ version: "0.644.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -13003,6 +13003,20 @@ async function readRequestBuffer(req, limit) {
13003
13003
  return Buffer.concat(chunks);
13004
13004
  }
13005
13005
 
13006
+ // src/commands/sessions/web/uploadSizeLimit.ts
13007
+ var MAX_IMAGE_BYTES = 25 * 1024 * 1024;
13008
+ var MAX_VIDEO_BYTES = 10 * 1024 * 1024;
13009
+ function uploadSizeLimit(contentType) {
13010
+ const mime = contentType.split(";")[0].trim().toLowerCase();
13011
+ return mime.startsWith("video/") ? {
13012
+ maxBytes: MAX_VIDEO_BYTES,
13013
+ tooLargeMessage: "Video too large (max 10MB)."
13014
+ } : {
13015
+ maxBytes: MAX_IMAGE_BYTES,
13016
+ tooLargeMessage: "Image too large (max 25MB)."
13017
+ };
13018
+ }
13019
+
13006
13020
  // src/commands/sessions/web/writeTempImage.ts
13007
13021
  import { mkdtemp, writeFile as writeFile2 } from "fs/promises";
13008
13022
  import { tmpdir } from "os";
@@ -13047,16 +13061,16 @@ async function writeTempImage(name, contentType, body) {
13047
13061
  }
13048
13062
 
13049
13063
  // src/commands/sessions/web/uploadPrImage.ts
13050
- var MAX_BYTES = 25 * 1024 * 1024;
13051
13064
  async function uploadPrImage(req, res) {
13052
13065
  const cwd = getCwdParam(req, res);
13053
13066
  if (!cwd) return;
13054
13067
  const url = new URL(req.url ?? "/", "http://localhost");
13055
13068
  const name = url.searchParams.get("name") ?? "";
13056
13069
  const contentType = req.headers["content-type"] ?? "";
13057
- const body = await readRequestBuffer(req, MAX_BYTES);
13070
+ const { maxBytes, tooLargeMessage } = uploadSizeLimit(contentType);
13071
+ const body = await readRequestBuffer(req, maxBytes);
13058
13072
  if (!body) {
13059
- respondJson(res, 413, { error: "Image too large (max 25MB)." });
13073
+ respondJson(res, 413, { error: tooLargeMessage });
13060
13074
  return;
13061
13075
  }
13062
13076
  if (body.length === 0) {
@@ -22792,7 +22806,7 @@ function registerCreateIssue(issueCommand) {
22792
22806
  []
22793
22807
  ).addHelpText(
22794
22808
  "after",
22795
- "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved.\nThe reviewer may also drop or paste screenshots into the pane; on approval these are appended to the issue body under a ## Screenshots section automatically, and on rejection they are discarded \u2014 so never author that section yourself.\n--type, --parent, --project, --status and --label are all resolved before the preview, so an unknown name, an unreadable parent, a missing project scope or --status without --project creates nothing.\nA bare --parent number is read against --repo, or the current repo; a parent in another repository is allowed.\nThe project scope is needed for --project: gh auth refresh -h github.com -s project"
22809
+ "\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved.\nThe reviewer may also drop or paste screenshots or video into the pane; on approval these are appended to the issue body under a ## Screenshots section automatically, and on rejection they are discarded \u2014 so never author that section yourself.\n--type, --parent, --project, --status and --label are all resolved before the preview, so an unknown name, an unreadable parent, a missing project scope or --status without --project creates nothing.\nA bare --parent number is read against --repo, or the current repo; a parent in another repository is allowed.\nThe project scope is needed for --project: gh auth refresh -h github.com -s project"
22796
22810
  ).action(createIssue);
22797
22811
  }
22798
22812
 
@@ -25228,25 +25242,25 @@ function isVisibleText(t) {
25228
25242
  return /[a-zA-Z]{3,}/.test(t);
25229
25243
  }
25230
25244
  var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
25231
- function collectRscText(v, resolve25, sink2, seen) {
25245
+ function collectRscText(v, resolve25, sink3, seen) {
25232
25246
  if (v == null) return;
25233
25247
  if (typeof v === "string") {
25234
25248
  if (isRscRef(v)) {
25235
25249
  if (!seen.has(v)) {
25236
25250
  seen.add(v);
25237
- collectRscText(resolve25(v), resolve25, sink2, seen);
25251
+ collectRscText(resolve25(v), resolve25, sink3, seen);
25238
25252
  }
25239
- } else if (isHashtag(v)) sink2.hashtags.push(v);
25240
- else if (isVisibleText(v)) sink2.text.push(v);
25253
+ } else if (isHashtag(v)) sink3.hashtags.push(v);
25254
+ else if (isVisibleText(v)) sink3.text.push(v);
25241
25255
  return;
25242
25256
  }
25243
25257
  if (Array.isArray(v)) {
25244
- for (const x of v) collectRscText(x, resolve25, sink2, seen);
25258
+ for (const x of v) collectRscText(x, resolve25, sink3, seen);
25245
25259
  return;
25246
25260
  }
25247
25261
  if (typeof v === "object") {
25248
25262
  for (const val of Object.values(v)) {
25249
- collectRscText(val, resolve25, sink2, seen);
25263
+ collectRscText(val, resolve25, sink3, seen);
25250
25264
  }
25251
25265
  }
25252
25266
  }
@@ -25285,9 +25299,9 @@ function buildMentionMap(rows, resolve25) {
25285
25299
  if (!url || o.children == null) return;
25286
25300
  const slug = slugFromProfileUrl(url);
25287
25301
  if (!slug || map.has(slug)) return;
25288
- const sink2 = { text: [], hashtags: [] };
25289
- collectRscText(o.children, resolve25, sink2, /* @__PURE__ */ new Set());
25290
- const name = sink2.text.join(" ").replace(/\s+/g, " ").trim();
25302
+ const sink3 = { text: [], hashtags: [] };
25303
+ collectRscText(o.children, resolve25, sink3, /* @__PURE__ */ new Set());
25304
+ const name = sink3.text.join(" ").replace(/\s+/g, " ").trim();
25291
25305
  map.set(slug, name ? { slug, name, url } : { slug, url });
25292
25306
  });
25293
25307
  return map;
@@ -25388,8 +25402,8 @@ function walkPostRow(v, resolve25, raw) {
25388
25402
  if (a) raw.related.push(a[0]);
25389
25403
  }
25390
25404
  if (isCommentary(o)) {
25391
- const sink2 = { text: raw.text, hashtags: raw.hashtags };
25392
- collectRscText(o.children, resolve25, sink2, /* @__PURE__ */ new Set());
25405
+ const sink3 = { text: raw.text, hashtags: raw.hashtags };
25406
+ collectRscText(o.children, resolve25, sink3, /* @__PURE__ */ new Set());
25393
25407
  }
25394
25408
  for (const val of Object.values(o)) walkPostRow(val, resolve25, raw);
25395
25409
  }
@@ -27212,8 +27226,8 @@ on rejection it exits non-zero with the reason. The reviewer may also attach
27212
27226
  inline comments to specific spans of the preview; on rejection these are printed
27213
27227
  as numbered quoted-span + note pairs on stderr. Address every comment (and the
27214
27228
  reason), then run the command again to re-preview the revised PR. Repeat until it
27215
- is approved. The reviewer may also drop or paste screenshots into the pane; on
27216
- approval these are appended to the PR body under a ## Screenshots section
27229
+ is approved. The reviewer may also drop or paste screenshots or video into the
27230
+ pane; on approval these are appended to the PR body under a ## Screenshots section
27217
27231
  automatically (they are discarded on rejection), so you never author that section
27218
27232
  yourself. Just compose the sections and run the command.`;
27219
27233
  function raiseHelpText(promptJira, draft) {
@@ -27460,12 +27474,12 @@ import chalk190 from "chalk";
27460
27474
 
27461
27475
  // src/shared/createConnectionAuth.ts
27462
27476
  import chalk185 from "chalk";
27463
- function listConnections(connections, format) {
27477
+ function listConnections(connections, format2) {
27464
27478
  if (connections.length === 0) {
27465
27479
  console.log("No connections configured.");
27466
27480
  } else {
27467
27481
  for (const c of connections) {
27468
- console.log(format(c));
27482
+ console.log(format2(c));
27469
27483
  }
27470
27484
  }
27471
27485
  }
@@ -30488,6 +30502,77 @@ function renderEntry(entry, frame) {
30488
30502
  return `${SPINNER_FRAMES2[frame]} ${entry.text}`;
30489
30503
  }
30490
30504
 
30505
+ // src/commands/review/startReviewLog.ts
30506
+ import { format } from "util";
30507
+
30508
+ // src/commands/review/createReviewLogSink.ts
30509
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync22 } from "fs";
30510
+ import { join as join73 } from "path";
30511
+
30512
+ // src/shared/stripAnsi.ts
30513
+ var ANSI = new RegExp(
30514
+ `${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`,
30515
+ "g"
30516
+ );
30517
+ function stripAnsi(text18) {
30518
+ return text18.replace(ANSI, "");
30519
+ }
30520
+
30521
+ // src/commands/review/createReviewLogSink.ts
30522
+ var LOG_FILE = "review.log";
30523
+ function createReviewLogSink() {
30524
+ let logPath2;
30525
+ let buffered = [];
30526
+ return {
30527
+ append(line) {
30528
+ const stripped = stripAnsi(line);
30529
+ if (!logPath2) {
30530
+ buffered.push(stripped);
30531
+ return;
30532
+ }
30533
+ appendFileSync2(logPath2, `${stripped}
30534
+ `);
30535
+ },
30536
+ attach(reviewDir) {
30537
+ mkdirSync22(reviewDir, { recursive: true });
30538
+ logPath2 = join73(reviewDir, LOG_FILE);
30539
+ const lines2 = [
30540
+ "",
30541
+ `=== ${(/* @__PURE__ */ new Date()).toISOString()} ===`,
30542
+ `$ ${process.argv.slice(1).join(" ")}`,
30543
+ ...buffered
30544
+ ];
30545
+ buffered = [];
30546
+ appendFileSync2(logPath2, `${lines2.join("\n")}
30547
+ `);
30548
+ }
30549
+ };
30550
+ }
30551
+
30552
+ // src/commands/review/startReviewLog.ts
30553
+ var sink2 = createReviewLogSink();
30554
+ var patched = false;
30555
+ function appendReviewLog(line) {
30556
+ sink2.append(line);
30557
+ }
30558
+ function attachReviewLog(reviewDir) {
30559
+ sink2.attach(reviewDir);
30560
+ }
30561
+ function patch(method) {
30562
+ const original = console[method].bind(console);
30563
+ console[method] = (...args) => {
30564
+ original(...args);
30565
+ appendReviewLog(format(...args));
30566
+ };
30567
+ }
30568
+ function startReviewLog() {
30569
+ if (patched) return;
30570
+ patched = true;
30571
+ patch("log");
30572
+ patch("error");
30573
+ patch("warn");
30574
+ }
30575
+
30491
30576
  // src/commands/review/MultiSpinner.ts
30492
30577
  var TICK_MS2 = 80;
30493
30578
  var MultiSpinner = class {
@@ -30532,6 +30617,7 @@ var MultiSpinner = class {
30532
30617
  entry.state = state;
30533
30618
  if (text18 !== void 0) entry.text = text18;
30534
30619
  entry.elapsedStart = void 0;
30620
+ appendReviewLog(renderEntry(entry, 0));
30535
30621
  this.render();
30536
30622
  this.maybeFinish();
30537
30623
  }
@@ -31442,6 +31528,7 @@ function runPostSynthesis(synthesisPath, prInfo, options2) {
31442
31528
  async function reviewPr(repoRoot2, options2) {
31443
31529
  const context = gatherChangedContext();
31444
31530
  const paths = setupReviewDir(repoRoot2, context, options2.force ?? false);
31531
+ attachReviewLog(paths.reviewDir);
31445
31532
  const synthesisOk = await runReviewPipeline(paths, {
31446
31533
  verbose: options2.verbose ?? false
31447
31534
  });
@@ -31485,6 +31572,7 @@ function validateCheckoutOnly(options2) {
31485
31572
  }
31486
31573
  async function review(options2 = {}) {
31487
31574
  validateOptions(options2);
31575
+ startReviewLog();
31488
31576
  const invokedIn = resolveRepoRoot();
31489
31577
  if (options2.checkoutOnly && options2.number)
31490
31578
  return checkoutOnlySession(options2.number);
@@ -32133,7 +32221,7 @@ function parseSlackThreadRef(value) {
32133
32221
  }
32134
32222
 
32135
32223
  // src/commands/slack/postSlackMessage.ts
32136
- import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync42 } from "fs";
32224
+ import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync42 } from "fs";
32137
32225
 
32138
32226
  // src/commands/slack/reviewProposedSlackMessage.ts
32139
32227
  import { randomUUID as randomUUID17 } from "crypto";
@@ -32158,11 +32246,11 @@ async function reviewProposedSlackMessage(target, body, workingPath) {
32158
32246
  }
32159
32247
 
32160
32248
  // src/commands/slack/slackWorkingFile.ts
32161
- import { join as join73 } from "path";
32249
+ import { join as join74 } from "path";
32162
32250
  function slackWorkingFile(channel) {
32163
32251
  const slug = channel.replace(/^[#@]/, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
32164
- const dir = join73(getStoreDir(), "slack");
32165
- return { dir, bodyPath: join73(dir, `${slug}.md`) };
32252
+ const dir = join74(getStoreDir(), "slack");
32253
+ return { dir, bodyPath: join74(dir, `${slug}.md`) };
32166
32254
  }
32167
32255
 
32168
32256
  // src/commands/slack/postSlackMessage.ts
@@ -32183,7 +32271,7 @@ async function postSlackMessage(channelArg, options2) {
32183
32271
  }
32184
32272
  const threadTs = options2.thread;
32185
32273
  const { dir, bodyPath } = slackWorkingFile(channel);
32186
- mkdirSync22(dir, { recursive: true });
32274
+ mkdirSync23(dir, { recursive: true });
32187
32275
  writeFileSync42(bodyPath, `${body}
32188
32276
  `);
32189
32277
  await reviewProposedSlackMessage({ channel, threadTs }, body, bodyPath);
@@ -33178,21 +33266,21 @@ var FORMATS = ["md", "vtt"];
33178
33266
  function isCleanFormat(value) {
33179
33267
  return FORMATS.includes(value);
33180
33268
  }
33181
- function serialise(cues, format, timestamps) {
33182
- return format === "vtt" ? formatVtt(cues) : formatChatLog(cuesToChatMessages(cues), { timestamps });
33269
+ function serialise(cues, format2, timestamps) {
33270
+ return format2 === "vtt" ? formatVtt(cues) : formatChatLog(cuesToChatMessages(cues), { timestamps });
33183
33271
  }
33184
33272
  function clean(file, options2 = {}) {
33185
- const format = options2.format ?? "md";
33186
- if (!isCleanFormat(format)) {
33273
+ const format2 = options2.format ?? "md";
33274
+ if (!isCleanFormat(format2)) {
33187
33275
  console.error(
33188
- `Error: --format must be one of: ${FORMATS.join(", ")} (got: ${format})`
33276
+ `Error: --format must be one of: ${FORMATS.join(", ")} (got: ${format2})`
33189
33277
  );
33190
33278
  process.exit(1);
33191
33279
  }
33192
33280
  const timestamps = options2.timestamps ?? false;
33193
- if (timestamps && format !== "md") {
33281
+ if (timestamps && format2 !== "md") {
33194
33282
  console.error(
33195
- `Error: --timestamps applies only to --format md (got: ${format})`
33283
+ `Error: --timestamps applies only to --format md (got: ${format2})`
33196
33284
  );
33197
33285
  process.exit(1);
33198
33286
  }
@@ -33205,7 +33293,7 @@ function clean(file, options2 = {}) {
33205
33293
  console.error(`Error: no cues found in: ${file}`);
33206
33294
  process.exit(1);
33207
33295
  }
33208
- console.log(serialise(cues, format, timestamps));
33296
+ console.log(serialise(cues, format2, timestamps));
33209
33297
  }
33210
33298
 
33211
33299
  // src/commands/transcript/shared.ts
@@ -33280,20 +33368,20 @@ async function configure() {
33280
33368
 
33281
33369
  // src/commands/transcript/list.ts
33282
33370
  import { existsSync as existsSync72, readdirSync as readdirSync20, statSync as statSync11 } from "fs";
33283
- import { join as join84 } from "path";
33371
+ import { join as join85 } from "path";
33284
33372
  function list4() {
33285
33373
  const { vttDir } = getTranscriptConfig();
33286
33374
  if (!existsSync72(vttDir)) return;
33287
33375
  for (const entry of readdirSync20(vttDir)) {
33288
33376
  if (!entry.endsWith(".vtt")) continue;
33289
- if (statSync11(join84(vttDir, entry)).isDirectory()) continue;
33377
+ if (statSync11(join85(vttDir, entry)).isDirectory()) continue;
33290
33378
  console.log(entry);
33291
33379
  }
33292
33380
  }
33293
33381
 
33294
33382
  // src/commands/transcript/move.ts
33295
- import { existsSync as existsSync73, mkdirSync as mkdirSync28, renameSync as renameSync2, writeFileSync as writeFileSync46 } from "fs";
33296
- import { basename as basename22, join as join85 } from "path";
33383
+ import { existsSync as existsSync73, mkdirSync as mkdirSync29, renameSync as renameSync2, writeFileSync as writeFileSync46 } from "fs";
33384
+ import { basename as basename22, join as join86 } from "path";
33297
33385
 
33298
33386
  // src/commands/transcript/convertVttToMarkdown.ts
33299
33387
  function convertVttToMarkdown(inputPath) {
@@ -33303,9 +33391,9 @@ function convertVttToMarkdown(inputPath) {
33303
33391
  // src/commands/transcript/move.ts
33304
33392
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
33305
33393
  function archiveRawVtt(vttDir, sourcePath, filename) {
33306
- const processedDir = join85(vttDir, "processed");
33307
- mkdirSync28(processedDir, { recursive: true });
33308
- renameSync2(sourcePath, join85(processedDir, filename));
33394
+ const processedDir = join86(vttDir, "processed");
33395
+ mkdirSync29(processedDir, { recursive: true });
33396
+ renameSync2(sourcePath, join86(processedDir, filename));
33309
33397
  }
33310
33398
  function move(file, options2) {
33311
33399
  const { date, client } = options2;
@@ -33315,19 +33403,19 @@ function move(file, options2) {
33315
33403
  }
33316
33404
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
33317
33405
  const filename = basename22(file);
33318
- const sourcePath = join85(vttDir, filename);
33406
+ const sourcePath = join86(vttDir, filename);
33319
33407
  if (!existsSync73(sourcePath)) {
33320
33408
  console.error(`Error: VTT file not found: ${sourcePath}`);
33321
33409
  process.exit(1);
33322
33410
  }
33323
33411
  const base = basename22(filename, ".vtt").replace(/ Transcription$/, "");
33324
33412
  const outputName = `${date} ${base}.md`;
33325
- const formattedDir = join85(transcriptsDir, client);
33326
- mkdirSync28(formattedDir, { recursive: true });
33327
- const formattedPath = join85(formattedDir, outputName);
33413
+ const formattedDir = join86(transcriptsDir, client);
33414
+ mkdirSync29(formattedDir, { recursive: true });
33415
+ const formattedPath = join86(formattedDir, outputName);
33328
33416
  writeFileSync46(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
33329
33417
  archiveRawVtt(vttDir, sourcePath, filename);
33330
- const summaryPath = join85(summaryDir, client, outputName);
33418
+ const summaryPath = join86(summaryDir, client, outputName);
33331
33419
  console.log(`Formatted transcript: ${formattedPath}`);
33332
33420
  console.log(`Summary target: ${summaryPath}`);
33333
33421
  }
@@ -33641,38 +33729,38 @@ function registerVerify(program2) {
33641
33729
 
33642
33730
  // src/commands/voice/devices.ts
33643
33731
  import { spawnSync as spawnSync9 } from "child_process";
33644
- import { join as join87 } from "path";
33732
+ import { join as join88 } from "path";
33645
33733
 
33646
33734
  // src/commands/voice/shared.ts
33647
33735
  import { homedir as homedir25 } from "os";
33648
- import { dirname as dirname36, join as join86 } from "path";
33736
+ import { dirname as dirname36, join as join87 } from "path";
33649
33737
  import { fileURLToPath as fileURLToPath9 } from "url";
33650
33738
  var __dirname6 = dirname36(fileURLToPath9(import.meta.url));
33651
- var VOICE_DIR = join86(homedir25(), ".assist", "voice");
33739
+ var VOICE_DIR = join87(homedir25(), ".assist", "voice");
33652
33740
  var voicePaths = {
33653
33741
  dir: VOICE_DIR,
33654
- pid: join86(VOICE_DIR, "voice.pid"),
33655
- log: join86(VOICE_DIR, "voice.log"),
33656
- venv: join86(VOICE_DIR, ".venv"),
33657
- lock: join86(VOICE_DIR, "voice.lock")
33742
+ pid: join87(VOICE_DIR, "voice.pid"),
33743
+ log: join87(VOICE_DIR, "voice.log"),
33744
+ venv: join87(VOICE_DIR, ".venv"),
33745
+ lock: join87(VOICE_DIR, "voice.lock")
33658
33746
  };
33659
33747
  function getPythonDir() {
33660
- return join86(__dirname6, "commands", "voice", "python");
33748
+ return join87(__dirname6, "commands", "voice", "python");
33661
33749
  }
33662
33750
  function getVenvPython() {
33663
- return process.platform === "win32" ? join86(voicePaths.venv, "Scripts", "python.exe") : join86(voicePaths.venv, "bin", "python");
33751
+ return process.platform === "win32" ? join87(voicePaths.venv, "Scripts", "python.exe") : join87(voicePaths.venv, "bin", "python");
33664
33752
  }
33665
33753
  function getLockDir() {
33666
33754
  const config = loadConfig();
33667
33755
  return config.voice?.lockDir ?? VOICE_DIR;
33668
33756
  }
33669
33757
  function getLockFile() {
33670
- return join86(getLockDir(), "voice.lock");
33758
+ return join87(getLockDir(), "voice.lock");
33671
33759
  }
33672
33760
 
33673
33761
  // src/commands/voice/devices.ts
33674
33762
  function devices() {
33675
- const script = join87(getPythonDir(), "list_devices.py");
33763
+ const script = join88(getPythonDir(), "list_devices.py");
33676
33764
  spawnSync9(getVenvPython(), [script], { stdio: "inherit" });
33677
33765
  }
33678
33766
 
@@ -33706,13 +33794,13 @@ function logs(options2) {
33706
33794
 
33707
33795
  // src/commands/voice/setup.ts
33708
33796
  import { spawnSync as spawnSync10 } from "child_process";
33709
- import { mkdirSync as mkdirSync30 } from "fs";
33710
- import { join as join89 } from "path";
33797
+ import { mkdirSync as mkdirSync31 } from "fs";
33798
+ import { join as join90 } from "path";
33711
33799
 
33712
33800
  // src/commands/voice/checkLockFile.ts
33713
33801
  import { execSync as execSync60 } from "child_process";
33714
- import { existsSync as existsSync76, mkdirSync as mkdirSync29, readFileSync as readFileSync58, writeFileSync as writeFileSync48 } from "fs";
33715
- import { join as join88 } from "path";
33802
+ import { existsSync as existsSync76, mkdirSync as mkdirSync30, readFileSync as readFileSync58, writeFileSync as writeFileSync48 } from "fs";
33803
+ import { join as join89 } from "path";
33716
33804
  function isProcessAlive2(pid) {
33717
33805
  try {
33718
33806
  process.kill(pid, 0);
@@ -33749,7 +33837,7 @@ function bootstrapVenv() {
33749
33837
  }
33750
33838
  function writeLockFile(pid) {
33751
33839
  const lockFile = getLockFile();
33752
- mkdirSync29(join88(lockFile, ".."), { recursive: true });
33840
+ mkdirSync30(join89(lockFile, ".."), { recursive: true });
33753
33841
  writeFileSync48(
33754
33842
  lockFile,
33755
33843
  JSON.stringify({
@@ -33762,10 +33850,10 @@ function writeLockFile(pid) {
33762
33850
 
33763
33851
  // src/commands/voice/setup.ts
33764
33852
  function setup() {
33765
- mkdirSync30(voicePaths.dir, { recursive: true });
33853
+ mkdirSync31(voicePaths.dir, { recursive: true });
33766
33854
  bootstrapVenv();
33767
33855
  console.log("\nDownloading models...\n");
33768
- const script = join89(getPythonDir(), "setup_models.py");
33856
+ const script = join90(getPythonDir(), "setup_models.py");
33769
33857
  const result = spawnSync10(getVenvPython(), [script], {
33770
33858
  stdio: "inherit",
33771
33859
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -33778,8 +33866,8 @@ function setup() {
33778
33866
 
33779
33867
  // src/commands/voice/start.ts
33780
33868
  import { spawn as spawn8 } from "child_process";
33781
- import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync49 } from "fs";
33782
- import { join as join90 } from "path";
33869
+ import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync49 } from "fs";
33870
+ import { join as join91 } from "path";
33783
33871
 
33784
33872
  // src/commands/voice/buildDaemonEnv.ts
33785
33873
  function buildDaemonEnv(options2) {
@@ -33812,12 +33900,12 @@ function spawnBackground(python, script, env) {
33812
33900
  console.log(`Voice daemon started (PID ${pid})`);
33813
33901
  }
33814
33902
  function start2(options2) {
33815
- mkdirSync31(voicePaths.dir, { recursive: true });
33903
+ mkdirSync32(voicePaths.dir, { recursive: true });
33816
33904
  checkLockFile();
33817
33905
  bootstrapVenv();
33818
33906
  const debug = options2.debug || options2.foreground || process.platform === "win32";
33819
33907
  const env = buildDaemonEnv({ debug });
33820
- const script = join90(getPythonDir(), "voice_daemon.py");
33908
+ const script = join91(getPythonDir(), "voice_daemon.py");
33821
33909
  const python = getVenvPython();
33822
33910
  if (options2.foreground) {
33823
33911
  spawnForeground(python, script, env);
@@ -33948,11 +34036,11 @@ function changedPaths(from, cwd) {
33948
34036
  }
33949
34037
 
33950
34038
  // src/commands/watch/readBuiltVersion.ts
33951
- import { join as join91 } from "path";
34039
+ import { join as join92 } from "path";
33952
34040
  function readBuiltVersion(cwd) {
33953
34041
  try {
33954
34042
  const root = runGit3(["rev-parse", "--show-toplevel"], cwd);
33955
- return readPackageJson(join91(root, "package.json")).version ?? "unknown";
34043
+ return readPackageJson(join92(root, "package.json")).version ?? "unknown";
33956
34044
  } catch {
33957
34045
  return "unknown";
33958
34046
  }
@@ -34313,13 +34401,13 @@ import { existsSync as existsSync81 } from "fs";
34313
34401
  // src/commands/run/resolveCommand.ts
34314
34402
  import { execFileSync as execFileSync18 } from "child_process";
34315
34403
  import { existsSync as existsSync80 } from "fs";
34316
- import { dirname as dirname37, join as join92, resolve as resolve20 } from "path";
34404
+ import { dirname as dirname37, join as join93, resolve as resolve20 } from "path";
34317
34405
  function resolveCommand2(command) {
34318
34406
  if (process.platform !== "win32" || command !== "bash") return command;
34319
34407
  try {
34320
34408
  const gitPath = execFileSync18("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
34321
34409
  const gitRoot = resolve20(dirname37(gitPath), "..");
34322
- const gitBash = join92(gitRoot, "bin", "bash.exe");
34410
+ const gitBash = join93(gitRoot, "bin", "bash.exe");
34323
34411
  if (existsSync80(gitBash)) return gitBash;
34324
34412
  } catch {
34325
34413
  return command;
@@ -34747,7 +34835,7 @@ async function auth() {
34747
34835
  // src/commands/roam/postRoamActivity.ts
34748
34836
  import { execFileSync as execFileSync20 } from "child_process";
34749
34837
  import { readdirSync as readdirSync21, readFileSync as readFileSync61, statSync as statSync12 } from "fs";
34750
- import { join as join93 } from "path";
34838
+ import { join as join94 } from "path";
34751
34839
  function findPortFile(roamDir) {
34752
34840
  let entries;
34753
34841
  try {
@@ -34756,7 +34844,7 @@ function findPortFile(roamDir) {
34756
34844
  return void 0;
34757
34845
  }
34758
34846
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
34759
- const path91 = join93(roamDir, name);
34847
+ const path91 = join94(roamDir, name);
34760
34848
  try {
34761
34849
  return { path: path91, mtimeMs: statSync12(path91).mtimeMs };
34762
34850
  } catch {
@@ -34773,7 +34861,7 @@ var PID_BY_APP = {
34773
34861
  function postRoamActivity(app, event) {
34774
34862
  const appData = process.env.APPDATA;
34775
34863
  if (!appData) return;
34776
- const portFile = findPortFile(join93(appData, "Roam"));
34864
+ const portFile = findPortFile(join94(appData, "Roam"));
34777
34865
  if (!portFile) return;
34778
34866
  let port;
34779
34867
  try {
@@ -34908,8 +34996,8 @@ async function run3(name, args) {
34908
34996
  }
34909
34997
 
34910
34998
  // src/commands/run/add.ts
34911
- import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync50 } from "fs";
34912
- import { join as join94 } from "path";
34999
+ import { mkdirSync as mkdirSync33, writeFileSync as writeFileSync50 } from "fs";
35000
+ import { join as join95 } from "path";
34913
35001
 
34914
35002
  // src/commands/run/extractOption.ts
34915
35003
  function extractOption(args, flag) {
@@ -34970,15 +35058,15 @@ function saveNewRunConfig(name, command, args, cwd) {
34970
35058
  saveConfig(config);
34971
35059
  }
34972
35060
  function createCommandFile(name) {
34973
- const dir = join94(".claude", "commands");
34974
- mkdirSync32(dir, { recursive: true });
35061
+ const dir = join95(".claude", "commands");
35062
+ mkdirSync33(dir, { recursive: true });
34975
35063
  const content = `---
34976
35064
  description: Run ${name}
34977
35065
  ---
34978
35066
 
34979
35067
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
34980
35068
  `;
34981
- const filePath = join94(dir, `${name}.md`);
35069
+ const filePath = join95(dir, `${name}.md`);
34982
35070
  writeFileSync50(filePath, content);
34983
35071
  console.log(`Created command file: ${filePath}`);
34984
35072
  }
@@ -35035,7 +35123,7 @@ function link2() {
35035
35123
 
35036
35124
  // src/commands/run/remove.ts
35037
35125
  import { existsSync as existsSync82, unlinkSync as unlinkSync21 } from "fs";
35038
- import { join as join95 } from "path";
35126
+ import { join as join96 } from "path";
35039
35127
  function findRemoveIndex() {
35040
35128
  const idx = process.argv.indexOf("remove");
35041
35129
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -35050,7 +35138,7 @@ function parseRemoveName() {
35050
35138
  return process.argv[idx + 1];
35051
35139
  }
35052
35140
  function deleteCommandFile(name) {
35053
- const filePath = join95(".claude", "commands", `${name}.md`);
35141
+ const filePath = join96(".claude", "commands", `${name}.md`);
35054
35142
  if (existsSync82(filePath)) {
35055
35143
  unlinkSync21(filePath);
35056
35144
  console.log(`Deleted command file: ${filePath}`);
@@ -35096,9 +35184,9 @@ function registerRun(program2) {
35096
35184
 
35097
35185
  // src/commands/screenshot/index.ts
35098
35186
  import { execSync as execSync62 } from "child_process";
35099
- import { existsSync as existsSync83, mkdirSync as mkdirSync33, unlinkSync as unlinkSync22, writeFileSync as writeFileSync51 } from "fs";
35187
+ import { existsSync as existsSync83, mkdirSync as mkdirSync34, unlinkSync as unlinkSync22, writeFileSync as writeFileSync51 } from "fs";
35100
35188
  import { tmpdir as tmpdir9 } from "os";
35101
- import { join as join96, resolve as resolve21 } from "path";
35189
+ import { join as join97, resolve as resolve21 } from "path";
35102
35190
  import chalk229 from "chalk";
35103
35191
 
35104
35192
  // src/commands/screenshot/captureWindowPs1.ts
@@ -35229,13 +35317,13 @@ Write-Output $OutputPath
35229
35317
  // src/commands/screenshot/index.ts
35230
35318
  function buildOutputPath(outputDir, processName) {
35231
35319
  if (!existsSync83(outputDir)) {
35232
- mkdirSync33(outputDir, { recursive: true });
35320
+ mkdirSync34(outputDir, { recursive: true });
35233
35321
  }
35234
35322
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
35235
35323
  return resolve21(outputDir, `${processName}-${timestamp6}.png`);
35236
35324
  }
35237
35325
  function runPowerShellScript(processName, outputPath) {
35238
- const scriptPath = join96(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
35326
+ const scriptPath = join97(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
35239
35327
  writeFileSync51(scriptPath, captureWindowPs1, "utf8");
35240
35328
  try {
35241
35329
  execSync62(
@@ -35469,7 +35557,7 @@ function requestDrain(socket, lines2) {
35469
35557
  }
35470
35558
 
35471
35559
  // src/commands/sessions/daemon/runDaemon.ts
35472
- import { mkdirSync as mkdirSync37 } from "fs";
35560
+ import { mkdirSync as mkdirSync38 } from "fs";
35473
35561
 
35474
35562
  // src/commands/sessions/daemon/createAutoExit.ts
35475
35563
  var DEFAULT_GRACE_MS = 6e4;
@@ -35990,12 +36078,12 @@ import { basename as basename24 } from "path";
35990
36078
 
35991
36079
  // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
35992
36080
  import { existsSync as existsSync87 } from "fs";
35993
- import { join as join99 } from "path";
36081
+ import { join as join100 } from "path";
35994
36082
 
35995
36083
  // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
35996
36084
  import { statSync as statSync14 } from "fs";
35997
36085
  import { rm as rm4 } from "fs/promises";
35998
- import { join as join98 } from "path";
36086
+ import { join as join99 } from "path";
35999
36087
  async function deleteTreeDirectly(clone, worktreePath, why) {
36000
36088
  if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
36001
36089
  const refusal = "it is a clone of its own, not a linked worktree";
@@ -36023,7 +36111,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
36023
36111
  return { removed: true };
36024
36112
  }
36025
36113
  function holdsAGitDirectoryRatherThanALink(worktreePath) {
36026
- return statSync14(join98(worktreePath, ".git"), {
36114
+ return statSync14(join99(worktreePath, ".git"), {
36027
36115
  throwIfNoEntry: false
36028
36116
  })?.isDirectory() === true;
36029
36117
  }
@@ -36059,7 +36147,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
36059
36147
  );
36060
36148
  }
36061
36149
  function strandedReason(worktreePath, cause) {
36062
- if (!existsSync87(join99(worktreePath, ".git")))
36150
+ if (!existsSync87(join100(worktreePath, ".git")))
36063
36151
  return "its .git link is already gone";
36064
36152
  if (/not a working tree|not a git repository/i.test(reason2(cause)))
36065
36153
  return "git no longer recognises it as a working tree";
@@ -36785,14 +36873,10 @@ function missingRunConfigCwd(session) {
36785
36873
  }
36786
36874
 
36787
36875
  // src/commands/sessions/daemon/exitOutputTail.ts
36788
- var ANSI = new RegExp(
36789
- `${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`,
36790
- "g"
36791
- );
36792
36876
  var MAX_TAIL_LINES = 5;
36793
36877
  var MAX_TAIL_CHARS = 500;
36794
36878
  function exitOutputTail(scrollback) {
36795
- const lines2 = scrollback.replace(ANSI, "").split(/\r?\n|\r/).map((line) => line.trim()).filter((line) => line.length > 0);
36879
+ const lines2 = stripAnsi(scrollback).split(/\r?\n|\r/).map((line) => line.trim()).filter((line) => line.length > 0);
36796
36880
  if (lines2.length === 0) return void 0;
36797
36881
  return lines2.slice(-MAX_TAIL_LINES).join(" | ").slice(-MAX_TAIL_CHARS);
36798
36882
  }
@@ -36821,7 +36905,7 @@ function handleFailedResume(session, exitCode, onStatusChange) {
36821
36905
  }
36822
36906
 
36823
36907
  // src/commands/sessions/daemon/watchActivity.ts
36824
- import { existsSync as existsSync91, mkdirSync as mkdirSync34, watch as watch2 } from "fs";
36908
+ import { existsSync as existsSync91, mkdirSync as mkdirSync35, watch as watch2 } from "fs";
36825
36909
  import { dirname as dirname39 } from "path";
36826
36910
 
36827
36911
  // src/commands/sessions/daemon/applyActivityToSession.ts
@@ -36886,7 +36970,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
36886
36970
  const path91 = activityPath(session.id);
36887
36971
  const dir = dirname39(path91);
36888
36972
  try {
36889
- mkdirSync34(dir, { recursive: true });
36973
+ mkdirSync35(dir, { recursive: true });
36890
36974
  } catch {
36891
36975
  return;
36892
36976
  }
@@ -37089,10 +37173,10 @@ function headContainsSessionId(filePath, claudeSessionId) {
37089
37173
  }
37090
37174
 
37091
37175
  // src/commands/sessions/daemon/ensureProjectDirExists.ts
37092
- import { mkdirSync as mkdirSync35 } from "fs";
37176
+ import { mkdirSync as mkdirSync36 } from "fs";
37093
37177
  function ensureProjectDirExists(dir, sessionId) {
37094
37178
  try {
37095
- mkdirSync35(dir, { recursive: true });
37179
+ mkdirSync36(dir, { recursive: true });
37096
37180
  return true;
37097
37181
  } catch (error) {
37098
37182
  daemonLog(
@@ -40273,8 +40357,8 @@ function resumeSession(id, sessionId, cwd, name, holdPty, harness) {
40273
40357
  import { existsSync as existsSync97 } from "fs";
40274
40358
 
40275
40359
  // src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
40276
- import { copyFileSync as copyFileSync7, existsSync as existsSync96, mkdirSync as mkdirSync36 } from "fs";
40277
- import { join as join101 } from "path";
40360
+ import { copyFileSync as copyFileSync7, existsSync as existsSync96, mkdirSync as mkdirSync37 } from "fs";
40361
+ import { join as join102 } from "path";
40278
40362
  function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
40279
40363
  const dir = projectDirForCwd(toCwd);
40280
40364
  if (dir === projectDirForCwd(fromCwd)) {
@@ -40283,7 +40367,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
40283
40367
  );
40284
40368
  return;
40285
40369
  }
40286
- const dest = join101(dir, `${claudeSessionId}.jsonl`);
40370
+ const dest = join102(dir, `${claudeSessionId}.jsonl`);
40287
40371
  if (existsSync96(dest)) {
40288
40372
  daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
40289
40373
  return;
@@ -40296,7 +40380,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
40296
40380
  return;
40297
40381
  }
40298
40382
  try {
40299
- mkdirSync36(dir, { recursive: true });
40383
+ mkdirSync37(dir, { recursive: true });
40300
40384
  copyFileSync7(source, dest);
40301
40385
  daemonLog(
40302
40386
  `transcript ${source} copied to ${dest} so ${toCwd} can resume it`
@@ -41136,7 +41220,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
41136
41220
 
41137
41221
  // src/commands/sessions/daemon/runDaemon.ts
41138
41222
  async function runDaemon() {
41139
- mkdirSync37(daemonPaths.dir, { recursive: true });
41223
+ mkdirSync38(daemonPaths.dir, { recursive: true });
41140
41224
  daemonLog(
41141
41225
  `starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
41142
41226
  );
@@ -41435,9 +41519,9 @@ function buildLimitsSegment(rateLimits) {
41435
41519
 
41436
41520
  // src/commands/readGitBranch.ts
41437
41521
  import { readFileSync as readFileSync67, statSync as statSync16 } from "fs";
41438
- import { isAbsolute as isAbsolute5, join as join102, resolve as resolve23 } from "path";
41522
+ import { isAbsolute as isAbsolute5, join as join103, resolve as resolve23 } from "path";
41439
41523
  function resolveGitDir(cwd) {
41440
- const dotGit = join102(cwd, ".git");
41524
+ const dotGit = join103(cwd, ".git");
41441
41525
  let stat4;
41442
41526
  try {
41443
41527
  stat4 = statSync16(dotGit);
@@ -41467,7 +41551,7 @@ function readGitBranch(cwd) {
41467
41551
  }
41468
41552
  let head;
41469
41553
  try {
41470
- head = readFileSync67(join102(gitDir, "HEAD"), "utf8");
41554
+ head = readFileSync67(join103(gitDir, "HEAD"), "utf8");
41471
41555
  } catch {
41472
41556
  return null;
41473
41557
  }