@staff0rd/assist 0.765.0 → 0.766.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.765.0",
9
+ version: "0.766.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -1792,9 +1792,9 @@ var daemonPaths = {
1792
1792
 
1793
1793
  // src/commands/sessions/daemon/connectToDaemon.ts
1794
1794
  function connectToDaemon() {
1795
- return new Promise((resolve27, reject) => {
1795
+ return new Promise((resolve28, reject) => {
1796
1796
  const socket = net.connect(daemonPaths.socket);
1797
- socket.once("connect", () => resolve27(socket));
1797
+ socket.once("connect", () => resolve28(socket));
1798
1798
  socket.once("error", reject);
1799
1799
  });
1800
1800
  }
@@ -2112,7 +2112,7 @@ ${failed3.length} script(s) failed:`);
2112
2112
  }
2113
2113
  }
2114
2114
  function runEntry(entry) {
2115
- return new Promise((resolve27) => {
2115
+ return new Promise((resolve28) => {
2116
2116
  const startTime = Date.now();
2117
2117
  const child = spawnCommand(
2118
2118
  entry.fullCommand,
@@ -2124,7 +2124,7 @@ function runEntry(entry) {
2124
2124
  child.on("close", (code) => {
2125
2125
  const exitCode = code ?? 1;
2126
2126
  flushIfFailed(exitCode, chunks);
2127
- resolve27({
2127
+ resolve28({
2128
2128
  script: entry.name,
2129
2129
  code: exitCode,
2130
2130
  durationMs: Date.now() - startTime
@@ -2941,13 +2941,21 @@ function toChecklist(value) {
2941
2941
  ];
2942
2942
  });
2943
2943
  }
2944
+ function toAttachments(value) {
2945
+ if (!Array.isArray(value)) return void 0;
2946
+ return value.flatMap((entry) => {
2947
+ const { path: path106, alt } = entry ?? {};
2948
+ if (typeof path106 !== "string" || path106 === "") return [];
2949
+ return [{ path: path106, alt: typeof alt === "string" ? alt : "" }];
2950
+ });
2951
+ }
2944
2952
  function toPreviewDecision(msg) {
2945
2953
  if (msg.decision !== "approve" && msg.decision !== "reject") return null;
2946
2954
  return {
2947
2955
  decision: msg.decision,
2948
2956
  reason: msg.reason,
2949
2957
  comments: Array.isArray(msg.comments) ? msg.comments : void 0,
2950
- screenshots: Array.isArray(msg.screenshots) ? msg.screenshots : void 0,
2958
+ screenshots: toAttachments(msg.screenshots),
2951
2959
  body: typeof msg.body === "string" ? msg.body : void 0,
2952
2960
  reviewAfter: msg.reviewAfter === true,
2953
2961
  announceAfter: msg.announceAfter === true,
@@ -2974,7 +2982,7 @@ function parsePreviewDecision(line, requestId) {
2974
2982
 
2975
2983
  // src/commands/sessions/shared/requestPreviewDecision.ts
2976
2984
  function requestPreviewDecision(request) {
2977
- return new Promise((resolve27, reject) => {
2985
+ return new Promise((resolve28, reject) => {
2978
2986
  connectToDaemon().then((socket) => {
2979
2987
  let settled = false;
2980
2988
  const finish2 = (error, decision) => {
@@ -2982,7 +2990,7 @@ function requestPreviewDecision(request) {
2982
2990
  settled = true;
2983
2991
  socket.destroy();
2984
2992
  if (error) reject(error);
2985
- else resolve27(decision);
2993
+ else resolve28(decision);
2986
2994
  };
2987
2995
  readSocketLines(socket, (line) => {
2988
2996
  const incoming = parsePreviewDecision(line, request.requestId);
@@ -7225,8 +7233,8 @@ function spawnInherit(command, args, options2 = {}) {
7225
7233
  env: { ...env, ...options2.env },
7226
7234
  cwd: options2.cwd
7227
7235
  });
7228
- const done2 = new Promise((resolve27, reject) => {
7229
- child.on("close", (code) => resolve27(code ?? 0));
7236
+ const done2 = new Promise((resolve28, reject) => {
7237
+ child.on("close", (code) => resolve28(code ?? 0));
7230
7238
  child.on("error", reject);
7231
7239
  });
7232
7240
  return { child, done: done2 };
@@ -7658,7 +7666,7 @@ Failed to launch Claude for ${context}: ${message3}`)
7658
7666
  // src/commands/sessions/daemon/sendToDaemon.ts
7659
7667
  var WRITE_TIMEOUT_MS = 500;
7660
7668
  function sendToDaemon(message3) {
7661
- return new Promise((resolve27, reject) => {
7669
+ return new Promise((resolve28, reject) => {
7662
7670
  connectToDaemon().then((socket) => {
7663
7671
  const timer = setTimeout(() => {
7664
7672
  socket.destroy();
@@ -7672,7 +7680,7 @@ function sendToDaemon(message3) {
7672
7680
  `, () => {
7673
7681
  clearTimeout(timer);
7674
7682
  socket.end();
7675
- resolve27();
7683
+ resolve28();
7676
7684
  });
7677
7685
  }, reject);
7678
7686
  });
@@ -7681,7 +7689,7 @@ function sendToDaemon(message3) {
7681
7689
  // src/commands/sessions/daemon/sendToDaemonAwaitAck.ts
7682
7690
  var ACK_TIMEOUT_MS = 1e3;
7683
7691
  function sendToDaemonAwaitAck(message3) {
7684
- return new Promise((resolve27, reject) => {
7692
+ return new Promise((resolve28, reject) => {
7685
7693
  connectToDaemon().then((socket) => {
7686
7694
  let settled = false;
7687
7695
  const finish2 = (error) => {
@@ -7690,7 +7698,7 @@ function sendToDaemonAwaitAck(message3) {
7690
7698
  clearTimeout(timer);
7691
7699
  socket.destroy();
7692
7700
  if (error) reject(error);
7693
- else resolve27();
7701
+ else resolve28();
7694
7702
  };
7695
7703
  const timer = setTimeout(
7696
7704
  () => finish2(new Error("timed out awaiting daemon ack")),
@@ -7781,7 +7789,7 @@ async function deliverReliably(sessionId, status2, payload) {
7781
7789
  }
7782
7790
  }
7783
7791
  function sleep(ms) {
7784
- return new Promise((resolve27) => setTimeout(resolve27, ms));
7792
+ return new Promise((resolve28) => setTimeout(resolve28, ms));
7785
7793
  }
7786
7794
  function describeError(error) {
7787
7795
  return error instanceof Error ? error.message : String(error);
@@ -10757,7 +10765,7 @@ function spawnDaemon(reason4) {
10757
10765
  child.unref();
10758
10766
  }
10759
10767
  function delay(ms) {
10760
- return new Promise((resolve27) => setTimeout(resolve27, ms));
10768
+ return new Promise((resolve28) => setTimeout(resolve28, ms));
10761
10769
  }
10762
10770
 
10763
10771
  // src/commands/sessions/daemon/originForCwd.ts
@@ -10799,10 +10807,10 @@ function gitInvocation(cwd, args) {
10799
10807
  }
10800
10808
  function git(cwd, args) {
10801
10809
  const { file, argv, options: options2 } = gitInvocation(cwd, args);
10802
- return new Promise((resolve27, reject) => {
10810
+ return new Promise((resolve28, reject) => {
10803
10811
  execFile2(file, argv, options2, (error, stdout) => {
10804
10812
  if (error) reject(error);
10805
- else resolve27(stdout.toString());
10813
+ else resolve28(stdout.toString());
10806
10814
  });
10807
10815
  });
10808
10816
  }
@@ -11061,7 +11069,7 @@ var defaultDeps = {
11061
11069
  serve: async (args) => {
11062
11070
  await runTailscale(args);
11063
11071
  },
11064
- sleep: (ms) => new Promise((resolve27) => setTimeout(resolve27, ms)),
11072
+ sleep: (ms) => new Promise((resolve28) => setTimeout(resolve28, ms)),
11065
11073
  httpsPort: tailnetHttpsPort
11066
11074
  };
11067
11075
  async function ensureTailscaleServe(port, deps2 = {}) {
@@ -11468,12 +11476,12 @@ async function loadVisibleItems(req) {
11468
11476
 
11469
11477
  // src/commands/backlog/web/parseStatusBody.ts
11470
11478
  function readBody(req) {
11471
- return new Promise((resolve27, reject) => {
11479
+ return new Promise((resolve28, reject) => {
11472
11480
  let body = "";
11473
11481
  req.on("data", (chunk) => {
11474
11482
  body += chunk.toString();
11475
11483
  });
11476
- req.on("end", () => resolve27(body));
11484
+ req.on("end", () => resolve28(body));
11477
11485
  req.on("error", reject);
11478
11486
  });
11479
11487
  }
@@ -13582,11 +13590,11 @@ async function queryNodes() {
13582
13590
  } catch {
13583
13591
  return void 0;
13584
13592
  }
13585
- return new Promise((resolve27) => {
13593
+ return new Promise((resolve28) => {
13586
13594
  const finish2 = (result) => {
13587
13595
  clearTimeout(timer);
13588
13596
  socket.destroy();
13589
- resolve27(result);
13597
+ resolve28(result);
13590
13598
  };
13591
13599
  const timer = setTimeout(() => finish2(void 0), QUERY_TIMEOUT_MS);
13592
13600
  const lines2 = createInterface5({ input: socket });
@@ -13659,8 +13667,8 @@ function subsequenceScore(text17, query) {
13659
13667
  function scoreFilePath(path106, query) {
13660
13668
  const needle = query.trim().toLowerCase();
13661
13669
  if (!needle) return 0;
13662
- const basename31 = path106.slice(path106.lastIndexOf("/") + 1);
13663
- const inBasename = subsequenceScore(basename31, needle);
13670
+ const basename32 = path106.slice(path106.lastIndexOf("/") + 1);
13671
+ const inBasename = subsequenceScore(basename32, needle);
13664
13672
  if (inBasename !== null) return BASENAME_WEIGHT + inBasename;
13665
13673
  return subsequenceScore(path106, needle);
13666
13674
  }
@@ -15078,7 +15086,7 @@ function forwardToPeer(req, res, node, url) {
15078
15086
  const label2 = `link ${node} http: ${req.method} ${url.pathname} trace=${traceId}`;
15079
15087
  const log2 = (outcome) => console.log(`${label2} -> ${outcome} (${Date.now() - started}ms)`);
15080
15088
  const send = url.protocol === "https:" ? httpsRequest : httpRequest;
15081
- return new Promise((resolve27) => {
15089
+ return new Promise((resolve28) => {
15082
15090
  const upstream = send(
15083
15091
  url,
15084
15092
  {
@@ -15090,7 +15098,7 @@ function forwardToPeer(req, res, node, url) {
15090
15098
  [TRACE_HEADER]: traceId
15091
15099
  }
15092
15100
  },
15093
- (peer) => relayPeerResponse(peer, res, url.pathname, log2, resolve27)
15101
+ (peer) => relayPeerResponse(peer, res, url.pathname, log2, resolve28)
15094
15102
  );
15095
15103
  boundUpstream(upstream, res, peerTimeoutFor(url.pathname));
15096
15104
  upstream.on("error", (error) => {
@@ -15100,7 +15108,7 @@ function forwardToPeer(req, res, node, url) {
15100
15108
  respondJson(res, 502, {
15101
15109
  error: `${node} unreachable: ${error.message}`
15102
15110
  });
15103
- resolve27();
15111
+ resolve28();
15104
15112
  });
15105
15113
  req.pipe(upstream);
15106
15114
  });
@@ -15153,64 +15161,74 @@ async function proxyToNode(req, res) {
15153
15161
  return true;
15154
15162
  }
15155
15163
 
15156
- // src/commands/sessions/web/ghAuthToken.ts
15157
- import { execFile as execFile9 } from "child_process";
15158
- import { promisify as promisify9 } from "util";
15159
- var execFileAsync8 = promisify9(execFile9);
15160
- async function ghAuthToken(cwd) {
15161
- const { stdout } = await execFileAsync8("gh", ["auth", "token"], {
15162
- cwd,
15163
- windowsHide: true
15164
- });
15165
- const token = stdout.trim();
15166
- if (!token) throw new Error("gh auth token produced no token");
15167
- return token;
15164
+ // src/commands/sessions/web/previewImage.ts
15165
+ import { createReadStream as createReadStream2 } from "fs";
15166
+ import { stat as stat3 } from "fs/promises";
15167
+
15168
+ // src/shared/isStagedAttachmentPath.ts
15169
+ import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve12, sep } from "path";
15170
+
15171
+ // src/shared/stagedAttachmentsDir.ts
15172
+ import { homedir as homedir15 } from "os";
15173
+ import { join as join38 } from "path";
15174
+ var stagedAttachmentsDir = join38(homedir15(), ".assist", "attachments");
15175
+
15176
+ // src/shared/isStagedAttachmentPath.ts
15177
+ function isStagedAttachmentPath(path106) {
15178
+ const rel = relative3(stagedAttachmentsDir, resolve12(path106));
15179
+ return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute3(rel);
15168
15180
  }
15169
15181
 
15170
- // src/commands/sessions/web/isUserAttachmentUrl.ts
15171
- var USER_ATTACHMENT = /^https:\/\/github\.com\/user-attachments\/assets\/[A-Za-z0-9-]+$/;
15172
- function isUserAttachmentUrl(url) {
15173
- return USER_ATTACHMENT.test(url);
15182
+ // src/commands/sessions/web/attachmentContentType.ts
15183
+ import { extname } from "path";
15184
+
15185
+ // src/commands/sessions/web/attachmentMimeTypes.ts
15186
+ var attachmentMimeTypes = {
15187
+ "image/png": "png",
15188
+ "image/jpeg": "jpg",
15189
+ "image/gif": "gif",
15190
+ "image/webp": "webp",
15191
+ "image/svg+xml": "svg",
15192
+ "image/bmp": "bmp",
15193
+ "image/avif": "avif",
15194
+ "video/mp4": "mp4",
15195
+ "video/webm": "webm",
15196
+ "video/quicktime": "mov",
15197
+ "video/ogg": "ogv"
15198
+ };
15199
+
15200
+ // src/commands/sessions/web/attachmentContentType.ts
15201
+ function attachmentContentType(path106) {
15202
+ const ext = extname(path106).replace(/^\./, "").toLowerCase();
15203
+ const match = Object.entries(attachmentMimeTypes).find(([, e]) => e === ext);
15204
+ return match?.[0] ?? "application/octet-stream";
15174
15205
  }
15175
15206
 
15176
15207
  // src/commands/sessions/web/previewImage.ts
15177
15208
  async function previewImage(req, res) {
15178
15209
  const url = new URL(req.url ?? "/", "http://localhost");
15179
- const target = url.searchParams.get("url") ?? "";
15180
- if (!isUserAttachmentUrl(target)) {
15181
- respondJson(res, 400, { error: "Not a GitHub attachment url." });
15182
- return;
15183
- }
15184
- let token;
15185
- try {
15186
- token = await ghAuthToken(url.searchParams.get("cwd") ?? void 0);
15187
- } catch {
15188
- respondJson(res, 502, { error: "Could not read a GitHub token." });
15189
- return;
15190
- }
15191
- let location;
15192
- try {
15193
- const upstream = await fetch(target, {
15194
- headers: { Authorization: `Bearer ${token}` },
15195
- redirect: "manual"
15196
- });
15197
- location = upstream.headers.get("location");
15198
- } catch {
15199
- respondJson(res, 502, { error: "Could not reach GitHub." });
15210
+ const path106 = url.searchParams.get("path") ?? "";
15211
+ if (!isStagedAttachmentPath(path106)) {
15212
+ respondJson(res, 400, { error: "Not a staged attachment." });
15200
15213
  return;
15201
15214
  }
15202
- if (!location) {
15203
- respondJson(res, 404, { error: "Attachment is no longer available." });
15215
+ const info = await stat3(path106).catch(() => null);
15216
+ if (!info?.isFile()) {
15217
+ respondJson(res, 404, { error: "Attachment is no longer staged." });
15204
15218
  return;
15205
15219
  }
15206
- res.writeHead(302, { Location: location, "Cache-Control": "no-store" });
15207
- res.end();
15220
+ res.writeHead(200, {
15221
+ "Content-Type": attachmentContentType(path106),
15222
+ "Content-Length": info.size,
15223
+ "Cache-Control": "no-store"
15224
+ });
15225
+ createReadStream2(path106).pipe(res);
15208
15226
  }
15209
15227
 
15210
15228
  // src/commands/sessions/web/prStatus.ts
15211
- import { execFile as execFile10 } from "child_process";
15212
- import { promisify as promisify10 } from "util";
15213
- var execFileAsync9 = promisify10(execFile10);
15229
+ import { execFile as execFile9 } from "child_process";
15230
+ import { promisify as promisify9 } from "util";
15231
+ var execFileAsync8 = promisify9(execFile9);
15214
15232
  function toPrSummary(parsed) {
15215
15233
  if (typeof parsed.number !== "number") return null;
15216
15234
  return {
@@ -15240,7 +15258,7 @@ var getOpenPrForBranch = createCachedGhJson(
15240
15258
  );
15241
15259
  async function getCurrentBranch(cwd) {
15242
15260
  try {
15243
- const { stdout } = await execFileAsync9(
15261
+ const { stdout } = await execFileAsync8(
15244
15262
  "git",
15245
15263
  ["rev-parse", "--abbrev-ref", "HEAD"],
15246
15264
  { encoding: "utf8", windowsHide: true, cwd }
@@ -15680,17 +15698,17 @@ async function stopDaemon() {
15680
15698
  }
15681
15699
  }
15682
15700
  function closedBeforeTimeout(socket) {
15683
- return new Promise((resolve27) => {
15701
+ return new Promise((resolve28) => {
15684
15702
  const timer = setTimeout(() => {
15685
15703
  socket.destroy();
15686
- resolve27(false);
15704
+ resolve28(false);
15687
15705
  }, STOP_TIMEOUT_MS);
15688
15706
  socket.resume();
15689
15707
  socket.on("error", () => {
15690
15708
  });
15691
15709
  socket.once("close", () => {
15692
15710
  clearTimeout(timer);
15693
- resolve27(true);
15711
+ resolve28(true);
15694
15712
  });
15695
15713
  });
15696
15714
  }
@@ -15748,8 +15766,8 @@ async function restartWeb(req, res, deps2 = {}) {
15748
15766
  return;
15749
15767
  }
15750
15768
  console.log(`restart ${target} ${linkedRequester(req)}`);
15751
- await new Promise((resolve27) => {
15752
- res.once("finish", resolve27);
15769
+ await new Promise((resolve28) => {
15770
+ res.once("finish", resolve28);
15753
15771
  respondJson(res, 200, { ok: true });
15754
15772
  });
15755
15773
  await performRestart(target, deps2);
@@ -15765,7 +15783,7 @@ async function performRestart(target, deps2 = {}) {
15765
15783
  }
15766
15784
 
15767
15785
  // src/commands/sessions/web/revertDiffFile.ts
15768
- import { relative as relative3 } from "path";
15786
+ import { relative as relative4 } from "path";
15769
15787
 
15770
15788
  // src/commands/sessions/web/revertPathChanges.ts
15771
15789
  async function isTracked(cwd, path106) {
@@ -15796,7 +15814,7 @@ async function revertPathChanges(cwd, path106) {
15796
15814
  async function revertDiffFile(req, res) {
15797
15815
  const resolved = getFileTarget(req, res);
15798
15816
  if (!resolved) return;
15799
- const path106 = relative3(repoRoot(resolved.cwd), resolved.target);
15817
+ const path106 = relative4(repoRoot(resolved.cwd), resolved.target);
15800
15818
  try {
15801
15819
  await revertPathChanges(resolved.cwd, path106);
15802
15820
  respondJson(res, 200, { reverted: path106 });
@@ -15814,13 +15832,13 @@ import { existsSync as existsSync39 } from "fs";
15814
15832
  // src/commands/run/resolveCommand.ts
15815
15833
  import { execFileSync as execFileSync4 } from "child_process";
15816
15834
  import { existsSync as existsSync38 } from "fs";
15817
- import { dirname as dirname23, join as join38, resolve as resolve12 } from "path";
15835
+ import { dirname as dirname23, join as join39, resolve as resolve13 } from "path";
15818
15836
  function resolveCommand(command) {
15819
15837
  if (process.platform !== "win32" || command !== "bash") return command;
15820
15838
  try {
15821
15839
  const gitPath = execFileSync4("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
15822
- const gitRoot = resolve12(dirname23(gitPath), "..");
15823
- const gitBash = join38(gitRoot, "bin", "bash.exe");
15840
+ const gitRoot = resolve13(dirname23(gitPath), "..");
15841
+ const gitBash = join39(gitRoot, "bin", "bash.exe");
15824
15842
  if (existsSync38(gitBash)) return gitBash;
15825
15843
  } catch {
15826
15844
  return command;
@@ -15885,15 +15903,15 @@ async function selfUpdate(req, res, deps2 = {}) {
15885
15903
  return;
15886
15904
  }
15887
15905
  console.log("self-update: updated; restarting daemon and web server");
15888
- await new Promise((resolve27) => {
15889
- res.once("finish", resolve27);
15906
+ await new Promise((resolve28) => {
15907
+ res.once("finish", resolve28);
15890
15908
  respondJson(res, 200, { ok: true });
15891
15909
  });
15892
15910
  await performRestart("both", restartDeps);
15893
15911
  }
15894
15912
 
15895
15913
  // src/commands/sessions/web/revertDiffPaths.ts
15896
- import { relative as relative4 } from "path";
15914
+ import { relative as relative5 } from "path";
15897
15915
  function requestedPaths(body) {
15898
15916
  const paths = body.paths;
15899
15917
  if (!Array.isArray(paths)) return null;
@@ -15923,7 +15941,7 @@ async function revertDiffPaths(req, res) {
15923
15941
  failed3.push({ path: path106, error: "Path outside cwd" });
15924
15942
  continue;
15925
15943
  }
15926
- const relativePath = relative4(root2, target);
15944
+ const relativePath = relative5(root2, target);
15927
15945
  try {
15928
15946
  await revertPathChanges(cwd, relativePath);
15929
15947
  reverted.push(relativePath);
@@ -15987,14 +16005,14 @@ function linkWebSocketUrl(url) {
15987
16005
  return target.toString();
15988
16006
  }
15989
16007
  function connectLinkWebSocket(url, handlers) {
15990
- return new Promise((resolve27, reject) => {
16008
+ return new Promise((resolve28, reject) => {
15991
16009
  const ws = new WebSocket(linkWebSocketUrl(url), {
15992
16010
  handshakeTimeout: HANDSHAKE_TIMEOUT_MS
15993
16011
  });
15994
16012
  let open = false;
15995
16013
  ws.on("open", () => {
15996
16014
  open = true;
15997
- resolve27({
16015
+ resolve28({
15998
16016
  send: (line) => {
15999
16017
  if (ws.readyState !== WebSocket.OPEN) return false;
16000
16018
  ws.send(line);
@@ -16020,8 +16038,8 @@ var HELLO_TIMEOUT_MS = 5e3;
16020
16038
  async function probePeerHello(url) {
16021
16039
  let settle = () => {
16022
16040
  };
16023
- const reply2 = new Promise((resolve27) => {
16024
- settle = resolve27;
16041
+ const reply2 = new Promise((resolve28) => {
16042
+ settle = resolve28;
16025
16043
  });
16026
16044
  const socket = await connectLinkWebSocket(url, {
16027
16045
  onLine: (line) => {
@@ -16900,47 +16918,6 @@ function unsetConfig(req, res) {
16900
16918
  });
16901
16919
  }
16902
16920
 
16903
- // src/commands/sessions/web/uploadPrImage.ts
16904
- import { rm } from "fs/promises";
16905
-
16906
- // src/commands/sessions/web/runGhImage.ts
16907
- import { execFile as execFile11 } from "child_process";
16908
- import { promisify as promisify11 } from "util";
16909
- var execFileAsync10 = promisify11(execFile11);
16910
- var GhImageUnavailableError = class extends Error {
16911
- name = "GhImageUnavailableError";
16912
- };
16913
- var GH_IMAGE_INSTALL_COMMAND = "gh extension install drogers0/gh-image";
16914
- var INSTALL_HINT = `Install the gh-image extension: ${GH_IMAGE_INSTALL_COMMAND}`;
16915
- async function runGhImage(filePath, cwd) {
16916
- let stdout;
16917
- try {
16918
- ({ stdout } = await execFileAsync10("gh", ["image", filePath], {
16919
- cwd,
16920
- windowsHide: true,
16921
- maxBuffer: 10 * 1024 * 1024
16922
- }));
16923
- } catch (error) {
16924
- const err = error;
16925
- if (err.code === "ENOENT")
16926
- throw new GhImageUnavailableError(
16927
- `The GitHub CLI (\`gh\`) is not installed. ${INSTALL_HINT}`
16928
- );
16929
- const stderr = err.stderr ?? "";
16930
- if (/unknown command "image"/i.test(stderr) || /extension.*not found/i.test(stderr))
16931
- throw new GhImageUnavailableError(
16932
- `The \`gh-image\` extension is not installed. ${INSTALL_HINT}`
16933
- );
16934
- throw new Error(
16935
- `gh image failed: ${stderr.trim() || err.message || "unknown error"}`
16936
- );
16937
- }
16938
- const lines2 = stdout.split("\n").map((line) => line.trim()).filter(Boolean);
16939
- const markdown = lines2.find((line) => /^!\[.*]\(.+\)$/.test(line)) ?? lines2.find((line) => /^https?:\/\/\S+$/.test(line)) ?? lines2.find((line) => line.includes("http")) ?? lines2[0];
16940
- if (!markdown) throw new Error("gh image produced no output");
16941
- return markdown;
16942
- }
16943
-
16944
16921
  // src/commands/sessions/web/readRequestBuffer.ts
16945
16922
  async function readRequestBuffer(req, limit) {
16946
16923
  const chunks = [];
@@ -16960,67 +16937,50 @@ async function readRequestBuffer(req, limit) {
16960
16937
  return overLimit ? null : Buffer.concat(chunks);
16961
16938
  }
16962
16939
 
16963
- // src/commands/sessions/web/uploadSizeLimit.ts
16964
- var MAX_IMAGE_BYTES = 25 * 1024 * 1024;
16965
- var MAX_VIDEO_BYTES = 100 * 1024 * 1024;
16966
- function uploadSizeLimit(contentType) {
16967
- const mime = contentType.split(";")[0].trim().toLowerCase();
16968
- return mime.startsWith("video/") ? {
16969
- maxBytes: MAX_VIDEO_BYTES,
16970
- tooLargeMessage: "Video too large (max 100MB)."
16971
- } : {
16972
- maxBytes: MAX_IMAGE_BYTES,
16973
- tooLargeMessage: "Image too large (max 25MB)."
16974
- };
16975
- }
16976
-
16977
- // src/commands/sessions/web/writeTempImage.ts
16978
- import { mkdtemp, writeFile as writeFile2 } from "fs/promises";
16979
- import { tmpdir as tmpdir2 } from "os";
16980
- import { extname, join as join39 } from "path";
16981
- var EXT_BY_MIME = {
16982
- "image/png": "png",
16983
- "image/jpeg": "jpg",
16984
- "image/gif": "gif",
16985
- "image/webp": "webp",
16986
- "image/svg+xml": "svg",
16987
- "image/bmp": "bmp",
16988
- "image/avif": "avif",
16989
- "video/mp4": "mp4",
16990
- "video/webm": "webm",
16991
- "video/quicktime": "mov",
16992
- "video/ogg": "ogv"
16993
- };
16940
+ // src/commands/sessions/web/stageAttachment.ts
16941
+ import { mkdir as mkdir4, mkdtemp, writeFile as writeFile2 } from "fs/promises";
16942
+ import { extname as extname2, join as join40 } from "path";
16994
16943
  function extensionFromMime(contentType) {
16995
16944
  const mime = contentType.split(";")[0].trim().toLowerCase();
16996
- const known = EXT_BY_MIME[mime];
16945
+ const known = attachmentMimeTypes[mime];
16997
16946
  if (known) return known;
16998
16947
  const subtype = mime.split("/")[1]?.replace(/^x-/, "").replace(/\+.*$/, "");
16999
16948
  return subtype && /^[a-z0-9]+$/.test(subtype) ? subtype : void 0;
17000
16949
  }
17001
16950
  function pickExtension(name, contentType) {
17002
- const fromName = extname(name).replace(/^\./, "").toLowerCase();
17003
- if (fromName) return fromName;
16951
+ const fromName = extname2(name).replace(/^\./, "").toLowerCase();
16952
+ if (/^[a-z0-9]+$/.test(fromName)) return fromName;
17004
16953
  return extensionFromMime(contentType) ?? "png";
17005
16954
  }
17006
16955
  function safeBaseName(name) {
17007
16956
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-");
17008
16957
  return base.replace(/^-+|-+$/g, "").slice(0, 60) || "screenshot";
17009
16958
  }
17010
- async function writeTempImage(name, contentType, body) {
17011
- const dir = await mkdtemp(join39(tmpdir2(), "assist-pr-img-"));
17012
- const filePath = join39(
17013
- dir,
17014
- `${safeBaseName(name)}.${pickExtension(name, contentType)}`
17015
- );
16959
+ async function stageAttachment(name, contentType, body) {
16960
+ await mkdir4(stagedAttachmentsDir, { recursive: true });
16961
+ const dir = await mkdtemp(join40(stagedAttachmentsDir, "upload-"));
16962
+ const alt = safeBaseName(name);
16963
+ const filePath = join40(dir, `${alt}.${pickExtension(name, contentType)}`);
17016
16964
  await writeFile2(filePath, body);
17017
- return { dir, filePath };
16965
+ return { dir, filePath, alt };
16966
+ }
16967
+
16968
+ // src/commands/sessions/web/uploadSizeLimit.ts
16969
+ var MAX_IMAGE_BYTES = 25 * 1024 * 1024;
16970
+ var MAX_VIDEO_BYTES = 100 * 1024 * 1024;
16971
+ function uploadSizeLimit(contentType) {
16972
+ const mime = contentType.split(";")[0].trim().toLowerCase();
16973
+ return mime.startsWith("video/") ? {
16974
+ maxBytes: MAX_VIDEO_BYTES,
16975
+ tooLargeMessage: "Video too large (max 100MB)."
16976
+ } : {
16977
+ maxBytes: MAX_IMAGE_BYTES,
16978
+ tooLargeMessage: "Image too large (max 25MB)."
16979
+ };
17018
16980
  }
17019
16981
 
17020
16982
  // src/commands/sessions/web/uploadPrImage.ts
17021
16983
  async function uploadPrImage(req, res) {
17022
- const cwd = getCwdParam(req, res);
17023
- if (!cwd) return;
17024
16984
  const url = new URL(req.url ?? "/", "http://localhost");
17025
16985
  const name = url.searchParams.get("name") ?? "";
17026
16986
  const contentType = req.headers["content-type"] ?? "";
@@ -17034,41 +16994,30 @@ async function uploadPrImage(req, res) {
17034
16994
  respondJson(res, 400, { error: "Empty upload." });
17035
16995
  return;
17036
16996
  }
17037
- const { dir, filePath } = await writeTempImage(name, contentType, body);
17038
16997
  try {
17039
- const markdown = await runGhImage(filePath, cwd);
17040
- respondJson(res, 200, { markdown });
16998
+ const { filePath, alt } = await stageAttachment(name, contentType, body);
16999
+ respondJson(res, 200, { path: filePath, alt });
17041
17000
  } catch (error) {
17042
- if (error instanceof GhImageUnavailableError) {
17043
- respondJson(res, 501, {
17044
- error: error.message,
17045
- command: GH_IMAGE_INSTALL_COMMAND
17046
- });
17047
- } else {
17048
- respondJson(res, 500, {
17049
- error: error instanceof Error ? error.message : "Upload failed"
17050
- });
17051
- }
17052
- } finally {
17053
- await rm(dir, { recursive: true, force: true }).catch(() => {
17001
+ respondJson(res, 500, {
17002
+ error: error instanceof Error ? error.message : "Staging failed"
17054
17003
  });
17055
17004
  }
17056
17005
  }
17057
17006
 
17058
17007
  // src/commands/sessions/web/writeFileContent.ts
17059
- import { readFile as readFile3, stat as stat3, writeFile as writeFile3 } from "fs/promises";
17008
+ import { readFile as readFile3, stat as stat4, writeFile as writeFile3 } from "fs/promises";
17060
17009
 
17061
17010
  // src/commands/sessions/web/formatWithOxfmt.ts
17062
- import { execFile as execFile12 } from "child_process";
17011
+ import { execFile as execFile10 } from "child_process";
17063
17012
  import { existsSync as existsSync40 } from "fs";
17064
- import { dirname as dirname24, join as join40 } from "path";
17065
- import { promisify as promisify12 } from "util";
17066
- var execFileAsync11 = promisify12(execFile12);
17013
+ import { dirname as dirname24, join as join41 } from "path";
17014
+ import { promisify as promisify10 } from "util";
17015
+ var execFileAsync9 = promisify10(execFile10);
17067
17016
  var TIMEOUT_MS = 15e3;
17068
17017
  function findOxfmtScript(root2) {
17069
17018
  let dir = root2;
17070
17019
  for (; ; ) {
17071
- const candidate = join40(dir, "node_modules", "oxfmt", "bin", "oxfmt");
17020
+ const candidate = join41(dir, "node_modules", "oxfmt", "bin", "oxfmt");
17072
17021
  if (existsSync40(candidate)) return candidate;
17073
17022
  const parent = dirname24(dir);
17074
17023
  if (parent === dir) return void 0;
@@ -17078,7 +17027,7 @@ function findOxfmtScript(root2) {
17078
17027
  async function formatWithOxfmt(target, root2) {
17079
17028
  const script = findOxfmtScript(root2);
17080
17029
  if (!script) return;
17081
- await execFileAsync11(process.execPath, [script, target], {
17030
+ await execFileAsync9(process.execPath, [script, target], {
17082
17031
  cwd: root2,
17083
17032
  windowsHide: true,
17084
17033
  timeout: TIMEOUT_MS
@@ -17110,7 +17059,7 @@ async function getFileWriteBody(req, res) {
17110
17059
  var STALE_MESSAGE = "The file changed on disk since it was opened";
17111
17060
  async function currentMtimeMs(target) {
17112
17061
  try {
17113
- return (await stat3(target)).mtimeMs;
17062
+ return (await stat4(target)).mtimeMs;
17114
17063
  } catch {
17115
17064
  return null;
17116
17065
  }
@@ -17915,7 +17864,7 @@ import { basename as basename12 } from "path";
17915
17864
  import { parse } from "shell-quote";
17916
17865
 
17917
17866
  // src/shared/consumeRedirect.ts
17918
- import { tmpdir as tmpdir3 } from "os";
17867
+ import { tmpdir as tmpdir2 } from "os";
17919
17868
 
17920
17869
  // src/shared/isRedirectTargetAllowed.ts
17921
17870
  function isRedirectTargetAllowed(target, tmp) {
@@ -17943,7 +17892,7 @@ function consumeRedirect(tokens, opIndex, current) {
17943
17892
  if (typeof target !== "string") {
17944
17893
  return { ok: false, error: "unable to parse" };
17945
17894
  }
17946
- if (!isRedirectTargetAllowed(target, tmpdir3())) {
17895
+ if (!isRedirectTargetAllowed(target, tmpdir2())) {
17947
17896
  return {
17948
17897
  ok: false,
17949
17898
  error: `redirect target '${target}' is outside the OS temp directory`
@@ -18485,7 +18434,7 @@ function findTruncatedReadDenyRaw(rawCommand) {
18485
18434
  }
18486
18435
 
18487
18436
  // src/shared/isApprovedRead.ts
18488
- import { resolve as resolve14, sep } from "path";
18437
+ import { resolve as resolve15, sep as sep2 } from "path";
18489
18438
 
18490
18439
  // src/shared/appliesFixStructure.ts
18491
18440
  var APPLY_RE = /^assist\s+github\s+issue\s+fix-structure\b.*\s--apply\b/;
@@ -18539,7 +18488,7 @@ function extractGraphqlQuery(args) {
18539
18488
 
18540
18489
  // src/shared/loadCliReads.ts
18541
18490
  import { existsSync as existsSync41, readFileSync as readFileSync26, writeFileSync as writeFileSync22 } from "fs";
18542
- import { dirname as dirname25, resolve as resolve13 } from "path";
18491
+ import { dirname as dirname25, resolve as resolve14 } from "path";
18543
18492
  import { fileURLToPath as fileURLToPath5 } from "url";
18544
18493
  var __filename3 = fileURLToPath5(import.meta.url);
18545
18494
  var __dirname4 = dirname25(__filename3);
@@ -18554,13 +18503,13 @@ var cachedReads;
18554
18503
  var cachedWrites;
18555
18504
  function getCliReadsLines() {
18556
18505
  if (!cachedReads) {
18557
- cachedReads = readLines(resolve13(packageRoot(), "allowed.cli-reads"));
18506
+ cachedReads = readLines(resolve14(packageRoot(), "allowed.cli-reads"));
18558
18507
  }
18559
18508
  return cachedReads;
18560
18509
  }
18561
18510
  function getCliWritesLines() {
18562
18511
  if (!cachedWrites) {
18563
- cachedWrites = readLines(resolve13(packageRoot(), "allowed.cli-writes"));
18512
+ cachedWrites = readLines(resolve14(packageRoot(), "allowed.cli-writes"));
18564
18513
  }
18565
18514
  return cachedWrites;
18566
18515
  }
@@ -18569,7 +18518,7 @@ function loadCliReads() {
18569
18518
  }
18570
18519
  function saveCliReads(commands) {
18571
18520
  writeFileSync22(
18572
- resolve13(packageRoot(), "allowed.cli-reads"),
18521
+ resolve14(packageRoot(), "allowed.cli-reads"),
18573
18522
  `${commands.join("\n")}
18574
18523
  `
18575
18524
  );
@@ -18595,13 +18544,13 @@ function findCliWrite(command) {
18595
18544
 
18596
18545
  // src/shared/readSettingsPerms.ts
18597
18546
  import { existsSync as existsSync42, readFileSync as readFileSync27 } from "fs";
18598
- import { homedir as homedir15 } from "os";
18599
- import { join as join41 } from "path";
18547
+ import { homedir as homedir16 } from "os";
18548
+ import { join as join42 } from "path";
18600
18549
  function readSettingsPerms(key) {
18601
18550
  const paths = [
18602
- join41(homedir15(), ".claude", "settings.json"),
18603
- join41(process.cwd(), ".claude", "settings.json"),
18604
- join41(process.cwd(), ".claude", "settings.local.json")
18551
+ join42(homedir16(), ".claude", "settings.json"),
18552
+ join42(process.cwd(), ".claude", "settings.json"),
18553
+ join42(process.cwd(), ".claude", "settings.local.json")
18605
18554
  ];
18606
18555
  const entries = [];
18607
18556
  for (const p of paths) {
@@ -18707,20 +18656,20 @@ function isCdToCwd(command) {
18707
18656
  const parts = command.split(/\s+/);
18708
18657
  if (parts[0] !== "cd" || parts.length > 2) return false;
18709
18658
  if (parts.length === 1) return false;
18710
- const resolved = resolve14(normalizeMsysPath(parts[1]));
18711
- return resolved === resolve14(process.cwd());
18659
+ const resolved = resolve15(normalizeMsysPath(parts[1]));
18660
+ return resolved === resolve15(process.cwd());
18712
18661
  }
18713
18662
  function isCdToReadAllowedDir(command) {
18714
18663
  const parts = command.split(/\s+/);
18715
18664
  if (parts[0] !== "cd" || parts.length !== 2) return void 0;
18716
- const target = resolve14(normalizeMsysPath(parts[1]));
18665
+ const target = resolve15(normalizeMsysPath(parts[1]));
18717
18666
  for (const entry of readSettingsPerms("allow")) {
18718
18667
  const m = entry.match(READ_RE);
18719
18668
  if (!m) continue;
18720
18669
  const base = globBaseDir(m[1]);
18721
18670
  if (!base) continue;
18722
- const resolved = resolve14(normalizeMsysPath(base));
18723
- if (target === resolved || target.startsWith(resolved + sep)) {
18671
+ const resolved = resolve15(normalizeMsysPath(base));
18672
+ if (target === resolved || target.startsWith(resolved + sep2)) {
18724
18673
  return `cd to Read-allowed directory: ${entry}`;
18725
18674
  }
18726
18675
  }
@@ -18824,12 +18773,12 @@ function decideCommand(toolName, rawCommand) {
18824
18773
 
18825
18774
  // src/commands/cliHook/logDeniedToolCall.ts
18826
18775
  import { mkdirSync as mkdirSync12 } from "fs";
18827
- import { homedir as homedir16 } from "os";
18828
- import { join as join42 } from "path";
18776
+ import { homedir as homedir17 } from "os";
18777
+ import { join as join43 } from "path";
18829
18778
  import Database from "better-sqlite3";
18830
18779
  var _db;
18831
18780
  function getDbDir() {
18832
- return join42(homedir16(), ".assist");
18781
+ return join43(homedir17(), ".assist");
18833
18782
  }
18834
18783
  function initSchema(db) {
18835
18784
  db.exec(`
@@ -18848,7 +18797,7 @@ function openPromptsDb(dir) {
18848
18797
  if (_db) return _db;
18849
18798
  const dbDir = dir ?? getDbDir();
18850
18799
  mkdirSync12(dbDir, { recursive: true });
18851
- const db = new Database(join42(dbDir, "assist.db"));
18800
+ const db = new Database(join43(dbDir, "assist.db"));
18852
18801
  db.pragma("journal_mode = WAL");
18853
18802
  initSchema(db);
18854
18803
  _db = db;
@@ -18968,8 +18917,8 @@ ${reasons.join("\n")}`);
18968
18917
 
18969
18918
  // src/commands/permitCliReads.ts
18970
18919
  import { existsSync as existsSync43, mkdirSync as mkdirSync13, readFileSync as readFileSync28, writeFileSync as writeFileSync23 } from "fs";
18971
- import { homedir as homedir17 } from "os";
18972
- import { join as join43 } from "path";
18920
+ import { homedir as homedir18 } from "os";
18921
+ import { join as join44 } from "path";
18973
18922
 
18974
18923
  // src/commands/permitCliReads/assertCliExists.ts
18975
18924
  function assertCliExists(cli) {
@@ -19060,12 +19009,12 @@ function hasSubcommands(helpText) {
19060
19009
  // src/commands/permitCliReads/runHelp.ts
19061
19010
  import { exec as exec2 } from "child_process";
19062
19011
  function runHelp(args) {
19063
- return new Promise((resolve27) => {
19012
+ return new Promise((resolve28) => {
19064
19013
  exec2(
19065
19014
  `${args.join(" ")} --help`,
19066
19015
  { encoding: "utf8", timeout: 3e4 },
19067
19016
  (_err, stdout, stderr) => {
19068
- resolve27(stdout || stderr || "");
19017
+ resolve28(stdout || stderr || "");
19069
19018
  }
19070
19019
  );
19071
19020
  });
@@ -19232,7 +19181,7 @@ function updateSettings(cli, commands) {
19232
19181
  // src/commands/permitCliReads.ts
19233
19182
  function logPath(cli) {
19234
19183
  const safeName = cli.replace(/\s+/g, "-");
19235
- return join43(homedir17(), ".assist", `cli-discover-${safeName}.log`);
19184
+ return join44(homedir18(), ".assist", `cli-discover-${safeName}.log`);
19236
19185
  }
19237
19186
  function readCache(cli) {
19238
19187
  const path106 = logPath(cli);
@@ -19240,7 +19189,7 @@ function readCache(cli) {
19240
19189
  return readFileSync28(path106, "utf8");
19241
19190
  }
19242
19191
  function writeCache(cli, output) {
19243
- const dir = join43(homedir17(), ".assist");
19192
+ const dir = join44(homedir18(), ".assist");
19244
19193
  mkdirSync13(dir, { recursive: true });
19245
19194
  writeFileSync23(logPath(cli), output);
19246
19195
  }
@@ -19404,18 +19353,18 @@ function isHashCommentFile(filePath) {
19404
19353
  }
19405
19354
 
19406
19355
  // src/commands/codeComment/getRestrictedDir.ts
19407
- import { homedir as homedir18 } from "os";
19408
- import { join as join44 } from "path";
19356
+ import { homedir as homedir19 } from "os";
19357
+ import { join as join45 } from "path";
19409
19358
  function getRestrictedDir() {
19410
- return join44(homedir18(), ".assist", "restricted");
19359
+ return join45(homedir19(), ".assist", "restricted");
19411
19360
  }
19412
19361
  function getPinStatePath(pin2) {
19413
- return join44(getRestrictedDir(), `code-comment-${pin2}.json`);
19362
+ return join45(getRestrictedDir(), `code-comment-${pin2}.json`);
19414
19363
  }
19415
19364
 
19416
19365
  // src/commands/codeComment/sweepRestrictedDir.ts
19417
19366
  import { readdirSync as readdirSync5, statSync as statSync7, unlinkSync as unlinkSync7 } from "fs";
19418
- import { join as join45 } from "path";
19367
+ import { join as join46 } from "path";
19419
19368
  var STALE_AFTER_MS = 30 * 60 * 1e3;
19420
19369
  function sweepRestrictedDir(dir = getRestrictedDir()) {
19421
19370
  let entries;
@@ -19426,7 +19375,7 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
19426
19375
  }
19427
19376
  const cutoff = Date.now() - STALE_AFTER_MS;
19428
19377
  for (const entry of entries) {
19429
- const path106 = join45(dir, entry);
19378
+ const path106 = join46(dir, entry);
19430
19379
  try {
19431
19380
  if (statSync7(path106).mtimeMs < cutoff) unlinkSync7(path106);
19432
19381
  } catch {
@@ -21080,18 +21029,18 @@ import chalk137 from "chalk";
21080
21029
 
21081
21030
  // src/commands/criteriaExtension/criteriaExtensionDir.ts
21082
21031
  import { existsSync as existsSync46 } from "fs";
21083
- import { dirname as dirname26, join as join46 } from "path";
21032
+ import { dirname as dirname26, join as join47 } from "path";
21084
21033
  import { fileURLToPath as fileURLToPath6 } from "url";
21085
21034
  var moduleDir = dirname26(fileURLToPath6(import.meta.url));
21086
21035
  function criteriaExtensionDir() {
21087
- const bundled = join46(
21036
+ const bundled = join47(
21088
21037
  moduleDir,
21089
21038
  "commands",
21090
21039
  "criteriaExtension",
21091
21040
  "criteria-extension"
21092
21041
  );
21093
21042
  if (existsSync46(bundled)) return bundled;
21094
- return join46(moduleDir, "..", "..", "..", "criteria-extension");
21043
+ return join47(moduleDir, "..", "..", "..", "criteria-extension");
21095
21044
  }
21096
21045
 
21097
21046
  // src/commands/criteriaExtension/criteriaExtension.ts
@@ -21118,17 +21067,17 @@ async function criteriaExtension() {
21118
21067
  }
21119
21068
 
21120
21069
  // src/commands/criteriaExtension/signCriteriaExtension.ts
21121
- import { rm as rm3 } from "fs/promises";
21122
- import { homedir as homedir19, tmpdir as tmpdir4 } from "os";
21123
- import { join as join52 } from "path";
21070
+ import { rm as rm2 } from "fs/promises";
21071
+ import { homedir as homedir20, tmpdir as tmpdir3 } from "os";
21072
+ import { join as join53 } from "path";
21124
21073
  import chalk139 from "chalk";
21125
21074
 
21126
21075
  // src/commands/criteriaExtension/copySignedXpi.ts
21127
21076
  import { copyFile } from "fs/promises";
21128
- import { join as join47 } from "path";
21077
+ import { join as join48 } from "path";
21129
21078
  var SIGNED_XPI_NAME = "criteria-extension.xpi";
21130
21079
  async function copySignedXpi(xpi, dir) {
21131
- const fixed2 = join47(dir, SIGNED_XPI_NAME);
21080
+ const fixed2 = join48(dir, SIGNED_XPI_NAME);
21132
21081
  if (fixed2 === xpi) return fixed2;
21133
21082
  await copyFile(xpi, fixed2);
21134
21083
  return fixed2;
@@ -21137,11 +21086,11 @@ async function copySignedXpi(xpi, dir) {
21137
21086
  // src/commands/criteriaExtension/findSignedXpi.ts
21138
21087
  import { existsSync as existsSync47 } from "fs";
21139
21088
  import { readdir } from "fs/promises";
21140
- import { join as join48 } from "path";
21089
+ import { join as join49 } from "path";
21141
21090
  async function findSignedXpi(dir) {
21142
21091
  if (!existsSync47(dir)) return null;
21143
21092
  const name = (await readdir(dir)).find((entry) => entry.endsWith(".xpi"));
21144
- return name ? join48(dir, name) : null;
21093
+ return name ? join49(dir, name) : null;
21145
21094
  }
21146
21095
 
21147
21096
  // src/commands/criteriaExtension/signedAddonInstallPath.ts
@@ -21164,10 +21113,10 @@ async function signedAddonInstallPath(xpi) {
21164
21113
 
21165
21114
  // src/commands/criteriaExtension/signPreflightProblem.ts
21166
21115
  import { existsSync as existsSync48 } from "fs";
21167
- import { join as join49 } from "path";
21116
+ import { join as join50 } from "path";
21168
21117
  var KEY_URL = "https://addons.mozilla.org/en-US/developers/addon/api/key/";
21169
21118
  function signPreflightProblem(source) {
21170
- if (!existsSync48(join49(source, "content.js")))
21119
+ if (!existsSync48(join50(source, "content.js")))
21171
21120
  return {
21172
21121
  message: `no content.js in ${source}`,
21173
21122
  hint: "run npm run build to bundle the content script"
@@ -21181,8 +21130,8 @@ function signPreflightProblem(source) {
21181
21130
  }
21182
21131
 
21183
21132
  // src/commands/criteriaExtension/stageCriteriaExtension.ts
21184
- import { cp as cp3, mkdir as mkdir4, readFile as readFile4, rm as rm2, writeFile as writeFile4 } from "fs/promises";
21185
- import { basename as basename13, join as join50 } from "path";
21133
+ import { cp as cp3, mkdir as mkdir5, readFile as readFile4, rm, writeFile as writeFile4 } from "fs/promises";
21134
+ import { basename as basename13, join as join51 } from "path";
21186
21135
 
21187
21136
  // src/commands/criteriaExtension/stampManifestVersion.ts
21188
21137
  function stampManifestVersion(manifest, version2) {
@@ -21193,13 +21142,13 @@ function stampManifestVersion(manifest, version2) {
21193
21142
 
21194
21143
  // src/commands/criteriaExtension/stageCriteriaExtension.ts
21195
21144
  async function stageCriteriaExtension(source, staging, version2) {
21196
- await rm2(staging, { recursive: true, force: true });
21197
- await mkdir4(staging, { recursive: true });
21145
+ await rm(staging, { recursive: true, force: true });
21146
+ await mkdir5(staging, { recursive: true });
21198
21147
  await cp3(source, staging, {
21199
21148
  recursive: true,
21200
21149
  filter: (path106) => basename13(path106) !== "updates.json"
21201
21150
  });
21202
- const manifest = join50(staging, "manifest.json");
21151
+ const manifest = join51(staging, "manifest.json");
21203
21152
  const stamped = stampManifestVersion(
21204
21153
  await readFile4(manifest, "utf8"),
21205
21154
  version2
@@ -21209,7 +21158,7 @@ async function stageCriteriaExtension(source, staging, version2) {
21209
21158
 
21210
21159
  // src/commands/criteriaExtension/writeUpdateManifest.ts
21211
21160
  import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
21212
- import { join as join51 } from "path";
21161
+ import { join as join52 } from "path";
21213
21162
 
21214
21163
  // src/commands/criteriaExtension/buildUpdateManifest.ts
21215
21164
  var RELEASE_DOWNLOAD_URL = "https://github.com/staff0rd/assist/releases/download";
@@ -21234,17 +21183,17 @@ function buildUpdateManifest(manifest, version2) {
21234
21183
  // src/commands/criteriaExtension/writeUpdateManifest.ts
21235
21184
  async function writeUpdateManifest(source, dir, version2) {
21236
21185
  await writeFile5(
21237
- join51(dir, "updates.json"),
21186
+ join52(dir, "updates.json"),
21238
21187
  buildUpdateManifest(
21239
- await readFile5(join51(source, "manifest.json"), "utf8"),
21188
+ await readFile5(join52(source, "manifest.json"), "utf8"),
21240
21189
  version2
21241
21190
  )
21242
21191
  );
21243
21192
  }
21244
21193
 
21245
21194
  // src/commands/criteriaExtension/signCriteriaExtension.ts
21246
- var ARTIFACTS_DIR = join52(homedir19(), ".assist", "criteria-extension");
21247
- var STAGING_DIR = join52(tmpdir4(), "assist-criteria-extension");
21195
+ var ARTIFACTS_DIR = join53(homedir20(), ".assist", "criteria-extension");
21196
+ var STAGING_DIR = join53(tmpdir3(), "assist-criteria-extension");
21248
21197
  async function signCriteriaExtension() {
21249
21198
  const source = criteriaExtensionDir();
21250
21199
  const problem = signPreflightProblem(source);
@@ -21256,7 +21205,7 @@ async function signCriteriaExtension() {
21256
21205
  }
21257
21206
  const { version: version2 } = package_default;
21258
21207
  await stageCriteriaExtension(source, STAGING_DIR, version2);
21259
- await rm3(ARTIFACTS_DIR, { recursive: true, force: true });
21208
+ await rm2(ARTIFACTS_DIR, { recursive: true, force: true });
21260
21209
  console.log(chalk139.bold(`signing version ${version2} for self-distribution`));
21261
21210
  const { done: done2 } = spawnInherit("npx", [
21262
21211
  "--yes",
@@ -21428,12 +21377,12 @@ import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync26 } from "fs"
21428
21377
  import chalk142 from "chalk";
21429
21378
 
21430
21379
  // src/commands/dbMigration/getMigrationPinPath.ts
21431
- import { join as join53 } from "path";
21380
+ import { join as join54 } from "path";
21432
21381
  function getMigrationPinPath(pin2) {
21433
- return join53(getRestrictedDir(), `db-migration-pin-${pin2}.json`);
21382
+ return join54(getRestrictedDir(), `db-migration-pin-${pin2}.json`);
21434
21383
  }
21435
21384
  function getMigrationApprovalPath(migrationId) {
21436
- return join53(getRestrictedDir(), `db-migration-approval-${migrationId}.json`);
21385
+ return join54(getRestrictedDir(), `db-migration-approval-${migrationId}.json`);
21437
21386
  }
21438
21387
 
21439
21388
  // src/commands/dbMigration/readMigrationPinState.ts
@@ -21570,11 +21519,11 @@ import { execFileSync as execFileSync5 } from "child_process";
21570
21519
  import { basename as basename15 } from "path";
21571
21520
 
21572
21521
  // src/commands/devlog/loadBlogSkipDays.ts
21573
- import { homedir as homedir20 } from "os";
21574
- import { join as join54 } from "path";
21575
- var BLOG_REPO_ROOT = join54(homedir20(), "git/blog");
21522
+ import { homedir as homedir21 } from "os";
21523
+ import { join as join55 } from "path";
21524
+ var BLOG_REPO_ROOT = join55(homedir21(), "git/blog");
21576
21525
  function loadBlogSkipDays(repoName) {
21577
- const config = loadRawYaml(join54(BLOG_REPO_ROOT, "assist.yml"));
21526
+ const config = loadRawYaml(join55(BLOG_REPO_ROOT, "assist.yml"));
21578
21527
  const devlog = config.devlog;
21579
21528
  const skip2 = devlog?.skip;
21580
21529
  return new Set(skip2?.[repoName]);
@@ -21586,13 +21535,13 @@ import chalk145 from "chalk";
21586
21535
 
21587
21536
  // src/shared/getRepoName.ts
21588
21537
  import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
21589
- import { basename as basename14, join as join55 } from "path";
21538
+ import { basename as basename14, join as join56 } from "path";
21590
21539
  function getRepoName() {
21591
21540
  const config = loadConfig();
21592
21541
  if (config.devlog?.name) {
21593
21542
  return config.devlog.name;
21594
21543
  }
21595
- const packageJsonPath = join55(process.cwd(), "package.json");
21544
+ const packageJsonPath = join56(process.cwd(), "package.json");
21596
21545
  if (existsSync51(packageJsonPath)) {
21597
21546
  try {
21598
21547
  const content = readFileSync33(packageJsonPath, "utf8");
@@ -21608,8 +21557,8 @@ function getRepoName() {
21608
21557
 
21609
21558
  // src/commands/devlog/loadDevlogEntries.ts
21610
21559
  import { readdirSync as readdirSync6, readFileSync as readFileSync34 } from "fs";
21611
- import { join as join56 } from "path";
21612
- var DEVLOG_DIR = join56(BLOG_REPO_ROOT, "src/content/devlog");
21560
+ import { join as join57 } from "path";
21561
+ var DEVLOG_DIR = join57(BLOG_REPO_ROOT, "src/content/devlog");
21613
21562
  function extractFrontmatter(content) {
21614
21563
  const fm = content.match(/^---\n([\s\S]*?)\n---/);
21615
21564
  return fm?.[1] ?? null;
@@ -21637,7 +21586,7 @@ function readDevlogFiles(callback) {
21637
21586
  try {
21638
21587
  const files = readdirSync6(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
21639
21588
  for (const file of files) {
21640
- const content = readFileSync34(join56(DEVLOG_DIR, file), "utf8");
21589
+ const content = readFileSync34(join57(DEVLOG_DIR, file), "utf8");
21641
21590
  const parsed = parseFrontmatter(content, file);
21642
21591
  if (parsed) callback(parsed);
21643
21592
  }
@@ -22025,11 +21974,11 @@ function repos(options2) {
22025
21974
 
22026
21975
  // src/commands/devlog/skip.ts
22027
21976
  import { writeFileSync as writeFileSync29 } from "fs";
22028
- import { join as join57 } from "path";
21977
+ import { join as join58 } from "path";
22029
21978
  import chalk150 from "chalk";
22030
21979
  import { stringify as stringifyYaml3 } from "yaml";
22031
21980
  function getBlogConfigPath() {
22032
- return join57(BLOG_REPO_ROOT, "assist.yml");
21981
+ return join58(BLOG_REPO_ROOT, "assist.yml");
22033
21982
  }
22034
21983
  function skip(date) {
22035
21984
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
@@ -22091,7 +22040,7 @@ function registerDevlog(program2) {
22091
22040
 
22092
22041
  // src/commands/dotnet/checkBuildLocks.ts
22093
22042
  import { closeSync as closeSync4, openSync as openSync5, readdirSync as readdirSync7 } from "fs";
22094
- import { join as join58 } from "path";
22043
+ import { join as join59 } from "path";
22095
22044
  import chalk152 from "chalk";
22096
22045
  var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "packages"]);
22097
22046
  function isLockedDll(debugDir) {
@@ -22103,7 +22052,7 @@ function isLockedDll(debugDir) {
22103
22052
  }
22104
22053
  for (const file of files) {
22105
22054
  if (!file.toLowerCase().endsWith(".dll")) continue;
22106
- const dllPath = join58(debugDir, file);
22055
+ const dllPath = join59(debugDir, file);
22107
22056
  try {
22108
22057
  const fd = openSync5(dllPath, "r+");
22109
22058
  closeSync4(fd);
@@ -22121,13 +22070,13 @@ function findFirstLockedDll(dir) {
22121
22070
  return null;
22122
22071
  }
22123
22072
  if (entries.includes("bin")) {
22124
- const locked = isLockedDll(join58(dir, "bin", "Debug"));
22073
+ const locked = isLockedDll(join59(dir, "bin", "Debug"));
22125
22074
  if (locked) return locked;
22126
22075
  }
22127
22076
  for (const entry of entries) {
22128
22077
  if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
22129
22078
  continue;
22130
- const found = findFirstLockedDll(join58(dir, entry));
22079
+ const found = findFirstLockedDll(join59(dir, entry));
22131
22080
  if (found) return found;
22132
22081
  }
22133
22082
  return null;
@@ -22212,10 +22161,10 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
22212
22161
  continue;
22213
22162
  const full = path35.join(dir, entry);
22214
22163
  try {
22215
- const stat4 = statSync8(full);
22216
- if (stat4.isFile() && entry.endsWith(".sln")) {
22164
+ const stat5 = statSync8(full);
22165
+ if (stat5.isFile() && entry.endsWith(".sln")) {
22217
22166
  results.push(full);
22218
- } else if (stat4.isDirectory()) {
22167
+ } else if (stat5.isDirectory()) {
22219
22168
  results.push(...findSlnFiles(full, maxDepth, depth + 1));
22220
22169
  }
22221
22170
  } catch {
@@ -22474,11 +22423,11 @@ import chalk158 from "chalk";
22474
22423
 
22475
22424
  // src/commands/dotnet/findSolution.ts
22476
22425
  import { readdirSync as readdirSync9 } from "fs";
22477
- import { dirname as dirname27, join as join59 } from "path";
22426
+ import { dirname as dirname27, join as join60 } from "path";
22478
22427
  import chalk157 from "chalk";
22479
22428
  function findSlnInDir(dir) {
22480
22429
  try {
22481
- return readdirSync9(dir).filter((f) => f.endsWith(".sln")).map((f) => join59(dir, f));
22430
+ return readdirSync9(dir).filter((f) => f.endsWith(".sln")).map((f) => join60(dir, f));
22482
22431
  } catch {
22483
22432
  return [];
22484
22433
  }
@@ -22550,7 +22499,7 @@ function parseInspectReport(json) {
22550
22499
  // src/commands/dotnet/runInspectCode.ts
22551
22500
  import { execSync as execSync35 } from "child_process";
22552
22501
  import { existsSync as existsSync54, readFileSync as readFileSync37, unlinkSync as unlinkSync10 } from "fs";
22553
- import { tmpdir as tmpdir5 } from "os";
22502
+ import { tmpdir as tmpdir4 } from "os";
22554
22503
  import path38 from "path";
22555
22504
  import chalk159 from "chalk";
22556
22505
  function assertJbInstalled() {
@@ -22565,7 +22514,7 @@ function assertJbInstalled() {
22565
22514
  }
22566
22515
  }
22567
22516
  function runInspectCode(slnPath, include, swea) {
22568
- const reportPath = path38.join(tmpdir5(), `inspect-${Date.now()}.xml`);
22517
+ const reportPath = path38.join(tmpdir4(), `inspect-${Date.now()}.xml`);
22569
22518
  const includeFlag = include ? ` --include="${include}"` : "";
22570
22519
  const sweaFlag = swea ? " --swea" : "";
22571
22520
  try {
@@ -23472,8 +23421,8 @@ function aggregateCommitters(authorLists) {
23472
23421
  // src/shared/runGhGraphql.ts
23473
23422
  import { spawnSync as spawnSync6 } from "child_process";
23474
23423
  import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
23475
- import { tmpdir as tmpdir6 } from "os";
23476
- import { join as join60 } from "path";
23424
+ import { tmpdir as tmpdir5 } from "os";
23425
+ import { join as join61 } from "path";
23477
23426
  function buildArgs2(queryFile, vars) {
23478
23427
  const args = ["api", "graphql", "-F", `query=@${queryFile}`];
23479
23428
  for (const [key, value] of Object.entries(vars)) {
@@ -23483,7 +23432,7 @@ function buildArgs2(queryFile, vars) {
23483
23432
  return args;
23484
23433
  }
23485
23434
  function runGhGraphql(mutation, vars) {
23486
- const queryFile = join60(tmpdir6(), `gh-query-${Date.now()}.graphql`);
23435
+ const queryFile = join61(tmpdir5(), `gh-query-${Date.now()}.graphql`);
23487
23436
  writeFileSync30(queryFile, mutation);
23488
23437
  try {
23489
23438
  const result = spawnSync6("gh", buildArgs2(queryFile, vars), {
@@ -24282,6 +24231,9 @@ function registerCommentIssue(issueCommand) {
24282
24231
  );
24283
24232
  }
24284
24233
 
24234
+ // src/commands/prs/minGhAttachVersion.ts
24235
+ var minGhAttachVersion = "2.99.0";
24236
+
24285
24237
  // src/commands/github/issue/collectLabels.ts
24286
24238
  function collectLabels(value, previous) {
24287
24239
  const added = value.split(",").map((label2) => label2.trim()).filter((label2) => label2.length > 0);
@@ -24289,13 +24241,17 @@ function collectLabels(value, previous) {
24289
24241
  }
24290
24242
 
24291
24243
  // src/commands/prs/appendScreenshots.ts
24292
- function appendScreenshots(body, screenshots) {
24293
- if (screenshots.length === 0) return body;
24244
+ function reference({ path: path106, alt }) {
24245
+ const target = /\s/.test(path106) ? `<${path106}>` : path106;
24246
+ return `![${alt}](${target})`;
24247
+ }
24248
+ function appendScreenshots(body, attachments) {
24249
+ if (attachments.length === 0) return body;
24294
24250
  return `${body}
24295
24251
 
24296
24252
  ## Screenshots
24297
24253
 
24298
- ${screenshots.join("\n\n")}`;
24254
+ ${attachments.map(reference).join("\n\n")}`;
24299
24255
  }
24300
24256
 
24301
24257
  // src/commands/github/issue/addIssueToProject.ts
@@ -24571,11 +24527,11 @@ function resolveIssueRepoTarget(repo) {
24571
24527
 
24572
24528
  // src/commands/github/issue/resolveCreateIssueParent.ts
24573
24529
  function resolveCreateIssueParent(target, parent) {
24574
- const reference = resolveFixStructureTarget(
24530
+ const reference2 = resolveFixStructureTarget(
24575
24531
  parent,
24576
24532
  `${target.owner}/${target.repo}`
24577
24533
  );
24578
- return { ...reference, id: fetchIssueNodeId(reference) };
24534
+ return { ...reference2, id: fetchIssueNodeId(reference2) };
24579
24535
  }
24580
24536
 
24581
24537
  // src/commands/github/issue/resolveCreateIssueProject.ts
@@ -24647,22 +24603,75 @@ async function reviewProposedIssue(title, body, metadata2 = []) {
24647
24603
  });
24648
24604
  }
24649
24605
 
24650
- // src/commands/github/issue/runGhIssueCreate.ts
24606
+ // src/commands/prs/attachArgs.ts
24607
+ function attachArgs(attachments) {
24608
+ return attachments.flatMap(({ path: path106, alt }) => [
24609
+ "--attach",
24610
+ alt ? `${path106}#${alt}` : path106
24611
+ ]);
24612
+ }
24613
+
24614
+ // src/commands/prs/runGhWithAttachments.ts
24651
24615
  import { execFileSync as execFileSync9 } from "child_process";
24652
- function runGhIssueCreate(title, body, repo, labels) {
24653
- const args = ["issue", "create", "--title", title, "--body", body];
24654
- if (repo) args.push("--repo", repo);
24655
- for (const label2 of labels ?? []) args.push("--label", label2);
24616
+ import { basename as basename16 } from "path";
24617
+
24618
+ // src/shared/removeStagedAttachments.ts
24619
+ import { rmSync as rmSync3 } from "fs";
24620
+ import { dirname as dirname28 } from "path";
24621
+ function removeStagedAttachments(attachments) {
24622
+ for (const { path: path106 } of attachments) {
24623
+ const dir = dirname28(path106);
24624
+ if (!isStagedAttachmentPath(dir)) continue;
24625
+ rmSync3(dir, { recursive: true, force: true });
24626
+ }
24627
+ }
24628
+
24629
+ // src/commands/prs/runGhWithAttachments.ts
24630
+ var PLACED_URL = /https:\/\/\S+\/(pull|issues)\/\d+/;
24631
+ function reportPartialFailure(attachments, stderr) {
24632
+ const failed3 = attachments.filter(
24633
+ ({ path: path106 }) => stderr.includes(path106) || stderr.includes(basename16(path106))
24634
+ );
24635
+ const named = failed3.length > 0 ? failed3 : attachments;
24636
+ console.error(
24637
+ `Some attachments failed to upload: ${named.map((a) => a.path).join(", ")}. The body still references their local paths, so re-attach them with gh's --attach flag; the staged files were kept.`
24638
+ );
24639
+ }
24640
+ function runGhWithAttachments(args, attachments) {
24641
+ const attaching = attachments.length > 0;
24656
24642
  try {
24657
- return execFileSync9("gh", args, {
24643
+ const stdout = execFileSync9("gh", args, {
24658
24644
  encoding: "utf8",
24659
- stdio: ["ignore", "pipe", "inherit"]
24645
+ stdio: ["inherit", "pipe", attaching ? "pipe" : "inherit"]
24660
24646
  });
24661
- } catch {
24647
+ removeStagedAttachments(attachments);
24648
+ return stdout;
24649
+ } catch (error) {
24650
+ const { stdout = "", stderr = "" } = error;
24651
+ if (stderr) process.stderr.write(stderr);
24652
+ if (/unknown flag:? --attach/.test(stderr)) {
24653
+ console.error(
24654
+ `Your gh does not support --attach. Upgrade the GitHub CLI to ${minGhAttachVersion} or later.`
24655
+ );
24656
+ process.exit(1);
24657
+ }
24658
+ if (attaching && PLACED_URL.test(stdout)) {
24659
+ reportPartialFailure(attachments, stderr);
24660
+ return stdout;
24661
+ }
24662
24662
  process.exit(1);
24663
24663
  }
24664
24664
  }
24665
24665
 
24666
+ // src/commands/github/issue/runGhIssueCreate.ts
24667
+ function runGhIssueCreate(title, body, repo, labels, attachments = []) {
24668
+ const args = ["issue", "create", "--title", title, "--body", body];
24669
+ if (repo) args.push("--repo", repo);
24670
+ for (const label2 of labels ?? []) args.push("--label", label2);
24671
+ args.push(...attachArgs(attachments));
24672
+ return runGhWithAttachments(args, attachments);
24673
+ }
24674
+
24666
24675
  // src/commands/github/issue/createIssue.ts
24667
24676
  var USAGE2 = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>] [--type <name>] [--parent <issue>] [--project <number>] [--status <name>] [--label <name>]";
24668
24677
  function preflight(options2) {
@@ -24690,11 +24699,13 @@ async function createIssue(options2) {
24690
24699
  body,
24691
24700
  issuePreviewMetadata(resolved)
24692
24701
  );
24702
+ const attachments = decision?.screenshots ?? [];
24693
24703
  const output = runGhIssueCreate(
24694
24704
  title,
24695
- appendScreenshots(body, decision?.screenshots ?? []),
24705
+ appendScreenshots(body, attachments),
24696
24706
  options2.repo,
24697
- resolved?.labels
24707
+ resolved?.labels,
24708
+ attachments
24698
24709
  );
24699
24710
  console.log(output.trim());
24700
24711
  if (resolved) applyCreatedIssueMetadata(output, resolved);
@@ -24724,7 +24735,13 @@ function registerCreateIssue(issueCommand) {
24724
24735
  []
24725
24736
  ).addHelpText(
24726
24737
  "after",
24727
- "\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 stay attached and reappear in the preview you re-propose \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"
24738
+ `
24739
+ There 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.
24740
+ In an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved.
24741
+ The reviewer may also drop or paste screenshots or video into the pane; on approval gh attaches them (gh ${minGhAttachVersion}+) under a ## Screenshots section of the issue body automatically, and on rejection they stay attached and reappear in the preview you re-propose \u2014 so never author that section yourself.
24742
+ --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.
24743
+ A bare --parent number is read against --repo, or the current repo; a parent in another repository is allowed.
24744
+ The project scope is needed for --project: gh auth refresh -h github.com -s project`
24728
24745
  ).action(createIssue);
24729
24746
  }
24730
24747
 
@@ -24763,14 +24780,14 @@ function fetchIssue2(number, repo) {
24763
24780
  import { existsSync as existsSync56, readFileSync as readFileSync38 } from "fs";
24764
24781
 
24765
24782
  // src/commands/github/issue/issueWorkingFile.ts
24766
- import { join as join61 } from "path";
24783
+ import { join as join62 } from "path";
24767
24784
  function issueWorkingFile(slug2, number) {
24768
24785
  const [owner = "unknown", repo = "unknown"] = slug2.split("/");
24769
- const dir = join61(getStoreDir(), "github-issues", owner, repo);
24786
+ const dir = join62(getStoreDir(), "github-issues", owner, repo);
24770
24787
  return {
24771
24788
  dir,
24772
- bodyPath: join61(dir, `${number}.md`),
24773
- metaPath: join61(dir, `${number}.json`)
24789
+ bodyPath: join62(dir, `${number}.md`),
24790
+ metaPath: join62(dir, `${number}.json`)
24774
24791
  };
24775
24792
  }
24776
24793
 
@@ -25399,28 +25416,28 @@ function recentDaemonLogLines(includeRelayed = true) {
25399
25416
 
25400
25417
  // src/commands/sessions/daemon/worktree/canonicalTreePath.ts
25401
25418
  import { realpathSync as realpathSync2 } from "fs";
25402
- import { resolve as resolve15 } from "path";
25419
+ import { resolve as resolve16 } from "path";
25403
25420
  function canonicalTreePath(path106) {
25404
25421
  try {
25405
25422
  return realpathSync2(path106);
25406
25423
  } catch {
25407
- return resolve15(path106);
25424
+ return resolve16(path106);
25408
25425
  }
25409
25426
  }
25410
25427
 
25411
25428
  // src/commands/sessions/daemon/worktree/createWorktree.ts
25412
25429
  import { existsSync as existsSync57 } from "fs";
25413
- import { basename as basename17, dirname as dirname28 } from "path";
25430
+ import { basename as basename18, dirname as dirname29 } from "path";
25414
25431
 
25415
25432
  // src/commands/sessions/daemon/worktree/planAllocation.ts
25416
- import { basename as basename16, join as join62 } from "path";
25433
+ import { basename as basename17, join as join63 } from "path";
25417
25434
  function planAllocation(clone, boundTreeRoots2) {
25418
25435
  return boundTreeRoots2.has(clone) ? "spill" : "primary";
25419
25436
  }
25420
25437
  function nextWorktreePath(clone, base, isTaken) {
25421
- const name = basename16(clone);
25438
+ const name = basename17(clone);
25422
25439
  for (let n = 2; n < 1e3; n++) {
25423
- const candidate = join62(base, `${name}-${n}`);
25440
+ const candidate = join63(base, `${name}-${n}`);
25424
25441
  if (!isTaken(candidate)) return candidate;
25425
25442
  }
25426
25443
  throw new Error(`no free worktree suffix for ${clone}`);
@@ -25453,10 +25470,10 @@ function cloneHead(clone) {
25453
25470
 
25454
25471
  // src/commands/sessions/daemon/worktree/createWorktree.ts
25455
25472
  function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
25456
- const base = strategy.root ? expandTilde2(strategy.root) : dirname28(clone);
25473
+ const base = strategy.root ? expandTilde2(strategy.root) : dirname29(clone);
25457
25474
  const registered = new Set(listWorktreePaths(clone));
25458
25475
  const branches = new Set(listLocalBranches(clone));
25459
- const isTaken = (candidate) => registered.has(candidate) || existsSync57(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename17(candidate));
25476
+ const isTaken = (candidate) => registered.has(candidate) || existsSync57(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename18(candidate));
25460
25477
  const path106 = preferredPath && !isTaken(preferredPath) ? preferredPath : nextWorktreePath(clone, base, isTaken);
25461
25478
  const start2 = worktreeStartPoint(clone, strategy.trunk);
25462
25479
  gitSync(clone, [
@@ -25464,13 +25481,13 @@ function createWorktree(clone, strategy, boundTreeRoots2, preferredPath) {
25464
25481
  "add",
25465
25482
  start2.track ? "--track" : "--no-track",
25466
25483
  "-b",
25467
- basename17(path106),
25484
+ basename18(path106),
25468
25485
  path106,
25469
25486
  start2.ref
25470
25487
  ]);
25471
25488
  recordWorktree(path106, clone, getCurrentOrigin(clone));
25472
25489
  daemonLog(
25473
- start2.track ? `worktree allocated ${path106} (branch ${basename17(path106)} tracking ${start2.ref}) for clone ${clone}` : `worktree allocated ${path106} (branch ${basename17(path106)} off ${start2.ref}, no mainline tracking) for clone ${clone}`
25490
+ start2.track ? `worktree allocated ${path106} (branch ${basename18(path106)} tracking ${start2.ref}) for clone ${clone}` : `worktree allocated ${path106} (branch ${basename18(path106)} off ${start2.ref}, no mainline tracking) for clone ${clone}`
25474
25491
  );
25475
25492
  return path106;
25476
25493
  }
@@ -25774,19 +25791,19 @@ function persistedTreeRoots() {
25774
25791
 
25775
25792
  // src/commands/sessions/daemon/worktree/seedWorktree.ts
25776
25793
  import { copyFileSync, existsSync as existsSync60, mkdirSync as mkdirSync17 } from "fs";
25777
- import { dirname as dirname29, join as join64 } from "path";
25794
+ import { dirname as dirname30, join as join65 } from "path";
25778
25795
 
25779
25796
  // src/commands/sessions/daemon/worktree/runInstall.ts
25780
- import { resolve as resolve16 } from "path";
25797
+ import { resolve as resolve17 } from "path";
25781
25798
 
25782
25799
  // src/commands/sessions/daemon/worktree/detectInstallCommand.ts
25783
25800
  import { existsSync as existsSync59 } from "fs";
25784
- import { join as join63 } from "path";
25801
+ import { join as join64 } from "path";
25785
25802
  function detectInstallCommand(dir) {
25786
- if (!existsSync59(join63(dir, "package.json"))) return null;
25787
- if (existsSync59(join63(dir, "pnpm-lock.yaml"))) return "pnpm install";
25788
- if (existsSync59(join63(dir, "yarn.lock"))) return "yarn install";
25789
- if (existsSync59(join63(dir, "bun.lockb"))) return "bun install";
25803
+ if (!existsSync59(join64(dir, "package.json"))) return null;
25804
+ if (existsSync59(join64(dir, "pnpm-lock.yaml"))) return "pnpm install";
25805
+ if (existsSync59(join64(dir, "yarn.lock"))) return "yarn install";
25806
+ if (existsSync59(join64(dir, "bun.lockb"))) return "bun install";
25790
25807
  return "npm install";
25791
25808
  }
25792
25809
 
@@ -25824,7 +25841,7 @@ function quoteForPosixShell(value) {
25824
25841
  }
25825
25842
 
25826
25843
  // src/commands/sessions/daemon/worktree/stopInstall.ts
25827
- import { execFile as execFile13 } from "child_process";
25844
+ import { execFile as execFile11 } from "child_process";
25828
25845
  var running2 = /* @__PURE__ */ new Map();
25829
25846
  function trackInstall(worktreePath, child) {
25830
25847
  running2.set(worktreePath, child);
@@ -25845,7 +25862,7 @@ function stopInstall(worktreePath) {
25845
25862
  }
25846
25863
  function killTree(pid) {
25847
25864
  if (process.platform === "win32") {
25848
- execFile13(
25865
+ execFile11(
25849
25866
  "taskkill",
25850
25867
  ["/T", "/F", "/PID", String(pid)],
25851
25868
  { windowsHide: true },
@@ -25915,7 +25932,7 @@ function installPaths(worktreePath, paths, onSeeded) {
25915
25932
  onSeeded();
25916
25933
  return;
25917
25934
  }
25918
- const dir = resolve16(worktreePath, rel);
25935
+ const dir = resolve17(worktreePath, rel);
25919
25936
  const command = detectInstallCommand(dir);
25920
25937
  if (!command) {
25921
25938
  daemonLog(
@@ -25948,11 +25965,11 @@ function seedWorktree(worktreePath, clone, onSeeded = () => {
25948
25965
  }
25949
25966
  function copyConfigFiles(worktreePath, clone, copy) {
25950
25967
  for (const rel of copy) {
25951
- const src = join64(clone, rel);
25968
+ const src = join65(clone, rel);
25952
25969
  if (!existsSync60(src)) continue;
25953
- const dest = join64(worktreePath, rel);
25970
+ const dest = join65(worktreePath, rel);
25954
25971
  try {
25955
- mkdirSync17(dirname29(dest), { recursive: true });
25972
+ mkdirSync17(dirname30(dest), { recursive: true });
25956
25973
  copyFileSync(src, dest);
25957
25974
  daemonLog(`worktree ${worktreePath} seeded ${rel}`);
25958
25975
  } catch (error) {
@@ -25973,7 +25990,7 @@ function placedByDaemon() {
25973
25990
  function seed(worktreePath, clone) {
25974
25991
  console.log(`Preparing ${worktreePath}\u2026`);
25975
25992
  return new Promise(
25976
- (resolve27) => seedWorktree(worktreePath, clone, resolve27)
25993
+ (resolve28) => seedWorktree(worktreePath, clone, resolve28)
25977
25994
  );
25978
25995
  }
25979
25996
  async function moveToPrCheckoutTree() {
@@ -26255,12 +26272,12 @@ function registerLitellm(program2) {
26255
26272
 
26256
26273
  // src/commands/mermaidExport.ts
26257
26274
  import { mkdirSync as mkdirSync18, readdirSync as readdirSync10 } from "fs";
26258
- import { resolve as resolve18 } from "path";
26275
+ import { resolve as resolve19 } from "path";
26259
26276
  import chalk174 from "chalk";
26260
26277
 
26261
26278
  // src/commands/mermaid/exportFile.ts
26262
26279
  import { readFileSync as readFileSync39, writeFileSync as writeFileSync32 } from "fs";
26263
- import { basename as basename18, extname as extname2, resolve as resolve17 } from "path";
26280
+ import { basename as basename19, extname as extname3, resolve as resolve18 } from "path";
26264
26281
  import chalk173 from "chalk";
26265
26282
 
26266
26283
  // src/commands/mermaid/renderBlock.ts
@@ -26287,7 +26304,7 @@ async function renderBlock(krokiUrl, source) {
26287
26304
  async function exportFile(file, outDir, krokiUrl, onlyIndex) {
26288
26305
  const content = readFileSync39(file, "utf8");
26289
26306
  const blocks = extractMermaidBlocks(content);
26290
- const stem = basename18(file, extname2(file));
26307
+ const stem = basename19(file, extname3(file));
26291
26308
  if (onlyIndex !== void 0) {
26292
26309
  if (onlyIndex < 1 || onlyIndex > blocks.length) {
26293
26310
  console.error(
@@ -26308,7 +26325,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
26308
26325
  for (const [i, source] of blocks.entries()) {
26309
26326
  const idx = i + 1;
26310
26327
  if (onlyIndex !== void 0 && idx !== onlyIndex) continue;
26311
- const outPath = resolve17(outDir, `${stem}-${idx}.svg`);
26328
+ const outPath = resolve18(outDir, `${stem}-${idx}.svg`);
26312
26329
  const svg = await renderBlock(krokiUrl, source);
26313
26330
  writeFileSync32(outPath, svg, "utf8");
26314
26331
  console.log(chalk173.green(` \u2192 ${outPath}`));
@@ -26322,7 +26339,7 @@ function extractMermaidBlocks(markdown) {
26322
26339
  // src/commands/mermaidExport.ts
26323
26340
  async function mermaidExport(file, options2 = {}) {
26324
26341
  const { mermaid } = loadConfig();
26325
- const outDir = resolve18(process.cwd(), options2.out ?? ".");
26342
+ const outDir = resolve19(process.cwd(), options2.out ?? ".");
26326
26343
  mkdirSync18(outDir, { recursive: true });
26327
26344
  if (options2.index !== void 0) {
26328
26345
  if (!Number.isInteger(options2.index) || options2.index < 1) {
@@ -26419,7 +26436,7 @@ import { stringify as stringify2 } from "yaml";
26419
26436
 
26420
26437
  // src/commands/miro/writeExtract.ts
26421
26438
  import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync33 } from "fs";
26422
- import { dirname as dirname30 } from "path";
26439
+ import { dirname as dirname31 } from "path";
26423
26440
  import { stringify } from "yaml";
26424
26441
  function headerLines(header) {
26425
26442
  const { rect } = header;
@@ -26432,7 +26449,7 @@ function headerLines(header) {
26432
26449
  ];
26433
26450
  }
26434
26451
  function writeExtract(file, header, texts) {
26435
- mkdirSync19(dirname30(file), { recursive: true });
26452
+ mkdirSync19(dirname31(file), { recursive: true });
26436
26453
  writeFileSync33(file, `${headerLines(header).join("\n")}
26437
26454
  ${stringify(texts)}`);
26438
26455
  }
@@ -26450,18 +26467,18 @@ function emitExtract(out, header, texts) {
26450
26467
  }
26451
26468
 
26452
26469
  // src/commands/miro/resolveExtractPath.ts
26453
- import { isAbsolute as isAbsolute3, relative as relative5, resolve as resolve19 } from "path";
26470
+ import { isAbsolute as isAbsolute4, relative as relative6, resolve as resolve20 } from "path";
26454
26471
  function extractRoot(cwd) {
26455
26472
  return findConfigUp(cwd)?.rootDir ?? cwd;
26456
26473
  }
26457
26474
  function resolveExtractPath(value, cwd) {
26458
26475
  if (value === void 0) return void 0;
26459
- return isAbsolute3(value) ? value : resolve19(extractRoot(cwd), value);
26476
+ return isAbsolute4(value) ? value : resolve20(extractRoot(cwd), value);
26460
26477
  }
26461
26478
  function storedExtractPath(value, cwd) {
26462
26479
  if (value === void 0) return void 0;
26463
- const absolute2 = resolve19(cwd, value);
26464
- const within = relative5(extractRoot(cwd), absolute2);
26480
+ const absolute2 = resolve20(cwd, value);
26481
+ const within = relative6(extractRoot(cwd), absolute2);
26465
26482
  return within.startsWith("..") ? absolute2 : within;
26466
26483
  }
26467
26484
 
@@ -26903,9 +26920,9 @@ function registerMiro(program2) {
26903
26920
  }
26904
26921
 
26905
26922
  // src/commands/netcap/netcap.ts
26906
- import { mkdir as mkdir5 } from "fs/promises";
26923
+ import { mkdir as mkdir6 } from "fs/promises";
26907
26924
  import { createServer as createServer2 } from "http";
26908
- import { dirname as dirname32 } from "path";
26925
+ import { dirname as dirname33 } from "path";
26909
26926
  import chalk178 from "chalk";
26910
26927
 
26911
26928
  // src/commands/netcap/corsHeaders.ts
@@ -26984,15 +27001,15 @@ function createNetcapHandler(options2) {
26984
27001
  // src/commands/netcap/prepareExtensionForLoad.ts
26985
27002
  import { cp as cp4, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
26986
27003
  import { networkInterfaces } from "os";
26987
- import { join as join66 } from "path";
27004
+ import { join as join67 } from "path";
26988
27005
  import chalk177 from "chalk";
26989
27006
 
26990
27007
  // src/commands/netcap/netcapExtensionDir.ts
26991
- import { dirname as dirname31, join as join65 } from "path";
27008
+ import { dirname as dirname32, join as join66 } from "path";
26992
27009
  import { fileURLToPath as fileURLToPath7 } from "url";
26993
- var moduleDir2 = dirname31(fileURLToPath7(import.meta.url));
27010
+ var moduleDir2 = dirname32(fileURLToPath7(import.meta.url));
26994
27011
  function netcapExtensionDir() {
26995
- return join65(moduleDir2, "commands", "netcap", "netcap-extension");
27012
+ return join66(moduleDir2, "commands", "netcap", "netcap-extension");
26996
27013
  }
26997
27014
 
26998
27015
  // src/commands/netcap/prepareExtensionForLoad.ts
@@ -27007,7 +27024,7 @@ function lanIPv4() {
27007
27024
  return void 0;
27008
27025
  }
27009
27026
  async function configureBackground(dir, host, port, filter) {
27010
- const file = join66(dir, "background.js");
27027
+ const file = join67(dir, "background.js");
27011
27028
  const source = await readFile6(file, "utf8");
27012
27029
  await writeFile6(
27013
27030
  file,
@@ -27047,20 +27064,20 @@ async function prepareExtensionForLoad(port, filter = "") {
27047
27064
  }
27048
27065
 
27049
27066
  // src/commands/netcap/resolveNetcapOutPath.ts
27050
- import { isAbsolute as isAbsolute4, join as join68, resolve as resolve20 } from "path";
27067
+ import { isAbsolute as isAbsolute5, join as join69, resolve as resolve21 } from "path";
27051
27068
 
27052
27069
  // src/commands/netcap/defaultCapturePath.ts
27053
- import { homedir as homedir21 } from "os";
27054
- import { join as join67 } from "path";
27070
+ import { homedir as homedir22 } from "os";
27071
+ import { join as join68 } from "path";
27055
27072
  function defaultCapturePath() {
27056
- return join67(homedir21(), ".assist", "netcap", "capture.jsonl");
27073
+ return join68(homedir22(), ".assist", "netcap", "capture.jsonl");
27057
27074
  }
27058
27075
 
27059
27076
  // src/commands/netcap/resolveNetcapOutPath.ts
27060
27077
  function resolveNetcapOutPath(out) {
27061
27078
  if (!out) return defaultCapturePath();
27062
- const dir = isAbsolute4(out) ? out : resolve20(process.cwd(), out);
27063
- return join68(dir, "capture.jsonl");
27079
+ const dir = isAbsolute5(out) ? out : resolve21(process.cwd(), out);
27080
+ return join69(dir, "capture.jsonl");
27064
27081
  }
27065
27082
 
27066
27083
  // src/commands/netcap/netcap.ts
@@ -27068,7 +27085,7 @@ async function netcap(options2) {
27068
27085
  const port = Number(options2.port);
27069
27086
  const outPath = resolveNetcapOutPath(options2.out);
27070
27087
  const filter = options2.filter ?? "";
27071
- await mkdir5(dirname32(outPath), { recursive: true });
27088
+ await mkdir6(dirname33(outPath), { recursive: true });
27072
27089
  const extensionPath = await prepareExtensionForLoad(port, filter);
27073
27090
  let count8 = 0;
27074
27091
  const handler = createNetcapHandler({
@@ -27107,7 +27124,7 @@ netcap stopped \u2014 captured ${count8} ${count8 === 1 ? "entry" : "entries"} t
27107
27124
 
27108
27125
  // src/commands/netcap/netcapExtract.ts
27109
27126
  import { writeFileSync as writeFileSync34 } from "fs";
27110
- import { join as join69 } from "path";
27127
+ import { join as join70 } from "path";
27111
27128
  import chalk179 from "chalk";
27112
27129
 
27113
27130
  // src/commands/netcap/extractPostsFromCapture.ts
@@ -27150,25 +27167,25 @@ function isVisibleText(t) {
27150
27167
  return /[a-zA-Z]{3,}/.test(t);
27151
27168
  }
27152
27169
  var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
27153
- function collectRscText(v, resolve27, sink3, seen) {
27170
+ function collectRscText(v, resolve28, sink3, seen) {
27154
27171
  if (v == null) return;
27155
27172
  if (typeof v === "string") {
27156
27173
  if (isRscRef(v)) {
27157
27174
  if (!seen.has(v)) {
27158
27175
  seen.add(v);
27159
- collectRscText(resolve27(v), resolve27, sink3, seen);
27176
+ collectRscText(resolve28(v), resolve28, sink3, seen);
27160
27177
  }
27161
27178
  } else if (isHashtag(v)) sink3.hashtags.push(v);
27162
27179
  else if (isVisibleText(v)) sink3.text.push(v);
27163
27180
  return;
27164
27181
  }
27165
27182
  if (Array.isArray(v)) {
27166
- for (const x of v) collectRscText(x, resolve27, sink3, seen);
27183
+ for (const x of v) collectRscText(x, resolve28, sink3, seen);
27167
27184
  return;
27168
27185
  }
27169
27186
  if (typeof v === "object") {
27170
27187
  for (const val of Object.values(v)) {
27171
- collectRscText(val, resolve27, sink3, seen);
27188
+ collectRscText(val, resolve28, sink3, seen);
27172
27189
  }
27173
27190
  }
27174
27191
  }
@@ -27200,7 +27217,7 @@ function visitObjects(root2, fn) {
27200
27217
  }
27201
27218
  }
27202
27219
  }
27203
- function buildMentionMap(rows, resolve27) {
27220
+ function buildMentionMap(rows, resolve28) {
27204
27221
  const map = /* @__PURE__ */ new Map();
27205
27222
  visitObjects(rows, (o) => {
27206
27223
  const url = profileActionUrl(o);
@@ -27208,7 +27225,7 @@ function buildMentionMap(rows, resolve27) {
27208
27225
  const slug2 = slugFromProfileUrl(url);
27209
27226
  if (!slug2 || map.has(slug2)) return;
27210
27227
  const sink3 = { text: [], hashtags: [] };
27211
- collectRscText(o.children, resolve27, sink3, /* @__PURE__ */ new Set());
27228
+ collectRscText(o.children, resolve28, sink3, /* @__PURE__ */ new Set());
27212
27229
  const name = sink3.text.join(" ").replace(/\s+/g, " ").trim();
27213
27230
  map.set(slug2, name ? { slug: slug2, name, url } : { slug: slug2, url });
27214
27231
  });
@@ -27294,10 +27311,10 @@ function buildPost(raw, mentionMap, author) {
27294
27311
 
27295
27312
  // src/commands/netcap/walkPostRow.ts
27296
27313
  var isCommentary = (o) => asObject(o.viewTrackingSpecs)?.viewName === "feed-commentary";
27297
- function walkPostRow(v, resolve27, raw) {
27314
+ function walkPostRow(v, resolve28, raw) {
27298
27315
  if (v == null || typeof v !== "object") return;
27299
27316
  if (Array.isArray(v)) {
27300
- for (const x of v) walkPostRow(x, resolve27, raw);
27317
+ for (const x of v) walkPostRow(x, resolve28, raw);
27301
27318
  return;
27302
27319
  }
27303
27320
  const o = v;
@@ -27311,9 +27328,9 @@ function walkPostRow(v, resolve27, raw) {
27311
27328
  }
27312
27329
  if (isCommentary(o)) {
27313
27330
  const sink3 = { text: raw.text, hashtags: raw.hashtags };
27314
- collectRscText(o.children, resolve27, sink3, /* @__PURE__ */ new Set());
27331
+ collectRscText(o.children, resolve28, sink3, /* @__PURE__ */ new Set());
27315
27332
  }
27316
- for (const val of Object.values(o)) walkPostRow(val, resolve27, raw);
27333
+ for (const val of Object.values(o)) walkPostRow(val, resolve28, raw);
27317
27334
  }
27318
27335
 
27319
27336
  // src/commands/netcap/extractLinkedInPosts.ts
@@ -27327,8 +27344,8 @@ function findCommentaryRows(rows) {
27327
27344
  }
27328
27345
  function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
27329
27346
  const rows = parseRscRows(flight);
27330
- const resolve27 = makeRscResolver(rows);
27331
- const mentionMap = buildMentionMap(rows, resolve27);
27347
+ const resolve28 = makeRscResolver(rows);
27348
+ const mentionMap = buildMentionMap(rows, resolve28);
27332
27349
  const posts = [];
27333
27350
  for (const id of findCommentaryRows(rows)) {
27334
27351
  const raw = {
@@ -27338,7 +27355,7 @@ function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
27338
27355
  links: [],
27339
27356
  related: []
27340
27357
  };
27341
- walkPostRow(rows[id], resolve27, raw);
27358
+ walkPostRow(rows[id], resolve28, raw);
27342
27359
  const post = buildPost(raw, mentionMap, author);
27343
27360
  if (post) posts.push(post);
27344
27361
  }
@@ -27552,7 +27569,7 @@ function extractPostsFromCapture(captureFile) {
27552
27569
  function netcapExtract(file) {
27553
27570
  const captureFile = file ?? defaultCapturePath();
27554
27571
  const posts = extractPostsFromCapture(captureFile);
27555
- const outFile = join69(captureFile, "..", "posts.json");
27572
+ const outFile = join70(captureFile, "..", "posts.json");
27556
27573
  writeFileSync34(outFile, `${JSON.stringify(posts, null, 2)}
27557
27574
  `);
27558
27575
  console.log(
@@ -27914,19 +27931,19 @@ import { execSync as execSync41 } from "child_process";
27914
27931
  // src/commands/prs/resolveCommentWithReply.ts
27915
27932
  import { execSync as execSync40 } from "child_process";
27916
27933
  import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync35 } from "fs";
27917
- import { tmpdir as tmpdir7 } from "os";
27918
- import { join as join71 } from "path";
27934
+ import { tmpdir as tmpdir6 } from "os";
27935
+ import { join as join72 } from "path";
27919
27936
 
27920
27937
  // src/commands/prs/loadCommentsCache.ts
27921
27938
  import { existsSync as existsSync62, readFileSync as readFileSync43, unlinkSync as unlinkSync13 } from "fs";
27922
27939
  import { parse as parse3 } from "yaml";
27923
27940
 
27924
27941
  // src/commands/prs/commentsCachePath.ts
27925
- import { homedir as homedir22 } from "os";
27926
- import { join as join70 } from "path";
27942
+ import { homedir as homedir23 } from "os";
27943
+ import { join as join71 } from "path";
27927
27944
  function commentsCachePath(org, repo, prNumber) {
27928
- return join70(
27929
- homedir22(),
27945
+ return join71(
27946
+ homedir23(),
27930
27947
  ".assist",
27931
27948
  "pr-comments",
27932
27949
  org,
@@ -27974,7 +27991,7 @@ function replyToComment(org, repo, prNumber, commentId, message3) {
27974
27991
  // src/commands/prs/resolveCommentWithReply.ts
27975
27992
  function resolveThread(threadId) {
27976
27993
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
27977
- const queryFile = join71(tmpdir7(), `gh-mutation-${Date.now()}.graphql`);
27994
+ const queryFile = join72(tmpdir6(), `gh-mutation-${Date.now()}.graphql`);
27978
27995
  writeFileSync35(queryFile, mutation);
27979
27996
  try {
27980
27997
  execSync40(
@@ -28058,11 +28075,11 @@ function fixed(commentId, sha) {
28058
28075
  // src/commands/prs/fetchThreadIds.ts
28059
28076
  import { execSync as execSync42 } from "child_process";
28060
28077
  import { unlinkSync as unlinkSync15, writeFileSync as writeFileSync36 } from "fs";
28061
- import { tmpdir as tmpdir8 } from "os";
28062
- import { join as join72 } from "path";
28078
+ import { tmpdir as tmpdir7 } from "os";
28079
+ import { join as join73 } from "path";
28063
28080
  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 } } } } } } }`;
28064
28081
  function fetchThreadIds(org, repo, prNumber) {
28065
- const queryFile = join72(tmpdir8(), `gh-query-${Date.now()}.graphql`);
28082
+ const queryFile = join73(tmpdir7(), `gh-query-${Date.now()}.graphql`);
28066
28083
  writeFileSync36(queryFile, THREAD_QUERY);
28067
28084
  try {
28068
28085
  const result = execSync42(
@@ -28132,15 +28149,15 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
28132
28149
 
28133
28150
  // src/commands/prs/listComments/updateCommentsCache.ts
28134
28151
  import { mkdirSync as mkdirSync20, writeFileSync as writeFileSync37 } from "fs";
28135
- import { dirname as dirname33 } from "path";
28152
+ import { dirname as dirname34 } from "path";
28136
28153
  import { stringify as stringify3 } from "yaml";
28137
28154
 
28138
28155
  // src/commands/prs/removeStaleCommentsCaches.ts
28139
28156
  import { readdirSync as readdirSync11, unlinkSync as unlinkSync16 } from "fs";
28140
- import { join as join73 } from "path";
28157
+ import { join as join74 } from "path";
28141
28158
  var STALE_PATTERN = /^pr-\d+-comments\.yaml$/;
28142
28159
  function removeStaleCommentsCaches(cwd = process.cwd()) {
28143
- const dir = join73(cwd, ".assist");
28160
+ const dir = join74(cwd, ".assist");
28144
28161
  let entries;
28145
28162
  try {
28146
28163
  entries = readdirSync11(dir);
@@ -28148,14 +28165,14 @@ function removeStaleCommentsCaches(cwd = process.cwd()) {
28148
28165
  return;
28149
28166
  }
28150
28167
  for (const entry of entries.filter((e) => STALE_PATTERN.test(e))) {
28151
- unlinkSync16(join73(dir, entry));
28168
+ unlinkSync16(join74(dir, entry));
28152
28169
  }
28153
28170
  }
28154
28171
 
28155
28172
  // src/commands/prs/listComments/updateCommentsCache.ts
28156
28173
  function writeCommentsCache(org, repo, prNumber, comments3) {
28157
28174
  const cachePath = commentsCachePath(org, repo, prNumber);
28158
- mkdirSync20(dirname33(cachePath), { recursive: true });
28175
+ mkdirSync20(dirname34(cachePath), { recursive: true });
28159
28176
  const cacheData = {
28160
28177
  prNumber,
28161
28178
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -28487,16 +28504,11 @@ function registerPrsComments(prsCommand) {
28487
28504
  import { randomUUID as randomUUID16 } from "crypto";
28488
28505
 
28489
28506
  // src/commands/prs/applyEdit.ts
28490
- import { execFileSync as execFileSync16 } from "child_process";
28491
- function applyEdit(number, title, body) {
28507
+ function applyEdit(number, title, body, attachments = []) {
28492
28508
  const args = ["pr", "edit", String(number)];
28493
28509
  if (title) args.push("--title", title);
28494
- args.push("--body", body);
28495
- try {
28496
- execFileSync16("gh", args, { stdio: "inherit" });
28497
- } catch {
28498
- process.exit(1);
28499
- }
28510
+ args.push("--body", body, ...attachArgs(attachments));
28511
+ process.stdout.write(runGhWithAttachments(args, attachments));
28500
28512
  }
28501
28513
 
28502
28514
  // src/commands/prs/formatResolvesReference.ts
@@ -28684,10 +28696,12 @@ async function edit(options2) {
28684
28696
  body: newBody,
28685
28697
  prNumber: number
28686
28698
  });
28699
+ const attachments = decision.screenshots ?? [];
28687
28700
  applyEdit(
28688
28701
  number,
28689
28702
  options2.title,
28690
- appendScreenshots(newBody, decision.screenshots ?? [])
28703
+ appendScreenshots(newBody, attachments),
28704
+ attachments
28691
28705
  );
28692
28706
  return;
28693
28707
  }
@@ -28785,14 +28799,19 @@ function buildValidatedBody(options2, usage) {
28785
28799
  }
28786
28800
 
28787
28801
  // src/commands/prs/placePr.ts
28788
- import { execFileSync as execFileSync17 } from "child_process";
28802
+ import { execFileSync as execFileSync16 } from "child_process";
28789
28803
 
28790
28804
  // src/commands/prs/buildCreateArgs.ts
28791
- function buildEditArgs(number, title, body) {
28792
- return ["pr", "edit", String(number), "--title", title, "--body", body];
28793
- }
28794
- function buildCreateArgs(title, body, options2) {
28795
- const args = ["pr", "create", "--title", title, "--body", body];
28805
+ function buildCreateArgs(title, body, options2, attachments = []) {
28806
+ const args = [
28807
+ "pr",
28808
+ "create",
28809
+ "--title",
28810
+ title,
28811
+ "--body",
28812
+ body,
28813
+ ...attachArgs(attachments)
28814
+ ];
28796
28815
  const valueFlags = [
28797
28816
  ["--base", options2.base],
28798
28817
  ["--head", options2.head],
@@ -28849,10 +28868,24 @@ async function recordPrActivity() {
28849
28868
  if (pr) await recordSessionRefs([pr]);
28850
28869
  }
28851
28870
 
28871
+ // src/commands/prs/buildEditArgs.ts
28872
+ function buildEditArgs(number, title, body, attachments = []) {
28873
+ return [
28874
+ "pr",
28875
+ "edit",
28876
+ String(number),
28877
+ "--title",
28878
+ title,
28879
+ "--body",
28880
+ body,
28881
+ ...attachArgs(attachments)
28882
+ ];
28883
+ }
28884
+
28852
28885
  // src/commands/prs/placePr.ts
28853
28886
  function hasUpstream2() {
28854
28887
  try {
28855
- execFileSync17(
28888
+ execFileSync16(
28856
28889
  "git",
28857
28890
  ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
28858
28891
  { stdio: "pipe" }
@@ -28864,16 +28897,16 @@ function hasUpstream2() {
28864
28897
  }
28865
28898
  function ensureBranchPushed() {
28866
28899
  const args = hasUpstream2() ? ["push"] : ["push", "--set-upstream", "origin", "HEAD"];
28867
- execFileSync17("git", args, { stdio: "inherit" });
28900
+ execFileSync16("git", args, { stdio: "inherit" });
28868
28901
  }
28869
- async function placePr(prNumber, title, body, options2) {
28870
- const args = prNumber !== null ? buildEditArgs(prNumber, title, body) : buildCreateArgs(title, body, options2);
28902
+ async function placePr(prNumber, title, body, options2, attachments = []) {
28903
+ const args = prNumber !== null ? buildEditArgs(prNumber, title, body, attachments) : buildCreateArgs(title, body, options2, attachments);
28871
28904
  try {
28872
28905
  if (prNumber === null && !options2.head) ensureBranchPushed();
28873
- execFileSync17("gh", args, { stdio: "inherit" });
28874
28906
  } catch {
28875
28907
  process.exit(1);
28876
28908
  }
28909
+ process.stdout.write(runGhWithAttachments(args, attachments));
28877
28910
  await recordPrActivity();
28878
28911
  }
28879
28912
 
@@ -28893,7 +28926,7 @@ function parseIncoming(line, type) {
28893
28926
  }
28894
28927
  }
28895
28928
  function requestSession(message3) {
28896
- return new Promise((resolve27, reject) => {
28929
+ return new Promise((resolve28, reject) => {
28897
28930
  connectToDaemon().then((socket) => {
28898
28931
  let settled = false;
28899
28932
  const finish2 = (error, sessionId) => {
@@ -28901,7 +28934,7 @@ function requestSession(message3) {
28901
28934
  settled = true;
28902
28935
  socket.destroy();
28903
28936
  if (error) reject(error);
28904
- else resolve27(sessionId);
28937
+ else resolve28(sessionId);
28905
28938
  };
28906
28939
  readSocketLines(socket, (line) => {
28907
28940
  const incoming = parseIncoming(line, message3.type);
@@ -29010,10 +29043,10 @@ function warn(reason4) {
29010
29043
  }
29011
29044
 
29012
29045
  // src/commands/prs/enableAutoMerge.ts
29013
- import { execFileSync as execFileSync18 } from "child_process";
29046
+ import { execFileSync as execFileSync17 } from "child_process";
29014
29047
  function enableAutoMerge() {
29015
29048
  try {
29016
- execFileSync18(
29049
+ execFileSync17(
29017
29050
  "gh",
29018
29051
  ["pr", "merge", getCurrentBranch2(), "--auto", "--squash"],
29019
29052
  { stdio: "inherit" }
@@ -29035,9 +29068,10 @@ async function previewAndPlace(args) {
29035
29068
  prNumber: args.prNumber,
29036
29069
  draft: args.options.draft === true
29037
29070
  });
29038
- const body = appendScreenshots(args.body, decision.screenshots ?? []);
29071
+ const attachments = decision.screenshots ?? [];
29072
+ const body = appendScreenshots(args.body, attachments);
29039
29073
  const options2 = decision.draft === void 0 ? args.options : { ...args.options, draft: decision.draft };
29040
- await placePr(args.prNumber, args.title, body, options2);
29074
+ await placePr(args.prNumber, args.title, body, options2, attachments);
29041
29075
  if (decision.autoMerge === true) enableAutoMerge();
29042
29076
  await chainAfterRaise(args.prNumber, decision);
29043
29077
  }
@@ -29178,7 +29212,7 @@ inline comments to specific spans of the preview; on rejection these are printed
29178
29212
  as numbered quoted-span + note pairs on stderr. Address every comment (and the
29179
29213
  reason), then run the command again to re-preview the revised PR. Repeat until it
29180
29214
  is approved. The reviewer may also drop or paste screenshots or video into the
29181
- pane; on approval these are appended to the PR body under a ## Screenshots section
29215
+ pane; on approval gh attaches them (gh ${minGhAttachVersion}+) under a ## Screenshots section
29182
29216
  automatically; on rejection they stay attached and reappear in the preview you
29183
29217
  re-propose, so you never author that section yourself. Just compose the sections
29184
29218
  and run the command.`;
@@ -29954,13 +29988,13 @@ ${errorText}`
29954
29988
  // src/commands/ravendb/resolveOpSecret.ts
29955
29989
  import { execSync as execSync50 } from "child_process";
29956
29990
  import chalk192 from "chalk";
29957
- function resolveOpSecret(reference) {
29958
- if (!reference.startsWith("op://")) {
29991
+ function resolveOpSecret(reference2) {
29992
+ if (!reference2.startsWith("op://")) {
29959
29993
  console.error(chalk192.red(`Invalid secret reference: must start with op://`));
29960
29994
  process.exit(1);
29961
29995
  }
29962
29996
  try {
29963
- return execSync50(`op read "${reference}"`, {
29997
+ return execSync50(`op read "${reference2}"`, {
29964
29998
  encoding: "utf8",
29965
29999
  stdio: ["pipe", "pipe", "pipe"]
29966
30000
  }).trim();
@@ -30769,8 +30803,8 @@ async function notify() {
30769
30803
  // src/commands/screenshot.ts
30770
30804
  import { execSync as execSync52 } from "child_process";
30771
30805
  import { existsSync as existsSync63, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync38 } from "fs";
30772
- import { tmpdir as tmpdir9 } from "os";
30773
- import { join as join74, resolve as resolve21 } from "path";
30806
+ import { tmpdir as tmpdir8 } from "os";
30807
+ import { join as join75, resolve as resolve22 } from "path";
30774
30808
  import chalk204 from "chalk";
30775
30809
 
30776
30810
  // src/commands/screenshot/captureWindowPs1.ts
@@ -30904,10 +30938,10 @@ function buildOutputPath(outputDir, processName) {
30904
30938
  mkdirSync21(outputDir, { recursive: true });
30905
30939
  }
30906
30940
  const timestamp5 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
30907
- return resolve21(outputDir, `${processName}-${timestamp5}.png`);
30941
+ return resolve22(outputDir, `${processName}-${timestamp5}.png`);
30908
30942
  }
30909
30943
  function runPowerShellScript(processName, outputPath) {
30910
- const scriptPath = join74(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
30944
+ const scriptPath = join75(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
30911
30945
  writeFileSync38(scriptPath, captureWindowPs1, "utf8");
30912
30946
  try {
30913
30947
  execSync52(
@@ -30920,7 +30954,7 @@ function runPowerShellScript(processName, outputPath) {
30920
30954
  }
30921
30955
  function screenshot(processName) {
30922
30956
  const config = loadConfig();
30923
- const outputDir = resolve21(config.screenshot.outputDir);
30957
+ const outputDir = resolve22(config.screenshot.outputDir);
30924
30958
  const outputPath = buildOutputPath(outputDir, processName);
30925
30959
  console.log(chalk204.gray(`Capturing window for process "${processName}" ...`));
30926
30960
  try {
@@ -31022,16 +31056,16 @@ function buildLimitsSegment(rateLimits) {
31022
31056
 
31023
31057
  // src/commands/readGitBranch.ts
31024
31058
  import { readFileSync as readFileSync46, statSync as statSync9 } from "fs";
31025
- import { isAbsolute as isAbsolute5, join as join75, resolve as resolve22 } from "path";
31059
+ import { isAbsolute as isAbsolute6, join as join76, resolve as resolve23 } from "path";
31026
31060
  function resolveGitDir(cwd) {
31027
- const dotGit = join75(cwd, ".git");
31028
- let stat4;
31061
+ const dotGit = join76(cwd, ".git");
31062
+ let stat5;
31029
31063
  try {
31030
- stat4 = statSync9(dotGit);
31064
+ stat5 = statSync9(dotGit);
31031
31065
  } catch {
31032
31066
  return null;
31033
31067
  }
31034
- if (stat4.isDirectory()) {
31068
+ if (stat5.isDirectory()) {
31035
31069
  return dotGit;
31036
31070
  }
31037
31071
  let contents;
@@ -31045,7 +31079,7 @@ function resolveGitDir(cwd) {
31045
31079
  return null;
31046
31080
  }
31047
31081
  const gitDir = match[1].trim();
31048
- return isAbsolute5(gitDir) ? gitDir : resolve22(cwd, gitDir);
31082
+ return isAbsolute6(gitDir) ? gitDir : resolve23(cwd, gitDir);
31049
31083
  }
31050
31084
  function readGitBranch(cwd) {
31051
31085
  const gitDir = resolveGitDir(cwd);
@@ -31054,7 +31088,7 @@ function readGitBranch(cwd) {
31054
31088
  }
31055
31089
  let head;
31056
31090
  try {
31057
- head = readFileSync46(join75(gitDir, "HEAD"), "utf8");
31091
+ head = readFileSync46(join76(gitDir, "HEAD"), "utf8");
31058
31092
  } catch {
31059
31093
  return null;
31060
31094
  }
@@ -31355,7 +31389,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES2) {
31355
31389
 
31356
31390
  // src/commands/refactor/check.ts
31357
31391
  function runScript(script, cwd) {
31358
- return new Promise((resolve27) => {
31392
+ return new Promise((resolve28) => {
31359
31393
  const child = spawn7("npm", ["run", script], {
31360
31394
  stdio: "pipe",
31361
31395
  shell: true,
@@ -31369,7 +31403,7 @@ function runScript(script, cwd) {
31369
31403
  output += data.toString();
31370
31404
  });
31371
31405
  child.on("close", (code) => {
31372
- resolve27({ script, code: code ?? 1, output });
31406
+ resolve28({ script, code: code ?? 1, output });
31373
31407
  });
31374
31408
  });
31375
31409
  }
@@ -33475,7 +33509,7 @@ function exitWith(message3) {
33475
33509
  }
33476
33510
 
33477
33511
  // src/commands/review/highLevel/proposeHighLevelGlobs.ts
33478
- import { execFileSync as execFileSync20 } from "child_process";
33512
+ import { execFileSync as execFileSync19 } from "child_process";
33479
33513
  import chalk227 from "chalk";
33480
33514
 
33481
33515
  // src/commands/review/highLevel/buildGlobProposalPrompt.ts
@@ -33523,8 +33557,8 @@ function readGlobs(value) {
33523
33557
  }
33524
33558
 
33525
33559
  // src/commands/review/highLevel/summariseRepoTree.ts
33526
- import { execFileSync as execFileSync19 } from "child_process";
33527
- import { dirname as dirname35, extname as extname3 } from "path";
33560
+ import { execFileSync as execFileSync18 } from "child_process";
33561
+ import { dirname as dirname36, extname as extname4 } from "path";
33528
33562
  var MAX_DIRECTORIES = 200;
33529
33563
  var MAX_EXTENSIONS_PER_DIRECTORY = 6;
33530
33564
  function summariseRepoTree(cwd = process.cwd()) {
@@ -33539,7 +33573,7 @@ function summariseRepoTree(cwd = process.cwd()) {
33539
33573
  }
33540
33574
  function listTrackedFiles(cwd) {
33541
33575
  try {
33542
- return execFileSync19("git", ["ls-files"], {
33576
+ return execFileSync18("git", ["ls-files"], {
33543
33577
  cwd,
33544
33578
  encoding: "utf8",
33545
33579
  maxBuffer: 64 * 1024 * 1024
@@ -33551,9 +33585,9 @@ function listTrackedFiles(cwd) {
33551
33585
  function countByDirectory(files) {
33552
33586
  const directories = /* @__PURE__ */ new Map();
33553
33587
  for (const file of files) {
33554
- const directory = dirname35(file) === "." ? "(repo root)" : dirname35(file);
33588
+ const directory = dirname36(file) === "." ? "(repo root)" : dirname36(file);
33555
33589
  const extensions = directories.get(directory) ?? /* @__PURE__ */ new Map();
33556
- const extension = extname3(file) === "" ? "(no extension)" : extname3(file);
33590
+ const extension = extname4(file) === "" ? "(no extension)" : extname4(file);
33557
33591
  extensions.set(extension, (extensions.get(extension) ?? 0) + 1);
33558
33592
  directories.set(directory, extensions);
33559
33593
  }
@@ -33584,7 +33618,7 @@ function proposeHighLevelGlobs(cwd = process.cwd()) {
33584
33618
  }
33585
33619
  function askClaude(prompt, cwd) {
33586
33620
  try {
33587
- return execFileSync20("claude", ["-p", "--model", "sonnet", prompt], {
33621
+ return execFileSync19("claude", ["-p", "--model", "sonnet", prompt], {
33588
33622
  cwd,
33589
33623
  encoding: "utf8",
33590
33624
  timeout: 12e4,
@@ -33677,7 +33711,7 @@ function groupFilesByDirectory(files) {
33677
33711
  }
33678
33712
 
33679
33713
  // src/commands/review/highLevel/buildHighLevelTree.ts
33680
- function basename19(path106) {
33714
+ function basename20(path106) {
33681
33715
  return path106.slice(path106.lastIndexOf("/") + 1);
33682
33716
  }
33683
33717
  function sum(nodes, key) {
@@ -33693,7 +33727,7 @@ function nodesOf(at2, prefix2) {
33693
33727
  const files = at2.files.map(
33694
33728
  (file) => ({
33695
33729
  kind: "file",
33696
- name: basename19(file.path),
33730
+ name: basename20(file.path),
33697
33731
  ...file
33698
33732
  })
33699
33733
  );
@@ -33809,13 +33843,13 @@ function firstMatch(body, pattern2) {
33809
33843
  return body.match(pattern2)?.[0] ?? null;
33810
33844
  }
33811
33845
  function checkDescriptionLinksIssue(body) {
33812
- const reference = firstMatch(body, ISSUE_URL_PATTERN) ?? firstMatch(body, CROSS_REPO_PATTERN) ?? firstMatch(body, SAME_REPO_PATTERN2);
33813
- if (!reference)
33846
+ const reference2 = firstMatch(body, ISSUE_URL_PATTERN) ?? firstMatch(body, CROSS_REPO_PATTERN) ?? firstMatch(body, SAME_REPO_PATTERN2);
33847
+ if (!reference2)
33814
33848
  return {
33815
33849
  status: "fail",
33816
33850
  reason: "no GitHub issue reference (`#123`, `owner/repo#123`, or an issue URL) in the description"
33817
33851
  };
33818
- return { status: "pass", reason: `links ${reference}` };
33852
+ return { status: "pass", reason: `links ${reference2}` };
33819
33853
  }
33820
33854
 
33821
33855
  // src/commands/review/highLevel/checkDescriptionSections.ts
@@ -34013,12 +34047,12 @@ function fetchHighLevelPr(prNumber, repo) {
34013
34047
  import { existsSync as existsSync64, readFileSync as readFileSync47 } from "fs";
34014
34048
 
34015
34049
  // src/commands/review/highLevel/highLevelReviewPath.ts
34016
- import { join as join76 } from "path";
34050
+ import { join as join77 } from "path";
34017
34051
  function slug(value) {
34018
34052
  return value.replace(/[^\w.-]+/g, "-");
34019
34053
  }
34020
34054
  function highLevelReviewPath(repo, headRef, headSha) {
34021
- return join76(
34055
+ return join77(
34022
34056
  getStoreDir(),
34023
34057
  "high-level-reviews",
34024
34058
  slug(repo),
@@ -34156,10 +34190,10 @@ function highLevelPreviewPayload(subject) {
34156
34190
 
34157
34191
  // src/commands/review/highLevel/saveHighLevelReview.ts
34158
34192
  import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync39 } from "fs";
34159
- import { dirname as dirname36 } from "path";
34193
+ import { dirname as dirname37 } from "path";
34160
34194
  function saveHighLevelReview(record) {
34161
34195
  const path106 = highLevelReviewPath(record.repo, record.headRef, record.headSha);
34162
- mkdirSync22(dirname36(path106), { recursive: true });
34196
+ mkdirSync22(dirname37(path106), { recursive: true });
34163
34197
  writeFileSync39(path106, `${JSON.stringify(record, null, 2)}
34164
34198
  `);
34165
34199
  return path106;
@@ -35094,7 +35128,7 @@ import { format } from "util";
35094
35128
 
35095
35129
  // src/commands/review/createReviewLogSink.ts
35096
35130
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync23 } from "fs";
35097
- import { join as join77 } from "path";
35131
+ import { join as join78 } from "path";
35098
35132
 
35099
35133
  // src/shared/stripAnsi.ts
35100
35134
  var ANSI = new RegExp(
@@ -35122,7 +35156,7 @@ function createReviewLogSink() {
35122
35156
  },
35123
35157
  attach(reviewDir) {
35124
35158
  mkdirSync23(reviewDir, { recursive: true });
35125
- logPath2 = join77(reviewDir, LOG_FILE);
35159
+ logPath2 = join78(reviewDir, LOG_FILE);
35126
35160
  const lines2 = [
35127
35161
  "",
35128
35162
  `=== ${(/* @__PURE__ */ new Date()).toISOString()} ===`,
@@ -35677,12 +35711,12 @@ function onCloseResult(ctx, code) {
35677
35711
  return { ...closed, stderr: ctx.stderr.value, stdout: ctx.stdout.value };
35678
35712
  }
35679
35713
  function waitForChildExit(ctx) {
35680
- return new Promise((resolve27) => {
35714
+ return new Promise((resolve28) => {
35681
35715
  let settled = false;
35682
35716
  const settle = (result) => {
35683
35717
  if (settled) return;
35684
35718
  settled = true;
35685
- resolve27(result);
35719
+ resolve28(result);
35686
35720
  };
35687
35721
  ctx.child.on("error", (err) => settle(onErrorResult(ctx, err)));
35688
35722
  ctx.child.on("close", (code) => settle(onCloseResult(ctx, code)));
@@ -36203,22 +36237,22 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
36203
36237
  }
36204
36238
 
36205
36239
  // src/commands/review/buildReviewPaths.ts
36206
- import { homedir as homedir23 } from "os";
36207
- import { basename as basename20, join as join78 } from "path";
36240
+ import { homedir as homedir24 } from "os";
36241
+ import { basename as basename21, join as join79 } from "path";
36208
36242
  function buildReviewPaths(repoRoot2, key) {
36209
- const reviewDir = join78(
36210
- homedir23(),
36243
+ const reviewDir = join79(
36244
+ homedir24(),
36211
36245
  ".assist",
36212
36246
  "reviews",
36213
- basename20(repoRoot2),
36247
+ basename21(repoRoot2),
36214
36248
  key
36215
36249
  );
36216
36250
  return {
36217
36251
  reviewDir,
36218
- requestPath: join78(reviewDir, "request.md"),
36219
- claudePath: join78(reviewDir, "claude.md"),
36220
- codexPath: join78(reviewDir, "codex.md"),
36221
- synthesisPath: join78(reviewDir, "synthesis.md")
36252
+ requestPath: join79(reviewDir, "request.md"),
36253
+ claudePath: join79(reviewDir, "claude.md"),
36254
+ codexPath: join79(reviewDir, "codex.md"),
36255
+ synthesisPath: join79(reviewDir, "synthesis.md")
36222
36256
  };
36223
36257
  }
36224
36258
 
@@ -37054,11 +37088,11 @@ import { randomUUID as randomUUID20 } from "crypto";
37054
37088
  // src/commands/sessions/shared/sendShowPreview.ts
37055
37089
  async function sendShowPreview(request) {
37056
37090
  const socket = await connectToDaemon();
37057
- await new Promise((resolve27, reject) => {
37091
+ await new Promise((resolve28, reject) => {
37058
37092
  const finish2 = (error) => {
37059
37093
  socket.destroy();
37060
37094
  if (error) reject(error);
37061
- else resolve27();
37095
+ else resolve28();
37062
37096
  };
37063
37097
  readSocketLines(socket, (line) => {
37064
37098
  const reply2 = parseReply(line);
@@ -37199,12 +37233,12 @@ async function reviewProposedSlackMessage(target, body, workingPath) {
37199
37233
  }
37200
37234
 
37201
37235
  // src/commands/slack/slackWorkingFile.ts
37202
- import { join as join79 } from "path";
37236
+ import { join as join80 } from "path";
37203
37237
  function slackWorkingFile(channel, partIndex) {
37204
37238
  const slug2 = channel.replace(/^[#@]/, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
37205
- const dir = join79(getStoreDir(), "slack");
37239
+ const dir = join80(getStoreDir(), "slack");
37206
37240
  const name = partIndex === void 0 ? slug2 : `${slug2}-${partIndex}`;
37207
- return { dir, bodyPath: join79(dir, `${name}.md`) };
37241
+ return { dir, bodyPath: join80(dir, `${name}.md`) };
37208
37242
  }
37209
37243
 
37210
37244
  // src/commands/slack/previewSlackThreadParts.ts
@@ -38321,9 +38355,9 @@ function createReadlineInterface() {
38321
38355
  });
38322
38356
  }
38323
38357
  function askQuestion(rl, question) {
38324
- return new Promise((resolve27) => {
38358
+ return new Promise((resolve28) => {
38325
38359
  rl.question(question, (answer) => {
38326
- resolve27(answer.trim());
38360
+ resolve28(answer.trim());
38327
38361
  });
38328
38362
  });
38329
38363
  }
@@ -38384,20 +38418,20 @@ async function configure() {
38384
38418
 
38385
38419
  // src/commands/transcript/list.ts
38386
38420
  import { existsSync as existsSync76, readdirSync as readdirSync19, statSync as statSync11 } from "fs";
38387
- import { join as join91 } from "path";
38421
+ import { join as join92 } from "path";
38388
38422
  function list3() {
38389
38423
  const { vttDir } = getTranscriptConfig();
38390
38424
  if (!existsSync76(vttDir)) return;
38391
38425
  for (const entry of readdirSync19(vttDir)) {
38392
38426
  if (!entry.endsWith(".vtt")) continue;
38393
- if (statSync11(join91(vttDir, entry)).isDirectory()) continue;
38427
+ if (statSync11(join92(vttDir, entry)).isDirectory()) continue;
38394
38428
  console.log(entry);
38395
38429
  }
38396
38430
  }
38397
38431
 
38398
38432
  // src/commands/transcript/move.ts
38399
38433
  import { existsSync as existsSync77, mkdirSync as mkdirSync32, renameSync as renameSync2, writeFileSync as writeFileSync50 } from "fs";
38400
- import { basename as basename24, join as join92 } from "path";
38434
+ import { basename as basename25, join as join93 } from "path";
38401
38435
 
38402
38436
  // src/commands/transcript/convertVttToMarkdown.ts
38403
38437
  function convertVttToMarkdown(inputPath) {
@@ -38407,9 +38441,9 @@ function convertVttToMarkdown(inputPath) {
38407
38441
  // src/commands/transcript/move.ts
38408
38442
  var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
38409
38443
  function archiveRawVtt(vttDir, sourcePath, filename) {
38410
- const processedDir = join92(vttDir, "processed");
38444
+ const processedDir = join93(vttDir, "processed");
38411
38445
  mkdirSync32(processedDir, { recursive: true });
38412
- renameSync2(sourcePath, join92(processedDir, filename));
38446
+ renameSync2(sourcePath, join93(processedDir, filename));
38413
38447
  }
38414
38448
  function move(file, options2) {
38415
38449
  const { date, client } = options2;
@@ -38418,27 +38452,27 @@ function move(file, options2) {
38418
38452
  process.exit(1);
38419
38453
  }
38420
38454
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
38421
- const filename = basename24(file);
38422
- const sourcePath = join92(vttDir, filename);
38455
+ const filename = basename25(file);
38456
+ const sourcePath = join93(vttDir, filename);
38423
38457
  if (!existsSync77(sourcePath)) {
38424
38458
  console.error(`Error: VTT file not found: ${sourcePath}`);
38425
38459
  process.exit(1);
38426
38460
  }
38427
- const base = basename24(filename, ".vtt").replace(/ Transcription$/, "");
38461
+ const base = basename25(filename, ".vtt").replace(/ Transcription$/, "");
38428
38462
  const outputName = `${date} ${base}.md`;
38429
- const formattedDir = join92(transcriptsDir, client);
38463
+ const formattedDir = join93(transcriptsDir, client);
38430
38464
  mkdirSync32(formattedDir, { recursive: true });
38431
- const formattedPath = join92(formattedDir, outputName);
38465
+ const formattedPath = join93(formattedDir, outputName);
38432
38466
  writeFileSync50(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
38433
38467
  archiveRawVtt(vttDir, sourcePath, filename);
38434
- const summaryPath = join92(summaryDir, client, outputName);
38468
+ const summaryPath = join93(summaryDir, client, outputName);
38435
38469
  console.log(`Formatted transcript: ${formattedPath}`);
38436
38470
  console.log(`Summary target: ${summaryPath}`);
38437
38471
  }
38438
38472
 
38439
38473
  // src/commands/transcript/merge.ts
38440
38474
  import { existsSync as existsSync78, writeFileSync as writeFileSync51 } from "fs";
38441
- import { basename as basename25 } from "path";
38475
+ import { basename as basename26 } from "path";
38442
38476
 
38443
38477
  // src/commands/transcript/failTranscript.ts
38444
38478
  function failTranscript(message3) {
@@ -38584,7 +38618,7 @@ function readSource3(file) {
38584
38618
  if (!existsSync78(file)) failTranscript(`VTT file not found: ${file}`);
38585
38619
  const cues = readCleanedCues(file);
38586
38620
  if (cues.length === 0) failTranscript(`no cues found in: ${file}`);
38587
- return { path: file, name: basename25(file), cues };
38621
+ return { path: file, name: basename26(file), cues };
38588
38622
  }
38589
38623
  function wholePassages(sources) {
38590
38624
  return sources.map((source) => ({
@@ -39245,7 +39279,7 @@ function listMigrationFiles(dir) {
39245
39279
 
39246
39280
  // src/commands/verify/migrations/readBaselineMigrations.ts
39247
39281
  import { execSync as execSync63 } from "child_process";
39248
- import { basename as basename26 } from "path";
39282
+ import { basename as basename27 } from "path";
39249
39283
  var MIGRATION_FILE3 = /^migration\d+[A-Za-z0-9]*\.ts$/;
39250
39284
  function readBaselineMigrations(repoRelativeDir, ref) {
39251
39285
  const baseline = /* @__PURE__ */ new Map();
@@ -39258,7 +39292,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
39258
39292
  } catch {
39259
39293
  return baseline;
39260
39294
  }
39261
- const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path106) => MIGRATION_FILE3.test(basename26(path106)));
39295
+ const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path106) => MIGRATION_FILE3.test(basename27(path106)));
39262
39296
  for (const path106 of paths) {
39263
39297
  try {
39264
39298
  const content = execSync63(`git show "${ref}:${path106}"`, {
@@ -39266,7 +39300,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
39266
39300
  maxBuffer: 16 * 1024 * 1024,
39267
39301
  stdio: ["pipe", "pipe", "pipe"]
39268
39302
  });
39269
- baseline.set(basename26(path106), content);
39303
+ baseline.set(basename27(path106), content);
39270
39304
  } catch {
39271
39305
  }
39272
39306
  }
@@ -39480,9 +39514,9 @@ function gitFailureReason(error) {
39480
39514
  }
39481
39515
 
39482
39516
  // src/commands/watch/resolveUpstream.ts
39483
- import { execFileSync as execFileSync21 } from "child_process";
39517
+ import { execFileSync as execFileSync20 } from "child_process";
39484
39518
  function runGit3(args, cwd) {
39485
- return execFileSync21("git", args, {
39519
+ return execFileSync20("git", args, {
39486
39520
  encoding: "utf8",
39487
39521
  stdio: ["pipe", "pipe", "pipe"],
39488
39522
  cwd
@@ -39520,9 +39554,9 @@ function resolveUpstream(cwd) {
39520
39554
  }
39521
39555
 
39522
39556
  // src/commands/watch/simulatedDivergencePath.ts
39523
- import { resolve as resolve24 } from "path";
39557
+ import { resolve as resolve25 } from "path";
39524
39558
  function simulatedDivergencePath(cwd) {
39525
- return resolve24(
39559
+ return resolve25(
39526
39560
  cwd ?? process.cwd(),
39527
39561
  runGit3(["rev-parse", "--git-path", "assist-simulate-divergence"], cwd)
39528
39562
  );
@@ -39554,12 +39588,12 @@ function decideLap(end, interrupted) {
39554
39588
  import { spawn as spawn9 } from "child_process";
39555
39589
  var WATCH_LAP_ARGS = ["watch", "wait", "--pull", "--build"];
39556
39590
  function runWatchLap() {
39557
- return new Promise((resolve27, reject) => {
39591
+ return new Promise((resolve28, reject) => {
39558
39592
  const assistFromPath = spawn9("assist", WATCH_LAP_ARGS, {
39559
39593
  stdio: "inherit",
39560
39594
  shell: process.platform === "win32"
39561
39595
  });
39562
- assistFromPath.on("close", (code, signal) => resolve27({ code, signal }));
39596
+ assistFromPath.on("close", (code, signal) => resolve28({ code, signal }));
39563
39597
  assistFromPath.on("error", reject);
39564
39598
  });
39565
39599
  }
@@ -39590,11 +39624,11 @@ function changedPaths(from, cwd) {
39590
39624
  }
39591
39625
 
39592
39626
  // src/commands/watch/readBuiltVersion.ts
39593
- import { join as join93 } from "path";
39627
+ import { join as join94 } from "path";
39594
39628
  function readBuiltVersion(cwd) {
39595
39629
  try {
39596
39630
  const root2 = runGit3(["rev-parse", "--show-toplevel"], cwd);
39597
- return readPackageJson(join93(root2, "package.json")).version ?? "unknown";
39631
+ return readPackageJson(join94(root2, "package.json")).version ?? "unknown";
39598
39632
  } catch {
39599
39633
  return "unknown";
39600
39634
  }
@@ -39930,7 +39964,7 @@ function resolveParams(params, cliArgs) {
39930
39964
 
39931
39965
  // src/commands/run/resolveRunCwd.ts
39932
39966
  import { existsSync as existsSync80 } from "fs";
39933
- import { resolve as resolve25 } from "path";
39967
+ import { resolve as resolve26 } from "path";
39934
39968
  var MissingRunCwdError = class extends Error {
39935
39969
  constructor(runName, cwd) {
39936
39970
  super(`run config "${runName}": cwd ${cwd} does not exist`);
@@ -39941,7 +39975,7 @@ var MissingRunCwdError = class extends Error {
39941
39975
  };
39942
39976
  function resolveRunCwd(config, baseDir = runConfigBaseDir()) {
39943
39977
  if (!config.cwd) return void 0;
39944
- const cwd = resolve25(baseDir, config.cwd);
39978
+ const cwd = resolve26(baseDir, config.cwd);
39945
39979
  if (!existsSync80(cwd)) throw new MissingRunCwdError(config.name, cwd);
39946
39980
  return cwd;
39947
39981
  }
@@ -40062,12 +40096,12 @@ ${buildWatchReport(from)}`);
40062
40096
  }
40063
40097
 
40064
40098
  // src/commands/watch/consumeSimulatedDivergence.ts
40065
- import { existsSync as existsSync81, rmSync as rmSync6 } from "fs";
40099
+ import { existsSync as existsSync81, rmSync as rmSync7 } from "fs";
40066
40100
  function consumeSimulatedDivergence(cwd) {
40067
40101
  try {
40068
40102
  const path106 = simulatedDivergencePath(cwd);
40069
40103
  if (!existsSync81(path106)) return false;
40070
- rmSync6(path106);
40104
+ rmSync7(path106);
40071
40105
  return true;
40072
40106
  } catch {
40073
40107
  return false;
@@ -40075,11 +40109,11 @@ function consumeSimulatedDivergence(cwd) {
40075
40109
  }
40076
40110
 
40077
40111
  // src/commands/watch/fetchQuietly.ts
40078
- import { execFileSync as execFileSync22 } from "child_process";
40112
+ import { execFileSync as execFileSync21 } from "child_process";
40079
40113
  var MIN_FETCH_TIMEOUT_MS = 6e4;
40080
40114
  function fetchQuietly(cwd, intervalMs) {
40081
40115
  try {
40082
- execFileSync22("git", ["fetch", "--quiet"], {
40116
+ execFileSync21("git", ["fetch", "--quiet"], {
40083
40117
  stdio: ["pipe", "pipe", "pipe"],
40084
40118
  cwd,
40085
40119
  timeout: Math.max(intervalMs, MIN_FETCH_TIMEOUT_MS)
@@ -40110,7 +40144,7 @@ function readMovement(cwd) {
40110
40144
  // src/commands/watch/pollForMovement.ts
40111
40145
  function pollForMovement(options2) {
40112
40146
  const { upstream, intervalMs, timeoutMs, timeout, cwd } = options2;
40113
- return new Promise((resolve27) => {
40147
+ return new Promise((resolve28) => {
40114
40148
  let settled = false;
40115
40149
  const finish2 = (outcome) => {
40116
40150
  if (settled) return;
@@ -40118,7 +40152,7 @@ function pollForMovement(options2) {
40118
40152
  clearInterval(ticker);
40119
40153
  clearTimeout(deadline);
40120
40154
  process.off("SIGINT", onInterrupt);
40121
- resolve27(outcome);
40155
+ resolve28(outcome);
40122
40156
  };
40123
40157
  const onInterrupt = () => finish2({ kind: "interrupted" });
40124
40158
  const ticker = setInterval(() => {
@@ -40238,7 +40272,7 @@ function extractCode(url, expectedState) {
40238
40272
  return code;
40239
40273
  }
40240
40274
  function waitForCallback(port, expectedState) {
40241
- return new Promise((resolve27, reject) => {
40275
+ return new Promise((resolve28, reject) => {
40242
40276
  const timeout = setTimeout(() => {
40243
40277
  server.close();
40244
40278
  reject(new Error("Authorization timed out after 120 seconds"));
@@ -40255,7 +40289,7 @@ function waitForCallback(port, expectedState) {
40255
40289
  const code = extractCode(url, expectedState);
40256
40290
  respondHtml(res, 200, "Authorization successful!");
40257
40291
  server.close();
40258
- resolve27(code);
40292
+ resolve28(code);
40259
40293
  } catch (error) {
40260
40294
  respondHtml(res, 400, error.message);
40261
40295
  server.close();
@@ -40375,9 +40409,9 @@ async function auth() {
40375
40409
  }
40376
40410
 
40377
40411
  // src/commands/roam/postRoamActivity.ts
40378
- import { execFileSync as execFileSync23 } from "child_process";
40412
+ import { execFileSync as execFileSync22 } from "child_process";
40379
40413
  import { readdirSync as readdirSync21, readFileSync as readFileSync62, statSync as statSync12 } from "fs";
40380
- import { join as join94 } from "path";
40414
+ import { join as join95 } from "path";
40381
40415
  function findPortFile(roamDir) {
40382
40416
  let entries;
40383
40417
  try {
@@ -40386,7 +40420,7 @@ function findPortFile(roamDir) {
40386
40420
  return void 0;
40387
40421
  }
40388
40422
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
40389
- const path106 = join94(roamDir, name);
40423
+ const path106 = join95(roamDir, name);
40390
40424
  try {
40391
40425
  return { path: path106, mtimeMs: statSync12(path106).mtimeMs };
40392
40426
  } catch {
@@ -40403,7 +40437,7 @@ var PID_BY_APP = {
40403
40437
  function postRoamActivity(app, event) {
40404
40438
  const appData = process.env.APPDATA;
40405
40439
  if (!appData) return;
40406
- const portFile = findPortFile(join94(appData, "Roam"));
40440
+ const portFile = findPortFile(join95(appData, "Roam"));
40407
40441
  if (!portFile) return;
40408
40442
  let port;
40409
40443
  try {
@@ -40414,7 +40448,7 @@ function postRoamActivity(app, event) {
40414
40448
  const pid = PID_BY_APP[app] ?? 99999;
40415
40449
  const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${pid}`;
40416
40450
  try {
40417
- execFileSync23("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
40451
+ execFileSync22("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
40418
40452
  stdio: "ignore"
40419
40453
  });
40420
40454
  } catch {
@@ -40539,7 +40573,7 @@ async function run3(name, args) {
40539
40573
 
40540
40574
  // src/commands/run/add.ts
40541
40575
  import { mkdirSync as mkdirSync33, writeFileSync as writeFileSync53 } from "fs";
40542
- import { join as join95 } from "path";
40576
+ import { join as join96 } from "path";
40543
40577
 
40544
40578
  // src/commands/run/extractOption.ts
40545
40579
  function extractOption(args, flag) {
@@ -40600,7 +40634,7 @@ function saveNewRunConfig(name, command, args, cwd) {
40600
40634
  saveConfig(config);
40601
40635
  }
40602
40636
  function createCommandFile(name) {
40603
- const dir = join95(".claude", "commands");
40637
+ const dir = join96(".claude", "commands");
40604
40638
  mkdirSync33(dir, { recursive: true });
40605
40639
  const content = `---
40606
40640
  description: Run ${name}
@@ -40608,7 +40642,7 @@ description: Run ${name}
40608
40642
 
40609
40643
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
40610
40644
  `;
40611
- const filePath = join95(dir, `${name}.md`);
40645
+ const filePath = join96(dir, `${name}.md`);
40612
40646
  writeFileSync53(filePath, content);
40613
40647
  console.log(`Created command file: ${filePath}`);
40614
40648
  }
@@ -40665,7 +40699,7 @@ function link2() {
40665
40699
 
40666
40700
  // src/commands/run/remove.ts
40667
40701
  import { existsSync as existsSync82, unlinkSync as unlinkSync21 } from "fs";
40668
- import { join as join96 } from "path";
40702
+ import { join as join97 } from "path";
40669
40703
  function findRemoveIndex() {
40670
40704
  const idx = process.argv.indexOf("remove");
40671
40705
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -40680,7 +40714,7 @@ function parseRemoveName() {
40680
40714
  return process.argv[idx + 1];
40681
40715
  }
40682
40716
  function deleteCommandFile(name) {
40683
- const filePath = join96(".claude", "commands", `${name}.md`);
40717
+ const filePath = join97(".claude", "commands", `${name}.md`);
40684
40718
  if (existsSync82(filePath)) {
40685
40719
  unlinkSync21(filePath);
40686
40720
  console.log(`Deleted command file: ${filePath}`);
@@ -40741,11 +40775,11 @@ function formatLink(link3) {
40741
40775
  }
40742
40776
 
40743
40777
  // src/commands/sessions/daemon/listDaemonPids.ts
40744
- import { execFileSync as execFileSync24 } from "child_process";
40778
+ import { execFileSync as execFileSync23 } from "child_process";
40745
40779
  function listDaemonPids() {
40746
40780
  if (process.platform === "win32") return [];
40747
40781
  try {
40748
- const out = execFileSync24("ps", ["-eo", "pid=,args="], {
40782
+ const out = execFileSync23("ps", ["-eo", "pid=,args="], {
40749
40783
  encoding: "utf8"
40750
40784
  });
40751
40785
  return out.split("\n").filter((line) => line.includes("assist") && / daemon run\b/.test(line)).map((line) => Number.parseInt(line.trim(), 10)).filter((pid) => Number.isInteger(pid));
@@ -40760,10 +40794,10 @@ var STATUS_TIMEOUT_MS2 = 5e3;
40760
40794
  function queryDaemon(socket) {
40761
40795
  socket.write(`${JSON.stringify({ type: "ping" })}
40762
40796
  `);
40763
- return new Promise((resolve27) => {
40797
+ return new Promise((resolve28) => {
40764
40798
  const result = { sessions: [] };
40765
40799
  const pending = /* @__PURE__ */ new Set(["sessions", "pong"]);
40766
- const timer = setTimeout(() => resolve27(result), STATUS_TIMEOUT_MS2);
40800
+ const timer = setTimeout(() => resolve28(result), STATUS_TIMEOUT_MS2);
40767
40801
  const lines2 = createInterface8({ input: socket });
40768
40802
  lines2.on("error", () => {
40769
40803
  });
@@ -40771,7 +40805,7 @@ function queryDaemon(socket) {
40771
40805
  applyLine(result, pending, line);
40772
40806
  if (pending.size === 0) {
40773
40807
  clearTimeout(timer);
40774
- resolve27(result);
40808
+ resolve28(result);
40775
40809
  }
40776
40810
  });
40777
40811
  });
@@ -40871,11 +40905,11 @@ function clearPersistedSessionsOnDrain() {
40871
40905
 
40872
40906
  // src/commands/sessions/daemon/readDaemonMessage.ts
40873
40907
  function readDaemonMessage(lines2, timeoutMs, fallback, match) {
40874
- return new Promise((resolve27) => {
40908
+ return new Promise((resolve28) => {
40875
40909
  const finish2 = (value) => {
40876
40910
  clearTimeout(timer);
40877
40911
  lines2.off("line", onLine);
40878
- resolve27(value);
40912
+ resolve28(value);
40879
40913
  };
40880
40914
  const timer = setTimeout(() => finish2(fallback), timeoutMs);
40881
40915
  const onLine = (line) => {
@@ -41691,16 +41725,16 @@ function setStatus2(session, newStatus) {
41691
41725
 
41692
41726
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
41693
41727
  import { existsSync as existsSync87 } from "fs";
41694
- import { basename as basename27 } from "path";
41728
+ import { basename as basename28 } from "path";
41695
41729
 
41696
41730
  // src/commands/sessions/daemon/worktree/deleteStrandedTree.ts
41697
41731
  import { existsSync as existsSync86 } from "fs";
41698
- import { join as join99 } from "path";
41732
+ import { join as join100 } from "path";
41699
41733
 
41700
41734
  // src/commands/sessions/daemon/worktree/deleteTreeDirectly.ts
41701
41735
  import { statSync as statSync14 } from "fs";
41702
- import { rm as rm4 } from "fs/promises";
41703
- import { join as join98 } from "path";
41736
+ import { rm as rm3 } from "fs/promises";
41737
+ import { join as join99 } from "path";
41704
41738
  async function deleteTreeDirectly(clone, worktreePath, why) {
41705
41739
  if (holdsAGitDirectoryRatherThanALink(worktreePath)) {
41706
41740
  const refusal = "it is a clone of its own, not a linked worktree";
@@ -41711,7 +41745,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
41711
41745
  }
41712
41746
  daemonLog(`worktree ${worktreePath} deleting its directory directly: ${why}`);
41713
41747
  try {
41714
- await rm4(worktreePath, {
41748
+ await rm3(worktreePath, {
41715
41749
  recursive: true,
41716
41750
  force: true,
41717
41751
  maxRetries: 3,
@@ -41728,7 +41762,7 @@ async function deleteTreeDirectly(clone, worktreePath, why) {
41728
41762
  return { removed: true };
41729
41763
  }
41730
41764
  function holdsAGitDirectoryRatherThanALink(worktreePath) {
41731
- return statSync14(join98(worktreePath, ".git"), {
41765
+ return statSync14(join99(worktreePath, ".git"), {
41732
41766
  throwIfNoEntry: false
41733
41767
  })?.isDirectory() === true;
41734
41768
  }
@@ -41764,7 +41798,7 @@ async function deleteStrandedTree(clone, worktreePath, cause) {
41764
41798
  );
41765
41799
  }
41766
41800
  function strandedReason(worktreePath, cause) {
41767
- if (!existsSync86(join99(worktreePath, ".git")))
41801
+ if (!existsSync86(join100(worktreePath, ".git")))
41768
41802
  return "its .git link is already gone";
41769
41803
  if (/not a working tree|not a git repository/i.test(reason2(cause)))
41770
41804
  return "git no longer recognises it as a working tree";
@@ -41834,7 +41868,7 @@ async function reapWorktree(worktreePath, force = false) {
41834
41868
  const clone = owningClone(worktreePath);
41835
41869
  const removal = await removeTree(clone, worktreePath, force);
41836
41870
  if (!removal.removed) return removal;
41837
- await deleteWorktreeBranch(clone, basename27(worktreePath));
41871
+ await deleteWorktreeBranch(clone, basename28(worktreePath));
41838
41872
  forgetWorktree(worktreePath);
41839
41873
  daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
41840
41874
  return removal;
@@ -42008,7 +42042,7 @@ function closeGateApplies(sessions, session) {
42008
42042
 
42009
42043
  // src/commands/sessions/daemon/worktree/liveProcessesInTree.ts
42010
42044
  import { readdirSync as readdirSync22, readlinkSync } from "fs";
42011
- import { sep as sep3 } from "path";
42045
+ import { sep as sep4 } from "path";
42012
42046
  function liveProcessesInTree(treePath, procRoot = "/proc") {
42013
42047
  let entries;
42014
42048
  try {
@@ -42021,7 +42055,7 @@ function liveProcessesInTree(treePath, procRoot = "/proc") {
42021
42055
  const pid = Number(entry);
42022
42056
  if (!Number.isInteger(pid) || pid === process.pid) continue;
42023
42057
  const cwd = processCwd(`${procRoot}/${entry}/cwd`);
42024
- if (cwd && (cwd === treePath || cwd.startsWith(treePath + sep3)))
42058
+ if (cwd && (cwd === treePath || cwd.startsWith(treePath + sep4)))
42025
42059
  pids.push(pid);
42026
42060
  }
42027
42061
  return pids;
@@ -42038,12 +42072,12 @@ function processCwd(link3) {
42038
42072
  var POLL_MS = 500;
42039
42073
  var GRACE_MS = 5e3;
42040
42074
  function awaitTreeVacated(session, treePath) {
42041
- return new Promise((resolve27) => {
42075
+ return new Promise((resolve28) => {
42042
42076
  let ticks = GRACE_MS / POLL_MS;
42043
42077
  const settle = (outcome) => {
42044
42078
  clearTimeout(timer);
42045
42079
  session.closeGrace = void 0;
42046
- resolve27(outcome);
42080
+ resolve28(outcome);
42047
42081
  };
42048
42082
  const tick = () => {
42049
42083
  if (liveProcessesInTree(treePath).length === 0) settle("vacated");
@@ -42579,13 +42613,13 @@ function isBacklogItemId(text17) {
42579
42613
  }
42580
42614
 
42581
42615
  // src/commands/sessions/daemon/generateSessionTitle.ts
42582
- import { execFile as execFile14 } from "child_process";
42583
- import { promisify as promisify13 } from "util";
42584
- var execFileAsync12 = promisify13(execFile14);
42616
+ import { execFile as execFile12 } from "child_process";
42617
+ import { promisify as promisify11 } from "util";
42618
+ var execFileAsync10 = promisify11(execFile12);
42585
42619
  var SESSION_TITLE_MAX_LENGTH = 48;
42586
42620
  async function generateSessionTitle(prompt) {
42587
42621
  try {
42588
- const { stdout } = await execFileAsync12(
42622
+ const { stdout } = await execFileAsync10(
42589
42623
  "claude",
42590
42624
  ["-p", "--model", "haiku", buildPrompt5(prompt)],
42591
42625
  { encoding: "utf8", windowsHide: true, timeout: 3e4 }
@@ -42665,7 +42699,7 @@ function emitSessionOutput(session, clients, data) {
42665
42699
 
42666
42700
  // src/commands/sessions/daemon/exitReason.ts
42667
42701
  import { existsSync as existsSync89 } from "fs";
42668
- import { resolve as resolve26 } from "path";
42702
+ import { resolve as resolve27 } from "path";
42669
42703
  function exitDetail(session) {
42670
42704
  if (session.cwd && !existsSync89(session.cwd))
42671
42705
  return `working directory ${session.cwd} no longer exists`;
@@ -42680,7 +42714,7 @@ function missingRunConfigCwd(session) {
42680
42714
  const dir = session.cwd ?? process.cwd();
42681
42715
  const config = resolveRunConfig(session.runName, dir);
42682
42716
  if (!config?.cwd) return void 0;
42683
- const configured = resolve26(runConfigBaseDirFrom(dir), config.cwd);
42717
+ const configured = resolve27(runConfigBaseDirFrom(dir), config.cwd);
42684
42718
  if (existsSync89(configured)) return void 0;
42685
42719
  return `run config "${config.name}": cwd ${configured} does not exist`;
42686
42720
  }
@@ -42730,7 +42764,7 @@ function handleRefusedRun(session, exitCode, onStatusChange) {
42730
42764
 
42731
42765
  // src/commands/sessions/daemon/watchActivity.ts
42732
42766
  import { existsSync as existsSync90, mkdirSync as mkdirSync34, watch as watch2 } from "fs";
42733
- import { dirname as dirname41 } from "path";
42767
+ import { dirname as dirname42 } from "path";
42734
42768
 
42735
42769
  // src/commands/sessions/daemon/applyActivityToSession.ts
42736
42770
  function applyActivityToSession(session, activity2) {
@@ -42792,7 +42826,7 @@ var DEBOUNCE_MS2 = 50;
42792
42826
  function watchActivity(session, notify2, onClaudeSessionId) {
42793
42827
  if (session.commandType !== "assist" || !session.cwd) return;
42794
42828
  const path106 = activityPath(session.id);
42795
- const dir = dirname41(path106);
42829
+ const dir = dirname42(path106);
42796
42830
  try {
42797
42831
  mkdirSync34(dir, { recursive: true });
42798
42832
  } catch {
@@ -44550,10 +44584,10 @@ function deferralNotice(persisted, cap2) {
44550
44584
 
44551
44585
  // src/commands/sessions/daemon/worktree/underTempRoot.ts
44552
44586
  import { realpathSync as realpathSync3 } from "fs";
44553
- import { tmpdir as tmpdir10 } from "os";
44554
- import { sep as sep4 } from "path";
44587
+ import { tmpdir as tmpdir9 } from "os";
44588
+ import { sep as sep5 } from "path";
44555
44589
  function tempRoots() {
44556
- const raw = tmpdir10();
44590
+ const raw = tmpdir9();
44557
44591
  const roots = /* @__PURE__ */ new Set([raw]);
44558
44592
  try {
44559
44593
  roots.add(realpathSync3(raw));
@@ -44564,7 +44598,7 @@ function tempRoots() {
44564
44598
  }
44565
44599
  function underTempRoot(path106) {
44566
44600
  return tempRoots().some(
44567
- (root2) => path106.startsWith(root2.endsWith(sep4) ? root2 : root2 + sep4)
44601
+ (root2) => path106.startsWith(root2.endsWith(sep5) ? root2 : root2 + sep5)
44568
44602
  );
44569
44603
  }
44570
44604
 
@@ -45045,7 +45079,7 @@ function rearmStoppedSessions(sessions, notify2) {
45045
45079
 
45046
45080
  // src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
45047
45081
  import { existsSync as existsSync93 } from "fs";
45048
- import { basename as basename29 } from "path";
45082
+ import { basename as basename30 } from "path";
45049
45083
 
45050
45084
  // src/commands/sessions/daemon/worktree/accountedTrees.ts
45051
45085
  function accountedTrees(sessions) {
@@ -45153,7 +45187,7 @@ function capped2(lines2) {
45153
45187
  }
45154
45188
 
45155
45189
  // src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
45156
- import { basename as basename28 } from "path";
45190
+ import { basename as basename29 } from "path";
45157
45191
  function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
45158
45192
  const { orphan, reason: reason4, held } = recovered;
45159
45193
  let id;
@@ -45176,7 +45210,7 @@ function orphanedSession(id, recovered) {
45176
45210
  const { orphan, reason: reason4, held } = recovered;
45177
45211
  return {
45178
45212
  ...sessionBase(id, "stopped"),
45179
- name: `recovered ${basename28(orphan.path)}`,
45213
+ name: `recovered ${basename29(orphan.path)}`,
45180
45214
  subtitle: `${held.summary} in ${orphan.path}`,
45181
45215
  commandType: "claude",
45182
45216
  pty: null,
@@ -45237,7 +45271,7 @@ async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
45237
45271
  logVanishedTree(sessions, path106);
45238
45272
  vanished.set(clone, [
45239
45273
  ...vanished.get(clone) ?? [],
45240
- { path: path106, branch: basename29(path106) }
45274
+ { path: path106, branch: basename30(path106) }
45241
45275
  ]);
45242
45276
  continue;
45243
45277
  }
@@ -45649,7 +45683,7 @@ function failPendingCreators(state, message3) {
45649
45683
  }
45650
45684
  function resetRelayState(state, reason4) {
45651
45685
  failPendingCreators(state, reason4);
45652
- for (const resolve27 of state.historyWaiters) resolve27([]);
45686
+ for (const resolve28 of state.historyWaiters) resolve28([]);
45653
45687
  state.historyWaiters = [];
45654
45688
  state.sessions = [];
45655
45689
  state.lastSnapshot = void 0;
@@ -46090,16 +46124,16 @@ var HISTORY_TIMEOUT_MS = 5e3;
46090
46124
  function requestLinkHistory(ctx) {
46091
46125
  if (!ctx.greeted) return Promise.resolve([]);
46092
46126
  const waiters = ctx.relay.historyWaiters;
46093
- return new Promise((resolve27) => {
46127
+ return new Promise((resolve28) => {
46094
46128
  const settle = (sessions) => {
46095
46129
  clearTimeout(timer);
46096
- resolve27(sessions);
46130
+ resolve28(sessions);
46097
46131
  };
46098
46132
  const timer = setTimeout(() => {
46099
46133
  const index2 = waiters.indexOf(settle);
46100
46134
  if (index2 !== -1) waiters.splice(index2, 1);
46101
46135
  daemonLog(`link ${ctx.spec.name} ws: history timed out`);
46102
- resolve27(ctx.relay.lastHistory ?? []);
46136
+ resolve28(ctx.relay.lastHistory ?? []);
46103
46137
  }, HISTORY_TIMEOUT_MS);
46104
46138
  timer.unref?.();
46105
46139
  waiters.push(settle);
@@ -46358,7 +46392,7 @@ import { existsSync as existsSync95 } from "fs";
46358
46392
 
46359
46393
  // src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
46360
46394
  import { copyFileSync as copyFileSync5, existsSync as existsSync94, mkdirSync as mkdirSync36 } from "fs";
46361
- import { join as join101 } from "path";
46395
+ import { join as join102 } from "path";
46362
46396
  function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
46363
46397
  const dir = projectDirForCwd(toCwd);
46364
46398
  if (dir === projectDirForCwd(fromCwd)) {
@@ -46367,7 +46401,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
46367
46401
  );
46368
46402
  return;
46369
46403
  }
46370
- const dest = join101(dir, `${claudeSessionId}.jsonl`);
46404
+ const dest = join102(dir, `${claudeSessionId}.jsonl`);
46371
46405
  if (existsSync94(dest)) {
46372
46406
  daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
46373
46407
  return;
@@ -47811,7 +47845,7 @@ function summaryPathFor(jsonlPath2) {
47811
47845
  }
47812
47846
 
47813
47847
  // src/commands/sessions/summarise/summariseSession.ts
47814
- import { execFileSync as execFileSync25 } from "child_process";
47848
+ import { execFileSync as execFileSync24 } from "child_process";
47815
47849
  function summariseSession(jsonlPath2) {
47816
47850
  const firstMessage = extractFirstUserMessage(jsonlPath2);
47817
47851
  const backlogIds = scanSessionBacklogRefs(jsonlPath2);
@@ -47820,7 +47854,7 @@ function summariseSession(jsonlPath2) {
47820
47854
  }
47821
47855
  const prompt = buildPrompt6(firstMessage, backlogIds);
47822
47856
  try {
47823
- const output = execFileSync25("claude", ["-p", "--model", "haiku", prompt], {
47857
+ const output = execFileSync24("claude", ["-p", "--model", "haiku", prompt], {
47824
47858
  encoding: "utf8",
47825
47859
  timeout: 3e4,
47826
47860
  stdio: ["ignore", "pipe", "ignore"]