@staff0rd/assist 0.428.0 → 0.429.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.428.0",
9
+ version: "0.429.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -9291,6 +9291,132 @@ async function restartWeb(req, res, deps2 = {}) {
9291
9291
  }
9292
9292
  }
9293
9293
 
9294
+ // src/commands/sessions/web/uploadPrImage.ts
9295
+ import { rm } from "fs/promises";
9296
+
9297
+ // src/commands/sessions/web/runGhImage.ts
9298
+ import { execFile as execFile6 } from "child_process";
9299
+ import { promisify as promisify7 } from "util";
9300
+ var execFileAsync6 = promisify7(execFile6);
9301
+ var GhImageUnavailableError = class extends Error {
9302
+ name = "GhImageUnavailableError";
9303
+ };
9304
+ var GH_IMAGE_INSTALL_COMMAND = "gh extension install drogers0/gh-image";
9305
+ var INSTALL_HINT = `Install the gh-image extension: ${GH_IMAGE_INSTALL_COMMAND}`;
9306
+ async function runGhImage(filePath, cwd) {
9307
+ let stdout;
9308
+ try {
9309
+ ({ stdout } = await execFileAsync6("gh", ["image", filePath], {
9310
+ cwd,
9311
+ maxBuffer: 10 * 1024 * 1024
9312
+ }));
9313
+ } catch (error) {
9314
+ const err = error;
9315
+ if (err.code === "ENOENT")
9316
+ throw new GhImageUnavailableError(
9317
+ `The GitHub CLI (\`gh\`) is not installed. ${INSTALL_HINT}`
9318
+ );
9319
+ const stderr = err.stderr ?? "";
9320
+ if (/unknown command "image"/i.test(stderr) || /extension.*not found/i.test(stderr))
9321
+ throw new GhImageUnavailableError(
9322
+ `The \`gh-image\` extension is not installed. ${INSTALL_HINT}`
9323
+ );
9324
+ throw new Error(
9325
+ `gh image failed: ${stderr.trim() || err.message || "unknown error"}`
9326
+ );
9327
+ }
9328
+ const lines = stdout.split("\n").map((line) => line.trim()).filter(Boolean);
9329
+ const markdown = lines.find((line) => /^!\[.*]\(.+\)$/.test(line)) ?? lines.find((line) => line.includes("http")) ?? lines[0];
9330
+ if (!markdown) throw new Error("gh image produced no output");
9331
+ return markdown;
9332
+ }
9333
+
9334
+ // src/commands/sessions/web/readRequestBuffer.ts
9335
+ async function readRequestBuffer(req, limit) {
9336
+ const chunks = [];
9337
+ let size = 0;
9338
+ for await (const chunk of req) {
9339
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
9340
+ size += buf.length;
9341
+ if (size > limit) {
9342
+ req.destroy();
9343
+ return null;
9344
+ }
9345
+ chunks.push(buf);
9346
+ }
9347
+ return Buffer.concat(chunks);
9348
+ }
9349
+
9350
+ // src/commands/sessions/web/writeTempImage.ts
9351
+ import { mkdtemp, writeFile as writeFile2 } from "fs/promises";
9352
+ import { tmpdir } from "os";
9353
+ import { extname, join as join28 } from "path";
9354
+ var EXT_BY_MIME = {
9355
+ "image/png": "png",
9356
+ "image/jpeg": "jpg",
9357
+ "image/gif": "gif",
9358
+ "image/webp": "webp",
9359
+ "image/svg+xml": "svg",
9360
+ "image/bmp": "bmp",
9361
+ "image/avif": "avif"
9362
+ };
9363
+ function pickExtension(name, contentType) {
9364
+ const fromName = extname(name).replace(/^\./, "").toLowerCase();
9365
+ if (fromName) return fromName;
9366
+ return EXT_BY_MIME[contentType.split(";")[0].trim().toLowerCase()] ?? "png";
9367
+ }
9368
+ function safeBaseName(name) {
9369
+ const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-");
9370
+ return base.replace(/^-+|-+$/g, "").slice(0, 60) || "screenshot";
9371
+ }
9372
+ async function writeTempImage(name, contentType, body) {
9373
+ const dir = await mkdtemp(join28(tmpdir(), "assist-pr-img-"));
9374
+ const filePath = join28(
9375
+ dir,
9376
+ `${safeBaseName(name)}.${pickExtension(name, contentType)}`
9377
+ );
9378
+ await writeFile2(filePath, body);
9379
+ return { dir, filePath };
9380
+ }
9381
+
9382
+ // src/commands/sessions/web/uploadPrImage.ts
9383
+ var MAX_BYTES = 25 * 1024 * 1024;
9384
+ async function uploadPrImage(req, res) {
9385
+ const cwd = getCwdParam(req, res);
9386
+ if (!cwd) return;
9387
+ const url = new URL(req.url ?? "/", "http://localhost");
9388
+ const name = url.searchParams.get("name") ?? "";
9389
+ const contentType = req.headers["content-type"] ?? "";
9390
+ const body = await readRequestBuffer(req, MAX_BYTES);
9391
+ if (!body) {
9392
+ respondJson(res, 413, { error: "Image too large (max 25MB)." });
9393
+ return;
9394
+ }
9395
+ if (body.length === 0) {
9396
+ respondJson(res, 400, { error: "Empty upload." });
9397
+ return;
9398
+ }
9399
+ const { dir, filePath } = await writeTempImage(name, contentType, body);
9400
+ try {
9401
+ const markdown = await runGhImage(filePath, cwd);
9402
+ respondJson(res, 200, { markdown });
9403
+ } catch (error) {
9404
+ if (error instanceof GhImageUnavailableError) {
9405
+ respondJson(res, 501, {
9406
+ error: error.message,
9407
+ command: GH_IMAGE_INSTALL_COMMAND
9408
+ });
9409
+ } else {
9410
+ respondJson(res, 500, {
9411
+ error: error instanceof Error ? error.message : "Upload failed"
9412
+ });
9413
+ }
9414
+ } finally {
9415
+ await rm(dir, { recursive: true, force: true }).catch(() => {
9416
+ });
9417
+ }
9418
+ }
9419
+
9294
9420
  // src/commands/sessions/web/createCssHandler.ts
9295
9421
  import { createHash as createHash2 } from "crypto";
9296
9422
  import { readFileSync as readFileSync21 } from "fs";
