@staff0rd/assist 0.767.0 → 0.767.2

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.767.0",
9
+ version: "0.767.2",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -13696,8 +13696,8 @@ function subsequenceScore(text17, query) {
13696
13696
  function scoreFilePath(path106, query) {
13697
13697
  const needle = query.trim().toLowerCase();
13698
13698
  if (!needle) return 0;
13699
- const basename32 = path106.slice(path106.lastIndexOf("/") + 1);
13700
- const inBasename = subsequenceScore(basename32, needle);
13699
+ const basename33 = path106.slice(path106.lastIndexOf("/") + 1);
13700
+ const inBasename = subsequenceScore(basename33, needle);
13701
13701
  if (inBasename !== null) return BASENAME_WEIGHT + inBasename;
13702
13702
  return subsequenceScore(path106, needle);
13703
13703
  }
@@ -15211,12 +15211,9 @@ var attachmentMimeTypes = {
15211
15211
  "image/gif": "gif",
15212
15212
  "image/webp": "webp",
15213
15213
  "image/svg+xml": "svg",
15214
- "image/bmp": "bmp",
15215
- "image/avif": "avif",
15216
15214
  "video/mp4": "mp4",
15217
15215
  "video/webm": "webm",
15218
- "video/quicktime": "mov",
15219
- "video/ogg": "ogv"
15216
+ "video/quicktime": "mov"
15220
15217
  };
15221
15218
 
15222
15219
  // src/commands/sessions/web/attachmentContentType.ts
@@ -16972,20 +16969,29 @@ function extensionFromMime(contentType) {
16972
16969
  const subtype = mime.split("/")[1]?.replace(/^x-/, "").replace(/\+.*$/, "");
16973
16970
  return subtype && /^[a-z0-9]+$/.test(subtype) ? subtype : void 0;
16974
16971
  }
16972
+ var ghAttachableExtensions = /* @__PURE__ */ new Set([
16973
+ ...Object.values(attachmentMimeTypes),
16974
+ "jpeg"
16975
+ ]);
16975
16976
  function pickExtension(name, contentType) {
16976
16977
  const fromName = extname2(name).replace(/^\./, "").toLowerCase();
16977
- if (/^[a-z0-9]+$/.test(fromName)) return fromName;
16978
- return extensionFromMime(contentType) ?? "png";
16978
+ const ext = /^[a-z0-9]+$/.test(fromName) ? fromName : extensionFromMime(contentType) ?? "png";
16979
+ if (!ghAttachableExtensions.has(ext))
16980
+ throw new Error(
16981
+ `gh cannot attach .${ext} files (supported: ${[...ghAttachableExtensions].join(", ")}).`
16982
+ );
16983
+ return ext;
16979
16984
  }
16980
16985
  function safeBaseName(name) {
16981
16986
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-");
16982
16987
  return base.replace(/^-+|-+$/g, "").slice(0, 60) || "screenshot";
16983
16988
  }
16984
16989
  async function stageAttachment(name, contentType, body) {
16990
+ const ext = pickExtension(name, contentType);
16985
16991
  await mkdir4(stagedAttachmentsDir, { recursive: true });
16986
16992
  const dir = await mkdtemp(join41(stagedAttachmentsDir, "upload-"));
16987
16993
  const alt = safeBaseName(name);
16988
- const filePath = join41(dir, `${alt}.${pickExtension(name, contentType)}`);
16994
+ const filePath = join41(dir, `${alt}.${ext}`);
16989
16995
  await writeFile2(filePath, body);
16990
16996
  return { dir, filePath, alt };
16991
16997
  }
@@ -24631,10 +24637,7 @@ async function reviewProposedIssue(title, body, metadata2 = []) {
24631
24637
 
24632
24638
  // src/commands/prs/attachArgs.ts
24633
24639
  function attachArgs(attachments) {
24634
- return attachments.flatMap(({ path: path106, alt }) => [
24635
- "--attach",
24636
- alt ? `${path106}#${alt}` : path106
24637
- ]);
24640
+ return attachments.flatMap(({ path: path106 }) => ["--attach", path106]);
24638
24641
  }
24639
24642
 
24640
24643
  // src/commands/prs/runGhWithAttachments.ts
@@ -41014,7 +41017,7 @@ function requestDrain(socket, lines2) {
41014
41017
  }
41015
41018
 
41016
41019
  // src/commands/sessions/daemon/runDaemon.ts
41017
- import { mkdirSync as mkdirSync37 } from "fs";
41020
+ import { mkdirSync as mkdirSync38 } from "fs";
41018
41021
 
41019
41022
  // src/commands/sessions/daemon/createAutoExit.ts
41020
41023
  var DEFAULT_GRACE_MS = 6e4;
@@ -41249,6 +41252,10 @@ function resizeSession(sessions, id, cols, rows, viewer = {}) {
41249
41252
  if (isInactiveViewer(s, viewer)) return;
41250
41253
  claimViewer(s, viewer, "resize");
41251
41254
  const unchanged = s.cols === cols && s.rows === rows;
41255
+ if (!unchanged || viewer.claim)
41256
+ daemonLog(
41257
+ `session ${id} resize ${s.cols}x${s.rows} -> ${cols}x${rows} by ${viewer.viewerId ?? "unknown viewer"} on ${viewer.viewerNode ?? "unknown node"}${viewer.claim ? " (takeover)" : ""}`
41258
+ );
41252
41259
  s.cols = cols;
41253
41260
  s.rows = rows;
41254
41261
  const resize = (c, r) => resizePty(s, c, r);
@@ -42719,10 +42726,37 @@ function startSessionTitleGeneration(session, notify2) {
42719
42726
  runSessionTitleGeneration(session, prompt, notify2, singleLineTitle(prompt));
42720
42727
  }
42721
42728
 
42729
+ // src/commands/sessions/daemon/worktree/appendWatcherLog.ts
42730
+ import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync34 } from "fs";
42731
+ import { dirname as dirname42 } from "path";
42732
+
42733
+ // src/commands/sessions/daemon/worktree/watcherLogPath.ts
42734
+ import { createHash as createHash4 } from "crypto";
42735
+ import { homedir as homedir26 } from "os";
42736
+ import { basename as basename29, join as join102 } from "path";
42737
+ function watcherLogPath(cwd) {
42738
+ const clone = canonicalTreePath(cwd);
42739
+ const key = createHash4("sha1").update(clone).digest("hex").slice(0, 8);
42740
+ const dir = process.env.ASSIST_WATCHER_LOG_DIR ?? join102(homedir26(), ".assist", "watchers");
42741
+ return join102(dir, `${basename29(clone) || "root"}-${key}.log`);
42742
+ }
42743
+
42744
+ // src/commands/sessions/daemon/worktree/appendWatcherLog.ts
42745
+ function appendWatcherLog(session, data) {
42746
+ if (session.watcher !== true || !session.cwd) return;
42747
+ try {
42748
+ const path106 = watcherLogPath(session.cwd);
42749
+ mkdirSync34(dirname42(path106), { recursive: true });
42750
+ appendFileSync3(path106, data);
42751
+ } catch {
42752
+ }
42753
+ }
42754
+
42722
42755
  // src/commands/sessions/daemon/emitSessionOutput.ts
42723
42756
  var MAX_SCROLLBACK = 256 * 1024;
42724
42757
  function emitSessionOutput(session, clients, data) {
42725
42758
  session.scrollback += data;
42759
+ appendWatcherLog(session, data);
42726
42760
  if (session.scrollback.length > MAX_SCROLLBACK) {
42727
42761
  session.scrollback = session.scrollback.slice(-MAX_SCROLLBACK);
42728
42762
  }
@@ -42795,8 +42829,8 @@ function handleRefusedRun(session, exitCode, onStatusChange) {
42795
42829
  }
42796
42830
 
42797
42831
  // src/commands/sessions/daemon/watchActivity.ts
42798
- import { existsSync as existsSync90, mkdirSync as mkdirSync34, watch as watch2 } from "fs";
42799
- import { dirname as dirname42 } from "path";
42832
+ import { existsSync as existsSync90, mkdirSync as mkdirSync35, watch as watch2 } from "fs";
42833
+ import { dirname as dirname43 } from "path";
42800
42834
 
42801
42835
  // src/commands/sessions/daemon/applyActivityToSession.ts
42802
42836
  function applyActivityToSession(session, activity2) {
@@ -42858,9 +42892,9 @@ var DEBOUNCE_MS2 = 50;
42858
42892
  function watchActivity(session, notify2, onClaudeSessionId) {
42859
42893
  if (session.commandType !== "assist" || !session.cwd) return;
42860
42894
  const path106 = activityPath(session.id);
42861
- const dir = dirname42(path106);
42895
+ const dir = dirname43(path106);
42862
42896
  try {
42863
- mkdirSync34(dir, { recursive: true });
42897
+ mkdirSync35(dir, { recursive: true });
42864
42898
  } catch {
42865
42899
  return;
42866
42900
  }
@@ -43064,10 +43098,10 @@ function headContainsSessionId(filePath, claudeSessionId) {
43064
43098
  }
43065
43099
 
43066
43100
  // src/commands/sessions/daemon/ensureProjectDirExists.ts
43067
- import { mkdirSync as mkdirSync35 } from "fs";
43101
+ import { mkdirSync as mkdirSync36 } from "fs";
43068
43102
  function ensureProjectDirExists(dir, sessionId) {
43069
43103
  try {
43070
- mkdirSync35(dir, { recursive: true });
43104
+ mkdirSync36(dir, { recursive: true });
43071
43105
  return true;
43072
43106
  } catch (error) {
43073
43107
  daemonLog(
@@ -44046,12 +44080,42 @@ function createAssistSession(id, assistArgs, cwd, meta, holdPty) {
44046
44080
  };
44047
44081
  }
44048
44082
 
44083
+ // src/commands/sessions/daemon/worktree/seedWatcherScrollback.ts
44084
+ import { readFileSync as readFileSync65, writeFileSync as writeFileSync54 } from "fs";
44085
+ var SCROLLBACK_TAIL = 256 * 1024;
44086
+ var MAX_LOG_SIZE = 4 * 1024 * 1024;
44087
+ function readLogTail2(path106) {
44088
+ let log2;
44089
+ try {
44090
+ log2 = readFileSync65(path106, "utf8");
44091
+ } catch {
44092
+ return "";
44093
+ }
44094
+ if (log2.length > MAX_LOG_SIZE) {
44095
+ log2 = log2.slice(-SCROLLBACK_TAIL);
44096
+ writeFileSync54(path106, log2);
44097
+ daemonLog(`watcher log ${path106} trimmed to its last ${log2.length} chars`);
44098
+ }
44099
+ return log2.slice(-SCROLLBACK_TAIL);
44100
+ }
44101
+ function seedWatcherScrollback(cwd, event) {
44102
+ const path106 = watcherLogPath(cwd);
44103
+ const history = readLogTail2(path106);
44104
+ const note = watcherNote(`${event} at ${(/* @__PURE__ */ new Date()).toLocaleString()}`);
44105
+ appendWatcherLog({ watcher: true, cwd }, note);
44106
+ daemonLog(
44107
+ `watcher in ${cwd} seeded with ${history.length} chars of history from ${path106} (${event})`
44108
+ );
44109
+ return history + note;
44110
+ }
44111
+
44049
44112
  // src/commands/sessions/daemon/createWatcherSession.ts
44050
44113
  var WATCHER_ARGS = ["watch", "loop"];
44051
44114
  function createWatcherSession(id, cwd) {
44052
44115
  return {
44053
44116
  ...createAssistSession(id, WATCHER_ARGS, cwd),
44054
- watcher: true
44117
+ watcher: true,
44118
+ scrollback: seedWatcherScrollback(cwd, "watcher started")
44055
44119
  };
44056
44120
  }
44057
44121
 
@@ -45030,7 +45094,17 @@ function relaunchConsoleWatcher(id, persisted, base) {
45030
45094
  daemonLog(
45031
45095
  `relaunching watcher session ${id} running ${command.join(" ")} in ${persisted.cwd ?? "(no cwd)"}`
45032
45096
  );
45033
- return runningSession(base, persisted, spawnPty(command, persisted.cwd, id));
45097
+ const session = runningSession(
45098
+ base,
45099
+ persisted,
45100
+ spawnPty(command, persisted.cwd, id)
45101
+ );
45102
+ if (persisted.cwd)
45103
+ session.scrollback = seedWatcherScrollback(
45104
+ persisted.cwd,
45105
+ "daemon restarted; watcher relaunched"
45106
+ );
45107
+ return session;
45034
45108
  }
45035
45109
 
45036
45110
  // src/commands/sessions/daemon/restoreSession.ts
@@ -45137,7 +45211,7 @@ function rearmStoppedSessions(sessions, notify2) {
45137
45211
 
45138
45212
  // src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
45139
45213
  import { existsSync as existsSync93 } from "fs";
45140
- import { basename as basename30 } from "path";
45214
+ import { basename as basename31 } from "path";
45141
45215
 
45142
45216
  // src/commands/sessions/daemon/worktree/accountedTrees.ts
45143
45217
  function accountedTrees(sessions) {
@@ -45245,7 +45319,7 @@ function capped2(lines2) {
45245
45319
  }
45246
45320
 
45247
45321
  // src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
45248
- import { basename as basename29 } from "path";
45322
+ import { basename as basename30 } from "path";
45249
45323
  function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
45250
45324
  const { orphan, reason: reason4, held } = recovered;
45251
45325
  let id;
@@ -45268,7 +45342,7 @@ function orphanedSession(id, recovered) {
45268
45342
  const { orphan, reason: reason4, held } = recovered;
45269
45343
  return {
45270
45344
  ...sessionBase(id, "stopped"),
45271
- name: `recovered ${basename29(orphan.path)}`,
45345
+ name: `recovered ${basename30(orphan.path)}`,
45272
45346
  subtitle: `${held.summary} in ${orphan.path}`,
45273
45347
  commandType: "claude",
45274
45348
  pty: null,
@@ -45329,7 +45403,7 @@ async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
45329
45403
  logVanishedTree(sessions, path106);
45330
45404
  vanished.set(clone, [
45331
45405
  ...vanished.get(clone) ?? [],
45332
- { path: path106, branch: basename30(path106) }
45406
+ { path: path106, branch: basename31(path106) }
45333
45407
  ]);
45334
45408
  continue;
45335
45409
  }
@@ -46449,8 +46523,8 @@ function resumeSession(id, sessionId, cwd, name, holdPty, harness) {
46449
46523
  import { existsSync as existsSync95 } from "fs";
46450
46524
 
46451
46525
  // src/commands/sessions/daemon/worktree/carryTranscriptToTree.ts
46452
- import { copyFileSync as copyFileSync5, existsSync as existsSync94, mkdirSync as mkdirSync36 } from "fs";
46453
- import { join as join103 } from "path";
46526
+ import { copyFileSync as copyFileSync5, existsSync as existsSync94, mkdirSync as mkdirSync37 } from "fs";
46527
+ import { join as join104 } from "path";
46454
46528
  function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
46455
46529
  const dir = projectDirForCwd(toCwd);
46456
46530
  if (dir === projectDirForCwd(fromCwd)) {
@@ -46459,7 +46533,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
46459
46533
  );
46460
46534
  return;
46461
46535
  }
46462
- const dest = join103(dir, `${claudeSessionId}.jsonl`);
46536
+ const dest = join104(dir, `${claudeSessionId}.jsonl`);
46463
46537
  if (existsSync94(dest)) {
46464
46538
  daemonLog(`transcript ${claudeSessionId} already present in ${dir}`);
46465
46539
  return;
@@ -46472,7 +46546,7 @@ function carryTranscriptToTree(claudeSessionId, fromCwd, toCwd) {
46472
46546
  return;
46473
46547
  }
46474
46548
  try {
46475
- mkdirSync36(dir, { recursive: true });
46549
+ mkdirSync37(dir, { recursive: true });
46476
46550
  copyFileSync5(source, dest);
46477
46551
  daemonLog(
46478
46552
  `transcript ${source} copied to ${dest} so ${toCwd} can resume it`
@@ -47347,10 +47421,10 @@ function handleConnection(socket, manager) {
47347
47421
  }
47348
47422
 
47349
47423
  // src/commands/sessions/daemon/onListening.ts
47350
- import { unlinkSync as unlinkSync22, writeFileSync as writeFileSync54 } from "fs";
47424
+ import { unlinkSync as unlinkSync22, writeFileSync as writeFileSync55 } from "fs";
47351
47425
 
47352
47426
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
47353
- import { readFileSync as readFileSync65 } from "fs";
47427
+ import { readFileSync as readFileSync66 } from "fs";
47354
47428
  var WATCHDOG_INTERVAL_MS = 5e3;
47355
47429
  function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
47356
47430
  const timer = setInterval(() => {
@@ -47361,7 +47435,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
47361
47435
  }
47362
47436
  function ownsPidFile() {
47363
47437
  try {
47364
- return readFileSync65(daemonPaths.pid, "utf8").trim() === String(process.pid);
47438
+ return readFileSync66(daemonPaths.pid, "utf8").trim() === String(process.pid);
47365
47439
  } catch {
47366
47440
  return false;
47367
47441
  }
@@ -47369,7 +47443,7 @@ function ownsPidFile() {
47369
47443
 
47370
47444
  // src/commands/sessions/daemon/onListening.ts
47371
47445
  function onListening(manager, checkAutoExit) {
47372
- writeFileSync54(daemonPaths.pid, String(process.pid));
47446
+ writeFileSync55(daemonPaths.pid, String(process.pid));
47373
47447
  startPidFileWatchdog(() => {
47374
47448
  daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
47375
47449
  void manager.flushActiveMs().finally(() => {
@@ -47457,7 +47531,7 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
47457
47531
 
47458
47532
  // src/commands/sessions/daemon/runDaemon.ts
47459
47533
  async function runDaemon() {
47460
- mkdirSync37(daemonPaths.dir, { recursive: true });
47534
+ mkdirSync38(daemonPaths.dir, { recursive: true });
47461
47535
  daemonLog(
47462
47536
  `starting (reason: ${process.env.ASSIST_DAEMON_SPAWN_REASON ?? "manual"})`
47463
47537
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.767.0",
3
+ "version": "0.767.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {