@staff0rd/assist 0.625.0 → 0.627.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.625.0",
9
+ version: "0.627.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -13796,6 +13796,7 @@ function toPreviewDecision(msg) {
13796
13796
  reviewAfter: msg.reviewAfter === true,
13797
13797
  announceAfter: msg.announceAfter === true,
13798
13798
  draft: typeof msg.draft === "boolean" ? msg.draft : void 0,
13799
+ autoMerge: msg.autoMerge === true,
13799
13800
  selection: toSelection(msg.selection)
13800
13801
  };
13801
13802
  }
@@ -26534,6 +26535,22 @@ function warn(reason4) {
26534
26535
  console.error(`Warning: could not chain sessions after raising: ${reason4}`);
26535
26536
  }
26536
26537
 
26538
+ // src/commands/prs/enableAutoMerge.ts
26539
+ import { execFileSync as execFileSync16 } from "child_process";
26540
+ function enableAutoMerge() {
26541
+ try {
26542
+ execFileSync16(
26543
+ "gh",
26544
+ ["pr", "merge", getCurrentBranch2(), "--auto", "--squash"],
26545
+ { stdio: "inherit" }
26546
+ );
26547
+ } catch (error) {
26548
+ console.error(
26549
+ `Warning: could not enable auto-merge: ${error instanceof Error ? error.message : String(error)}`
26550
+ );
26551
+ }
26552
+ }
26553
+
26537
26554
  // src/commands/prs/previewAndPlace.ts