@@ -9333,6 +9459,7 @@ var routes2 = {
9333
9459
  "GET /api/items": listItems,
9334
9460
  "GET /api/backlog/summary": getBacklogSummary,
9335
9461
  "POST /api/open-in-code": openInCode,
9462
+ "POST /api/pr-preview/upload-image": uploadPrImage,
9336
9463
  "POST /api/restart": restartWeb,
9337
9464
  "GET /api/github-url": githubUrl,
9338
9465
  "GET /api/git-status": gitStatus,
@@ -10390,8 +10517,8 @@ function ensureRemoteOrigin() {
10390
10517
  // src/commands/backlog/add/shared.ts
10391
10518
  import { spawnSync as spawnSync3 } from "child_process";
10392
10519
  import { mkdtempSync, readFileSync as readFileSync22, unlinkSync as unlinkSync6, writeFileSync as writeFileSync21 } from "fs";
10393
- import { tmpdir } from "os";
10394
- import { join as join28 } from "path";
10520
+ import { tmpdir as tmpdir2 } from "os";
10521
+ import { join as join29 } from "path";
10395
10522
  import enquirer6 from "enquirer";
10396
10523
  async function promptType() {
10397
10524
  const { type } = await enquirer6.prompt({
@@ -10431,8 +10558,8 @@ async function promptDescription() {
10431
10558
  }
10432
10559
  function openEditor() {
10433
10560
  const editor = process.env.EDITOR || process.env.VISUAL || "vi";
10434
- const dir = mkdtempSync(join28(tmpdir(), "assist-"));
10435
- const filePath = join28(dir, "description.md");
10561
+ const dir = mkdtempSync(join29(tmpdir2(), "assist-"));
10562
+ const filePath = join29(dir, "description.md");
10436
10563
  writeFileSync21(filePath, "");
10437
10564
  const result = spawnSync3(editor, [filePath], { stdio: "inherit" });
10438
10565
  if (result.status !== 0) {
@@ -12065,7 +12192,7 @@ import { basename as basename7 } from "path";
12065
12192
  import { parse } from "shell-quote";
12066
12193
 
12067
12194
  // src/shared/consumeRedirect.ts
12068
- import { tmpdir as tmpdir2 } from "os";
12195
+ import { tmpdir as tmpdir3 } from "os";
12069
12196
 
12070
12197
  // src/shared/isRedirectTargetAllowed.ts
12071
12198
  function isRedirectTargetAllowed(target, tmp) {
@@ -12093,7 +12220,7 @@ function consumeRedirect(tokens, opIndex, current) {
12093
12220
  if (typeof target !== "string") {
12094
12221
  return { ok: false, error: "unable to parse" };
12095
12222
  }
12096
- if (!isRedirectTargetAllowed(target, tmpdir2())) {
12223
+ if (!isRedirectTargetAllowed(target, tmpdir3())) {
12097
12224
  return {
12098
12225
  ok: false,
12099
12226
  error: `redirect target '${target}' is outside the OS temp directory`
@@ -12384,12 +12511,12 @@ function findCliWrite(command) {
12384
12511
  // src/shared/readSettingsPerms.ts
12385
12512
  import { existsSync as existsSync30, readFileSync as readFileSync24 } from "fs";
12386
12513
  import { homedir as homedir14 } from "os";
12387
- import { join as join29 } from "path";
12514
+ import { join as join30 } from "path";
12388
12515
  function readSettingsPerms(key) {
12389
12516
  const paths = [
12390
- join29(homedir14(), ".claude", "settings.json"),
12391
- join29(process.cwd(), ".claude", "settings.json"),
12392
- join29(process.cwd(), ".claude", "settings.local.json")
12517
+ join30(homedir14(), ".claude", "settings.json"),
12518
+ join30(process.cwd(), ".claude", "settings.json"),
12519
+ join30(process.cwd(), ".claude", "settings.local.json")
12393
12520
  ];
12394
12521
  const entries = [];
12395
12522
  for (const p of paths) {
@@ -12591,11 +12718,11 @@ function decideCommand(toolName, rawCommand) {
12591
12718
  // src/commands/cliHook/logDeniedToolCall.ts
12592
12719
  import { mkdirSync as mkdirSync12 } from "fs";
12593
12720
  import { homedir as homedir15 } from "os";
12594
- import { join as join30 } from "path";
12721
+ import { join as join31 } from "path";
12595
12722
  import Database from "better-sqlite3";
12596
12723
  var _db;
12597
12724
  function getDbDir() {
12598
- return join30(homedir15(), ".assist");
12725
+ return join31(homedir15(), ".assist");
12599
12726
  }
12600
12727
  function initSchema(db) {
12601
12728
  db.exec(`
@@ -12614,7 +12741,7 @@ function openPromptsDb(dir) {
12614
12741
  if (_db) return _db;
12615
12742
  const dbDir = dir ?? getDbDir();
12616
12743
  mkdirSync12(dbDir, { recursive: true });
12617
- const db = new Database(join30(dbDir, "assist.db"));
12744
+ const db = new Database(join31(dbDir, "assist.db"));
12618
12745
  db.pragma("journal_mode = WAL");
12619
12746
  initSchema(db);
12620
12747
  _db = db;
@@ -12712,7 +12839,7 @@ ${reasons.join("\n")}`);
12712
12839
  // src/commands/permitCliReads/index.ts
12713
12840
  import { existsSync as existsSync31, mkdirSync as mkdirSync13, readFileSync as readFileSync25, writeFileSync as writeFileSync23 } from "fs";
12714
12841
  import { homedir as homedir16 } from "os";
12715
- import { join as join31 } from "path";
12842
+ import { join as join32 } from "path";
12716
12843
 
12717
12844
  // src/commands/permitCliReads/assertCliExists.ts
12718
12845
  function assertCliExists(cli) {
@@ -12980,7 +13107,7 @@ function updateSettings(cli, commands) {
12980
13107
  // src/commands/permitCliReads/index.ts
12981
13108
  function logPath(cli) {
12982
13109
  const safeName = cli.replace(/\s+/g, "-");
12983
- return join31(homedir16(), ".assist", `cli-discover-${safeName}.log`);
13110
+ return join32(homedir16(), ".assist", `cli-discover-${safeName}.log`);
12984
13111
  }
12985
13112
  function readCache(cli) {
12986
13113
  const path71 = logPath(cli);
@@ -12988,7 +13115,7 @@ function readCache(cli) {
12988
13115
  return readFileSync25(path71, "utf8");
12989
13116
  }
12990
13117
  function writeCache(cli, output) {
12991
- const dir = join31(homedir16(), ".assist");
13118
+ const dir = join32(homedir16(), ".assist");
12992
13119
  mkdirSync13(dir, { recursive: true });
12993
13120
  writeFileSync23(logPath(cli), output);
12994
13121
  }
@@ -13136,17 +13263,17 @@ import chalk113 from "chalk";
13136
13263
 
13137
13264
  // src/commands/codeComment/getRestrictedDir.ts
13138
13265
  import { homedir as homedir17 } from "os";
13139
- import { join as join32 } from "path";
13266
+ import { join as join33 } from "path";
13140
13267
  function getRestrictedDir() {
13141
- return join32(homedir17(), ".assist", "restricted");
13268
+ return join33(homedir17(), ".assist", "restricted");
13142
13269
  }
13143
13270
  function getPinStatePath(pin) {
13144
- return join32(getRestrictedDir(), `code-comment-${pin}.json`);
13271
+ return join33(getRestrictedDir(), `code-comment-${pin}.json`);
13145
13272
  }
13146
13273
 
13147
13274
  // src/commands/codeComment/sweepRestrictedDir.ts
13148
13275
  import { readdirSync as readdirSync3, statSync as statSync3, unlinkSync as unlinkSync7 } from "fs";
13149
- import { join as join33 } from "path";
13276
+ import { join as join34 } from "path";
13150
13277
  var STALE_AFTER_MS = 30 * 60 * 1e3;
13151
13278
  function sweepRestrictedDir(dir = getRestrictedDir()) {
13152
13279
  let entries;
@@ -13157,7 +13284,7 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
13157
13284
  }
13158
13285
  const cutoff = Date.now() - STALE_AFTER_MS;
13159
13286
  for (const entry of entries) {
13160
- const path71 = join33(dir, entry);
13287
+ const path71 = join34(dir, entry);
13161
13288
  try {
13162
13289
  if (statSync3(path71).mtimeMs < cutoff) unlinkSync7(path71);
13163
13290
  } catch {
@@ -14327,12 +14454,12 @@ import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync26 } from "fs"
14327
14454
  import chalk129 from "chalk";
14328
14455
 
14329
14456
  // src/commands/dbMigration/getMigrationPinPath.ts
14330
- import { join as join34 } from "path";
14457
+ import { join as join35 } from "path";
14331
14458
  function getMigrationPinPath(pin) {
14332
- return join34(getRestrictedDir(), `db-migration-pin-${pin}.json`);
14459
+ return join35(getRestrictedDir(), `db-migration-pin-${pin}.json`);
14333
14460
  }
14334
14461
  function getMigrationApprovalPath(migrationId) {
14335
- return join34(getRestrictedDir(), `db-migration-approval-${migrationId}.json`);
14462
+ return join35(getRestrictedDir(), `db-migration-approval-${migrationId}.json`);
14336
14463
  }
14337
14464
 
14338
14465
  // src/commands/dbMigration/readMigrationPinState.ts
@@ -14470,10 +14597,10 @@ import { basename as basename9 } from "path";
14470
14597
 
14471
14598
  // src/commands/devlog/loadBlogSkipDays.ts
14472
14599
  import { homedir as homedir18 } from "os";
14473
- import { join as join35 } from "path";
14474
- var BLOG_REPO_ROOT = join35(homedir18(), "git/blog");
14600
+ import { join as join36 } from "path";
14601
+ var BLOG_REPO_ROOT = join36(homedir18(), "git/blog");
14475
14602
  function loadBlogSkipDays(repoName) {
14476
- const config = loadRawYaml(join35(BLOG_REPO_ROOT, "assist.yml"));
14603
+ const config = loadRawYaml(join36(BLOG_REPO_ROOT, "assist.yml"));
14477
14604
  const devlog = config.devlog;
14478
14605
  const skip2 = devlog?.skip;
14479
14606
  return new Set(skip2?.[repoName]);
@@ -14485,13 +14612,13 @@ import chalk132 from "chalk";
14485
14612
 
14486
14613
  // src/shared/getRepoName.ts
14487
14614
  import { existsSync as existsSync36, readFileSync as readFileSync30 } from "fs";
14488
- import { basename as basename8, join as join36 } from "path";
14615
+ import { basename as basename8, join as join37 } from "path";
14489
14616
  function getRepoName() {
14490
14617
  const config = loadConfig();
14491
14618
  if (config.devlog?.name) {
14492
14619
  return config.devlog.name;
14493
14620
  }
14494
- const packageJsonPath = join36(process.cwd(), "package.json");
14621
+ const packageJsonPath = join37(process.cwd(), "package.json");
14495
14622
  if (existsSync36(packageJsonPath)) {
14496
14623
  try {
14497
14624
  const content = readFileSync30(packageJsonPath, "utf8");
@@ -14507,8 +14634,8 @@ function getRepoName() {
14507
14634
 
14508
14635
  // src/commands/devlog/loadDevlogEntries.ts
14509
14636
  import { readdirSync as readdirSync4, readFileSync as readFileSync31 } from "fs";
14510
- import { join as join37 } from "path";
14511
- var DEVLOG_DIR = join37(BLOG_REPO_ROOT, "src/content/devlog");
14637
+ import { join as join38 } from "path";
14638
+ var DEVLOG_DIR = join38(BLOG_REPO_ROOT, "src/content/devlog");
14512
14639
  function extractFrontmatter(content) {
14513
14640
  const fm = content.match(/^---\n([\s\S]*?)\n---/);
14514
14641
  return fm?.[1] ?? null;
@@ -14536,7 +14663,7 @@ function readDevlogFiles(callback) {
14536
14663
  try {
14537
14664
  const files = readdirSync4(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
14538
14665
  for (const file of files) {
14539
- const content = readFileSync31(join37(DEVLOG_DIR, file), "utf8");
14666
+ const content = readFileSync31(join38(DEVLOG_DIR, file), "utf8");
14540
14667
  const parsed = parseFrontmatter(content, file);
14541
14668
  if (parsed) callback(parsed);
14542
14669
  }
@@ -14924,11 +15051,11 @@ function repos(options2) {
14924
15051
 
14925
15052
  // src/commands/devlog/skip.ts
14926
15053
  import { writeFileSync as writeFileSync29 } from "fs";
14927
- import { join as join38 } from "path";
15054
+ import { join as join39 } from "path";
14928
15055
  import chalk137 from "chalk";
14929
15056
  import { stringify as stringifyYaml3 } from "yaml";
14930
15057
  function getBlogConfigPath() {
14931
- return join38(BLOG_REPO_ROOT, "assist.yml");
15058
+ return join39(BLOG_REPO_ROOT, "assist.yml");
14932
15059
  }
14933
15060
  function skip(date) {
14934
15061
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
@@ -15009,7 +15136,7 @@ function registerDevlog(program2) {
15009
15136
 
15010
15137
  // src/commands/dotnet/checkBuildLocks.ts
15011
15138
  import { closeSync as closeSync3, openSync as openSync3, readdirSync as readdirSync5 } from "fs";
15012
- import { join as join39 } from "path";
15139
+ import { join as join40 } from "path";
15013
15140
  import chalk139 from "chalk";
15014
15141
 
15015
15142
  // src/shared/findRepoRoot.ts
@@ -15037,7 +15164,7 @@ function isLockedDll(debugDir) {
15037
15164
  }
15038
15165
  for (const file of files) {
15039
15166
  if (!file.toLowerCase().endsWith(".dll")) continue;
15040
- const dllPath = join39(debugDir, file);
15167
+ const dllPath = join40(debugDir, file);
15041
15168
  try {
15042
15169
  const fd = openSync3(dllPath, "r+");
15043
15170
  closeSync3(fd);
@@ -15055,13 +15182,13 @@ function findFirstLockedDll(dir) {
15055
15182
  return null;
15056
15183
  }
15057
15184
  if (entries.includes("bin")) {
15058
- const locked = isLockedDll(join39(dir, "bin", "Debug"));
15185
+ const locked = isLockedDll(join40(dir, "bin", "Debug"));
15059
15186
  if (locked) return locked;
15060
15187
  }
15061
15188
  for (const entry of entries) {
15062
15189
  if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
15063
15190
  continue;
15064
- const found = findFirstLockedDll(join39(dir, entry));
15191
+ const found = findFirstLockedDll(join40(dir, entry));
15065
15192
  if (found) return found;
15066
15193
  }
15067
15194
  return null;
@@ -15408,11 +15535,11 @@ import chalk145 from "chalk";
15408
15535
 
15409
15536
  // src/commands/dotnet/findSolution.ts
15410
15537
  import { readdirSync as readdirSync7 } from "fs";
15411
- import { dirname as dirname22, join as join40 } from "path";
15538
+ import { dirname as dirname22, join as join41 } from "path";
15412
15539
  import chalk144 from "chalk";
15413
15540
  function findSlnInDir(dir) {
15414
15541
  try {
15415
- return readdirSync7(dir).filter((f) => f.endsWith(".sln")).map((f) => join40(dir, f));
15542
+ return readdirSync7(dir).filter((f) => f.endsWith(".sln")).map((f) => join41(dir, f));
15416
15543
  } catch {
15417
15544
  return [];
15418
15545
  }
@@ -15484,7 +15611,7 @@ function parseInspectReport(json) {
15484
15611
  // src/commands/dotnet/runInspectCode.ts
15485
15612
  import { execSync as execSync37 } from "child_process";
15486
15613
  import { existsSync as existsSync40, readFileSync as readFileSync34, unlinkSync as unlinkSync10 } from "fs";
15487
- import { tmpdir as tmpdir3 } from "os";
15614
+ import { tmpdir as tmpdir4 } from "os";
15488
15615
  import path35 from "path";
15489
15616
  import chalk146 from "chalk";
15490
15617
  function assertJbInstalled() {
@@ -15499,7 +15626,7 @@ function assertJbInstalled() {
15499
15626
  }
15500
15627
  }
15501
15628
  function runInspectCode(slnPath, include, swea) {
15502
- const reportPath = path35.join(tmpdir3(), `inspect-${Date.now()}.xml`);
15629
+ const reportPath = path35.join(tmpdir4(), `inspect-${Date.now()}.xml`);
15503
15630
  const includeFlag = include ? ` --include="${include}"` : "";
15504
15631
  const sweaFlag = swea ? " --swea" : "";
15505
15632
  try {
@@ -15900,8 +16027,8 @@ function aggregateCommitters(authorLists) {
15900
16027
  // src/shared/runGhGraphql.ts
15901
16028
  import { spawnSync as spawnSync4 } from "child_process";
15902
16029
  import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
15903
- import { tmpdir as tmpdir4 } from "os";
15904
- import { join as join41 } from "path";
16030
+ import { tmpdir as tmpdir5 } from "os";
16031
+ import { join as join42 } from "path";
15905
16032
  function buildArgs2(queryFile, vars) {
15906
16033
  const args = ["api", "graphql", "-F", `query=@${queryFile}`];
15907
16034
  for (const [key, value] of Object.entries(vars)) {
@@ -15926,7 +16053,7 @@ function throwOnGraphqlErrors(stdout) {
15926
16053
  throw new Error(messages || "GraphQL request returned errors");
15927
16054
  }
15928
16055
  function runGhGraphql(mutation, vars) {
15929
- const queryFile = join41(tmpdir4(), `gh-query-${Date.now()}.graphql`);
16056
+ const queryFile = join42(tmpdir5(), `gh-query-${Date.now()}.graphql`);
15930
16057
  writeFileSync30(queryFile, mutation);
15931
16058
  try {
15932
16059
  const result = spawnSync4("gh", buildArgs2(queryFile, vars), {
@@ -16119,18 +16246,18 @@ import {
16119
16246
  rmSync as rmSync3,
16120
16247
  statSync as statSync5
16121
16248
  } from "fs";
16122
- import { basename as basename10, join as join44 } from "path";
16249
+ import { basename as basename10, join as join45 } from "path";
16123
16250
 
16124
16251
  // src/commands/handover/getHandoverPath.ts
16125
- import { join as join42 } from "path";
16252
+ import { join as join43 } from "path";
16126
16253
  function getHandoverPath(cwd = process.cwd()) {
16127
- return join42(cwd, ".assist", "HANDOVER.md");
16254
+ return join43(cwd, ".assist", "HANDOVER.md");
16128
16255
  }
16129
16256
 
16130
16257
  // src/commands/handover/getHandoversDir.ts
16131
- import { join as join43 } from "path";
16258
+ import { join as join44 } from "path";
16132
16259
  function getHandoversDir(cwd = process.cwd()) {
16133
- return join43(cwd, ".assist", "handovers");
16260
+ return join44(cwd, ".assist", "handovers");
16134
16261
  }
16135
16262
 
16136
16263
  // src/commands/handover/parseArchiveTimestamp.ts
@@ -16171,7 +16298,7 @@ function collectMarkdown(dir) {
16171
16298
  if (!existsSync42(dir)) return [];
16172
16299
  const out = [];
16173
16300
  for (const entry of readdirSync8(dir, { withFileTypes: true })) {
16174
- const full = join44(dir, entry.name);
16301
+ const full = join45(dir, entry.name);
16175
16302
  if (entry.isDirectory()) out.push(...collectMarkdown(full));
16176
16303
  else if (entry.isFile() && entry.name.endsWith(".md")) out.push(full);
16177
16304
  }
@@ -16619,7 +16746,7 @@ import chalk156 from "chalk";
16619
16746
 
16620
16747
  // src/commands/mermaid/exportFile.ts
16621
16748
  import { readFileSync as readFileSync36, writeFileSync as writeFileSync31 } from "fs";
16622
- import { basename as basename11, extname, resolve as resolve11 } from "path";
16749
+ import { basename as basename11, extname as extname2, resolve as resolve11 } from "path";
16623
16750
  import chalk155 from "chalk";
16624
16751
 
16625
16752
  // src/commands/mermaid/renderBlock.ts
@@ -16646,7 +16773,7 @@ async function renderBlock(krokiUrl, source) {
16646
16773
  async function exportFile(file, outDir, krokiUrl, onlyIndex) {
16647
16774
  const content = readFileSync36(file, "utf8");
16648
16775
  const blocks = extractMermaidBlocks(content);
16649
- const stem = basename11(file, extname(file));
16776
+ const stem = basename11(file, extname2(file));
16650
16777
  if (onlyIndex !== void 0) {
16651
16778
  if (onlyIndex < 1 || onlyIndex > blocks.length) {
16652
16779
  console.error(
@@ -16806,17 +16933,17 @@ function createNetcapHandler(options2) {
16806
16933
  }
16807
16934
 
16808
16935
  // src/commands/netcap/prepareExtensionForLoad.ts
16809
- import { cp, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
16936
+ import { cp, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
16810
16937
  import { networkInterfaces } from "os";
16811
- import { join as join46 } from "path";
16938
+ import { join as join47 } from "path";
16812
16939
  import chalk157 from "chalk";
16813
16940
 
16814
16941
  // src/commands/netcap/netcapExtensionDir.ts
16815
- import { dirname as dirname23, join as join45 } from "path";
16942
+ import { dirname as dirname23, join as join46 } from "path";
16816
16943
  import { fileURLToPath as fileURLToPath6 } from "url";
16817
16944
  var moduleDir = dirname23(fileURLToPath6(import.meta.url));
16818
16945
  function netcapExtensionDir() {
16819
- return join45(moduleDir, "commands", "netcap", "netcap-extension");
16946
+ return join46(moduleDir, "commands", "netcap", "netcap-extension");
16820
16947
  }
16821
16948
 
16822
16949
  // src/commands/netcap/prepareExtensionForLoad.ts
@@ -16831,9 +16958,9 @@ function lanIPv4() {
16831
16958
  return void 0;
16832
16959
  }
16833
16960
  async function configureBackground(dir, host, port, filter) {
16834
- const file = join46(dir, "background.js");
16961
+ const file = join47(dir, "background.js");
16835
16962
  const source = await readFile2(file, "utf8");
16836
- await writeFile2(
16963
+ await writeFile3(
16837
16964
  file,
16838
16965
  source.replace(
16839
16966
  /const RECEIVER = "[^"]*";/,
@@ -16871,20 +16998,20 @@ async function prepareExtensionForLoad(port, filter = "") {
16871
16998
  }
16872
16999
 
16873
17000
  // src/commands/netcap/resolveNetcapOutPath.ts
16874
- import { isAbsolute, join as join48, resolve as resolve13 } from "path";
17001
+ import { isAbsolute, join as join49, resolve as resolve13 } from "path";
16875
17002
 
16876
17003
  // src/commands/netcap/defaultCapturePath.ts
16877
17004
  import { homedir as homedir19 } from "os";
16878
- import { join as join47 } from "path";
17005
+ import { join as join48 } from "path";
16879
17006
  function defaultCapturePath() {
16880
- return join47(homedir19(), ".assist", "netcap", "capture.jsonl");
17007
+ return join48(homedir19(), ".assist", "netcap", "capture.jsonl");
16881
17008
  }
16882
17009
 
16883
17010
  // src/commands/netcap/resolveNetcapOutPath.ts
16884
17011
  function resolveNetcapOutPath(out) {
16885
17012
  if (!out) return defaultCapturePath();
16886
17013
  const dir = isAbsolute(out) ? out : resolve13(process.cwd(), out);
16887
- return join48(dir, "capture.jsonl");
17014
+ return join49(dir, "capture.jsonl");
16888
17015
  }
16889
17016
 
16890
17017
  // src/commands/netcap/netcap.ts
@@ -16931,7 +17058,7 @@ netcap stopped \u2014 captured ${count7} ${count7 === 1 ? "entry" : "entries"} t
16931
17058
 
16932
17059
  // src/commands/netcap/netcapExtract.ts
16933
17060
  import { writeFileSync as writeFileSync32 } from "fs";
16934
- import { join as join49 } from "path";
17061
+ import { join as join50 } from "path";
16935
17062
  import chalk159 from "chalk";
16936
17063
 
16937
17064
  // src/commands/netcap/extractPostsFromCapture.ts
@@ -17376,7 +17503,7 @@ function extractPostsFromCapture(captureFile) {
17376
17503
  function netcapExtract(file) {
17377
17504
  const captureFile = file ?? defaultCapturePath();
17378
17505
  const posts = extractPostsFromCapture(captureFile);
17379
- const outFile = join49(captureFile, "..", "posts.json");
17506
+ const outFile = join50(captureFile, "..", "posts.json");
17380
17507
  writeFileSync32(outFile, `${JSON.stringify(posts, null, 2)}
17381
17508
  `);
17382
17509
  console.log(
@@ -17866,15 +17993,15 @@ import { execSync as execSync43 } from "child_process";
17866
17993
  // src/commands/prs/resolveCommentWithReply.ts
17867
17994
  import { execSync as execSync42 } from "child_process";
17868
17995
  import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync33 } from "fs";
17869
- import { tmpdir as tmpdir5 } from "os";
17870
- import { join as join51 } from "path";
17996
+ import { tmpdir as tmpdir6 } from "os";
17997
+ import { join as join52 } from "path";
17871
17998
 
17872
17999
  // src/commands/prs/loadCommentsCache.ts
17873
18000
  import { existsSync as existsSync43, readFileSync as readFileSync38, unlinkSync as unlinkSync13 } from "fs";
17874
- import { join as join50 } from "path";
18001
+ import { join as join51 } from "path";
17875
18002
  import { parse as parse2 } from "yaml";
17876
18003
  function getCachePath(prNumber) {
17877
- return join50(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
18004
+ return join51(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
17878
18005
  }
17879
18006
  function loadCommentsCache(prNumber) {
17880
18007
  const cachePath = getCachePath(prNumber);
@@ -17904,7 +18031,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
17904
18031
  // src/commands/prs/resolveCommentWithReply.ts
17905
18032
  function resolveThread(threadId) {
17906
18033
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
17907
- const queryFile = join51(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
18034
+ const queryFile = join52(tmpdir6(), `gh-mutation-${Date.now()}.graphql`);
17908
18035
  writeFileSync33(queryFile, mutation);
17909
18036
  try {
17910
18037
  execSync42(
@@ -17987,17 +18114,17 @@ function fixed(commentId, sha) {
17987
18114
 
17988
18115
  // src/commands/prs/listComments/index.ts
17989
18116
  import { existsSync as existsSync44, mkdirSync as mkdirSync17, writeFileSync as writeFileSync35 } from "fs";
17990
- import { join as join53 } from "path";
18117
+ import { join as join54 } from "path";
17991
18118
  import { stringify } from "yaml";
17992
18119
 
17993
18120
  // src/commands/prs/fetchThreadIds.ts
17994
18121
  import { execSync as execSync44 } from "child_process";
17995
18122
  import { unlinkSync as unlinkSync15, writeFileSync as writeFileSync34 } from "fs";
17996
- import { tmpdir as tmpdir6 } from "os";
17997
- import { join as join52 } from "path";
18123
+ import { tmpdir as tmpdir7 } from "os";
18124
+ import { join as join53 } from "path";
17998
18125
  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 } } } } } } }`;
17999
18126
  function fetchThreadIds(org, repo, prNumber) {
18000
- const queryFile = join52(tmpdir6(), `gh-query-${Date.now()}.graphql`);
18127
+ const queryFile = join53(tmpdir7(), `gh-query-${Date.now()}.graphql`);
18001
18128
  writeFileSync34(queryFile, THREAD_QUERY);
18002
18129
  try {
18003
18130
  const result = execSync44(
@@ -18111,7 +18238,7 @@ function printComments2(result) {
18111
18238
 
18112
18239
  // src/commands/prs/listComments/index.ts
18113
18240
  function writeCommentsCache(prNumber, comments3) {
18114
- const assistDir = join53(process.cwd(), ".assist");
18241
+ const assistDir = join54(process.cwd(), ".assist");
18115
18242
  if (!existsSync44(assistDir)) {
18116
18243
  mkdirSync17(assistDir, { recursive: true });
18117
18244
  }
@@ -18120,7 +18247,7 @@ function writeCommentsCache(prNumber, comments3) {
18120
18247
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
18121
18248
  comments: comments3
18122
18249
  };
18123
- const cachePath = join53(assistDir, `pr-${prNumber}-comments.yaml`);
18250
+ const cachePath = join54(assistDir, `pr-${prNumber}-comments.yaml`);
18124
18251
  writeFileSync35(cachePath, stringify(cacheData));
18125
18252
  }
18126
18253
  function handleKnownErrors(error) {
@@ -18153,7 +18280,7 @@ async function listComments() {
18153
18280
  ];
18154
18281
  updateCache(prNumber, allComments);
18155
18282
  const hasLineComments = allComments.some((c) => c.type === "line");
18156
- const cachePath = hasLineComments ? join53(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
18283
+ const cachePath = hasLineComments ? join54(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
18157
18284
  return { comments: allComments, cachePath };
18158
18285
  } catch (error) {
18159
18286
  const handled = handleKnownErrors(error);
@@ -18404,6 +18531,39 @@ async function placePr(prNumber, title, body, options2) {
18404
18531
  // src/commands/prs/previewAndPlace.ts
18405
18532
  import { randomUUID as randomUUID4 } from "crypto";
18406
18533
 
18534
+ // src/commands/prs/appendScreenshots.ts
18535
+ function appendScreenshots(body, screenshots) {
18536
+ if (screenshots.length === 0) return body;
18537
+ return `${body}
18538
+
18539
+ ## Screenshots
18540
+
18541
+ ${screenshots.join("\n\n")}`;
18542
+ }
18543
+
18544
+ // src/commands/prs/reportPrRejection.ts
18545
+ function reportPrRejection(decision) {
18546
+ console.error(
18547
+ `PR preview rejected${decision.reason ? `: ${decision.reason}` : "."}`
18548
+ );
18549
+ const comments3 = decision.comments ?? [];
18550
+ if (comments3.length > 0) {
18551
+ console.error(
18552
+ `
18553
+ The reviewer left ${comments3.length} comment${comments3.length === 1 ? "" : "s"} on the preview. Address each one, then re-run this command:
18554
+ `
18555
+ );
18556
+ for (const [i, c] of comments3.entries()) {
18557
+ const quoted = c.quote.split("\n").map((line) => ` > ${line}`).join("\n");
18558
+ console.error(`${i + 1}. On:
18559
+ ${quoted}
18560
+ Comment: ${c.note}
18561
+ `);
18562
+ }
18563
+ }
18564
+ process.exit(1);
18565
+ }
18566
+
18407
18567
  // src/commands/prs/parseIncoming.ts
18408
18568
  function parseIncoming(line, requestId) {
18409
18569
  try {
@@ -18417,7 +18577,8 @@ function parseIncoming(line, requestId) {
18417
18577
  decision: {
18418
18578
  decision: msg.decision,
18419
18579
  reason: msg.reason,
18420
- comments: Array.isArray(msg.comments) ? msg.comments : void 0
18580
+ comments: Array.isArray(msg.comments) ? msg.comments : void 0,
18581
+ screenshots: Array.isArray(msg.screenshots) ? msg.screenshots : void 0
18421
18582
  }
18422
18583
  };
18423
18584
  } catch {
@@ -18472,28 +18633,9 @@ async function previewAndPlace(args) {
18472
18633
  );
18473
18634
  process.exit(1);
18474
18635
  }
18475
- if (decision.decision === "reject") {
18476
- console.error(
18477
- `PR preview rejected${decision.reason ? `: ${decision.reason}` : "."}`
18478
- );
18479
- const comments3 = decision.comments ?? [];
18480
- if (comments3.length > 0) {
18481
- console.error(
18482
- `
18483
- The reviewer left ${comments3.length} comment${comments3.length === 1 ? "" : "s"} on the preview. Address each one, then re-run this command:
18484
- `
18485
- );
18486
- for (const [i, c] of comments3.entries()) {
18487
- const quoted = c.quote.split("\n").map((line) => ` > ${line}`).join("\n");
18488
- console.error(`${i + 1}. On:
18489
- ${quoted}
18490
- Comment: ${c.note}
18491
- `);
18492
- }
18493
- }
18494
- process.exit(1);
18495
- }
18496
- await placePr(args.prNumber, args.title, args.body, args.options);
18636
+ if (decision.decision === "reject") reportPrRejection(decision);
18637
+ const body = appendScreenshots(args.body, decision.screenshots ?? []);
18638
+ await placePr(args.prNumber, args.title, body, args.options);
18497
18639
  }
18498
18640
 
18499
18641
  // src/commands/prs/raise.ts
@@ -18706,7 +18848,10 @@ on rejection it exits non-zero with the reason. The reviewer may also attach
18706
18848
  inline comments to specific spans of the preview; on rejection these are printed
18707
18849
  as numbered quoted-span + note pairs on stderr. Address every comment (and the
18708
18850
  reason), then run the command again to re-preview the revised PR. Repeat until it
18709
- is approved. Just compose the sections and run the command.`;
18851
+ is approved. The reviewer may also drop or paste screenshots into the pane; on
18852
+ approval these are appended to the PR body under a ## Screenshots section
18853
+ automatically (they are discarded on rejection), so you never author that section
18854
+ yourself. Just compose the sections and run the command.`;
18710
18855
  function raiseHelpText(promptJira) {
18711
18856
  const prompt = promptJira ?? loadConfig().prs?.promptJira ?? false;
18712
18857
  const confirm = process.env.ASSIST_SESSION === "1" ? WEB_CONFIRM : TERMINAL_CONFIRM;
@@ -21014,9 +21159,9 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
21014
21159
 
21015
21160
  // src/commands/review/buildReviewPaths.ts
21016
21161
  import { homedir as homedir20 } from "os";
21017
- import { basename as basename12, join as join54 } from "path";
21162
+ import { basename as basename12, join as join55 } from "path";
21018
21163
  function buildReviewPaths(repoRoot, key) {
21019
- const reviewDir = join54(
21164
+ const reviewDir = join55(
21020
21165
  homedir20(),
21021
21166
  ".assist",
21022
21167
  "reviews",
@@ -21025,10 +21170,10 @@ function buildReviewPaths(repoRoot, key) {
21025
21170
  );
21026
21171
  return {
21027
21172
  reviewDir,
21028
- requestPath: join54(reviewDir, "request.md"),
21029
- claudePath: join54(reviewDir, "claude.md"),
21030
- codexPath: join54(reviewDir, "codex.md"),
21031
- synthesisPath: join54(reviewDir, "synthesis.md")
21173
+ requestPath: join55(reviewDir, "request.md"),
21174
+ claudePath: join55(reviewDir, "claude.md"),
21175
+ codexPath: join55(reviewDir, "codex.md"),
21176
+ synthesisPath: join55(reviewDir, "synthesis.md")
21032
21177
  };
21033
21178
  }
21034
21179
 
@@ -23354,13 +23499,13 @@ async function configure() {
23354
23499
 
23355
23500
  // src/commands/transcript/list.ts
23356
23501
  import { existsSync as existsSync48, readdirSync as readdirSync10, statSync as statSync7 } from "fs";
23357
- import { join as join55 } from "path";
23502
+ import { join as join56 } from "path";
23358
23503
  function list4() {
23359
23504
  const { vttDir } = getTranscriptConfig();
23360
23505
  if (!existsSync48(vttDir)) return;
23361
23506
  for (const entry of readdirSync10(vttDir)) {
23362
23507
  if (!entry.endsWith(".vtt")) continue;
23363
- if (statSync7(join55(vttDir, entry)).isDirectory()) continue;
23508
+ if (statSync7(join56(vttDir, entry)).isDirectory()) continue;
23364
23509
  console.log(entry);
23365
23510
  }
23366
23511
  }
@@ -23373,7 +23518,7 @@ import {
23373
23518
  renameSync as renameSync2,
23374
23519
  writeFileSync as writeFileSync38
23375
23520
  } from "fs";
23376
- import { basename as basename13, join as join56 } from "path";
23521
+ import { basename as basename13, join as join57 } from "path";
23377
23522
 
23378
23523
  // src/commands/transcript/cleanText.ts
23379
23524
  function cleanText(text17) {
@@ -23586,9 +23731,9 @@ function convertVttToMarkdown(inputPath) {
23586
23731
  return formatChatLog(messages);
23587
23732
  }
23588
23733
  function archiveRawVtt(vttDir, sourcePath, filename) {
23589
- const processedDir = join56(vttDir, "processed");
23734
+ const processedDir = join57(vttDir, "processed");
23590
23735
  mkdirSync19(processedDir, { recursive: true });
23591
- renameSync2(sourcePath, join56(processedDir, filename));
23736
+ renameSync2(sourcePath, join57(processedDir, filename));
23592
23737
  }
23593
23738
  function move(file, options2) {
23594
23739
  const { date, client } = options2;
@@ -23598,19 +23743,19 @@ function move(file, options2) {
23598
23743
  }
23599
23744
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
23600
23745
  const filename = basename13(file);
23601
- const sourcePath = join56(vttDir, filename);
23746
+ const sourcePath = join57(vttDir, filename);
23602
23747
  if (!existsSync49(sourcePath)) {
23603
23748
  console.error(`Error: VTT file not found: ${sourcePath}`);
23604
23749
  process.exit(1);
23605
23750
  }
23606
23751
  const base = basename13(filename, ".vtt").replace(/ Transcription$/, "");
23607
23752
  const outputName = `${date} ${base}.md`;
23608
- const formattedDir = join56(transcriptsDir, client);
23753
+ const formattedDir = join57(transcriptsDir, client);
23609
23754
  mkdirSync19(formattedDir, { recursive: true });
23610
- const formattedPath = join56(formattedDir, outputName);
23755
+ const formattedPath = join57(formattedDir, outputName);
23611
23756
  writeFileSync38(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
23612
23757
  archiveRawVtt(vttDir, sourcePath, filename);
23613
- const summaryPath = join56(summaryDir, client, outputName);
23758
+ const summaryPath = join57(summaryDir, client, outputName);
23614
23759
  console.log(`Formatted transcript: ${formattedPath}`);
23615
23760
  console.log(`Summary target: ${summaryPath}`);
23616
23761
  }
@@ -23730,38 +23875,38 @@ function registerVerify(program2) {
23730
23875
 
23731
23876
  // src/commands/voice/devices.ts
23732
23877
  import { spawnSync as spawnSync6 } from "child_process";
23733
- import { join as join58 } from "path";
23878
+ import { join as join59 } from "path";
23734
23879
 
23735
23880
  // src/commands/voice/shared.ts
23736
23881
  import { homedir as homedir21 } from "os";
23737
- import { dirname as dirname26, join as join57 } from "path";
23882
+ import { dirname as dirname26, join as join58 } from "path";
23738
23883
  import { fileURLToPath as fileURLToPath7 } from "url";
23739
23884
  var __dirname5 = dirname26(fileURLToPath7(import.meta.url));
23740
- var VOICE_DIR = join57(homedir21(), ".assist", "voice");
23885
+ var VOICE_DIR = join58(homedir21(), ".assist", "voice");
23741
23886
  var voicePaths = {
23742
23887
  dir: VOICE_DIR,
23743
- pid: join57(VOICE_DIR, "voice.pid"),
23744
- log: join57(VOICE_DIR, "voice.log"),
23745
- venv: join57(VOICE_DIR, ".venv"),
23746
- lock: join57(VOICE_DIR, "voice.lock")
23888
+ pid: join58(VOICE_DIR, "voice.pid"),
23889
+ log: join58(VOICE_DIR, "voice.log"),
23890
+ venv: join58(VOICE_DIR, ".venv"),
23891
+ lock: join58(VOICE_DIR, "voice.lock")
23747
23892
  };
23748
23893
  function getPythonDir() {
23749
- return join57(__dirname5, "commands", "voice", "python");
23894
+ return join58(__dirname5, "commands", "voice", "python");
23750
23895
  }
23751
23896
  function getVenvPython() {
23752
- return process.platform === "win32" ? join57(voicePaths.venv, "Scripts", "python.exe") : join57(voicePaths.venv, "bin", "python");
23897
+ return process.platform === "win32" ? join58(voicePaths.venv, "Scripts", "python.exe") : join58(voicePaths.venv, "bin", "python");
23753
23898
  }
23754
23899
  function getLockDir() {
23755
23900
  const config = loadConfig();
23756
23901
  return config.voice?.lockDir ?? VOICE_DIR;
23757
23902
  }
23758
23903
  function getLockFile() {
23759
- return join57(getLockDir(), "voice.lock");
23904
+ return join58(getLockDir(), "voice.lock");
23760
23905
  }
23761
23906
 
23762
23907
  // src/commands/voice/devices.ts
23763
23908
  function devices() {
23764
- const script = join58(getPythonDir(), "list_devices.py");
23909
+ const script = join59(getPythonDir(), "list_devices.py");
23765
23910
  spawnSync6(getVenvPython(), [script], { stdio: "inherit" });
23766
23911
  }
23767
23912
 
@@ -23796,12 +23941,12 @@ function logs(options2) {
23796
23941
  // src/commands/voice/setup.ts
23797
23942
  import { spawnSync as spawnSync7 } from "child_process";
23798
23943
  import { mkdirSync as mkdirSync21 } from "fs";
23799
- import { join as join60 } from "path";
23944
+ import { join as join61 } from "path";
23800
23945
 
23801
23946
  // src/commands/voice/checkLockFile.ts
23802
23947
  import { execSync as execSync56 } from "child_process";
23803
23948
  import { existsSync as existsSync51, mkdirSync as mkdirSync20, readFileSync as readFileSync43, writeFileSync as writeFileSync39 } from "fs";
23804
- import { join as join59 } from "path";
23949
+ import { join as join60 } from "path";
23805
23950
  function isProcessAlive2(pid) {
23806
23951
  try {
23807
23952
  process.kill(pid, 0);
@@ -23838,7 +23983,7 @@ function bootstrapVenv() {
23838
23983
  }
23839
23984
  function writeLockFile(pid) {
23840
23985
  const lockFile = getLockFile();
23841
- mkdirSync20(join59(lockFile, ".."), { recursive: true });
23986
+ mkdirSync20(join60(lockFile, ".."), { recursive: true });
23842
23987
  writeFileSync39(
23843
23988
  lockFile,
23844
23989
  JSON.stringify({
@@ -23854,7 +23999,7 @@ function setup() {
23854
23999
  mkdirSync21(voicePaths.dir, { recursive: true });
23855
24000
  bootstrapVenv();
23856
24001
  console.log("\nDownloading models...\n");
23857
- const script = join60(getPythonDir(), "setup_models.py");
24002
+ const script = join61(getPythonDir(), "setup_models.py");
23858
24003
  const result = spawnSync7(getVenvPython(), [script], {
23859
24004
  stdio: "inherit",
23860
24005
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -23868,7 +24013,7 @@ function setup() {
23868
24013
  // src/commands/voice/start.ts
23869
24014
  import { spawn as spawn7 } from "child_process";
23870
24015
  import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync40 } from "fs";
23871
- import { join as join61 } from "path";
24016
+ import { join as join62 } from "path";
23872
24017
 
23873
24018
  // src/commands/voice/buildDaemonEnv.ts
23874
24019
  function buildDaemonEnv(options2) {
@@ -23906,7 +24051,7 @@ function start2(options2) {
23906
24051
  bootstrapVenv();
23907
24052
  const debug = options2.debug || options2.foreground || process.platform === "win32";
23908
24053
  const env = buildDaemonEnv({ debug });
23909
- const script = join61(getPythonDir(), "voice_daemon.py");
24054
+ const script = join62(getPythonDir(), "voice_daemon.py");
23910
24055
  const python = getVenvPython();
23911
24056
  if (options2.foreground) {
23912
24057
  spawnForeground(python, script, env);
@@ -24197,7 +24342,7 @@ async function auth() {
24197
24342
  // src/commands/roam/postRoamActivity.ts
24198
24343
  import { execFileSync as execFileSync9 } from "child_process";
24199
24344
  import { readdirSync as readdirSync11, readFileSync as readFileSync46, statSync as statSync8 } from "fs";
24200
- import { join as join62 } from "path";
24345
+ import { join as join63 } from "path";
24201
24346
  function findPortFile(roamDir) {
24202
24347
  let entries;
24203
24348
  try {
@@ -24206,7 +24351,7 @@ function findPortFile(roamDir) {
24206
24351
  return void 0;
24207
24352
  }
24208
24353
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
24209
- const path71 = join62(roamDir, name);
24354
+ const path71 = join63(roamDir, name);
24210
24355
  try {
24211
24356
  return { path: path71, mtimeMs: statSync8(path71).mtimeMs };
24212
24357
  } catch {
@@ -24218,7 +24363,7 @@ function findPortFile(roamDir) {
24218
24363
  function postRoamActivity(app, event) {
24219
24364
  const appData = process.env.APPDATA;
24220
24365
  if (!appData) return;
24221
- const portFile = findPortFile(join62(appData, "Roam"));
24366
+ const portFile = findPortFile(join63(appData, "Roam"));
24222
24367
  if (!portFile) return;
24223
24368
  let port;
24224
24369
  try {
@@ -24439,13 +24584,13 @@ function runPreCommands(pre, cwd) {
24439
24584
  // src/commands/run/spawnRunCommand.ts
24440
24585
  import { execFileSync as execFileSync10, spawn as spawn8 } from "child_process";
24441
24586
  import { existsSync as existsSync54 } from "fs";
24442
- import { dirname as dirname27, join as join63, resolve as resolve14 } from "path";
24587
+ import { dirname as dirname27, join as join64, resolve as resolve14 } from "path";
24443
24588
  function resolveCommand2(command) {
24444
24589
  if (process.platform !== "win32" || command !== "bash") return command;
24445
24590
  try {
24446
24591
  const gitPath = execFileSync10("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
24447
24592
  const gitRoot = resolve14(dirname27(gitPath), "..");
24448
- const gitBash = join63(gitRoot, "bin", "bash.exe");
24593
+ const gitBash = join64(gitRoot, "bin", "bash.exe");
24449
24594
  if (existsSync54(gitBash)) return gitBash;
24450
24595
  } catch {
24451
24596
  }
@@ -24534,7 +24679,7 @@ async function run3(name, args) {
24534
24679
 
24535
24680
  // src/commands/run/add.ts
24536
24681
  import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync41 } from "fs";
24537
- import { join as join64 } from "path";
24682
+ import { join as join65 } from "path";
24538
24683
 
24539
24684
  // src/commands/run/extractOption.ts
24540
24685
  function extractOption(args, flag) {
@@ -24595,7 +24740,7 @@ function saveNewRunConfig(name, command, args, cwd) {
24595
24740
  saveConfig(config);
24596
24741
  }
24597
24742
  function createCommandFile(name) {
24598
- const dir = join64(".claude", "commands");
24743
+ const dir = join65(".claude", "commands");
24599
24744
  mkdirSync23(dir, { recursive: true });
24600
24745
  const content = `---
24601
24746
  description: Run ${name}
@@ -24603,7 +24748,7 @@ description: Run ${name}
24603
24748
 
24604
24749
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
24605
24750
  `;
24606
- const filePath = join64(dir, `${name}.md`);
24751
+ const filePath = join65(dir, `${name}.md`);
24607
24752
  writeFileSync41(filePath, content);
24608
24753
  console.log(`Created command file: ${filePath}`);
24609
24754
  }
@@ -24660,7 +24805,7 @@ function link2() {
24660
24805
 
24661
24806
  // src/commands/run/remove.ts
24662
24807
  import { existsSync as existsSync55, unlinkSync as unlinkSync20 } from "fs";
24663
- import { join as join65 } from "path";
24808
+ import { join as join66 } from "path";
24664
24809
  function findRemoveIndex() {
24665
24810
  const idx = process.argv.indexOf("remove");
24666
24811
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -24675,7 +24820,7 @@ function parseRemoveName() {
24675
24820
  return process.argv[idx + 1];
24676
24821
  }
24677
24822
  function deleteCommandFile(name) {
24678
- const filePath = join65(".claude", "commands", `${name}.md`);
24823
+ const filePath = join66(".claude", "commands", `${name}.md`);
24679
24824
  if (existsSync55(filePath)) {
24680
24825
  unlinkSync20(filePath);
24681
24826
  console.log(`Deleted command file: ${filePath}`);
@@ -24731,8 +24876,8 @@ function registerRun(program2) {
24731
24876
  // src/commands/screenshot/index.ts
24732
24877
  import { execSync as execSync58 } from "child_process";
24733
24878
  import { existsSync as existsSync56, mkdirSync as mkdirSync24, unlinkSync as unlinkSync21, writeFileSync as writeFileSync42 } from "fs";
24734
- import { tmpdir as tmpdir7 } from "os";
24735
- import { join as join66, resolve as resolve16 } from "path";
24879
+ import { tmpdir as tmpdir8 } from "os";
24880
+ import { join as join67, resolve as resolve16 } from "path";
24736
24881
  import chalk203 from "chalk";
24737
24882
 
24738
24883
  // src/commands/screenshot/captureWindowPs1.ts
@@ -24869,7 +25014,7 @@ function buildOutputPath(outputDir, processName) {
24869
25014
  return resolve16(outputDir, `${processName}-${timestamp6}.png`);
24870
25015
  }
24871
25016
  function runPowerShellScript(processName, outputPath) {
24872
- const scriptPath = join66(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
25017
+ const scriptPath = join67(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
24873
25018
  writeFileSync42(scriptPath, captureWindowPs1, "utf8");
24874
25019
  try {
24875
25020
  execSync58(
@@ -25673,8 +25818,9 @@ function decidePrPreview(sessions, waiters, notify2, d) {
25673
25818
  return;
25674
25819
  }
25675
25820
  const commentCount = Array.isArray(d.comments) ? d.comments.length : 0;
25821
+ const screenshotCount = Array.isArray(d.screenshots) ? d.screenshots.length : 0;
25676
25822
  daemonLog(
25677
- `pr-decision received: id=${id} requestId=${requestId} decision=${d.decision} comments=${commentCount}`
25823
+ `pr-decision received: id=${id} requestId=${requestId} decision=${d.decision} comments=${commentCount} screenshots=${screenshotCount}`
25678
25824
  );
25679
25825
  const waiter = waiters.get(id);
25680
25826
  if (waiter)
@@ -25683,7 +25829,8 @@ function decidePrPreview(sessions, waiters, notify2, d) {
25683
25829
  requestId,
25684
25830
  decision: d.decision,
25685
25831
  reason: d.reason,
25686
- comments: d.comments
25832
+ comments: d.comments,
25833
+ screenshots: d.screenshots
25687
25834
  });
25688
25835
  waiters.delete(id);
25689
25836
  session.pendingPrPreview = void 0;
@@ -28469,9 +28616,9 @@ function buildLimitsSegment(rateLimits) {
28469
28616
 
28470
28617
  // src/commands/readGitBranch.ts
28471
28618
  import { readFileSync as readFileSync52, statSync as statSync11 } from "fs";
28472
- import { isAbsolute as isAbsolute2, join as join69, resolve as resolve17 } from "path";
28619
+ import { isAbsolute as isAbsolute2, join as join70, resolve as resolve17 } from "path";
28473
28620
  function resolveGitDir(cwd) {
28474
- const dotGit = join69(cwd, ".git");
28621
+ const dotGit = join70(cwd, ".git");
28475
28622
  let stat2;
28476
28623
  try {
28477
28624
  stat2 = statSync11(dotGit);
@@ -28501,7 +28648,7 @@ function readGitBranch(cwd) {
28501
28648
  }
28502
28649
  let head;
28503
28650
  try {
28504
- head = readFileSync52(join69(gitDir, "HEAD"), "utf8");
28651
+ head = readFileSync52(join70(gitDir, "HEAD"), "utf8");
28505
28652
  } catch {
28506
28653
  return null;
28507
28654
  }