26538
26555
  async function previewAndPlace(args) {
26539
26556
  const decision = await awaitPreviewApproval("PR preview", {
@@ -26547,6 +26564,7 @@ async function previewAndPlace(args) {
26547
26564
  const body = appendScreenshots(args.body, decision.screenshots ?? []);
26548
26565
  const options2 = decision.draft === void 0 ? args.options : { ...args.options, draft: decision.draft };
26549
26566
  await placePr(args.prNumber, args.title, body, options2);
26567
+ if (decision.autoMerge === true) enableAutoMerge();
26550
26568
  await chainAfterRaise(args.prNumber, decision);
26551
26569
  }
26552
26570
 
@@ -26583,6 +26601,83 @@ async function raise(options2, command) {
26583
26601
  await placePr(existing, title, body, resolved);
26584
26602
  }
26585
26603
 
26604
+ // src/commands/prs/readTime.ts
26605
+ import { execSync as execSync51 } from "child_process";
26606
+ import { readFileSync as readFileSync45 } from "fs";
26607
+
26608
+ // src/commands/prs/formatReadDuration.ts
26609
+ function formatReadDuration(seconds) {
26610
+ if (seconds < 60) return `${seconds}s`;
26611
+ const minutes = Math.floor(seconds / 60);
26612
+ const remainder = seconds % 60;
26613
+ return remainder === 0 ? `${minutes}m` : `${minutes}m ${remainder}s`;
26614
+ }
26615
+
26616
+ // src/commands/prs/resolveReadTimeTarget.ts
26617
+ var PR_URL_PATTERN = /^(https:\/\/github\.com\/[^/\s]+\/[^/\s]+)\/pull\/(\d+)(?:[/?#].*)?$/;
26618
+ function resolveReadTimeTarget(target) {
26619
+ const trimmed = target.trim();
26620
+ if (trimmed === "-") return { kind: "stdin" };
26621
+ if (/^\d+$/.test(trimmed)) {
26622
+ return { kind: "pr", number: Number(trimmed), repo: null };
26623
+ }
26624
+ const url = PR_URL_PATTERN.exec(trimmed);
26625
+ if (url) {
26626
+ const repo = parseGitHubUrl(url[1]);
26627
+ if (repo) return { kind: "pr", number: Number(url[2]), repo };
26628
+ }
26629
+ return { kind: "file", path: target };
26630
+ }
26631
+
26632
+ // src/commands/prs/readTime.ts
26633
+ var WORDS_PER_MINUTE = 200;
26634
+ async function readTime(target) {
26635
+ const body = await loadBody(resolveReadTimeTarget(target));
26636
+ const words = countWords(body);
26637
+ const seconds = Math.round(words / WORDS_PER_MINUTE * 60);
26638
+ const label2 = words === 1 ? "word" : "words";
26639
+ console.log(`${words} ${label2} \xB7 ~${formatReadDuration(seconds)} read`);
26640
+ }
26641
+ function countWords(body) {
26642
+ return body.split(/\s+/).filter(Boolean).length;
26643
+ }
26644
+ async function loadBody(target) {
26645
+ if (target.kind === "stdin") return readBodyArgument("-");
26646
+ if (target.kind === "file") return readDraftFile(target.path);
26647
+ return fetchPrBody(target.number, target.repo);
26648
+ }
26649
+ function readDraftFile(path90) {
26650
+ try {
26651
+ return readFileSync45(path90, "utf8");
26652
+ } catch {
26653
+ console.error(`Error: Could not read \`${path90}\`.`);
26654
+ console.error(
26655
+ "Pass a pull request number, a GitHub pull request URL, - for stdin, or a path to a file."
26656
+ );
26657
+ process.exit(1);
26658
+ }
26659
+ }
26660
+ function fetchPrBody(number, repo) {
26661
+ const { org, repo: name } = repo ?? getRepoInfo();
26662
+ try {
26663
+ const raw = execSync51(`gh pr view ${number} --json body -R ${org}/${name}`, {
26664
+ encoding: "utf8"
26665
+ });
26666
+ return JSON.parse(raw).body ?? "";
26667
+ } catch (error) {
26668
+ if (isGhNotInstalled(error)) {
26669
+ console.error("Error: GitHub CLI (gh) is not installed.");
26670
+ console.error("Install it from https://cli.github.com/");
26671
+ process.exit(1);
26672
+ }
26673
+ if (isNotFound(error)) {
26674
+ console.error(`Error: Pull request ${org}/${name}#${number} not found.`);
26675
+ process.exit(1);
26676
+ }
26677
+ throw error;
26678
+ }
26679
+ }
26680
+
26586
26681
  // src/commands/prs/reply.ts
26587
26682
  function validateBody2(body) {
26588
26683
  const lowerBody = body.toLowerCase();
@@ -26610,7 +26705,7 @@ async function reply(commentId, body) {
26610
26705
  }
26611
26706
 
26612
26707
  // src/commands/prs/wontfix.ts
26613
- import { execSync as execSync51 } from "child_process";
26708
+ import { execSync as execSync52 } from "child_process";
26614
26709
  function validateReason(reason4) {
26615
26710
  const lowerReason = reason4.toLowerCase();
26616
26711
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -26627,7 +26722,7 @@ function validateShaReferences(reason4) {
26627
26722
  const invalidShas = [];
26628
26723
  for (const sha of shas) {
26629
26724
  try {
26630
- execSync51(`git cat-file -t ${sha}`, { stdio: "pipe" });
26725
+ execSync52(`git cat-file -t ${sha}`, { stdio: "pipe" });
26631
26726
  } catch {
26632
26727
  invalidShas.push(sha);
26633
26728
  }
@@ -26894,12 +26989,22 @@ function registerPrsRaise(prsCommand) {
26894
26989
  configHelp(raiseCommand, prsRaiseConfigHelp);
26895
26990
  }
26896
26991
 
26992
+ // src/commands/registerPrsReadTime.ts
26993
+ function registerPrsReadTime(prsCommand) {
26994
+ prsCommand.command("read-time <target>").description(
26995
+ "Estimate how long a pull request description takes to read (target is a PR number, a GitHub PR URL, - for stdin, or a file path)"
26996
+ ).action(async (target) => {
26997
+ await readTime(target);
26998
+ });
26999
+ }
27000
+
26897
27001
  // src/commands/registerPrs.ts
26898
27002
  function registerPrs(program2) {
26899
27003
  const prsCommand = program2.command("prs").description("Pull request utilities").option("--open", "List only open pull requests").option("--closed", "List only closed pull requests").action(prs);
26900
27004
  registerPrsRaise(prsCommand);
26901
27005
  registerPrsEdit(prsCommand);
26902
27006
  registerPrsComments(prsCommand);
27007
+ registerPrsReadTime(prsCommand);
26903
27008
  configHelp(prsCommand, prsConfigHelp);
26904
27009
  }
26905
27010
 
@@ -26973,10 +27078,10 @@ import chalk187 from "chalk";
26973
27078
  import Enquirer2 from "enquirer";
26974
27079
 
26975
27080
  // src/commands/ravendb/searchItems.ts
26976
- import { execSync as execSync52 } from "child_process";
27081
+ import { execSync as execSync53 } from "child_process";
26977
27082
  import chalk186 from "chalk";
26978
27083
  function opExec(args) {
26979
- return execSync52(`op ${args}`, {
27084
+ return execSync53(`op ${args}`, {
26980
27085
  encoding: "utf8",
26981
27086
  stdio: ["pipe", "pipe", "pipe"]
26982
27087
  }).trim();
@@ -27128,7 +27233,7 @@ ${errorText}`
27128
27233
  }
27129
27234
 
27130
27235
  // src/commands/ravendb/resolveOpSecret.ts
27131
- import { execSync as execSync53 } from "child_process";
27236
+ import { execSync as execSync54 } from "child_process";
27132
27237
  import chalk191 from "chalk";
27133
27238
  function resolveOpSecret(reference) {
27134
27239
  if (!reference.startsWith("op://")) {
@@ -27136,7 +27241,7 @@ function resolveOpSecret(reference) {
27136
27241
  process.exit(1);
27137
27242
  }
27138
27243
  try {
27139
- return execSync53(`op read "${reference}"`, {
27244
+ return execSync54(`op read "${reference}"`, {
27140
27245
  encoding: "utf8",
27141
27246
  stdio: ["pipe", "pipe", "pipe"]
27142
27247
  }).trim();
@@ -27386,7 +27491,7 @@ Refactor check failed:
27386
27491
  }
27387
27492
 
27388
27493
  // src/commands/refactor/check/getViolations/index.ts
27389
- import { execSync as execSync54 } from "child_process";
27494
+ import { execSync as execSync55 } from "child_process";
27390
27495
  import fs30 from "fs";
27391
27496
  import { minimatch as minimatch6 } from "minimatch";
27392
27497
 
@@ -27436,7 +27541,7 @@ function getGitFiles(options2) {
27436
27541
  }
27437
27542
  const files = /* @__PURE__ */ new Set();
27438
27543
  if (options2.staged || options2.modified) {
27439
- const staged = execSync54("git diff --cached --name-only", {
27544
+ const staged = execSync55("git diff --cached --name-only", {
27440
27545
  encoding: "utf8"
27441
27546
  });
27442
27547
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -27444,7 +27549,7 @@ function getGitFiles(options2) {
27444
27549
  }
27445
27550
  }
27446
27551
  if (options2.unstaged || options2.modified) {
27447
- const unstaged = execSync54("git diff --name-only", { encoding: "utf8" });
27552
+ const unstaged = execSync55("git diff --name-only", { encoding: "utf8" });
27448
27553
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
27449
27554
  files.add(file);
27450
27555
  }
@@ -29155,9 +29260,9 @@ function buildReviewPaths(repoRoot2, key) {
29155
29260
  }
29156
29261
 
29157
29262
  // src/commands/review/fetchExistingComments.ts
29158
- import { execSync as execSync55 } from "child_process";
29263
+ import { execSync as execSync56 } from "child_process";
29159
29264
  function fetchRawComments(org, repo, prNumber) {
29160
- const out = execSync55(
29265
+ const out = execSync56(
29161
29266
  `gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
29162
29267
  { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }
29163
29268
  );
@@ -29188,14 +29293,14 @@ function fetchExistingComments() {
29188
29293
  }
29189
29294
 
29190
29295
  // src/commands/review/gatherContext.ts
29191
- import { execSync as execSync58 } from "child_process";
29296
+ import { execSync as execSync59 } from "child_process";
29192
29297
 
29193
29298
  // src/commands/review/fetchPrDiff.ts
29194
- import { execSync as execSync56 } from "child_process";
29299
+ import { execSync as execSync57 } from "child_process";
29195
29300
  function fetchPrDiff(prNumber, baseSha, headSha) {
29196
29301
  const { org, repo } = getRepoInfo();
29197
29302
  try {
29198
- return execSync56(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
29303
+ return execSync57(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
29199
29304
  encoding: "utf8",
29200
29305
  maxBuffer: 256 * 1024 * 1024,
29201
29306
  stdio: ["ignore", "pipe", "pipe"]
@@ -29210,19 +29315,19 @@ function isDiffTooLarge(error) {
29210
29315
  }
29211
29316
  function fetchDiffViaGit(baseSha, headSha) {
29212
29317
  try {
29213
- execSync56(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
29318
+ execSync57(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
29214
29319
  } catch {
29215
29320
  }
29216
- return execSync56(`git diff ${baseSha}...${headSha}`, {
29321
+ return execSync57(`git diff ${baseSha}...${headSha}`, {
29217
29322
  encoding: "utf8",
29218
29323
  maxBuffer: 256 * 1024 * 1024
29219
29324
  });
29220
29325
  }
29221
29326
 
29222
29327
  // src/commands/review/fetchPrDiffInfo.ts
29223
- import { execSync as execSync57 } from "child_process";
29328
+ import { execSync as execSync58 } from "child_process";
29224
29329
  function getCurrentBranch3() {
29225
- return execSync57("git rev-parse --abbrev-ref HEAD", {
29330
+ return execSync58("git rev-parse --abbrev-ref HEAD", {
29226
29331
  encoding: "utf8"
29227
29332
  }).trim();
29228
29333
  }
@@ -29230,7 +29335,7 @@ function fetchPrDiffInfo() {
29230
29335
  const { org, repo } = getRepoInfo();
29231
29336
  const branch2 = getCurrentBranch3();
29232
29337
  const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
29233
- const raw = execSync57(
29338
+ const raw = execSync58(
29234
29339
  `gh pr list --state open --head ${branch2} --json ${fields} -R ${org}/${repo}`,
29235
29340
  {
29236
29341
  encoding: "utf8",
@@ -29255,7 +29360,7 @@ function fetchPrDiffInfo() {
29255
29360
  }
29256
29361
  function fetchPrChangedFiles(prNumber) {
29257
29362
  const { org, repo } = getRepoInfo();
29258
- const out = execSync57(
29363
+ const out = execSync58(
29259
29364
  `gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
29260
29365
  {
29261
29366
  encoding: "utf8",
@@ -29267,11 +29372,11 @@ function fetchPrChangedFiles(prNumber) {
29267
29372
 
29268
29373
  // src/commands/review/gatherContext.ts
29269
29374
  function gatherContext() {
29270
- const branch2 = execSync58("git rev-parse --abbrev-ref HEAD", {
29375
+ const branch2 = execSync59("git rev-parse --abbrev-ref HEAD", {
29271
29376
  encoding: "utf8"
29272
29377
  }).trim();
29273
- const sha = execSync58("git rev-parse HEAD", { encoding: "utf8" }).trim();
29274
- const shortSha = execSync58("git rev-parse --short=7 HEAD", {
29378
+ const sha = execSync59("git rev-parse HEAD", { encoding: "utf8" }).trim();
29379
+ const shortSha = execSync59("git rev-parse --short=7 HEAD", {
29275
29380
  encoding: "utf8"
29276
29381
  }).trim();
29277
29382
  const prInfo = fetchPrDiffInfo();
@@ -29292,7 +29397,7 @@ function gatherContext() {
29292
29397
  }
29293
29398
 
29294
29399
  // src/commands/review/postReviewToPr.ts
29295
- import { readFileSync as readFileSync45 } from "fs";
29400
+ import { readFileSync as readFileSync46 } from "fs";
29296
29401
 
29297
29402
  // src/commands/review/carriedUnanchoredFindings.ts
29298
29403
  function carriedUnanchoredFindings(unanchored) {
@@ -29740,7 +29845,7 @@ async function confirmPost(prNumber, work, options2) {
29740
29845
  return promptConfirm(`Post ${work} to PR #${prNumber}?`, false);
29741
29846
  }
29742
29847
  async function postFindingsToPr(prInfo, synthesisPath, options2) {
29743
- const markdown = readFileSync45(synthesisPath, "utf8");
29848
+ const markdown = readFileSync46(synthesisPath, "utf8");
29744
29849
  const { inDiff, unanchored } = selectPostableFindings(markdown, prInfo);
29745
29850
  const carried = carriedUnanchoredFindings(unanchored);
29746
29851
  if (inDiff.length === 0 && carried.length === 0) return NOTHING_POSTED;
@@ -30629,7 +30734,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
30629
30734
  }
30630
30735
 
30631
30736
  // src/commands/review/synthesise.ts
30632
- import { readFileSync as readFileSync46 } from "fs";
30737
+ import { readFileSync as readFileSync47 } from "fs";
30633
30738
 
30634
30739
  // src/commands/review/buildSynthesisStdin.ts
30635
30740
  var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
@@ -30694,7 +30799,7 @@ Files:
30694
30799
 
30695
30800
  // src/commands/review/synthesise.ts
30696
30801
  function printSummary2(synthesisPath) {
30697
- const markdown = readFileSync46(synthesisPath, "utf8");
30802
+ const markdown = readFileSync47(synthesisPath, "utf8");
30698
30803
  console.log("");
30699
30804
  console.log(buildReviewSummary(markdown));
30700
30805
  console.log("");
@@ -30928,7 +31033,7 @@ function registerReview(program2) {
30928
31033
  }
30929
31034
 
30930
31035
  // src/commands/rules/addRule.ts
30931
- import { existsSync as existsSync66, readFileSync as readFileSync50, writeFileSync as writeFileSync41 } from "fs";
31036
+ import { existsSync as existsSync66, readFileSync as readFileSync51, writeFileSync as writeFileSync41 } from "fs";
30932
31037
  import path71 from "path";
30933
31038
  import chalk211 from "chalk";
30934
31039
 
@@ -30953,7 +31058,7 @@ function insertRuleBullet(content, rule) {
30953
31058
  }
30954
31059
 
30955
31060
  // src/commands/rules/nextRuleCode.ts
30956
- import { readFileSync as readFileSync47 } from "fs";
31061
+ import { readFileSync as readFileSync48 } from "fs";
30957
31062
 
30958
31063
  // src/commands/rules/findClaudeFiles.ts
30959
31064
  import { readdirSync as readdirSync13 } from "fs";
@@ -30977,7 +31082,7 @@ function findClaudeFiles(dir) {
30977
31082
  var CODE_PREFIX = "R";
30978
31083
  function nextRuleCode(root) {
30979
31084
  const numbers = findClaudeFiles(root).flatMap(
30980
- (file) => parseRulesSection(readFileSync47(file, "utf8")).map(
31085
+ (file) => parseRulesSection(readFileSync48(file, "utf8")).map(
30981
31086
  (rule) => Number(/(\d+)\s*$/.exec(rule.code)?.[1] ?? 0)
30982
31087
  )
30983
31088
  );
@@ -31003,15 +31108,15 @@ function resolveRuleScope(target) {
31003
31108
  }
31004
31109
 
31005
31110
  // src/commands/rules/updateScopedRulesIndex.ts
31006
- import { existsSync as existsSync65, readFileSync as readFileSync49, writeFileSync as writeFileSync40 } from "fs";
31111
+ import { existsSync as existsSync65, readFileSync as readFileSync50, writeFileSync as writeFileSync40 } from "fs";
31007
31112
  import path70 from "path";
31008
31113
 
31009
31114
  // src/commands/rules/scopedRuleDirectories.ts
31010
- import { readFileSync as readFileSync48 } from "fs";
31115
+ import { readFileSync as readFileSync49 } from "fs";
31011
31116
  import path69 from "path";
31012
31117
  function scopedRuleDirectories(root) {
31013
31118
  return findClaudeFiles(root).filter(
31014
- (file) => path69.dirname(file) !== root && parseRulesSection(readFileSync48(file, "utf8")).length > 0
31119
+ (file) => path69.dirname(file) !== root && parseRulesSection(readFileSync49(file, "utf8")).length > 0
31015
31120
  ).map(
31016
31121
  (file) => `${path69.relative(root, path69.dirname(file)).split(path69.sep).join("/")}/`
31017
31122
  ).sort();
@@ -31053,7 +31158,7 @@ function upsertScopedRulesPointer(content, directories) {
31053
31158
  function updateScopedRulesIndex(root) {
31054
31159
  const directories = scopedRuleDirectories(root);
31055
31160
  const rootFile = path70.join(root, "CLAUDE.md");
31056
- const before = existsSync65(rootFile) ? readFileSync49(rootFile, "utf8") : "";
31161
+ const before = existsSync65(rootFile) ? readFileSync50(rootFile, "utf8") : "";
31057
31162
  const after = upsertScopedRulesPointer(before, directories);
31058
31163
  if (after !== before) writeFileSync40(rootFile, after);
31059
31164
  return directories;
@@ -31061,7 +31166,7 @@ function updateScopedRulesIndex(root) {
31061
31166
 
31062
31167
  // src/commands/rules/addRule.ts
31063
31168
  function read2(file) {
31064
- return existsSync66(file) ? readFileSync50(file, "utf8") : "";
31169
+ return existsSync66(file) ? readFileSync51(file, "utf8") : "";
31065
31170
  }
31066
31171
  function addRule(text18, options2) {
31067
31172
  const rule = text18.trim();
@@ -32554,9 +32659,9 @@ function formatVttPassages(passages, notes = [], { sourceMarks = true } = {}) {
32554
32659
  }
32555
32660
 
32556
32661
  // src/commands/transcript/convert/readCleanedCues.ts
32557
- import { readFileSync as readFileSync55 } from "fs";
32662
+ import { readFileSync as readFileSync56 } from "fs";
32558
32663
  function readCleanedCues(inputPath) {
32559
- return deduplicateCues(parseVtt(readFileSync55(inputPath, "utf8")));
32664
+ return deduplicateCues(parseVtt(readFileSync56(inputPath, "utf8")));
32560
32665
  }
32561
32666
 
32562
32667
  // src/commands/transcript/clean.ts
@@ -33063,14 +33168,14 @@ function devices() {
33063
33168
  }
33064
33169
 
33065
33170
  // src/commands/voice/logs.ts
33066
- import { existsSync as existsSync75, readFileSync as readFileSync56 } from "fs";
33171
+ import { existsSync as existsSync75, readFileSync as readFileSync57 } from "fs";
33067
33172
  function logs(options2) {
33068
33173
  if (!existsSync75(voicePaths.log)) {
33069
33174
  console.log("No voice log file found");
33070
33175
  return;
33071
33176
  }
33072
33177
  const count8 = Number.parseInt(options2.lines ?? "150", 10);
33073
- const content = readFileSync56(voicePaths.log, "utf8").trim();
33178
+ const content = readFileSync57(voicePaths.log, "utf8").trim();
33074
33179
  if (!content) {
33075
33180
  console.log("Voice log is empty");
33076
33181
  return;
@@ -33096,8 +33201,8 @@ import { mkdirSync as mkdirSync30 } from "fs";
33096
33201
  import { join as join89 } from "path";
33097
33202
 
33098
33203
  // src/commands/voice/checkLockFile.ts
33099
- import { execSync as execSync59 } from "child_process";
33100
- import { existsSync as existsSync76, mkdirSync as mkdirSync29, readFileSync as readFileSync57, writeFileSync as writeFileSync48 } from "fs";
33204
+ import { execSync as execSync60 } from "child_process";
33205
+ import { existsSync as existsSync76, mkdirSync as mkdirSync29, readFileSync as readFileSync58, writeFileSync as writeFileSync48 } from "fs";
33101
33206
  import { join as join88 } from "path";
33102
33207
  function isProcessAlive2(pid) {
33103
33208
  try {
@@ -33111,7 +33216,7 @@ function checkLockFile() {
33111
33216
  const lockFile = getLockFile();
33112
33217
  if (!existsSync76(lockFile)) return;
33113
33218
  try {
33114
- const lock2 = JSON.parse(readFileSync57(lockFile, "utf8"));
33219
+ const lock2 = JSON.parse(readFileSync58(lockFile, "utf8"));
33115
33220
  if (lock2.pid && isProcessAlive2(lock2.pid)) {
33116
33221
  console.error(
33117
33222
  `Voice daemon already running (PID ${lock2.pid}, env: ${lock2.env}). Stop it first with: assist voice stop`
@@ -33125,7 +33230,7 @@ function bootstrapVenv() {
33125
33230
  if (existsSync76(getVenvPython())) return;
33126
33231
  console.log("Setting up Python environment...");
33127
33232
  const pythonDir = getPythonDir();
33128
- execSync59(
33233
+ execSync60(
33129
33234
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
33130
33235
  {
33131
33236
  stdio: "inherit",
@@ -33213,7 +33318,7 @@ function start2(options2) {
33213
33318
  }
33214
33319
 
33215
33320
  // src/commands/voice/status.ts
33216
- import { existsSync as existsSync77, readFileSync as readFileSync58 } from "fs";
33321
+ import { existsSync as existsSync77, readFileSync as readFileSync59 } from "fs";
33217
33322
  function isProcessAlive3(pid) {
33218
33323
  try {
33219
33324
  process.kill(pid, 0);
@@ -33224,7 +33329,7 @@ function isProcessAlive3(pid) {
33224
33329
  }
33225
33330
  function readRecentLogs(count8) {
33226
33331
  if (!existsSync77(voicePaths.log)) return [];
33227
- const lines2 = readFileSync58(voicePaths.log, "utf8").trim().split("\n");
33332
+ const lines2 = readFileSync59(voicePaths.log, "utf8").trim().split("\n");
33228
33333
  return lines2.slice(-count8);
33229
33334
  }
33230
33335
  function status2() {
@@ -33232,7 +33337,7 @@ function status2() {
33232
33337
  console.log("Voice daemon: not running (no PID file)");
33233
33338
  return;
33234
33339
  }
33235
- const pid = Number.parseInt(readFileSync58(voicePaths.pid, "utf8").trim(), 10);
33340
+ const pid = Number.parseInt(readFileSync59(voicePaths.pid, "utf8").trim(), 10);
33236
33341
  const alive = isProcessAlive3(pid);
33237
33342
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
33238
33343
  const recent = readRecentLogs(5);
@@ -33251,13 +33356,13 @@ function status2() {
33251
33356
  }
33252
33357
 
33253
33358
  // src/commands/voice/stop.ts
33254
- import { existsSync as existsSync78, readFileSync as readFileSync59, unlinkSync as unlinkSync20 } from "fs";
33359
+ import { existsSync as existsSync78, readFileSync as readFileSync60, unlinkSync as unlinkSync20 } from "fs";
33255
33360
  function stop2() {
33256
33361
  if (!existsSync78(voicePaths.pid)) {
33257
33362
  console.log("Voice daemon is not running (no PID file)");
33258
33363
  return;
33259
33364
  }
33260
- const pid = Number.parseInt(readFileSync59(voicePaths.pid, "utf8").trim(), 10);
33365
+ const pid = Number.parseInt(readFileSync60(voicePaths.pid, "utf8").trim(), 10);
33261
33366
  try {
33262
33367
  process.kill(pid, "SIGTERM");
33263
33368
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -33289,9 +33394,9 @@ function registerVoice(program2) {
33289
33394
  }
33290
33395
 
33291
33396
  // src/commands/watch/resolveUpstream.ts
33292
- import { execFileSync as execFileSync16 } from "child_process";
33397
+ import { execFileSync as execFileSync17 } from "child_process";
33293
33398
  function runGit3(args, cwd) {
33294
- return execFileSync16("git", args, {
33399
+ return execFileSync17("git", args, {
33295
33400
  encoding: "utf8",
33296
33401
  stdio: ["pipe", "pipe", "pipe"],
33297
33402
  cwd
@@ -33697,13 +33802,13 @@ import { spawn as spawn9 } from "child_process";
33697
33802
  import { existsSync as existsSync81 } from "fs";
33698
33803
 
33699
33804
  // src/commands/run/resolveCommand.ts
33700
- import { execFileSync as execFileSync17 } from "child_process";
33805
+ import { execFileSync as execFileSync18 } from "child_process";
33701
33806
  import { existsSync as existsSync80 } from "fs";
33702
33807
  import { dirname as dirname37, join as join92, resolve as resolve20 } from "path";
33703
33808
  function resolveCommand2(command) {
33704
33809
  if (process.platform !== "win32" || command !== "bash") return command;
33705
33810
  try {
33706
- const gitPath = execFileSync17("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
33811
+ const gitPath = execFileSync18("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
33707
33812
  const gitRoot = resolve20(dirname37(gitPath), "..");
33708
33813
  const gitBash = join92(gitRoot, "bin", "bash.exe");
33709
33814
  if (existsSync80(gitBash)) return gitBash;
@@ -33750,11 +33855,11 @@ function runCommandToCompletion(command, args, env, cwd, quiet) {
33750
33855
  }
33751
33856
 
33752
33857
  // src/commands/run/runPreCommands.ts
33753
- import { execSync as execSync60 } from "child_process";
33858
+ import { execSync as execSync61 } from "child_process";
33754
33859
  function runPreCommands(pre, cwd) {
33755
33860
  for (const cmd of pre) {
33756
33861
  try {
33757
- execSync60(cmd, { stdio: "inherit", cwd });
33862
+ execSync61(cmd, { stdio: "inherit", cwd });
33758
33863
  } catch (error) {
33759
33864
  const code = error && typeof error === "object" && "status" in error ? error.status : 1;
33760
33865
  process.exit(code);
@@ -33825,11 +33930,11 @@ async function reportSyncOrExit() {
33825
33930
  }
33826
33931
 
33827
33932
  // src/commands/watch/fetchQuietly.ts
33828
- import { execFileSync as execFileSync18 } from "child_process";
33933
+ import { execFileSync as execFileSync19 } from "child_process";
33829
33934
  var MIN_FETCH_TIMEOUT_MS = 6e4;
33830
33935
  function fetchQuietly(cwd, intervalMs) {
33831
33936
  try {
33832
- execFileSync18("git", ["fetch", "--quiet"], {
33937
+ execFileSync19("git", ["fetch", "--quiet"], {
33833
33938
  stdio: ["pipe", "pipe", "pipe"],
33834
33939
  cwd,
33835
33940
  timeout: Math.max(intervalMs, MIN_FETCH_TIMEOUT_MS)
@@ -34131,8 +34236,8 @@ async function auth() {
34131
34236
  }
34132
34237
 
34133
34238
  // src/commands/roam/postRoamActivity.ts
34134
- import { execFileSync as execFileSync19 } from "child_process";
34135
- import { readdirSync as readdirSync21, readFileSync as readFileSync60, statSync as statSync12 } from "fs";
34239
+ import { execFileSync as execFileSync20 } from "child_process";
34240
+ import { readdirSync as readdirSync21, readFileSync as readFileSync61, statSync as statSync12 } from "fs";
34136
34241
  import { join as join93 } from "path";
34137
34242
  function findPortFile(roamDir) {
34138
34243
  let entries;
@@ -34163,14 +34268,14 @@ function postRoamActivity(app, event) {
34163
34268
  if (!portFile) return;
34164
34269
  let port;
34165
34270
  try {
34166
- port = readFileSync60(portFile, "utf8").trim();
34271
+ port = readFileSync61(portFile, "utf8").trim();
34167
34272
  } catch {
34168
34273
  return;
34169
34274
  }
34170
34275
  const pid = PID_BY_APP[app] ?? 99999;
34171
34276
  const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${pid}`;
34172
34277
  try {
34173
- execFileSync19("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
34278
+ execFileSync20("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
34174
34279
  stdio: "ignore"
34175
34280
  });
34176
34281
  } catch {
@@ -34481,7 +34586,7 @@ function registerRun(program2) {
34481
34586
  }
34482
34587
 
34483
34588
  // src/commands/screenshot/index.ts
34484
- import { execSync as execSync61 } from "child_process";
34589
+ import { execSync as execSync62 } from "child_process";
34485
34590
  import { existsSync as existsSync83, mkdirSync as mkdirSync33, unlinkSync as unlinkSync22, writeFileSync as writeFileSync51 } from "fs";
34486
34591
  import { tmpdir as tmpdir9 } from "os";
34487
34592
  import { join as join96, resolve as resolve21 } from "path";
@@ -34624,7 +34729,7 @@ function runPowerShellScript(processName, outputPath) {
34624
34729
  const scriptPath = join96(tmpdir9(), `assist-screenshot-${Date.now()}.ps1`);
34625
34730
  writeFileSync51(scriptPath, captureWindowPs1, "utf8");
34626
34731
  try {
34627
- execSync61(
34732
+ execSync62(
34628
34733
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
34629
34734
  { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }
34630
34735
  );
@@ -34648,11 +34753,11 @@ function screenshot(processName) {
34648
34753
  }
34649
34754
 
34650
34755
  // src/commands/sessions/daemon/listDaemonPids.ts
34651
- import { execFileSync as execFileSync20 } from "child_process";
34756
+ import { execFileSync as execFileSync21 } from "child_process";
34652
34757
  function listDaemonPids() {
34653
34758
  if (process.platform === "win32") return [];
34654
34759
  try {
34655
- const out = execFileSync20("ps", ["-eo", "pid=,args="], {
34760
+ const out = execFileSync21("ps", ["-eo", "pid=,args="], {
34656
34761
  encoding: "utf8"
34657
34762
  });
34658
34763
  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));
@@ -34698,11 +34803,11 @@ function applyLine(result, pending, line) {
34698
34803
  }
34699
34804
 
34700
34805
  // src/commands/sessions/daemon/readDaemonPidFile.ts
34701
- import { readFileSync as readFileSync61 } from "fs";
34806
+ import { readFileSync as readFileSync62 } from "fs";
34702
34807
  function readDaemonPidFile() {
34703
34808
  try {
34704
34809
  const pid = Number.parseInt(
34705
- readFileSync61(daemonPaths.pid, "utf8").trim(),
34810
+ readFileSync62(daemonPaths.pid, "utf8").trim(),
34706
34811
  10
34707
34812
  );
34708
34813
  return Number.isInteger(pid) ? pid : void 0;
@@ -35875,7 +35980,7 @@ function decidePrPreview(sessions, waiters, notify2, d) {
35875
35980
  const commentCount = Array.isArray(d.comments) ? d.comments.length : 0;
35876
35981
  const screenshotCount = Array.isArray(d.screenshots) ? d.screenshots.length : 0;
35877
35982
  daemonLog(
35878
- `pr-decision received: id=${id} requestId=${requestId} decision=${d.decision} comments=${commentCount} screenshots=${screenshotCount} reviewAfter=${d.reviewAfter === true} announceAfter=${d.announceAfter === true} draft=${d.draft}`
35983
+ `pr-decision received: id=${id} requestId=${requestId} decision=${d.decision} comments=${commentCount} screenshots=${screenshotCount} reviewAfter=${d.reviewAfter === true} announceAfter=${d.announceAfter === true} draft=${d.draft} autoMerge=${d.autoMerge === true}`
35879
35984
  );
35880
35985
  const waiter = waiters.get(id);
35881
35986
  if (waiter)
@@ -35889,7 +35994,8 @@ function decidePrPreview(sessions, waiters, notify2, d) {
35889
35994
  body: d.body,
35890
35995
  reviewAfter: d.reviewAfter,
35891
35996
  announceAfter: d.announceAfter,
35892
- draft: d.draft
35997
+ draft: d.draft,
35998
+ autoMerge: d.autoMerge
35893
35999
  });
35894
36000
  waiters.delete(id);
35895
36001
  session.pendingPrPreview = void 0;
@@ -38877,14 +38983,14 @@ async function defaultConnect() {
38877
38983
  }
38878
38984
 
38879
38985
  // src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
38880
- import { existsSync as existsSync95, readFileSync as readFileSync63 } from "fs";
38986
+ import { existsSync as existsSync95, readFileSync as readFileSync64 } from "fs";
38881
38987
  import { posix as posix3 } from "path";
38882
38988
  function hasPersistedWindowsSessions() {
38883
38989
  const sessionsFile = windowsSessionsFileFromWsl();
38884
38990
  if (!sessionsFile) return false;
38885
38991
  try {
38886
38992
  if (!existsSync95(sessionsFile)) return false;
38887
- const data = JSON.parse(readFileSync63(sessionsFile, "utf8"));
38993
+ const data = JSON.parse(readFileSync64(sessionsFile, "utf8"));
38888
38994
  return Array.isArray(data) && data.length > 0;
38889
38995
  } catch (error) {
38890
38996
  const message3 = error instanceof Error ? error.message : String(error);
@@ -40309,7 +40415,7 @@ function handleConnection(socket, manager) {
40309
40415
  import { unlinkSync as unlinkSync23, writeFileSync as writeFileSync52 } from "fs";
40310
40416
 
40311
40417
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
40312
- import { readFileSync as readFileSync64 } from "fs";
40418
+ import { readFileSync as readFileSync65 } from "fs";
40313
40419
  var WATCHDOG_INTERVAL_MS = 5e3;
40314
40420
  function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
40315
40421
  const timer = setInterval(() => {
@@ -40320,7 +40426,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
40320
40426
  }
40321
40427
  function ownsPidFile() {
40322
40428
  try {
40323
- return readFileSync64(daemonPaths.pid, "utf8").trim() === String(process.pid);
40429
+ return readFileSync65(daemonPaths.pid, "utf8").trim() === String(process.pid);
40324
40430
  } catch {
40325
40431
  return false;
40326
40432
  }
@@ -40369,7 +40475,7 @@ function cleanupOwnedFiles() {
40369
40475
  import * as net3 from "net";
40370
40476
 
40371
40477
  // src/commands/sessions/daemon/findPortHolderPid.ts
40372
- import { execFileSync as execFileSync21 } from "child_process";
40478
+ import { execFileSync as execFileSync22 } from "child_process";
40373
40479
  var PROBE_TIMEOUT_MS = 3e3;
40374
40480
  function findPortHolderPid(port) {
40375
40481
  try {
@@ -40379,7 +40485,7 @@ function findPortHolderPid(port) {
40379
40485
  }
40380
40486
  }
40381
40487
  function probe(command, args) {
40382
- return execFileSync21(command, args, {
40488
+ return execFileSync22(command, args, {
40383
40489
  encoding: "utf8",
40384
40490
  timeout: PROBE_TIMEOUT_MS,
40385
40491
  stdio: ["ignore", "pipe", "ignore"]
@@ -40618,7 +40724,7 @@ function summaryPathFor(jsonlPath2) {
40618
40724
  }
40619
40725
 
40620
40726
  // src/commands/sessions/summarise/summariseSession.ts
40621
- import { execFileSync as execFileSync22 } from "child_process";
40727
+ import { execFileSync as execFileSync23 } from "child_process";
40622
40728
  function summariseSession(jsonlPath2) {
40623
40729
  const firstMessage = extractFirstUserMessage(jsonlPath2);
40624
40730
  const backlogIds = scanSessionBacklogRefs(jsonlPath2);
@@ -40627,7 +40733,7 @@ function summariseSession(jsonlPath2) {
40627
40733
  }
40628
40734
  const prompt = buildPrompt6(firstMessage, backlogIds);
40629
40735
  try {
40630
- const output = execFileSync22("claude", ["-p", "--model", "haiku", prompt], {
40736
+ const output = execFileSync23("claude", ["-p", "--model", "haiku", prompt], {
40631
40737
  encoding: "utf8",
40632
40738
  timeout: 3e4,
40633
40739
  stdio: ["ignore", "pipe", "ignore"]
@@ -40813,7 +40919,7 @@ function buildLimitsSegment(rateLimits) {
40813
40919
  }
40814
40920
 
40815
40921
  // src/commands/readGitBranch.ts
40816
- import { readFileSync as readFileSync66, statSync as statSync16 } from "fs";
40922
+ import { readFileSync as readFileSync67, statSync as statSync16 } from "fs";
40817
40923
  import { isAbsolute as isAbsolute5, join as join102, resolve as resolve23 } from "path";
40818
40924
  function resolveGitDir(cwd) {
40819
40925
  const dotGit = join102(cwd, ".git");
@@ -40828,7 +40934,7 @@ function resolveGitDir(cwd) {
40828
40934
  }
40829
40935
  let contents;
40830
40936
  try {
40831
- contents = readFileSync66(dotGit, "utf8");
40937
+ contents = readFileSync67(dotGit, "utf8");
40832
40938
  } catch {
40833
40939
  return null;
40834
40940
  }
@@ -40846,7 +40952,7 @@ function readGitBranch(cwd) {
40846
40952
  }
40847
40953
  let head;
40848
40954
  try {
40849
- head = readFileSync66(join102(gitDir, "HEAD"), "utf8");
40955
+ head = readFileSync67(join102(gitDir, "HEAD"), "utf8");
40850
40956
  } catch {
40851
40957
  return null;
40852
40958
  }
@@ -40914,7 +41020,7 @@ async function statusLine() {
40914
41020
  }
40915
41021
 
40916
41022
  // src/commands/update.ts
40917
- import { execSync as execSync62 } from "child_process";
41023
+ import { execSync as execSync63 } from "child_process";
40918
41024
  import * as path89 from "path";
40919
41025
 
40920
41026
  // src/commands/restartDaemonAfterUpdate.ts
@@ -40938,7 +41044,7 @@ function isGlobalNpmInstall(dir) {
40938
41044
  if (resolved.split(path89.sep).includes("node_modules")) {
40939
41045
  return true;
40940
41046
  }
40941
- const globalPrefix = execSync62("npm prefix -g", { stdio: "pipe" }).toString().trim();
41047
+ const globalPrefix = execSync63("npm prefix -g", { stdio: "pipe" }).toString().trim();
40942
41048
  return resolved.toLowerCase().startsWith(path89.resolve(globalPrefix).toLowerCase());
40943
41049
  } catch {
40944
41050
  return false;
@@ -40949,18 +41055,18 @@ async function update2() {
40949
41055
  console.log(`Assist is installed at: ${installDir}`);
40950
41056
  if (isGitRepo(installDir)) {
40951
41057
  console.log("Detected git repo installation, pulling latest...");
40952
- execSync62("git pull", { cwd: installDir, stdio: "inherit" });
41058
+ execSync63("git pull", { cwd: installDir, stdio: "inherit" });
40953
41059
  console.log("Installing dependencies...");
40954
- execSync62("npm i", { cwd: installDir, stdio: "inherit" });
41060
+ execSync63("npm i", { cwd: installDir, stdio: "inherit" });
40955
41061
  console.log("Building...");
40956
- execSync62("npm run build", { cwd: installDir, stdio: "inherit" });
41062
+ execSync63("npm run build", { cwd: installDir, stdio: "inherit" });
40957
41063
  console.log("Syncing commands...");
40958
- execSync62("assist sync", { stdio: "inherit" });
41064
+ execSync63("assist sync", { stdio: "inherit" });
40959
41065
  } else if (isGlobalNpmInstall(installDir)) {
40960
41066
  console.log("Detected global npm installation, updating...");
40961
- execSync62("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
41067
+ execSync63("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
40962
41068
  console.log("Syncing commands...");
40963
- execSync62("assist sync", { stdio: "inherit" });
41069
+ execSync63("assist sync", { stdio: "inherit" });
40964
41070
  } else {
40965
41071
  console.error(
40966
41072
  "Could not determine installation method. Expected a git repo or global npm install."