@staff0rd/assist 0.444.1 → 0.445.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.444.1",
9
+ version: "0.445.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -121,7 +121,7 @@ var package_default = {
121
121
  };
122
122
 
123
123
  // src/commands/commit.ts
124
- import { execSync as execSync6 } from "child_process";
124
+ import { execSync as execSync7 } from "child_process";
125
125
 
126
126
  // src/shared/resolveSessionItemId.ts
127
127
  var ITEM_ID_ENV = "ASSIST_BACKLOG_ITEM_ID";
@@ -435,6 +435,7 @@ var assistConfigSchema = z2.strictObject({
435
435
  repos: z2.record(z2.string(), z2.record(z2.string(), z2.unknown())).optional(),
436
436
  worktree: z2.strictObject({
437
437
  enabled: z2.boolean().default(false),
438
+ trunk: z2.boolean().default(false),
438
439
  root: z2.string().optional(),
439
440
  install: z2.union([z2.boolean(), z2.string()]).default(true),
440
441
  commitBeforeManualChecks: z2.boolean().default(false),
@@ -1782,17 +1783,49 @@ function git(args) {
1782
1783
  }
1783
1784
  }
1784
1785
 
1785
- // src/commands/commit/stageAndCommit.ts
1786
+ // src/commands/commit/pushCommit.ts
1786
1787
  import { execSync as execSync5 } from "child_process";
1788
+ var HEADS_PREFIX = "refs/heads/";
1789
+ function pushCommit() {
1790
+ const target = renamedUpstream();
1791
+ const command = target ? `git push ${shellQuote(target.remote)} HEAD:${shellQuote(target.branch)}` : "git push";
1792
+ execSync5(command, { stdio: "inherit" });
1793
+ }
1794
+ function renamedUpstream() {
1795
+ const branch2 = gitOrNull("git symbolic-ref --short HEAD");
1796
+ if (!branch2) return null;
1797
+ const remote = gitOrNull(
1798
+ `git config --get branch.${shellQuote(branch2)}.remote`
1799
+ );
1800
+ const merge = gitOrNull(
1801
+ `git config --get branch.${shellQuote(branch2)}.merge`
1802
+ );
1803
+ if (!remote || !merge) return null;
1804
+ const upstream = merge.startsWith(HEADS_PREFIX) ? merge.slice(HEADS_PREFIX.length) : merge;
1805
+ return upstream === branch2 ? null : { remote, branch: upstream };
1806
+ }
1807
+ function gitOrNull(command) {
1808
+ try {
1809
+ return execSync5(command, {
1810
+ encoding: "utf8",
1811
+ stdio: ["pipe", "pipe", "pipe"]
1812
+ }).trim() || null;
1813
+ } catch {
1814
+ return null;
1815
+ }
1816
+ }
1817
+
1818
+ // src/commands/commit/stageAndCommit.ts
1819
+ import { execSync as execSync6 } from "child_process";
1787
1820
  function commitStaged(message2) {
1788
- execSync5(`git commit -m ${shellQuote(message2)}`, { stdio: "inherit" });
1789
- return execSync5("git rev-parse --short=7 HEAD", {
1821
+ execSync6(`git commit -m ${shellQuote(message2)}`, { stdio: "inherit" });
1822
+ return execSync6("git rev-parse --short=7 HEAD", {
1790
1823
  encoding: "utf8"
1791
1824
  }).trim();
1792
1825
  }
1793
1826
  function stageAndCommit(files, message2) {
1794
1827
  const escaped = files.map(shellQuote).join(" ");
1795
- execSync5(`git add ${escaped}`, { stdio: "inherit" });
1828
+ execSync6(`git add ${escaped}`, { stdio: "inherit" });
1796
1829
  return commitStaged(message2);
1797
1830
  }
1798
1831
 
@@ -1920,13 +1953,13 @@ async function execCommit(files, message2, config) {
1920
1953
  warnIfUnexpectedBranch(config);
1921
1954
  const pulled = Boolean(config.commit?.pull);
1922
1955
  if (pulled) {
1923
- execSync6("git pull --autostash", { stdio: "inherit" });
1956
+ execSync7("git pull --autostash", { stdio: "inherit" });
1924
1957
  }
1925
1958
  abortOnConflicts(files, pulled);
1926
1959
  const sha = files.length > 0 ? stageAndCommit(files, message2) : commitStaged(message2);
1927
1960
  console.log(`Committed: ${sha}`);
1928
1961
  if (config.commit?.push) {
1929
- execSync6("git push", { stdio: "inherit" });
1962
+ pushCommit();
1930
1963
  console.log("Pushed to remote");
1931
1964
  }
1932
1965
  await recordCommitActivity(message2);
@@ -1941,7 +1974,7 @@ async function recordCommitActivity(message2) {
1941
1974
  }
1942
1975
  async function commit(args) {
1943
1976
  if (args[0] === "status") {
1944
- execSync6("git status && echo '---DIFF---' && git diff", {
1977
+ execSync7("git status && echo '---DIFF---' && git diff", {
1945
1978
  stdio: "inherit"
1946
1979
  });
1947
1980
  return;
@@ -1958,9 +1991,9 @@ async function commit(args) {
1958
1991
  }
1959
1992
 
1960
1993
  // src/commands/coverage.ts
1961
- import { execSync as execSync7 } from "child_process";
1994
+ import { execSync as execSync8 } from "child_process";
1962
1995
  function coverage() {
1963
- const output = execSync7(
1996
+ const output = execSync8(
1964
1997
  "npx vitest run --coverage --coverage.include='src/**/*.ts' --coverage.all --coverage.reporter=text 2>&1",
1965
1998
  { encoding: "utf8", timeout: 12e4 }
1966
1999
  );
@@ -2060,7 +2093,7 @@ function findPackageJsonWithVerifyScripts(startDir) {
2060
2093
  }
2061
2094
 
2062
2095
  // src/commands/verify/installPackage.ts
2063
- import { execSync as execSync8 } from "child_process";
2096
+ import { execSync as execSync9 } from "child_process";
2064
2097
  import { writeFileSync as writeFileSync2 } from "fs";
2065
2098
  import chalk6 from "chalk";
2066
2099
  function writePackageJson(filePath, pkg) {
@@ -2079,7 +2112,7 @@ function addScript(pkg, name, command) {
2079
2112
  function installPackage(name, cwd) {
2080
2113
  console.log(chalk6.dim(`Installing ${name}...`));
2081
2114
  try {
2082
- execSync8(`npm install -D ${name}`, { stdio: "inherit", cwd });
2115
+ execSync9(`npm install -D ${name}`, { stdio: "inherit", cwd });
2083
2116
  return true;
2084
2117
  } catch {
2085
2118
  console.error(chalk6.red(`Failed to install ${name}`));
@@ -2323,7 +2356,7 @@ import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync
2323
2356
  import chalk14 from "chalk";
2324
2357
 
2325
2358
  // src/shared/removeEslint/index.ts
2326
- import { execSync as execSync9 } from "child_process";
2359
+ import { execSync as execSync10 } from "child_process";
2327
2360
  import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
2328
2361
 
2329
2362
  // src/shared/removeEslint/removeEslintConfigFiles.ts
@@ -2358,7 +2391,7 @@ function removeEslint(options2 = {}) {
2358
2391
  const removedConfigFiles = removeEslintConfigFiles();
2359
2392
  if (removedFromPackageJson || removedConfigFiles) {
2360
2393
  console.log("Running npm install...");
2361
- execSync9("npm install", { stdio: "inherit" });
2394
+ execSync10("npm install", { stdio: "inherit" });
2362
2395
  return true;
2363
2396
  }
2364
2397
  return false;
@@ -3206,11 +3239,11 @@ function lint(options2 = {}) {
3206
3239
  }
3207
3240
 
3208
3241
  // src/commands/new/registerNew/newCli/index.ts
3209
- import { execSync as execSync18 } from "child_process";
3242
+ import { execSync as execSync19 } from "child_process";
3210
3243
  import { basename as basename2, resolve as resolve5 } from "path";
3211
3244
 
3212
3245
  // src/commands/verify/blockCodeComments/findComments.ts
3213
- import { execSync as execSync10 } from "child_process";
3246
+ import { execSync as execSync11 } from "child_process";
3214
3247
  import fs15 from "fs";
3215
3248
  import { minimatch } from "minimatch";
3216
3249
  import { Project as Project2 } from "ts-morph";
@@ -3470,7 +3503,7 @@ function shouldScan(file, ignoreGlobs) {
3470
3503
  return fs15.existsSync(file);
3471
3504
  }
3472
3505
  function findComments(options2) {
3473
- const diff3 = execSync10("git diff HEAD", {
3506
+ const diff3 = execSync11("git diff HEAD", {
3474
3507
  encoding: "utf8",
3475
3508
  maxBuffer: 64 * 1024 * 1024
3476
3509
  });
@@ -3716,13 +3749,13 @@ Total: ${violations.length} forbidden string(s).`);
3716
3749
  }
3717
3750
 
3718
3751
  // src/commands/verify/hardcodedColors.ts
3719
- import { execSync as execSync11 } from "child_process";
3752
+ import { execSync as execSync12 } from "child_process";
3720
3753
  import { minimatch as minimatch3 } from "minimatch";
3721
3754
  var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
3722
3755
  function hardcodedColors() {
3723
3756
  const ignoreGlobs = loadConfig().hardcodedColors?.ignore ?? [];
3724
3757
  try {
3725
- const output = execSync11(`grep -rEnH '${pattern}' src/`, {
3758
+ const output = execSync12(`grep -rEnH '${pattern}' src/`, {
3726
3759
  encoding: "utf8"
3727
3760
  });
3728
3761
  const lines = output.trim().split("\n").filter((line) => {
@@ -3983,14 +4016,14 @@ function listMigrationFiles(dir) {
3983
4016
  }
3984
4017
 
3985
4018
  // src/commands/verify/migrations/readBaselineMigrations.ts
3986
- import { execSync as execSync12 } from "child_process";
4019
+ import { execSync as execSync13 } from "child_process";
3987
4020
  import { basename } from "path";
3988
4021
  var MIGRATION_FILE3 = /^migration\d+[A-Za-z0-9]*\.ts$/;
3989
4022
  function readBaselineMigrations(repoRelativeDir, ref) {
3990
4023
  const baseline = /* @__PURE__ */ new Map();
3991
4024
  let listing;
3992
4025
  try {
3993
- listing = execSync12(
4026
+ listing = execSync13(
3994
4027
  `git ls-tree -r --name-only "${ref}" -- "${repoRelativeDir}"`,
3995
4028
  { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
3996
4029
  );
@@ -4000,7 +4033,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
4000
4033
  const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path71) => MIGRATION_FILE3.test(basename(path71)));
4001
4034
  for (const path71 of paths) {
4002
4035
  try {
4003
- const content = execSync12(`git show "${ref}:${path71}"`, {
4036
+ const content = execSync13(`git show "${ref}:${path71}"`, {
4004
4037
  encoding: "utf8",
4005
4038
  maxBuffer: 16 * 1024 * 1024,
4006
4039
  stdio: ["pipe", "pipe", "pipe"]
@@ -4013,10 +4046,10 @@ function readBaselineMigrations(repoRelativeDir, ref) {
4013
4046
  }
4014
4047
 
4015
4048
  // src/commands/verify/migrations/resolveBaselineRef.ts
4016
- import { execSync as execSync13 } from "child_process";
4049
+ import { execSync as execSync14 } from "child_process";
4017
4050
  function refExists(ref) {
4018
4051
  try {
4019
- execSync13(`git rev-parse --verify --quiet "${ref}"`, {
4052
+ execSync14(`git rev-parse --verify --quiet "${ref}"`, {
4020
4053
  stdio: ["pipe", "pipe", "pipe"]
4021
4054
  });
4022
4055
  return true;
@@ -4088,10 +4121,10 @@ Total: ${problems.length} violation(s).`);
4088
4121
  }
4089
4122
 
4090
4123
  // src/commands/verify/noVenv.ts
4091
- import { execSync as execSync14 } from "child_process";
4124
+ import { execSync as execSync15 } from "child_process";
4092
4125
  function noVenv() {
4093
4126
  try {
4094
- const output = execSync14(
4127
+ const output = execSync15(
4095
4128
  "find . -type d -name venv -not -path '*/node_modules/*'",
4096
4129
  {
4097
4130
  encoding: "utf8"
@@ -4123,9 +4156,9 @@ Total: ${folders.length} venv folder(s)`);
4123
4156
  import { minimatch as minimatch4 } from "minimatch";
4124
4157
 
4125
4158
  // src/commands/verify/run/getChangedFiles.ts
4126
- import { execSync as execSync15 } from "child_process";
4159
+ import { execSync as execSync16 } from "child_process";
4127
4160
  function getChangedFiles() {
4128
- const output = execSync15("git diff --name-only HEAD", {
4161
+ const output = execSync16("git diff --name-only HEAD", {
4129
4162
  encoding: "utf8"
4130
4163
  }).trim();
4131
4164
  if (output === "") return [];
@@ -4297,25 +4330,25 @@ async function run(options2 = {}) {
4297
4330
  }
4298
4331
 
4299
4332
  // src/commands/new/registerNew/initGit.ts
4300
- import { execSync as execSync16 } from "child_process";
4333
+ import { execSync as execSync17 } from "child_process";
4301
4334
  import { writeFileSync as writeFileSync10 } from "fs";
4302
4335
  function initGit() {
4303
4336
  console.log("Initializing git repository...");
4304
- execSync16("git init", { stdio: "inherit" });
4337
+ execSync17("git init", { stdio: "inherit" });
4305
4338
  writeFileSync10(".gitignore", "dist\nnode_modules\n");
4306
4339
  }
4307
4340
 
4308
4341
  // src/commands/new/registerNew/newCli/initPackageJson.ts
4309
- import { execSync as execSync17 } from "child_process";
4342
+ import { execSync as execSync18 } from "child_process";
4310
4343
  function initPackageJson(name) {
4311
4344
  console.log("Initializing package.json...");
4312
- execSync17("npm init -y", { stdio: "inherit" });
4345
+ execSync18("npm init -y", { stdio: "inherit" });
4313
4346
  console.log("Configuring package.json...");
4314
- execSync17("npm pkg delete main", { stdio: "inherit" });
4315
- execSync17("npm pkg set type=module", { stdio: "inherit" });
4316
- execSync17(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
4317
- execSync17("npm pkg set scripts.build=tsup", { stdio: "inherit" });
4318
- execSync17('npm pkg set scripts.start="node dist/index.js"', {
4347
+ execSync18("npm pkg delete main", { stdio: "inherit" });
4348
+ execSync18("npm pkg set type=module", { stdio: "inherit" });
4349
+ execSync18(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
4350
+ execSync18("npm pkg set scripts.build=tsup", { stdio: "inherit" });
4351
+ execSync18('npm pkg set scripts.start="node dist/index.js"', {
4319
4352
  stdio: "inherit"
4320
4353
  });
4321
4354
  }
@@ -4380,8 +4413,8 @@ async function newCli() {
4380
4413
  initGit();
4381
4414
  initPackageJson(name);
4382
4415
  console.log("Installing dependencies...");
4383
- execSync18("npm install commander", { stdio: "inherit" });
4384
- execSync18("npm install -D tsup typescript @types/node", {
4416
+ execSync19("npm install commander", { stdio: "inherit" });
4417
+ execSync19("npm install -D tsup typescript @types/node", {
4385
4418
  stdio: "inherit"
4386
4419
  });
4387
4420
  writeCliTemplate(name);
@@ -4390,11 +4423,11 @@ async function newCli() {
4390
4423
  }
4391
4424
 
4392
4425
  // src/commands/new/registerNew/newProject.ts
4393
- import { execSync as execSync20 } from "child_process";
4426
+ import { execSync as execSync21 } from "child_process";
4394
4427
  import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync13 } from "fs";
4395
4428
 
4396
4429
  // src/commands/deploy/init/index.ts
4397
- import { execSync as execSync19 } from "child_process";
4430
+ import { execSync as execSync20 } from "child_process";
4398
4431
  import chalk28 from "chalk";
4399
4432
  import enquirer3 from "enquirer";
4400
4433
 
@@ -4447,7 +4480,7 @@ Created ${WORKFLOW_PATH}`));
4447
4480
  // src/commands/deploy/init/index.ts
4448
4481
  async function ensureNetlifyCli() {
4449
4482
  try {
4450
- execSync19("netlify sites:create --disable-linking", { stdio: "inherit" });
4483
+ execSync20("netlify sites:create --disable-linking", { stdio: "inherit" });
4451
4484
  } catch (error) {
4452
4485
  if (!(error instanceof Error) || !error.message.includes("command not found"))
4453
4486
  throw error;
@@ -4462,9 +4495,9 @@ async function ensureNetlifyCli() {
4462
4495
  process.exit(1);
4463
4496
  }
4464
4497
  console.log(chalk28.dim("\nInstalling netlify-cli...\n"));
4465
- execSync19("npm install -g netlify-cli", { stdio: "inherit" });
4498
+ execSync20("npm install -g netlify-cli", { stdio: "inherit" });
4466
4499
  console.log();
4467
- execSync19("netlify sites:create --disable-linking", { stdio: "inherit" });
4500
+ execSync20("netlify sites:create --disable-linking", { stdio: "inherit" });
4468
4501
  }
4469
4502
  }
4470
4503
  function printSetupInstructions() {
@@ -4507,7 +4540,7 @@ async function init6() {
4507
4540
  // src/commands/new/registerNew/newProject.ts
4508
4541
  async function newProject() {
4509
4542
  console.log("Initializing Vite with react-ts template...");
4510
- execSync20("npm create vite@latest . -- --template react-ts", {
4543
+ execSync21("npm create vite@latest . -- --template react-ts", {
4511
4544
  stdio: "inherit"
4512
4545
  });
4513
4546
  initGit();
@@ -4698,11 +4731,11 @@ function activityChart(data, range) {
4698
4731
  }
4699
4732
 
4700
4733
  // src/commands/activity/fetchCommitsPerDay.ts
4701
- import { execSync as execSync21 } from "child_process";
4734
+ import { execSync as execSync22 } from "child_process";
4702
4735
  function fetchContributions(from, to) {
4703
4736
  const query = `{ viewer { contributionsCollection(from: "${from}T00:00:00Z", to: "${to}T23:59:59Z") { contributionCalendar { weeks { contributionDays { date contributionCount } } } } } }`;
4704
4737
  const jq = ".data.viewer.contributionsCollection.contributionCalendar.weeks[].contributionDays[]";
4705
- const raw = execSync21(`gh api graphql -f query='${query}' --jq '${jq}'`, {
4738
+ const raw = execSync22(`gh api graphql -f query='${query}' --jq '${jq}'`, {
4706
4739
  encoding: "utf8"
4707
4740
  }).trim();
4708
4741
  if (!raw) return [];
@@ -4789,10 +4822,10 @@ import { join as join10 } from "path";
4789
4822
  import chalk29 from "chalk";
4790
4823
 
4791
4824
  // src/commands/backup/readCrontab.ts
4792
- import { execSync as execSync22 } from "child_process";
4825
+ import { execSync as execSync23 } from "child_process";
4793
4826
  function readCrontab() {
4794
4827
  try {
4795
- return execSync22("crontab -l", {
4828
+ return execSync23("crontab -l", {
4796
4829
  encoding: "utf8",
4797
4830
  stdio: ["ignore", "pipe", "ignore"]
4798
4831
  });
@@ -4802,7 +4835,7 @@ function readCrontab() {
4802
4835
  }
4803
4836
  function writeCrontab(content) {
4804
4837
  try {
4805
- execSync22("crontab -", {
4838
+ execSync23("crontab -", {
4806
4839
  input: content,
4807
4840
  stdio: ["pipe", "ignore", "pipe"]
4808
4841
  });
@@ -5143,7 +5176,7 @@ import chalk46 from "chalk";
5143
5176
  import enquirer5 from "enquirer";
5144
5177
 
5145
5178
  // src/shared/pullIfConfigured.ts
5146
- import { execSync as execSync23 } from "child_process";
5179
+ import { execSync as execSync24 } from "child_process";
5147
5180
  import chalk32 from "chalk";
5148
5181
  function pullIfConfigured() {
5149
5182
  const config = loadConfig();
@@ -5157,7 +5190,7 @@ function pullIfConfigured() {
5157
5190
  return;
5158
5191
  }
5159
5192
  try {
5160
- execSync23("git pull --ff-only", { stdio: "inherit" });
5193
+ execSync24("git pull --ff-only", { stdio: "inherit" });
5161
5194
  } catch {
5162
5195
  console.error(chalk32.red("git pull --ff-only failed; aborting."));
5163
5196
  process.exit(1);
@@ -5165,7 +5198,7 @@ function pullIfConfigured() {
5165
5198
  }
5166
5199
  function hasLocalChanges() {
5167
5200
  try {
5168
- const status3 = execSync23("git status --porcelain", {
5201
+ const status3 = execSync24("git status --porcelain", {
5169
5202
  encoding: "utf8"
5170
5203
  });
5171
5204
  return status3.trim().length > 0;
@@ -5432,7 +5465,7 @@ function buildArgs(prompt, options2) {
5432
5465
  }
5433
5466
 
5434
5467
  // src/commands/branch/createBranch.ts
5435
- import { execSync as execSync25 } from "child_process";
5468
+ import { execSync as execSync26 } from "child_process";
5436
5469
 
5437
5470
  // src/commands/branch/buildBranchName.ts
5438
5471
  function buildBranchName({
@@ -5448,12 +5481,12 @@ function buildBranchName({
5448
5481
  }
5449
5482
 
5450
5483
  // src/commands/branch/resolveDefaultBranch.ts
5451
- import { execSync as execSync24 } from "child_process";
5484
+ import { execSync as execSync25 } from "child_process";
5452
5485
  var REMOTE_HEAD_REGEX = /^ref:\s+refs\/heads\/(\S+)\s+HEAD$/m;
5453
5486
  function resolveDefaultBranch(override, cwd) {
5454
5487
  if (override) return override;
5455
5488
  try {
5456
- const output = execSync24("git ls-remote --symref origin HEAD", {
5489
+ const output = execSync25("git ls-remote --symref origin HEAD", {
5457
5490
  encoding: "utf8",
5458
5491
  stdio: ["pipe", "pipe", "pipe"],
5459
5492
  cwd
@@ -5477,11 +5510,11 @@ async function createBranch({
5477
5510
  jira,
5478
5511
  slug
5479
5512
  });
5480
- execSync25("git fetch", { stdio: "inherit" });
5513
+ execSync26("git fetch", { stdio: "inherit" });
5481
5514
  let baseRef;
5482
5515
  if (from) {
5483
5516
  try {
5484
- execSync25(`git rev-parse --verify ${shellQuote(from)}`, {
5517
+ execSync26(`git rev-parse --verify ${shellQuote(from)}`, {
5485
5518
  stdio: ["pipe", "pipe", "pipe"]
5486
5519
  });
5487
5520
  } catch {
@@ -5491,7 +5524,7 @@ async function createBranch({
5491
5524
  } else {
5492
5525
  baseRef = `origin/${resolveDefaultBranch(config.branch?.defaultBranch)}`;
5493
5526
  }
5494
- execSync25(`git switch -c ${shellQuote(branchName)} ${shellQuote(baseRef)}`, {
5527
+ execSync26(`git switch -c ${shellQuote(branchName)} ${shellQuote(baseRef)}`, {
5495
5528
  stdio: "inherit"
5496
5529
  });
5497
5530
  await recordBranchActivity(branchName);
@@ -5631,11 +5664,11 @@ function backupLocalBacklogFiles(dir) {
5631
5664
  }
5632
5665
 
5633
5666
  // src/commands/backlog/gitPullBacklog.ts
5634
- import { execSync as execSync26 } from "child_process";
5667
+ import { execSync as execSync27 } from "child_process";
5635
5668
  import chalk35 from "chalk";
5636
5669
  function gitPullBacklog(dir) {
5637
5670
  try {
5638
- execSync26("git pull --ff-only", {
5671
+ execSync27("git pull --ff-only", {
5639
5672
  cwd: dir,
5640
5673
  stdio: ["pipe", "pipe", "pipe"]
5641
5674
  });
@@ -7925,7 +7958,7 @@ import chalk61 from "chalk";
7925
7958
  import { WebSocketServer } from "ws";
7926
7959
 
7927
7960
  // src/shared/getInstallDir.ts
7928
- import { execSync as execSync27 } from "child_process";
7961
+ import { execSync as execSync28 } from "child_process";
7929
7962
  import { dirname as dirname18, resolve as resolve7 } from "path";
7930
7963
  import { fileURLToPath as fileURLToPath3 } from "url";
7931
7964
  var __filename2 = fileURLToPath3(import.meta.url);
@@ -7935,7 +7968,7 @@ function getInstallDir() {
7935
7968
  }
7936
7969
  function isGitRepo(dir) {
7937
7970
  try {
7938
- const result = execSync27("git rev-parse --show-toplevel", {
7971
+ const result = execSync28("git rev-parse --show-toplevel", {
7939
7972
  cwd: dir,
7940
7973
  stdio: "pipe"
7941
7974
  }).toString().trim();
@@ -7952,11 +7985,11 @@ import {
7952
7985
  import chalk57 from "chalk";
7953
7986
 
7954
7987
  // src/lib/openBrowser.ts
7955
- import { execSync as execSync28 } from "child_process";
7988
+ import { execSync as execSync29 } from "child_process";
7956
7989
  function tryExec(commands) {
7957
7990
  for (const cmd of commands) {
7958
7991
  try {
7959
- execSync28(cmd, { stdio: "ignore" });
7992
+ execSync29(cmd, { stdio: "ignore" });
7960
7993
  return true;
7961
7994
  } catch {
7962
7995
  }
@@ -8188,7 +8221,7 @@ function git2(cwd, args) {
8188
8221
  });
8189
8222
  });
8190
8223
  }
8191
- async function gitOrNull(cwd, args) {
8224
+ async function gitOrNull2(cwd, args) {
8192
8225
  try {
8193
8226
  return (await git2(cwd, args)).trim() || null;
8194
8227
  } catch {
@@ -9146,7 +9179,7 @@ import * as os3 from "os";
9146
9179
  import * as path25 from "path";
9147
9180
 
9148
9181
  // src/shared/checkCliAvailable.ts
9149
- import { execSync as execSync29 } from "child_process";
9182
+ import { execSync as execSync30 } from "child_process";
9150
9183
  function checkCliAvailable(cli) {
9151
9184
  const binary = cli.split(/\s+/)[0];
9152
9185
  const opts = {
@@ -9154,11 +9187,11 @@ function checkCliAvailable(cli) {
9154
9187
  stdio: ["ignore", "pipe", "pipe"]
9155
9188
  };
9156
9189
  try {
9157
- execSync29(`command -v ${binary}`, opts);
9190
+ execSync30(`command -v ${binary}`, opts);
9158
9191
  return true;
9159
9192
  } catch {
9160
9193
  try {
9161
- execSync29(`where ${binary}`, opts);
9194
+ execSync30(`where ${binary}`, opts);
9162
9195
  return true;
9163
9196
  } catch {
9164
9197
  return false;
@@ -9249,8 +9282,8 @@ function subsequenceScore(text17, query) {
9249
9282
  function scoreFilePath(path71, query) {
9250
9283
  const needle = query.trim().toLowerCase();
9251
9284
  if (!needle) return 0;
9252
- const basename18 = path71.slice(path71.lastIndexOf("/") + 1);
9253
- const inBasename = subsequenceScore(basename18, needle);
9285
+ const basename19 = path71.slice(path71.lastIndexOf("/") + 1);
9286
+ const inBasename = subsequenceScore(basename19, needle);
9254
9287
  if (inBasename !== null) return BASENAME_WEIGHT + inBasename;
9255
9288
  return subsequenceScore(path71, needle);
9256
9289
  }
@@ -10561,13 +10594,13 @@ async function beginAssociation(id, options2, clearPatch, label2) {
10561
10594
  }
10562
10595
 
10563
10596
  // src/commands/backlog/associate-github/fetchGithubIssueTitle.ts
10564
- import { execSync as execSync30 } from "child_process";
10597
+ import { execSync as execSync31 } from "child_process";
10565
10598
  function fetchGithubIssueTitle(issue) {
10566
10599
  const match = /^([^/]+)\/([^#]+)#(\d+)$/.exec(issue);
10567
10600
  if (!match) return void 0;
10568
10601
  const [, owner, repo, number] = match;
10569
10602
  try {
10570
- const result = execSync30(
10603
+ const result = execSync31(
10571
10604
  `gh issue view ${number} -R ${owner}/${repo} --json title`,
10572
10605
  { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
10573
10606
  );
@@ -10634,12 +10667,12 @@ import chalk66 from "chalk";
10634
10667
  import { eq as eq19 } from "drizzle-orm";
10635
10668
 
10636
10669
  // src/commands/jira/fetchIssue.ts
10637
- import { execSync as execSync31 } from "child_process";
10670
+ import { execSync as execSync32 } from "child_process";
10638
10671
  import chalk65 from "chalk";
10639
10672
  function fetchIssue(issueKey, fields) {
10640
10673
  let result;
10641
10674
  try {
10642
- result = execSync31(
10675
+ result = execSync32(
10643
10676
  `acli jira workitem view ${issueKey} -f ${fields} --json`,
10644
10677
  { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
10645
10678
  );
@@ -14721,10 +14754,10 @@ function formatResultLine(entry, failing) {
14721
14754
  }
14722
14755
 
14723
14756
  // src/commands/complexity/maintainability/getMaintainabilityGitState.ts
14724
- import { execSync as execSync32 } from "child_process";
14757
+ import { execSync as execSync33 } from "child_process";
14725
14758
  import path28 from "path";
14726
14759
  function git3(command) {
14727
- return execSync32(command, { encoding: "utf8" });
14760
+ return execSync33(command, { encoding: "utf8" });
14728
14761
  }
14729
14762
  function toAbsolute(root, repoRelative) {
14730
14763
  return path28.resolve(root, repoRelative);
@@ -15298,7 +15331,7 @@ function loadBlogSkipDays(repoName) {
15298
15331
  }
15299
15332
 
15300
15333
  // src/commands/devlog/shared.ts
15301
- import { execSync as execSync33 } from "child_process";
15334
+ import { execSync as execSync34 } from "child_process";
15302
15335
  import chalk134 from "chalk";
15303
15336
 
15304
15337
  // src/shared/getRepoName.ts
@@ -15390,7 +15423,7 @@ function loadAllDevlogLatestDates() {
15390
15423
  // src/commands/devlog/shared.ts
15391
15424
  function getCommitFiles(hash) {
15392
15425
  try {
15393
- const output = execSync33(`git show --name-only --format="" ${hash}`, {
15426
+ const output = execSync34(`git show --name-only --format="" ${hash}`, {
15394
15427
  encoding: "utf8"
15395
15428
  });
15396
15429
  return output.trim().split("\n").filter(Boolean);
@@ -15486,11 +15519,11 @@ function list3(options2) {
15486
15519
  }
15487
15520
 
15488
15521
  // src/commands/devlog/getLastVersionInfo.ts
15489
- import { execFileSync as execFileSync4, execSync as execSync34 } from "child_process";
15522
+ import { execFileSync as execFileSync4, execSync as execSync35 } from "child_process";
15490
15523
  import semver from "semver";
15491
15524
  function getVersionAtCommit(hash) {
15492
15525
  try {
15493
- const content = execSync34(`git show ${hash}:package.json`, {
15526
+ const content = execSync35(`git show ${hash}:package.json`, {
15494
15527
  encoding: "utf8"
15495
15528
  });
15496
15529
  const pkg = JSON.parse(content);
@@ -15663,7 +15696,7 @@ function next2(options2) {
15663
15696
  }
15664
15697
 
15665
15698
  // src/commands/devlog/repos/index.ts
15666
- import { execSync as execSync35 } from "child_process";
15699
+ import { execSync as execSync36 } from "child_process";
15667
15700
 
15668
15701
  // src/commands/devlog/repos/printReposTable.ts
15669
15702
  import chalk138 from "chalk";
@@ -15698,7 +15731,7 @@ function getStatus(lastPush, lastDevlog) {
15698
15731
  return lastDevlog < lastPush ? "outdated" : "ok";
15699
15732
  }
15700
15733
  function fetchRepos(days, all) {
15701
- const json = execSync35(
15734
+ const json = execSync36(
15702
15735
  "gh repo list staff0rd --json name,pushedAt,isArchived --limit 200",
15703
15736
  { encoding: "utf8" }
15704
15737
  );
@@ -16078,7 +16111,7 @@ async function deps(csprojPath, options2) {
16078
16111
  }
16079
16112
 
16080
16113
  // src/commands/dotnet/getChangedCsFiles.ts
16081
- import { execSync as execSync36 } from "child_process";
16114
+ import { execSync as execSync37 } from "child_process";
16082
16115
  var SCOPE_ALL = "all";
16083
16116
  var SCOPE_BASE = "base:";
16084
16117
  var SCOPE_COMMIT = "commit:";
@@ -16102,7 +16135,7 @@ function getChangedCsFiles(scope) {
16102
16135
  } else {
16103
16136
  cmd = "git diff --name-only HEAD";
16104
16137
  }
16105
- const output = execSync36(cmd, { encoding: "utf8" }).trim();
16138
+ const output = execSync37(cmd, { encoding: "utf8" }).trim();
16106
16139
  if (output === "") return [];
16107
16140
  return output.split("\n").filter((f) => f.toLowerCase().endsWith(".cs"));
16108
16141
  }
@@ -16300,14 +16333,14 @@ function parseInspectReport(json) {
16300
16333
  }
16301
16334
 
16302
16335
  // src/commands/dotnet/runInspectCode.ts
16303
- import { execSync as execSync37 } from "child_process";
16336
+ import { execSync as execSync38 } from "child_process";
16304
16337
  import { existsSync as existsSync40, readFileSync as readFileSync35, unlinkSync as unlinkSync10 } from "fs";
16305
16338
  import { tmpdir as tmpdir4 } from "os";
16306
16339
  import path35 from "path";
16307
16340
  import chalk148 from "chalk";
16308
16341
  function assertJbInstalled() {
16309
16342
  try {
16310
- execSync37("jb inspectcode --version", { stdio: "pipe" });
16343
+ execSync38("jb inspectcode --version", { stdio: "pipe" });
16311
16344
  } catch {
16312
16345
  console.error(chalk148.red("jb is not installed. Install with:"));
16313
16346
  console.error(
@@ -16321,7 +16354,7 @@ function runInspectCode(slnPath, include, swea) {
16321
16354
  const includeFlag = include ? ` --include="${include}"` : "";
16322
16355
  const sweaFlag = swea ? " --swea" : "";
16323
16356
  try {
16324
- execSync37(
16357
+ execSync38(
16325
16358
  `jb inspectcode "${slnPath}" -o="${reportPath}"${includeFlag}${sweaFlag} --verbosity=OFF`,
16326
16359
  { stdio: "pipe" }
16327
16360
  );
@@ -16342,7 +16375,7 @@ function runInspectCode(slnPath, include, swea) {
16342
16375
  }
16343
16376
 
16344
16377
  // src/commands/dotnet/runRoslynInspect.ts
16345
- import { execSync as execSync38 } from "child_process";
16378
+ import { execSync as execSync39 } from "child_process";
16346
16379
  import chalk149 from "chalk";
16347
16380
  function resolveMsbuildPath() {
16348
16381
  const { run: run4 } = loadConfig();
@@ -16353,7 +16386,7 @@ function resolveMsbuildPath() {
16353
16386
  function assertMsbuildInstalled() {
16354
16387
  const msbuild = resolveMsbuildPath();
16355
16388
  try {
16356
- execSync38(`"${msbuild}" -version`, { stdio: "pipe" });
16389
+ execSync39(`"${msbuild}" -version`, { stdio: "pipe" });
16357
16390
  } catch {
16358
16391
  console.error(chalk149.red(`msbuild not found at: ${msbuild}`));
16359
16392
  console.error(
@@ -16379,7 +16412,7 @@ function runRoslynInspect(slnPath) {
16379
16412
  const msbuild = resolveMsbuildPath();
16380
16413
  let output;
16381
16414
  try {
16382
- output = execSync38(
16415
+ output = execSync39(
16383
16416
  `"${msbuild}" "${slnPath}" -t:Build -v:minimal -maxcpucount -p:EnforceCodeStyleInBuild=true -p:RunAnalyzersDuringBuild=true 2>&1`,
16384
16417
  { encoding: "utf8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
16385
16418
  );
@@ -17226,7 +17259,7 @@ function acceptanceCriteria(issueKey) {
17226
17259
  }
17227
17260
 
17228
17261
  // src/commands/jira/jiraAuth.ts
17229
- import { execSync as execSync39 } from "child_process";
17262
+ import { execSync as execSync40 } from "child_process";
17230
17263
 
17231
17264
  // src/shared/promptInput.ts
17232
17265
  import Enquirer from "enquirer";
@@ -17261,7 +17294,7 @@ async function jiraAuth() {
17261
17294
  console.error("All fields are required.");
17262
17295
  process.exit(1);
17263
17296
  }
17264
- execSync39(`acli jira auth login --site ${site} --email "${email}" --token`, {
17297
+ execSync40(`acli jira auth login --site ${site} --email "${email}" --token`, {
17265
17298
  encoding: "utf8",
17266
17299
  input: token,
17267
17300
  stdio: ["pipe", "inherit", "inherit"]
@@ -17352,175 +17385,538 @@ function registerRefineLaunch(program2, resumeFlag) {
17352
17385
  }
17353
17386
 
17354
17387
  // src/commands/reviewPrComments.ts
17355
- import { execFileSync as execFileSync6 } from "child_process";
17356
17388
  import { randomUUID as randomUUID4 } from "crypto";
17389
+
17390
+ // src/commands/review/checkoutPr.ts
17391
+ import { execFileSync as execFileSync6 } from "child_process";
17357
17392
  import chalk155 from "chalk";
17358
- async function reviewPrComments(number) {
17359
- if (number) {
17360
- try {
17361
- execFileSync6("gh", ["pr", "checkout", number], { stdio: "inherit" });
17362
- } catch {
17363
- console.error(chalk155.red(`gh pr checkout ${number} failed; aborting.`));
17364
- process.exit(1);
17365
- }
17366
- }
17367
- const claudeSessionId = randomUUID4();
17368
- emitActivity({
17369
- kind: "command",
17370
- name: "review-pr-comments",
17371
- claudeSessionId
17372
- });
17373
- const { done: done2 } = spawnClaude("/review-pr-comments", {
17374
- permissionMode: "acceptEdits",
17375
- sessionId: claudeSessionId
17376
- });
17377
- await done2;
17378
- }
17379
17393
 
17380
- // src/commands/registerLaunch.ts
17381
- var RESUME_SESSION_FLAG = "Resume an interrupted Claude session (used by the sessions daemon on restart)";
17382
- function registerNext(program2) {
17383
- program2.command("next").argument("[id]", "Backlog item ID to run first").description("Alias for backlog next").option("--once", "Exit after the first completed item run").action(
17384
- (id, opts) => next({ allowEdits: true, once: opts.once }, id)
17385
- );
17394
+ // src/commands/sessions/daemon/daemonLog.ts
17395
+ var RING_CAPACITY = 1e3;
17396
+ var ring = [];
17397
+ var sink;
17398
+ function daemonLog(message2) {
17399
+ emit3(`${(/* @__PURE__ */ new Date()).toISOString()} [${process.pid}] ${message2}`);
17386
17400
  }
17387
- function registerDescriptionLaunch(program2, name, slashCommand, description, alias) {
17388
- const command = program2.command(name).argument(
17389
- "[description]",
17390
- `Text to forward to the /${slashCommand} slash command`
17391
- ).description(description).option("--once", "Exit when the initial task completes").option("--resume-session <id>", RESUME_SESSION_FLAG).action(
17392
- (text17, opts) => launchMode(slashCommand, {
17393
- once: opts.once,
17394
- description: text17,
17395
- resumeSessionId: opts.resumeSession
17396
- })
17397
- );
17398
- if (alias) command.alias(alias);
17401
+ function relayDaemonLog(line) {
17402
+ emit3(`[windows] ${line}`);
17399
17403
  }
17400
- function registerReviewPrComments(program2) {
17401
- program2.command("review-pr-comments").argument("[number]", "PR number to check out first").description("Launch Claude in /review-pr-comments mode (single session)").action((number) => reviewPrComments(number));
17404
+ function emit3(line) {
17405
+ console.log(line);
17406
+ ring.push(line);
17407
+ if (ring.length > RING_CAPACITY) ring.shift();
17408
+ sink?.(line);
17402
17409
  }
17403
- function registerLaunch(program2) {
17404
- registerNext(program2);
17405
- registerDescriptionLaunch(
17406
- program2,
17407
- "draft",
17408
- "draft",
17409
- "Launch Claude in /draft mode, chain into next on /next signal",
17410
- "feat"
17411
- );
17412
- registerDescriptionLaunch(
17413
- program2,
17414
- "bug",
17415
- "bug",
17416
- "Launch Claude in /bug mode, chain into next on /next signal"
17417
- );
17418
- registerReviewPrComments(program2);
17419
- registerRefineLaunch(program2, RESUME_SESSION_FLAG);
17410
+ function setDaemonLogSink(next3) {
17411
+ sink = next3;
17420
17412
  }
17421
-
17422
- // src/commands/registerList.ts
17423
- function registerList(program2) {
17424
- program2.command("list").alias("ls").description("Alias for backlog list").option(
17425
- "--status <type>",
17426
- "Filter by status (todo, in-progress, done, wontdo)"
17427
- ).option("-a, --all", "Include done/wontdo items").option("--all-repos", "List items across all repositories").option("-v, --verbose", "Show all item details").option("--dir <path>", "Override directory for backlog file discovery").action((options2) => {
17428
- setBacklogDir(options2.dir);
17429
- return list2(options2);
17430
- });
17413
+ function recentDaemonLogLines() {
17414
+ return [...ring];
17431
17415
  }
17432
17416
 
17433
- // src/commands/mermaid/index.ts
17434
- import { mkdirSync as mkdirSync16, readdirSync as readdirSync9 } from "fs";
17435
- import { resolve as resolve13 } from "path";
17436
- import chalk158 from "chalk";
17437
-
17438
- // src/commands/mermaid/exportFile.ts
17439
- import { readFileSync as readFileSync37, writeFileSync as writeFileSync31 } from "fs";
17440
- import { basename as basename11, extname as extname2, resolve as resolve12 } from "path";
17441
- import chalk157 from "chalk";
17417
+ // src/commands/sessions/daemon/worktree/createWorktree.ts
17418
+ import { existsSync as existsSync43 } from "fs";
17419
+ import { basename as basename12, dirname as dirname23 } from "path";
17442
17420
 
17443
- // src/commands/mermaid/renderBlock.ts
17444
- import chalk156 from "chalk";
17445
- async function renderBlock(krokiUrl, source) {
17446
- const response = await fetch(`${krokiUrl}/mermaid/svg`, {
17447
- method: "POST",
17448
- headers: { "Content-Type": "text/plain" },
17449
- body: source
17450
- });
17451
- if (!response.ok) {
17452
- console.error(
17453
- chalk156.red(
17454
- `Kroki request failed: ${response.status} ${response.statusText}`
17455
- )
17456
- );
17457
- console.error(await response.text());
17458
- process.exit(1);
17421
+ // src/commands/sessions/daemon/worktree/planAllocation.ts
17422
+ import { basename as basename11, join as join46 } from "path";
17423
+ function planAllocation(clone, boundTreeRoots2) {
17424
+ return boundTreeRoots2.has(clone) ? "spill" : "primary";
17425
+ }
17426
+ function nextWorktreePath(clone, base, isTaken) {
17427
+ const name = basename11(clone);
17428
+ for (let n = 2; n < 1e3; n++) {
17429
+ const candidate = join46(base, `${name}-${n}`);
17430
+ if (!isTaken(candidate)) return candidate;
17459
17431
  }
17460
- return await response.text();
17432
+ throw new Error(`no free worktree suffix for ${clone}`);
17461
17433
  }
17462
17434
 
17463
- // src/commands/mermaid/exportFile.ts
17464
- async function exportFile(file, outDir, krokiUrl, onlyIndex) {
17465
- const content = readFileSync37(file, "utf8");
17466
- const blocks = extractMermaidBlocks(content);
17467
- const stem = basename11(file, extname2(file));
17468
- if (onlyIndex !== void 0) {
17469
- if (onlyIndex < 1 || onlyIndex > blocks.length) {
17470
- console.error(
17471
- chalk157.red(
17472
- `${file}: --index ${onlyIndex} out of range (file has ${blocks.length} diagram(s))`
17473
- )
17474
- );
17475
- process.exit(1);
17476
- }
17477
- console.log(
17478
- chalk157.gray(
17479
- `${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
17480
- )
17481
- );
17482
- } else {
17483
- console.log(chalk157.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
17484
- }
17485
- for (const [i, source] of blocks.entries()) {
17486
- const idx = i + 1;
17487
- if (onlyIndex !== void 0 && idx !== onlyIndex) continue;
17488
- const outPath = resolve12(outDir, `${stem}-${idx}.svg`);
17489
- const svg = await renderBlock(krokiUrl, source);
17490
- writeFileSync31(outPath, svg, "utf8");
17491
- console.log(chalk157.green(` \u2192 ${outPath}`));
17492
- }
17435
+ // src/commands/sessions/daemon/worktree/worktreeStartPoint.ts
17436
+ function worktreeStartPoint(clone, trunk) {
17437
+ const branch2 = trunk ? cloneTrunkBranch(clone) : remoteDefaultBranch(clone);
17438
+ const ref = `origin/${branch2}`;
17439
+ if (gitSyncOrNull(clone, ["rev-parse", "--verify", "--quiet", ref]))
17440
+ return { ref, track: trunk };
17441
+ return { ref: "HEAD", track: false };
17493
17442
  }
17494
- function extractMermaidBlocks(markdown) {
17495
- const matches = [...markdown.matchAll(/```mermaid\n([\s\S]*?)\n```/g)];
17496
- return matches.map(([, src]) => src);
17443
+ function cloneTrunkBranch(clone) {
17444
+ return cloneHead(clone) ?? remoteDefaultBranch(clone);
17497
17445
  }
17498
-
17499
- // src/commands/mermaid/index.ts
17500
- async function mermaidExport(file, options2 = {}) {
17501
- const { mermaid } = loadConfig();
17502
- const outDir = resolve13(process.cwd(), options2.out ?? ".");
17503
- mkdirSync16(outDir, { recursive: true });
17504
- if (options2.index !== void 0) {
17505
- if (!Number.isInteger(options2.index) || options2.index < 1) {
17506
- console.error(
17507
- chalk158.red(`--index must be a positive integer (got ${options2.index})`)
17508
- );
17509
- process.exit(1);
17510
- }
17511
- if (!file) {
17512
- console.error(chalk158.red("--index requires a file argument"));
17513
- process.exit(1);
17514
- }
17515
- }
17516
- const files = file ? [file] : readdirSync9(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
17517
- if (files.length === 0) {
17518
- console.log(chalk158.gray("No markdown files found in current directory."));
17519
- return;
17520
- }
17521
- for (const f of files) {
17522
- await exportFile(f, outDir, mermaid.krokiUrl, options2.index);
17523
- }
17446
+ function remoteDefaultBranch(clone) {
17447
+ const head = gitSyncOrNull(clone, [
17448
+ "symbolic-ref",
17449
+ "--short",
17450
+ "refs/remotes/origin/HEAD"
17451
+ ]);
17452
+ if (!head) return cloneHead(clone) ?? "main";
17453
+ const slash = head.indexOf("/");
17454
+ return slash === -1 ? head : head.slice(slash + 1);
17455
+ }
17456
+ function cloneHead(clone) {
17457
+ return gitSyncOrNull(clone, ["symbolic-ref", "--short", "HEAD"]);
17458
+ }
17459
+
17460
+ // src/commands/sessions/daemon/worktree/createWorktree.ts
17461
+ function createWorktree(clone, strategy, boundTreeRoots2) {
17462
+ const base = strategy.root ? expandTilde2(strategy.root) : dirname23(clone);
17463
+ const registered = new Set(listWorktreePaths(clone));
17464
+ const branches = new Set(listLocalBranches(clone));
17465
+ const path71 = nextWorktreePath(
17466
+ clone,
17467
+ base,
17468
+ (candidate) => registered.has(candidate) || existsSync43(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename12(candidate))
17469
+ );
17470
+ const start3 = worktreeStartPoint(clone, strategy.trunk);
17471
+ gitSync(clone, [
17472
+ "worktree",
17473
+ "add",
17474
+ start3.track ? "--track" : "--no-track",
17475
+ "-b",
17476
+ basename12(path71),
17477
+ path71,
17478
+ start3.ref
17479
+ ]);
17480
+ recordWorktree(path71, clone, getCurrentOrigin(clone));
17481
+ daemonLog(
17482
+ start3.track ? `worktree allocated ${path71} (branch ${basename12(path71)} tracking ${start3.ref}) for clone ${clone}` : `worktree allocated ${path71} (branch ${basename12(path71)} off ${start3.ref}, no mainline tracking) for clone ${clone}`
17483
+ );
17484
+ return path71;
17485
+ }
17486
+
17487
+ // src/commands/sessions/daemon/worktree/treeDurability.ts
17488
+ import { existsSync as existsSync44 } from "fs";
17489
+ function treeDurability(state) {
17490
+ if (state.dirty) return { durable: false, reason: "uncommitted changes" };
17491
+ if (state.localOnlyCommits)
17492
+ return { durable: false, reason: "unpushed commits" };
17493
+ return { durable: true };
17494
+ }
17495
+ function* durabilityProbes() {
17496
+ const status3 = yield ["status", "--porcelain"];
17497
+ if (!status3.ok)
17498
+ return { durable: false, reason: `tree state unreadable: ${status3.error}` };
17499
+ const upstream = yield [
17500
+ "rev-parse",
17501
+ "--abbrev-ref",
17502
+ "--symbolic-full-name",
17503
+ "@{upstream}"
17504
+ ];
17505
+ let localOnlyCommits;
17506
+ if (upstream.ok && upstream.out) {
17507
+ const ahead = yield ["rev-list", "--count", "@{upstream}..HEAD"];
17508
+ localOnlyCommits = !ahead.ok || Number(ahead.out) > 0;
17509
+ } else {
17510
+ const remoteBranches = yield ["branch", "-r", "--contains", "HEAD"];
17511
+ localOnlyCommits = !remoteBranches.ok || remoteBranches.out === "";
17512
+ }
17513
+ return treeDurability({ dirty: status3.out !== "", localOnlyCommits });
17514
+ }
17515
+ async function checkDurability(cwd) {
17516
+ if (!existsSync44(cwd)) return { durable: true };
17517
+ const probes = durabilityProbes();
17518
+ let step = probes.next();
17519
+ while (!step.done) step = probes.next(await gitResult(cwd, step.value));
17520
+ return step.value;
17521
+ }
17522
+ function checkDurabilitySync(cwd) {
17523
+ if (!existsSync44(cwd)) return { durable: true };
17524
+ const probes = durabilityProbes();
17525
+ let step = probes.next();
17526
+ while (!step.done) step = probes.next(gitSyncResult(cwd, step.value));
17527
+ return step.value;
17528
+ }
17529
+
17530
+ // src/commands/sessions/daemon/worktree/worktreeConfigFor.ts
17531
+ var DISABLED = {
17532
+ enabled: false,
17533
+ trunk: false,
17534
+ install: true,
17535
+ commitBeforeManualChecks: false,
17536
+ copy: [".env", "settings.local.json", ".claude/settings.local.json"]
17537
+ };
17538
+ function worktreeConfigFor(cwd) {
17539
+ try {
17540
+ return loadConfigFrom(cwd).worktree ?? DISABLED;
17541
+ } catch {
17542
+ return DISABLED;
17543
+ }
17544
+ }
17545
+
17546
+ // src/commands/sessions/daemon/worktree/allocateTree.ts
17547
+ function allocateTree(requestedCwd, boundTreeRoots2, options2 = {}) {
17548
+ if (!requestedCwd)
17549
+ return { cwd: requestedCwd, kind: "primary", created: false };
17550
+ const repoRoot = findRepoRoot(requestedCwd) ?? requestedCwd;
17551
+ const cfg = worktreeConfigFor(repoRoot);
17552
+ if (!cfg.enabled)
17553
+ return { cwd: requestedCwd, kind: "primary", created: false };
17554
+ const clone = mainWorktree(repoRoot) ?? repoRoot;
17555
+ if (planAllocation(clone, boundTreeRoots2) === "primary" && !wouldDisturbWorkInProgress(clone, options2.forCheckout === true))
17556
+ return { cwd: clone, kind: "primary", created: false, clone };
17557
+ const path71 = createWorktree(
17558
+ clone,
17559
+ { root: cfg.root, trunk: cfg.trunk },
17560
+ boundTreeRoots2
17561
+ );
17562
+ return { cwd: path71, kind: "worktree", created: true, clone };
17563
+ }
17564
+ function wouldDisturbWorkInProgress(clone, forCheckout) {
17565
+ if (!forCheckout) return false;
17566
+ const durability = checkDurabilitySync(clone);
17567
+ if (durability.durable) return false;
17568
+ daemonLog(
17569
+ `tree ${clone} not used for a PR checkout: ${durability.reason} \u2014 spilling to a worktree`
17570
+ );
17571
+ return true;
17572
+ }
17573
+
17574
+ // src/commands/sessions/daemon/persistedSessionSchema.ts
17575
+ import { z as z6 } from "zod";
17576
+ var persistedSessionSchema = z6.object({
17577
+ name: z6.string(),
17578
+ title: z6.string().optional(),
17579
+ subtitle: z6.string().optional(),
17580
+ commandType: z6.enum(["claude", "run", "assist"]),
17581
+ harness: z6.enum(["claude", "codex", "pi"]).optional(),
17582
+ status: z6.enum(["running", "waiting", "done", "error", "stopped"]).optional(),
17583
+ cwd: z6.string(),
17584
+ startedAt: z6.number(),
17585
+ runningMs: z6.number().optional(),
17586
+ claudeSessionId: z6.string().optional(),
17587
+ initialPrompt: z6.string().optional(),
17588
+ runName: z6.string().optional(),
17589
+ runArgs: z6.array(z6.string()).optional(),
17590
+ assistArgs: z6.array(z6.string()).optional(),
17591
+ activity: activitySchema.optional(),
17592
+ starred: z6.boolean().optional(),
17593
+ undurable: z6.object({ reason: z6.string(), removesTree: z6.boolean().optional() }).optional()
17594
+ });
17595
+
17596
+ // src/commands/sessions/daemon/toPersistedSession.ts
17597
+ function toPersistedSession(session) {
17598
+ return {
17599
+ name: session.name,
17600
+ title: session.title,
17601
+ subtitle: session.subtitle,
17602
+ commandType: session.commandType,
17603
+ harness: session.harness,
17604
+ status: session.status,
17605
+ cwd: session.cwd ?? process.cwd(),
17606
+ startedAt: session.startedAt,
17607
+ runningMs: accumulatedRunningMs(session),
17608
+ claudeSessionId: session.claudeSessionId,
17609
+ initialPrompt: session.initialPrompt,
17610
+ runName: session.runName,
17611
+ runArgs: session.runArgs,
17612
+ assistArgs: session.assistArgs,
17613
+ activity: session.activity,
17614
+ starred: session.starred,
17615
+ undurable: session.undurable
17616
+ };
17617
+ }
17618
+ function accumulatedRunningMs(session) {
17619
+ return session.runningSince != null ? session.runningMs + Date.now() - session.runningSince : session.runningMs;
17620
+ }
17621
+
17622
+ // src/commands/sessions/daemon/loadPersistedSessions.ts
17623
+ var SESSIONS_FILE = "sessions.json";
17624
+ function loadPersistedSessions() {
17625
+ const data = loadJson(SESSIONS_FILE);
17626
+ if (!Array.isArray(data)) return [];
17627
+ return data.flatMap((entry) => {
17628
+ const parsed = persistedSessionSchema.safeParse(entry);
17629
+ return parsed.success ? [parsed.data] : [];
17630
+ });
17631
+ }
17632
+ function savePersistedSessions(sessions) {
17633
+ saveJson(SESSIONS_FILE, sessions);
17634
+ }
17635
+ function persistLiveSessions(sessions) {
17636
+ const live = [...sessions.values()].filter(
17637
+ (s) => (s.pty || s.status === "stopped") && s.status !== "done"
17638
+ );
17639
+ savePersistedSessions(live.map(toPersistedSession));
17640
+ logPersist(live);
17641
+ }
17642
+ var lastPersistSignature = "";
17643
+ function logPersist(live) {
17644
+ const signature = live.map((s) => `${s.id}:${s.status}`).join(",");
17645
+ if (signature === lastPersistSignature) return;
17646
+ lastPersistSignature = signature;
17647
+ daemonLog(
17648
+ live.length > 0 ? `persisted ${live.length} session(s): ${live.map((s) => s.name).join(", ")}` : "persisted 0 sessions (sessions.json cleared)"
17649
+ );
17650
+ }
17651
+
17652
+ // src/commands/sessions/daemon/worktree/persistedTreeRoots.ts
17653
+ function persistedTreeRoots() {
17654
+ const roots = /* @__PURE__ */ new Set();
17655
+ for (const { cwd } of loadPersistedSessions()) {
17656
+ if (cwd) roots.add(findRepoRoot(cwd) ?? cwd);
17657
+ }
17658
+ return roots;
17659
+ }
17660
+
17661
+ // src/commands/sessions/daemon/worktree/seedWorktree.ts
17662
+ import { execFile as execFile8 } from "child_process";
17663
+ import { copyFileSync, existsSync as existsSync46, mkdirSync as mkdirSync16 } from "fs";
17664
+ import { dirname as dirname24, join as join48 } from "path";
17665
+
17666
+ // src/commands/sessions/daemon/worktree/resolveInstallCommand.ts
17667
+ import { existsSync as existsSync45 } from "fs";
17668
+ import { join as join47 } from "path";
17669
+ function detectInstallCommand(repoRoot) {
17670
+ if (!existsSync45(join47(repoRoot, "package.json"))) return null;
17671
+ if (existsSync45(join47(repoRoot, "pnpm-lock.yaml"))) return "pnpm install";
17672
+ if (existsSync45(join47(repoRoot, "yarn.lock"))) return "yarn install";
17673
+ if (existsSync45(join47(repoRoot, "bun.lockb"))) return "bun install";
17674
+ return "npm install";
17675
+ }
17676
+ function resolveInstallCommand(repoRoot, install) {
17677
+ if (install === false) return null;
17678
+ if (typeof install === "string") return install;
17679
+ return detectInstallCommand(repoRoot);
17680
+ }
17681
+
17682
+ // src/commands/sessions/daemon/worktree/seedWorktree.ts
17683
+ function seedWorktree(worktreePath, clone, onSeeded = () => {
17684
+ }) {
17685
+ const cfg = worktreeConfigFor(clone);
17686
+ copyConfigFiles(worktreePath, clone, cfg.copy);
17687
+ runInstall(worktreePath, clone, cfg.install, onSeeded);
17688
+ }
17689
+ function copyConfigFiles(worktreePath, clone, copy) {
17690
+ for (const rel of copy) {
17691
+ const src = join48(clone, rel);
17692
+ if (!existsSync46(src)) continue;
17693
+ const dest = join48(worktreePath, rel);
17694
+ try {
17695
+ mkdirSync16(dirname24(dest), { recursive: true });
17696
+ copyFileSync(src, dest);
17697
+ daemonLog(`worktree ${worktreePath} seeded ${rel}`);
17698
+ } catch (error) {
17699
+ daemonLog(
17700
+ `worktree ${worktreePath} failed to seed ${rel}: ${message(error)}`
17701
+ );
17702
+ }
17703
+ }
17704
+ }
17705
+ function runInstall(worktreePath, clone, install, onSeeded) {
17706
+ const command = resolveInstallCommand(clone, install);
17707
+ if (!command) {
17708
+ onSeeded();
17709
+ return;
17710
+ }
17711
+ const windows = /^[A-Za-z]:[\\/]/.test(worktreePath);
17712
+ const shell = windows ? "cmd.exe" : process.env.SHELL ?? "bash";
17713
+ const shellArgs = windows ? ["/c", command] : ["-l", "-c", command];
17714
+ daemonLog(`worktree ${worktreePath} installing deps: ${command}`);
17715
+ execFile8(shell, shellArgs, { cwd: worktreePath }, (error) => {
17716
+ daemonLog(
17717
+ error ? `worktree ${worktreePath} install failed: ${error.message}` : `worktree ${worktreePath} install complete`
17718
+ );
17719
+ onSeeded();
17720
+ });
17721
+ }
17722
+ function message(error) {
17723
+ return error instanceof Error ? error.message : String(error);
17724
+ }
17725
+
17726
+ // src/commands/review/moveToPrCheckoutTree.ts
17727
+ function placedByDaemon() {
17728
+ return process.env.ASSIST_SESSION === "1";
17729
+ }
17730
+ function seed(worktreePath, clone) {
17731
+ console.log(`Preparing ${worktreePath}\u2026`);
17732
+ return new Promise(
17733
+ (resolve20) => seedWorktree(worktreePath, clone, resolve20)
17734
+ );
17735
+ }
17736
+ async function moveToPrCheckoutTree() {
17737
+ if (placedByDaemon()) return;
17738
+ const from = process.cwd();
17739
+ const alloc = allocateTree(from, persistedTreeRoots(), {
17740
+ forCheckout: true
17741
+ });
17742
+ if (!alloc.cwd || alloc.cwd === from) return;
17743
+ process.chdir(alloc.cwd);
17744
+ console.log(`Checking the PR out in ${alloc.cwd}`);
17745
+ appendDaemonLog(`pr checkout placed in ${alloc.cwd} (invoked from ${from})`);
17746
+ if (alloc.created && alloc.clone) await seed(alloc.cwd, alloc.clone);
17747
+ }
17748
+
17749
+ // src/commands/review/checkoutPr.ts
17750
+ async function checkoutPr(number) {
17751
+ await moveToPrCheckoutTree();
17752
+ try {
17753
+ execFileSync6("gh", ["pr", "checkout", number], { stdio: "inherit" });
17754
+ } catch {
17755
+ console.error(chalk155.red(`gh pr checkout ${number} failed; aborting.`));
17756
+ process.exit(1);
17757
+ }
17758
+ }
17759
+
17760
+ // src/commands/reviewPrComments.ts
17761
+ async function reviewPrComments(number) {
17762
+ if (number) await checkoutPr(number);
17763
+ const claudeSessionId = randomUUID4();
17764
+ emitActivity({
17765
+ kind: "command",
17766
+ name: "review-pr-comments",
17767
+ claudeSessionId
17768
+ });
17769
+ const { done: done2 } = spawnClaude("/review-pr-comments", {
17770
+ permissionMode: "acceptEdits",
17771
+ sessionId: claudeSessionId
17772
+ });
17773
+ await done2;
17774
+ }
17775
+
17776
+ // src/commands/registerLaunch.ts
17777
+ var RESUME_SESSION_FLAG = "Resume an interrupted Claude session (used by the sessions daemon on restart)";
17778
+ function registerNext(program2) {
17779
+ program2.command("next").argument("[id]", "Backlog item ID to run first").description("Alias for backlog next").option("--once", "Exit after the first completed item run").action(
17780
+ (id, opts) => next({ allowEdits: true, once: opts.once }, id)
17781
+ );
17782
+ }
17783
+ function registerDescriptionLaunch(program2, name, slashCommand, description, alias) {
17784
+ const command = program2.command(name).argument(
17785
+ "[description]",
17786
+ `Text to forward to the /${slashCommand} slash command`
17787
+ ).description(description).option("--once", "Exit when the initial task completes").option("--resume-session <id>", RESUME_SESSION_FLAG).action(
17788
+ (text17, opts) => launchMode(slashCommand, {
17789
+ once: opts.once,
17790
+ description: text17,
17791
+ resumeSessionId: opts.resumeSession
17792
+ })
17793
+ );
17794
+ if (alias) command.alias(alias);
17795
+ }
17796
+ function registerReviewPrComments(program2) {
17797
+ program2.command("review-pr-comments").argument("[number]", "PR number to check out first").description("Launch Claude in /review-pr-comments mode (single session)").action((number) => reviewPrComments(number));
17798
+ }
17799
+ function registerLaunch(program2) {
17800
+ registerNext(program2);
17801
+ registerDescriptionLaunch(
17802
+ program2,
17803
+ "draft",
17804
+ "draft",
17805
+ "Launch Claude in /draft mode, chain into next on /next signal",
17806
+ "feat"
17807
+ );
17808
+ registerDescriptionLaunch(
17809
+ program2,
17810
+ "bug",
17811
+ "bug",
17812
+ "Launch Claude in /bug mode, chain into next on /next signal"
17813
+ );
17814
+ registerReviewPrComments(program2);
17815
+ registerRefineLaunch(program2, RESUME_SESSION_FLAG);
17816
+ }
17817
+
17818
+ // src/commands/registerList.ts
17819
+ function registerList(program2) {
17820
+ program2.command("list").alias("ls").description("Alias for backlog list").option(
17821
+ "--status <type>",
17822
+ "Filter by status (todo, in-progress, done, wontdo)"
17823
+ ).option("-a, --all", "Include done/wontdo items").option("--all-repos", "List items across all repositories").option("-v, --verbose", "Show all item details").option("--dir <path>", "Override directory for backlog file discovery").action((options2) => {
17824
+ setBacklogDir(options2.dir);
17825
+ return list2(options2);
17826
+ });
17827
+ }
17828
+
17829
+ // src/commands/mermaid/index.ts
17830
+ import { mkdirSync as mkdirSync17, readdirSync as readdirSync9 } from "fs";
17831
+ import { resolve as resolve13 } from "path";
17832
+ import chalk158 from "chalk";
17833
+
17834
+ // src/commands/mermaid/exportFile.ts
17835
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync31 } from "fs";
17836
+ import { basename as basename13, extname as extname2, resolve as resolve12 } from "path";
17837
+ import chalk157 from "chalk";
17838
+
17839
+ // src/commands/mermaid/renderBlock.ts
17840
+ import chalk156 from "chalk";
17841
+ async function renderBlock(krokiUrl, source) {
17842
+ const response = await fetch(`${krokiUrl}/mermaid/svg`, {
17843
+ method: "POST",
17844
+ headers: { "Content-Type": "text/plain" },
17845
+ body: source
17846
+ });
17847
+ if (!response.ok) {
17848
+ console.error(
17849
+ chalk156.red(
17850
+ `Kroki request failed: ${response.status} ${response.statusText}`
17851
+ )
17852
+ );
17853
+ console.error(await response.text());
17854
+ process.exit(1);
17855
+ }
17856
+ return await response.text();
17857
+ }
17858
+
17859
+ // src/commands/mermaid/exportFile.ts
17860
+ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
17861
+ const content = readFileSync37(file, "utf8");
17862
+ const blocks = extractMermaidBlocks(content);
17863
+ const stem = basename13(file, extname2(file));
17864
+ if (onlyIndex !== void 0) {
17865
+ if (onlyIndex < 1 || onlyIndex > blocks.length) {
17866
+ console.error(
17867
+ chalk157.red(
17868
+ `${file}: --index ${onlyIndex} out of range (file has ${blocks.length} diagram(s))`
17869
+ )
17870
+ );
17871
+ process.exit(1);
17872
+ }
17873
+ console.log(
17874
+ chalk157.gray(
17875
+ `${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
17876
+ )
17877
+ );
17878
+ } else {
17879
+ console.log(chalk157.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
17880
+ }
17881
+ for (const [i, source] of blocks.entries()) {
17882
+ const idx = i + 1;
17883
+ if (onlyIndex !== void 0 && idx !== onlyIndex) continue;
17884
+ const outPath = resolve12(outDir, `${stem}-${idx}.svg`);
17885
+ const svg = await renderBlock(krokiUrl, source);
17886
+ writeFileSync31(outPath, svg, "utf8");
17887
+ console.log(chalk157.green(` \u2192 ${outPath}`));
17888
+ }
17889
+ }
17890
+ function extractMermaidBlocks(markdown) {
17891
+ const matches = [...markdown.matchAll(/```mermaid\n([\s\S]*?)\n```/g)];
17892
+ return matches.map(([, src]) => src);
17893
+ }
17894
+
17895
+ // src/commands/mermaid/index.ts
17896
+ async function mermaidExport(file, options2 = {}) {
17897
+ const { mermaid } = loadConfig();
17898
+ const outDir = resolve13(process.cwd(), options2.out ?? ".");
17899
+ mkdirSync17(outDir, { recursive: true });
17900
+ if (options2.index !== void 0) {
17901
+ if (!Number.isInteger(options2.index) || options2.index < 1) {
17902
+ console.error(
17903
+ chalk158.red(`--index must be a positive integer (got ${options2.index})`)
17904
+ );
17905
+ process.exit(1);
17906
+ }
17907
+ if (!file) {
17908
+ console.error(chalk158.red("--index requires a file argument"));
17909
+ process.exit(1);
17910
+ }
17911
+ }
17912
+ const files = file ? [file] : readdirSync9(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
17913
+ if (files.length === 0) {
17914
+ console.log(chalk158.gray("No markdown files found in current directory."));
17915
+ return;
17916
+ }
17917
+ for (const f of files) {
17918
+ await exportFile(f, outDir, mermaid.krokiUrl, options2.index);
17919
+ }
17524
17920
  }
17525
17921
 
17526
17922
  // src/commands/registerMermaid.ts
@@ -17547,7 +17943,7 @@ function registerMermaid(program2) {
17547
17943
  // src/commands/netcap/netcap.ts
17548
17944
  import { mkdir as mkdir4 } from "fs/promises";
17549
17945
  import { createServer as createServer2 } from "http";
17550
- import { dirname as dirname24 } from "path";
17946
+ import { dirname as dirname26 } from "path";
17551
17947
  import chalk160 from "chalk";
17552
17948
 
17553
17949
  // src/commands/netcap/corsHeaders.ts
@@ -17626,15 +18022,15 @@ function createNetcapHandler(options2) {
17626
18022
  // src/commands/netcap/prepareExtensionForLoad.ts
17627
18023
  import { cp, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
17628
18024
  import { networkInterfaces } from "os";
17629
- import { join as join47 } from "path";
18025
+ import { join as join50 } from "path";
17630
18026
  import chalk159 from "chalk";
17631
18027
 
17632
18028
  // src/commands/netcap/netcapExtensionDir.ts
17633
- import { dirname as dirname23, join as join46 } from "path";
18029
+ import { dirname as dirname25, join as join49 } from "path";
17634
18030
  import { fileURLToPath as fileURLToPath6 } from "url";
17635
- var moduleDir = dirname23(fileURLToPath6(import.meta.url));
18031
+ var moduleDir = dirname25(fileURLToPath6(import.meta.url));
17636
18032
  function netcapExtensionDir() {
17637
- return join46(moduleDir, "commands", "netcap", "netcap-extension");
18033
+ return join49(moduleDir, "commands", "netcap", "netcap-extension");
17638
18034
  }
17639
18035
 
17640
18036
  // src/commands/netcap/prepareExtensionForLoad.ts
@@ -17649,7 +18045,7 @@ function lanIPv4() {
17649
18045
  return void 0;
17650
18046
  }
17651
18047
  async function configureBackground(dir, host, port, filter) {
17652
- const file = join47(dir, "background.js");
18048
+ const file = join50(dir, "background.js");
17653
18049
  const source = await readFile3(file, "utf8");
17654
18050
  await writeFile3(
17655
18051
  file,
@@ -17689,20 +18085,20 @@ async function prepareExtensionForLoad(port, filter = "") {
17689
18085
  }
17690
18086
 
17691
18087
  // src/commands/netcap/resolveNetcapOutPath.ts
17692
- import { isAbsolute as isAbsolute2, join as join49, resolve as resolve14 } from "path";
18088
+ import { isAbsolute as isAbsolute2, join as join52, resolve as resolve14 } from "path";
17693
18089
 
17694
18090
  // src/commands/netcap/defaultCapturePath.ts
17695
18091
  import { homedir as homedir19 } from "os";
17696
- import { join as join48 } from "path";
18092
+ import { join as join51 } from "path";
17697
18093
  function defaultCapturePath() {
17698
- return join48(homedir19(), ".assist", "netcap", "capture.jsonl");
18094
+ return join51(homedir19(), ".assist", "netcap", "capture.jsonl");
17699
18095
  }
17700
18096
 
17701
18097
  // src/commands/netcap/resolveNetcapOutPath.ts
17702
18098
  function resolveNetcapOutPath(out) {
17703
18099
  if (!out) return defaultCapturePath();
17704
18100
  const dir = isAbsolute2(out) ? out : resolve14(process.cwd(), out);
17705
- return join49(dir, "capture.jsonl");
18101
+ return join52(dir, "capture.jsonl");
17706
18102
  }
17707
18103
 
17708
18104
  // src/commands/netcap/netcap.ts
@@ -17710,7 +18106,7 @@ async function netcap(options2) {
17710
18106
  const port = Number(options2.port);
17711
18107
  const outPath = resolveNetcapOutPath(options2.out);
17712
18108
  const filter = options2.filter ?? "";
17713
- await mkdir4(dirname24(outPath), { recursive: true });
18109
+ await mkdir4(dirname26(outPath), { recursive: true });
17714
18110
  const extensionPath = await prepareExtensionForLoad(port, filter);
17715
18111
  let count7 = 0;
17716
18112
  const handler = createNetcapHandler({
@@ -17749,7 +18145,7 @@ netcap stopped \u2014 captured ${count7} ${count7 === 1 ? "entry" : "entries"} t
17749
18145
 
17750
18146
  // src/commands/netcap/netcapExtract.ts
17751
18147
  import { writeFileSync as writeFileSync32 } from "fs";
17752
- import { join as join50 } from "path";
18148
+ import { join as join53 } from "path";
17753
18149
  import chalk161 from "chalk";
17754
18150
 
17755
18151
  // src/commands/netcap/extractPostsFromCapture.ts
@@ -18194,7 +18590,7 @@ function extractPostsFromCapture(captureFile) {
18194
18590
  function netcapExtract(file) {
18195
18591
  const captureFile = file ?? defaultCapturePath();
18196
18592
  const posts = extractPostsFromCapture(captureFile);
18197
- const outFile = join50(captureFile, "..", "posts.json");
18593
+ const outFile = join53(captureFile, "..", "posts.json");
18198
18594
  writeFileSync32(outFile, `${JSON.stringify(posts, null, 2)}
18199
18595
  `);
18200
18596
  console.log(
@@ -18346,7 +18742,7 @@ function registerPrompts(program2) {
18346
18742
  }
18347
18743
 
18348
18744
  // src/commands/prs/shared.ts
18349
- import { execSync as execSync40 } from "child_process";
18745
+ import { execSync as execSync41 } from "child_process";
18350
18746
  function isGhNotInstalled(error) {
18351
18747
  if (error instanceof Error) {
18352
18748
  const msg = error.message.toLowerCase();
@@ -18364,12 +18760,12 @@ function getRepoInfo() {
18364
18760
  const preferred = getPreferredRemoteRepo();
18365
18761
  if (preferred) return preferred;
18366
18762
  const repoInfo = JSON.parse(
18367
- execSync40("gh repo view --json owner,name", { encoding: "utf8" })
18763
+ execSync41("gh repo view --json owner,name", { encoding: "utf8" })
18368
18764
  );
18369
18765
  return { org: repoInfo.owner.login, repo: repoInfo.name };
18370
18766
  }
18371
18767
  function getCurrentBranch2() {
18372
- return execSync40("git rev-parse --abbrev-ref HEAD", {
18768
+ return execSync41("git rev-parse --abbrev-ref HEAD", {
18373
18769
  encoding: "utf8"
18374
18770
  }).trim();
18375
18771
  }
@@ -18377,7 +18773,7 @@ function viewCurrentPr(fields) {
18377
18773
  const { org, repo } = getRepoInfo();
18378
18774
  const branch2 = getCurrentBranch2();
18379
18775
  return JSON.parse(
18380
- execSync40(`gh pr view ${branch2} --json ${fields} -R ${org}/${repo}`, {
18776
+ execSync41(`gh pr view ${branch2} --json ${fields} -R ${org}/${repo}`, {
18381
18777
  encoding: "utf8"
18382
18778
  })
18383
18779
  );
@@ -18679,24 +19075,24 @@ function edit(options2) {
18679
19075
  }
18680
19076
 
18681
19077
  // src/commands/prs/fixed.ts
18682
- import { execSync as execSync43 } from "child_process";
19078
+ import { execSync as execSync44 } from "child_process";
18683
19079
 
18684
19080
  // src/commands/prs/resolveCommentWithReply.ts
18685
- import { execSync as execSync42 } from "child_process";
19081
+ import { execSync as execSync43 } from "child_process";
18686
19082
  import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync33 } from "fs";
18687
19083
  import { tmpdir as tmpdir6 } from "os";
18688
- import { join as join52 } from "path";
19084
+ import { join as join55 } from "path";
18689
19085
 
18690
19086
  // src/commands/prs/loadCommentsCache.ts
18691
- import { existsSync as existsSync43, readFileSync as readFileSync39, unlinkSync as unlinkSync13 } from "fs";
18692
- import { join as join51 } from "path";
19087
+ import { existsSync as existsSync47, readFileSync as readFileSync39, unlinkSync as unlinkSync13 } from "fs";
19088
+ import { join as join54 } from "path";
18693
19089
  import { parse as parse2 } from "yaml";
18694
19090
  function getCachePath(prNumber) {
18695
- return join51(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
19091
+ return join54(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
18696
19092
  }
18697
19093
  function loadCommentsCache(prNumber) {
18698
19094
  const cachePath = getCachePath(prNumber);
18699
- if (!existsSync43(cachePath)) {
19095
+ if (!existsSync47(cachePath)) {
18700
19096
  return null;
18701
19097
  }
18702
19098
  const content = readFileSync39(cachePath, "utf8");
@@ -18704,16 +19100,16 @@ function loadCommentsCache(prNumber) {
18704
19100
  }
18705
19101
  function deleteCommentsCache(prNumber) {
18706
19102
  const cachePath = getCachePath(prNumber);
18707
- if (existsSync43(cachePath)) {
19103
+ if (existsSync47(cachePath)) {
18708
19104
  unlinkSync13(cachePath);
18709
19105
  console.log("No more unresolved line comments. Cache dropped.");
18710
19106
  }
18711
19107
  }
18712
19108
 
18713
19109
  // src/commands/prs/replyToComment.ts
18714
- import { execSync as execSync41 } from "child_process";
19110
+ import { execSync as execSync42 } from "child_process";
18715
19111
  function replyToComment(org, repo, prNumber, commentId, message2) {
18716
- execSync41(
19112
+ execSync42(
18717
19113
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message2.replace(/"/g, String.raw`\"`)}" -F in_reply_to=${commentId}`,
18718
19114
  { stdio: ["inherit", "pipe", "inherit"] }
18719
19115
  );
@@ -18722,10 +19118,10 @@ function replyToComment(org, repo, prNumber, commentId, message2) {
18722
19118
  // src/commands/prs/resolveCommentWithReply.ts
18723
19119
  function resolveThread(threadId) {
18724
19120
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
18725
- const queryFile = join52(tmpdir6(), `gh-mutation-${Date.now()}.graphql`);
19121
+ const queryFile = join55(tmpdir6(), `gh-mutation-${Date.now()}.graphql`);
18726
19122
  writeFileSync33(queryFile, mutation);
18727
19123
  try {
18728
- execSync42(
19124
+ execSync43(
18729
19125
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
18730
19126
  { stdio: ["inherit", "pipe", "inherit"] }
18731
19127
  );
@@ -18777,7 +19173,7 @@ function resolveCommentWithReply(commentId, message2) {
18777
19173
  // src/commands/prs/fixed.ts
18778
19174
  function verifySha(sha) {
18779
19175
  try {
18780
- return execSync43(`git rev-parse --verify ${sha}`, {
19176
+ return execSync44(`git rev-parse --verify ${sha}`, {
18781
19177
  encoding: "utf8"
18782
19178
  }).trim();
18783
19179
  } catch {
@@ -18791,7 +19187,7 @@ function fixed(commentId, sha) {
18791
19187
  const { org, repo } = getRepoInfo();
18792
19188
  const repoUrl = `https://github.com/${org}/${repo}`;
18793
19189
  const message2 = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
18794
- execSync43("git push", { stdio: "inherit" });
19190
+ pushCommit();
18795
19191
  resolveCommentWithReply(commentId, message2);
18796
19192
  } catch (error) {
18797
19193
  if (isGhNotInstalled(error)) {
@@ -18804,21 +19200,21 @@ function fixed(commentId, sha) {
18804
19200
  }
18805
19201
 
18806
19202
  // src/commands/prs/listComments/index.ts
18807
- import { existsSync as existsSync44, mkdirSync as mkdirSync17, writeFileSync as writeFileSync35 } from "fs";
18808
- import { join as join54 } from "path";
19203
+ import { existsSync as existsSync48, mkdirSync as mkdirSync18, writeFileSync as writeFileSync35 } from "fs";
19204
+ import { join as join57 } from "path";
18809
19205
  import { stringify } from "yaml";
18810
19206
 
18811
19207
  // src/commands/prs/fetchThreadIds.ts
18812
- import { execSync as execSync44 } from "child_process";
19208
+ import { execSync as execSync45 } from "child_process";
18813
19209
  import { unlinkSync as unlinkSync15, writeFileSync as writeFileSync34 } from "fs";
18814
19210
  import { tmpdir as tmpdir7 } from "os";
18815
- import { join as join53 } from "path";
19211
+ import { join as join56 } from "path";
18816
19212
  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 } } } } } } }`;
18817
19213
  function fetchThreadIds(org, repo, prNumber) {
18818
- const queryFile = join53(tmpdir7(), `gh-query-${Date.now()}.graphql`);
19214
+ const queryFile = join56(tmpdir7(), `gh-query-${Date.now()}.graphql`);
18819
19215
  writeFileSync34(queryFile, THREAD_QUERY);
18820
19216
  try {
18821
- const result = execSync44(
19217
+ const result = execSync45(
18822
19218
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
18823
19219
  { encoding: "utf8" }
18824
19220
  );
@@ -18840,9 +19236,9 @@ function fetchThreadIds(org, repo, prNumber) {
18840
19236
  }
18841
19237
 
18842
19238
  // src/commands/prs/listComments/fetchReviewComments.ts
18843
- import { execSync as execSync45 } from "child_process";
19239
+ import { execSync as execSync46 } from "child_process";
18844
19240
  function fetchJson(endpoint) {
18845
- const result = execSync45(`gh api --paginate ${endpoint}`, {
19241
+ const result = execSync46(`gh api --paginate ${endpoint}`, {
18846
19242
  encoding: "utf8"
18847
19243
  });
18848
19244
  if (!result.trim()) return [];
@@ -18929,16 +19325,16 @@ function printComments2(result) {
18929
19325
 
18930
19326
  // src/commands/prs/listComments/index.ts
18931
19327
  function writeCommentsCache(prNumber, comments3) {
18932
- const assistDir = join54(process.cwd(), ".assist");
18933
- if (!existsSync44(assistDir)) {
18934
- mkdirSync17(assistDir, { recursive: true });
19328
+ const assistDir = join57(process.cwd(), ".assist");
19329
+ if (!existsSync48(assistDir)) {
19330
+ mkdirSync18(assistDir, { recursive: true });
18935
19331
  }
18936
19332
  const cacheData = {
18937
19333
  prNumber,
18938
19334
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
18939
19335
  comments: comments3
18940
19336
  };
18941
- const cachePath = join54(assistDir, `pr-${prNumber}-comments.yaml`);
19337
+ const cachePath = join57(assistDir, `pr-${prNumber}-comments.yaml`);
18942
19338
  writeFileSync35(cachePath, stringify(cacheData));
18943
19339
  }
18944
19340
  function handleKnownErrors(error) {
@@ -18971,7 +19367,7 @@ async function listComments() {
18971
19367
  ];
18972
19368
  updateCache(prNumber, allComments);
18973
19369
  const hasLineComments = allComments.some((c) => c.type === "line");
18974
- const cachePath = hasLineComments ? join54(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
19370
+ const cachePath = hasLineComments ? join57(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
18975
19371
  return { comments: allComments, cachePath };
18976
19372
  } catch (error) {
18977
19373
  const handled = handleKnownErrors(error);
@@ -18981,7 +19377,7 @@ async function listComments() {
18981
19377
  }
18982
19378
 
18983
19379
  // src/commands/prs/prs/index.ts
18984
- import { execSync as execSync46 } from "child_process";
19380
+ import { execSync as execSync47 } from "child_process";
18985
19381
 
18986
19382
  // src/commands/prs/prs/displayPaginated/index.ts
18987
19383
  import enquirer9 from "enquirer";
@@ -19088,7 +19484,7 @@ async function prs(options2) {
19088
19484
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
19089
19485
  try {
19090
19486
  const { org, repo } = getRepoInfo();
19091
- const result = execSync46(
19487
+ const result = execSync47(
19092
19488
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100 -R ${org}/${repo}`,
19093
19489
  { encoding: "utf8" }
19094
19490
  );
@@ -19159,16 +19555,16 @@ function buildCreateArgs(title, body, options2) {
19159
19555
  }
19160
19556
 
19161
19557
  // src/commands/prs/readSessionPrRef.ts
19162
- import { execSync as execSync47 } from "child_process";
19558
+ import { execSync as execSync48 } from "child_process";
19163
19559
  function readSessionPrRef() {
19164
19560
  try {
19165
- const branch2 = execSync47("git rev-parse --abbrev-ref HEAD", {
19561
+ const branch2 = execSync48("git rev-parse --abbrev-ref HEAD", {
19166
19562
  encoding: "utf8",
19167
19563
  stdio: ["pipe", "pipe", "pipe"]
19168
19564
  }).trim();
19169
19565
  if (!branch2 || branch2 === "HEAD") return null;
19170
19566
  const pr = JSON.parse(
19171
- execSync47(`gh pr view ${branch2} --json number,title,url,state`, {
19567
+ execSync48(`gh pr view ${branch2} --json number,title,url,state`, {
19172
19568
  encoding: "utf8",
19173
19569
  stdio: ["pipe", "pipe", "pipe"]
19174
19570
  })
@@ -19296,7 +19692,7 @@ function reply(commentId, body) {
19296
19692
  }
19297
19693
 
19298
19694
  // src/commands/prs/wontfix.ts
19299
- import { execSync as execSync48 } from "child_process";
19695
+ import { execSync as execSync49 } from "child_process";
19300
19696
  function validateReason(reason2) {
19301
19697
  const lowerReason = reason2.toLowerCase();
19302
19698
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -19313,7 +19709,7 @@ function validateShaReferences(reason2) {
19313
19709
  const invalidShas = [];
19314
19710
  for (const sha of shas) {
19315
19711
  try {
19316
- execSync48(`git cat-file -t ${sha}`, { stdio: "pipe" });
19712
+ execSync49(`git cat-file -t ${sha}`, { stdio: "pipe" });
19317
19713
  } catch {
19318
19714
  invalidShas.push(sha);
19319
19715
  }
@@ -19590,10 +19986,10 @@ import chalk168 from "chalk";
19590
19986
  import Enquirer2 from "enquirer";
19591
19987
 
19592
19988
  // src/commands/ravendb/searchItems.ts
19593
- import { execSync as execSync49 } from "child_process";
19989
+ import { execSync as execSync50 } from "child_process";
19594
19990
  import chalk167 from "chalk";
19595
19991
  function opExec(args) {
19596
- return execSync49(`op ${args}`, {
19992
+ return execSync50(`op ${args}`, {
19597
19993
  encoding: "utf8",
19598
19994
  stdio: ["pipe", "pipe", "pipe"]
19599
19995
  }).trim();
@@ -19745,7 +20141,7 @@ ${errorText}`
19745
20141
  }
19746
20142
 
19747
20143
  // src/commands/ravendb/resolveOpSecret.ts
19748
- import { execSync as execSync50 } from "child_process";
20144
+ import { execSync as execSync51 } from "child_process";
19749
20145
  import chalk172 from "chalk";
19750
20146
  function resolveOpSecret(reference) {
19751
20147
  if (!reference.startsWith("op://")) {
@@ -19753,7 +20149,7 @@ function resolveOpSecret(reference) {
19753
20149
  process.exit(1);
19754
20150
  }
19755
20151
  try {
19756
- return execSync50(`op read "${reference}"`, {
20152
+ return execSync51(`op read "${reference}"`, {
19757
20153
  encoding: "utf8",
19758
20154
  stdio: ["pipe", "pipe", "pipe"]
19759
20155
  }).trim();
@@ -20017,7 +20413,7 @@ Refactor check failed:
20017
20413
  }
20018
20414
 
20019
20415
  // src/commands/refactor/check/getViolations/index.ts
20020
- import { execSync as execSync51 } from "child_process";
20416
+ import { execSync as execSync52 } from "child_process";
20021
20417
  import fs25 from "fs";
20022
20418
  import { minimatch as minimatch6 } from "minimatch";
20023
20419
 
@@ -20067,7 +20463,7 @@ function getGitFiles(options2) {
20067
20463
  }
20068
20464
  const files = /* @__PURE__ */ new Set();
20069
20465
  if (options2.staged || options2.modified) {
20070
- const staged = execSync51("git diff --cached --name-only", {
20466
+ const staged = execSync52("git diff --cached --name-only", {
20071
20467
  encoding: "utf8"
20072
20468
  });
20073
20469
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -20075,7 +20471,7 @@ function getGitFiles(options2) {
20075
20471
  }
20076
20472
  }
20077
20473
  if (options2.unstaged || options2.modified) {
20078
- const unstaged = execSync51("git diff --name-only", { encoding: "utf8" });
20474
+ const unstaged = execSync52("git diff --name-only", { encoding: "utf8" });
20079
20475
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
20080
20476
  files.add(file);
20081
20477
  }
@@ -21342,8 +21738,8 @@ function findRootParent(file, importedBy, visited) {
21342
21738
  function clusterFiles(graph) {
21343
21739
  const clusters = /* @__PURE__ */ new Map();
21344
21740
  for (const file of graph.files) {
21345
- const basename18 = path52.basename(file, path52.extname(file));
21346
- if (basename18 === "index") continue;
21741
+ const basename19 = path52.basename(file, path52.extname(file));
21742
+ if (basename19 === "index") continue;
21347
21743
  const importers = graph.importedBy.get(file);
21348
21744
  if (!importers || importers.size !== 1) continue;
21349
21745
  const parent = [...importers][0];
@@ -21649,9 +22045,6 @@ function registerRefactor(program2) {
21649
22045
  registerRestructure(refactorCommand);
21650
22046
  }
21651
22047
 
21652
- // src/commands/review/review.ts
21653
- import { execFileSync as execFileSync9 } from "child_process";
21654
-
21655
22048
  // src/commands/review/annotateDiffWithLineNumbers.ts
21656
22049
  var FILE_HEADER2 = /^\+\+\+ (?:b\/)?(.+)$/;
21657
22050
  var HUNK_HEADER2 = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
@@ -21766,28 +22159,28 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
21766
22159
 
21767
22160
  // src/commands/review/buildReviewPaths.ts
21768
22161
  import { homedir as homedir20 } from "os";
21769
- import { basename as basename12, join as join55 } from "path";
22162
+ import { basename as basename14, join as join58 } from "path";
21770
22163
  function buildReviewPaths(repoRoot, key) {
21771
- const reviewDir = join55(
22164
+ const reviewDir = join58(
21772
22165
  homedir20(),
21773
22166
  ".assist",
21774
22167
  "reviews",
21775
- basename12(repoRoot),
22168
+ basename14(repoRoot),
21776
22169
  key
21777
22170
  );
21778
22171
  return {
21779
22172
  reviewDir,
21780
- requestPath: join55(reviewDir, "request.md"),
21781
- claudePath: join55(reviewDir, "claude.md"),
21782
- codexPath: join55(reviewDir, "codex.md"),
21783
- synthesisPath: join55(reviewDir, "synthesis.md")
22173
+ requestPath: join58(reviewDir, "request.md"),
22174
+ claudePath: join58(reviewDir, "claude.md"),
22175
+ codexPath: join58(reviewDir, "codex.md"),
22176
+ synthesisPath: join58(reviewDir, "synthesis.md")
21784
22177
  };
21785
22178
  }
21786
22179
 
21787
22180
  // src/commands/review/fetchExistingComments.ts
21788
- import { execSync as execSync52 } from "child_process";
22181
+ import { execSync as execSync53 } from "child_process";
21789
22182
  function fetchRawComments(org, repo, prNumber) {
21790
- const out = execSync52(
22183
+ const out = execSync53(
21791
22184
  `gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
21792
22185
  { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }
21793
22186
  );
@@ -21818,14 +22211,14 @@ function fetchExistingComments() {
21818
22211
  }
21819
22212
 
21820
22213
  // src/commands/review/gatherContext.ts
21821
- import { execSync as execSync55 } from "child_process";
22214
+ import { execSync as execSync56 } from "child_process";
21822
22215
 
21823
22216
  // src/commands/review/fetchPrDiff.ts
21824
- import { execSync as execSync53 } from "child_process";
22217
+ import { execSync as execSync54 } from "child_process";
21825
22218
  function fetchPrDiff(prNumber, baseSha, headSha) {
21826
22219
  const { org, repo } = getRepoInfo();
21827
22220
  try {
21828
- return execSync53(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
22221
+ return execSync54(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
21829
22222
  encoding: "utf8",
21830
22223
  maxBuffer: 256 * 1024 * 1024,
21831
22224
  stdio: ["ignore", "pipe", "pipe"]
@@ -21840,19 +22233,19 @@ function isDiffTooLarge(error) {
21840
22233
  }
21841
22234
  function fetchDiffViaGit(baseSha, headSha) {
21842
22235
  try {
21843
- execSync53(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
22236
+ execSync54(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
21844
22237
  } catch {
21845
22238
  }
21846
- return execSync53(`git diff ${baseSha}...${headSha}`, {
22239
+ return execSync54(`git diff ${baseSha}...${headSha}`, {
21847
22240
  encoding: "utf8",
21848
22241
  maxBuffer: 256 * 1024 * 1024
21849
22242
  });
21850
22243
  }
21851
22244
 
21852
22245
  // src/commands/review/fetchPrDiffInfo.ts
21853
- import { execSync as execSync54 } from "child_process";
22246
+ import { execSync as execSync55 } from "child_process";
21854
22247
  function getCurrentBranch3() {
21855
- return execSync54("git rev-parse --abbrev-ref HEAD", {
22248
+ return execSync55("git rev-parse --abbrev-ref HEAD", {
21856
22249
  encoding: "utf8"
21857
22250
  }).trim();
21858
22251
  }
@@ -21860,7 +22253,7 @@ function fetchPrDiffInfo() {
21860
22253
  const { org, repo } = getRepoInfo();
21861
22254
  const branch2 = getCurrentBranch3();
21862
22255
  const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
21863
- const raw = execSync54(
22256
+ const raw = execSync55(
21864
22257
  `gh pr list --state open --head ${branch2} --json ${fields} -R ${org}/${repo}`,
21865
22258
  {
21866
22259
  encoding: "utf8",
@@ -21885,7 +22278,7 @@ function fetchPrDiffInfo() {
21885
22278
  }
21886
22279
  function fetchPrChangedFiles(prNumber) {
21887
22280
  const { org, repo } = getRepoInfo();
21888
- const out = execSync54(
22281
+ const out = execSync55(
21889
22282
  `gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
21890
22283
  {
21891
22284
  encoding: "utf8",
@@ -21897,11 +22290,11 @@ function fetchPrChangedFiles(prNumber) {
21897
22290
 
21898
22291
  // src/commands/review/gatherContext.ts
21899
22292
  function gatherContext() {
21900
- const branch2 = execSync55("git rev-parse --abbrev-ref HEAD", {
22293
+ const branch2 = execSync56("git rev-parse --abbrev-ref HEAD", {
21901
22294
  encoding: "utf8"
21902
22295
  }).trim();
21903
- const sha = execSync55("git rev-parse HEAD", { encoding: "utf8" }).trim();
21904
- const shortSha = execSync55("git rev-parse --short=7 HEAD", {
22296
+ const sha = execSync56("git rev-parse HEAD", { encoding: "utf8" }).trim();
22297
+ const shortSha = execSync56("git rev-parse --short=7 HEAD", {
21905
22298
  encoding: "utf8"
21906
22299
  }).trim();
21907
22300
  const prInfo = fetchPrDiffInfo();
@@ -22319,14 +22712,14 @@ async function handlePostSynthesis(synthesisPath, options2) {
22319
22712
  }
22320
22713
 
22321
22714
  // src/commands/review/prepareReviewDir.ts
22322
- import { existsSync as existsSync45, mkdirSync as mkdirSync18, unlinkSync as unlinkSync16, writeFileSync as writeFileSync36 } from "fs";
22715
+ import { existsSync as existsSync49, mkdirSync as mkdirSync19, unlinkSync as unlinkSync16, writeFileSync as writeFileSync36 } from "fs";
22323
22716
  function clearReviewFiles(paths) {
22324
22717
  for (const path71 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
22325
- if (existsSync45(path71)) unlinkSync16(path71);
22718
+ if (existsSync49(path71)) unlinkSync16(path71);
22326
22719
  }
22327
22720
  }
22328
22721
  function prepareReviewDir(paths, requestBody, force) {
22329
- mkdirSync18(paths.reviewDir, { recursive: true });
22722
+ mkdirSync19(paths.reviewDir, { recursive: true });
22330
22723
  if (force) clearReviewFiles(paths);
22331
22724
  writeFileSync36(paths.requestPath, requestBody);
22332
22725
  }
@@ -22607,7 +23000,7 @@ function printReviewerFailures(results) {
22607
23000
  }
22608
23001
 
22609
23002
  // src/commands/review/runAndSynthesise.ts
22610
- import { existsSync as existsSync47, unlinkSync as unlinkSync18 } from "fs";
23003
+ import { existsSync as existsSync51, unlinkSync as unlinkSync18 } from "fs";
22611
23004
 
22612
23005
  // src/commands/review/buildReviewerStdin.ts
22613
23006
  var REVIEW_PROMPT = `You are acting as a reviewer for a proposed code change made by another engineer. The full review request \u2014 branch, base, changed files, and unified diff \u2014 is in the request file whose absolute path is given below.
@@ -23027,7 +23420,7 @@ function resolveClaude(args) {
23027
23420
  }
23028
23421
 
23029
23422
  // src/commands/review/runCodexReviewer.ts
23030
- import { existsSync as existsSync46, unlinkSync as unlinkSync17 } from "fs";
23423
+ import { existsSync as existsSync50, unlinkSync as unlinkSync17 } from "fs";
23031
23424
 
23032
23425
  // src/commands/review/parseCodexEvent.ts
23033
23426
  function isItemStarted(value) {
@@ -23079,7 +23472,7 @@ async function runCodexReviewer(spec) {
23079
23472
  reportReviewerToolUse(spec.name, event, spinner);
23080
23473
  }
23081
23474
  });
23082
- if (result.exitCode !== 0 && existsSync46(spec.outputPath)) {
23475
+ if (result.exitCode !== 0 && existsSync50(spec.outputPath)) {
23083
23476
  unlinkSync17(spec.outputPath);
23084
23477
  }
23085
23478
  return finaliseReviewerRun({ ...spec, command }, spinner, result);
@@ -23225,7 +23618,7 @@ async function runAndSynthesise(args) {
23225
23618
  console.error("Both reviewers failed; skipping synthesis.");
23226
23619
  return { ok: false, failures };
23227
23620
  }
23228
- if (anyFresh && existsSync47(paths.synthesisPath)) {
23621
+ if (anyFresh && existsSync51(paths.synthesisPath)) {
23229
23622
  unlinkSync18(paths.synthesisPath);
23230
23623
  }
23231
23624
  const synthesisResult = await synthesise(paths, { multi });
@@ -23346,20 +23739,13 @@ function validateOptions(options2) {
23346
23739
  process.exit(1);
23347
23740
  }
23348
23741
  }
23349
- function checkoutPr(number) {
23350
- try {
23351
- execFileSync9("gh", ["pr", "checkout", number], { stdio: "inherit" });
23352
- } catch {
23353
- console.error(`gh pr checkout ${number} failed; aborting.`);
23354
- process.exit(1);
23355
- }
23356
- }
23357
23742
  async function review(options2 = {}) {
23358
23743
  validateOptions(options2);
23359
- const repoRoot = resolveRepoRoot();
23744
+ const invokedIn = resolveRepoRoot();
23360
23745
  emitActivity({ kind: "command", name: "review" });
23361
- if (options2.number) checkoutPr(options2.number);
23362
- await reviewPr(repoRoot, options2);
23746
+ if (!options2.number) return reviewPr(invokedIn, options2);
23747
+ await checkoutPr(options2.number);
23748
+ return reviewPr(resolveRepoRoot(), options2);
23363
23749
  }
23364
23750
 
23365
23751
  // src/commands/registerReview.ts
@@ -24105,27 +24491,27 @@ async function configure() {
24105
24491
  }
24106
24492
 
24107
24493
  // src/commands/transcript/list.ts
24108
- import { existsSync as existsSync48, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
24109
- import { join as join56 } from "path";
24494
+ import { existsSync as existsSync52, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
24495
+ import { join as join59 } from "path";
24110
24496
  function list4() {
24111
24497
  const { vttDir } = getTranscriptConfig();
24112
- if (!existsSync48(vttDir)) return;
24498
+ if (!existsSync52(vttDir)) return;
24113
24499
  for (const entry of readdirSync10(vttDir)) {
24114
24500
  if (!entry.endsWith(".vtt")) continue;
24115
- if (statSync8(join56(vttDir, entry)).isDirectory()) continue;
24501
+ if (statSync8(join59(vttDir, entry)).isDirectory()) continue;
24116
24502
  console.log(entry);
24117
24503
  }
24118
24504
  }
24119
24505
 
24120
24506
  // src/commands/transcript/move.ts
24121
24507
  import {
24122
- existsSync as existsSync49,
24123
- mkdirSync as mkdirSync19,
24508
+ existsSync as existsSync53,
24509
+ mkdirSync as mkdirSync20,
24124
24510
  readFileSync as readFileSync42,
24125
24511
  renameSync as renameSync2,
24126
24512
  writeFileSync as writeFileSync38
24127
24513
  } from "fs";
24128
- import { basename as basename13, join as join57 } from "path";
24514
+ import { basename as basename15, join as join60 } from "path";
24129
24515
 
24130
24516
  // src/commands/transcript/cleanText.ts
24131
24517
  function cleanText(text17) {
@@ -24338,9 +24724,9 @@ function convertVttToMarkdown(inputPath) {
24338
24724
  return formatChatLog(messages);
24339
24725
  }
24340
24726
  function archiveRawVtt(vttDir, sourcePath, filename) {
24341
- const processedDir = join57(vttDir, "processed");
24342
- mkdirSync19(processedDir, { recursive: true });
24343
- renameSync2(sourcePath, join57(processedDir, filename));
24727
+ const processedDir = join60(vttDir, "processed");
24728
+ mkdirSync20(processedDir, { recursive: true });
24729
+ renameSync2(sourcePath, join60(processedDir, filename));
24344
24730
  }
24345
24731
  function move(file, options2) {
24346
24732
  const { date, client } = options2;
@@ -24349,20 +24735,20 @@ function move(file, options2) {
24349
24735
  process.exit(1);
24350
24736
  }
24351
24737
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
24352
- const filename = basename13(file);
24353
- const sourcePath = join57(vttDir, filename);
24354
- if (!existsSync49(sourcePath)) {
24738
+ const filename = basename15(file);
24739
+ const sourcePath = join60(vttDir, filename);
24740
+ if (!existsSync53(sourcePath)) {
24355
24741
  console.error(`Error: VTT file not found: ${sourcePath}`);
24356
24742
  process.exit(1);
24357
24743
  }
24358
- const base = basename13(filename, ".vtt").replace(/ Transcription$/, "");
24744
+ const base = basename15(filename, ".vtt").replace(/ Transcription$/, "");
24359
24745
  const outputName = `${date} ${base}.md`;
24360
- const formattedDir = join57(transcriptsDir, client);
24361
- mkdirSync19(formattedDir, { recursive: true });
24362
- const formattedPath = join57(formattedDir, outputName);
24746
+ const formattedDir = join60(transcriptsDir, client);
24747
+ mkdirSync20(formattedDir, { recursive: true });
24748
+ const formattedPath = join60(formattedDir, outputName);
24363
24749
  writeFileSync38(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
24364
24750
  archiveRawVtt(vttDir, sourcePath, filename);
24365
- const summaryPath = join57(summaryDir, client, outputName);
24751
+ const summaryPath = join60(summaryDir, client, outputName);
24366
24752
  console.log(`Formatted transcript: ${formattedPath}`);
24367
24753
  console.log(`Summary target: ${summaryPath}`);
24368
24754
  }
@@ -24482,45 +24868,45 @@ function registerVerify(program2) {
24482
24868
 
24483
24869
  // src/commands/voice/devices.ts
24484
24870
  import { spawnSync as spawnSync6 } from "child_process";
24485
- import { join as join59 } from "path";
24871
+ import { join as join62 } from "path";
24486
24872
 
24487
24873
  // src/commands/voice/shared.ts
24488
24874
  import { homedir as homedir21 } from "os";
24489
- import { dirname as dirname26, join as join58 } from "path";
24875
+ import { dirname as dirname28, join as join61 } from "path";
24490
24876
  import { fileURLToPath as fileURLToPath7 } from "url";
24491
- var __dirname5 = dirname26(fileURLToPath7(import.meta.url));
24492
- var VOICE_DIR = join58(homedir21(), ".assist", "voice");
24877
+ var __dirname5 = dirname28(fileURLToPath7(import.meta.url));
24878
+ var VOICE_DIR = join61(homedir21(), ".assist", "voice");
24493
24879
  var voicePaths = {
24494
24880
  dir: VOICE_DIR,
24495
- pid: join58(VOICE_DIR, "voice.pid"),
24496
- log: join58(VOICE_DIR, "voice.log"),
24497
- venv: join58(VOICE_DIR, ".venv"),
24498
- lock: join58(VOICE_DIR, "voice.lock")
24881
+ pid: join61(VOICE_DIR, "voice.pid"),
24882
+ log: join61(VOICE_DIR, "voice.log"),
24883
+ venv: join61(VOICE_DIR, ".venv"),
24884
+ lock: join61(VOICE_DIR, "voice.lock")
24499
24885
  };
24500
24886
  function getPythonDir() {
24501
- return join58(__dirname5, "commands", "voice", "python");
24887
+ return join61(__dirname5, "commands", "voice", "python");
24502
24888
  }
24503
24889
  function getVenvPython() {
24504
- return process.platform === "win32" ? join58(voicePaths.venv, "Scripts", "python.exe") : join58(voicePaths.venv, "bin", "python");
24890
+ return process.platform === "win32" ? join61(voicePaths.venv, "Scripts", "python.exe") : join61(voicePaths.venv, "bin", "python");
24505
24891
  }
24506
24892
  function getLockDir() {
24507
24893
  const config = loadConfig();
24508
24894
  return config.voice?.lockDir ?? VOICE_DIR;
24509
24895
  }
24510
24896
  function getLockFile() {
24511
- return join58(getLockDir(), "voice.lock");
24897
+ return join61(getLockDir(), "voice.lock");
24512
24898
  }
24513
24899
 
24514
24900
  // src/commands/voice/devices.ts
24515
24901
  function devices() {
24516
- const script = join59(getPythonDir(), "list_devices.py");
24902
+ const script = join62(getPythonDir(), "list_devices.py");
24517
24903
  spawnSync6(getVenvPython(), [script], { stdio: "inherit" });
24518
24904
  }
24519
24905
 
24520
24906
  // src/commands/voice/logs.ts
24521
- import { existsSync as existsSync50, readFileSync as readFileSync43 } from "fs";
24907
+ import { existsSync as existsSync54, readFileSync as readFileSync43 } from "fs";
24522
24908
  function logs(options2) {
24523
- if (!existsSync50(voicePaths.log)) {
24909
+ if (!existsSync54(voicePaths.log)) {
24524
24910
  console.log("No voice log file found");
24525
24911
  return;
24526
24912
  }
@@ -24547,13 +24933,13 @@ function logs(options2) {
24547
24933
 
24548
24934
  // src/commands/voice/setup.ts
24549
24935
  import { spawnSync as spawnSync7 } from "child_process";
24550
- import { mkdirSync as mkdirSync21 } from "fs";
24551
- import { join as join61 } from "path";
24936
+ import { mkdirSync as mkdirSync22 } from "fs";
24937
+ import { join as join64 } from "path";
24552
24938
 
24553
24939
  // src/commands/voice/checkLockFile.ts
24554
- import { execSync as execSync56 } from "child_process";
24555
- import { existsSync as existsSync51, mkdirSync as mkdirSync20, readFileSync as readFileSync44, writeFileSync as writeFileSync39 } from "fs";
24556
- import { join as join60 } from "path";
24940
+ import { execSync as execSync57 } from "child_process";
24941
+ import { existsSync as existsSync55, mkdirSync as mkdirSync21, readFileSync as readFileSync44, writeFileSync as writeFileSync39 } from "fs";
24942
+ import { join as join63 } from "path";
24557
24943
  function isProcessAlive2(pid) {
24558
24944
  try {
24559
24945
  process.kill(pid, 0);
@@ -24564,7 +24950,7 @@ function isProcessAlive2(pid) {
24564
24950
  }
24565
24951
  function checkLockFile() {
24566
24952
  const lockFile = getLockFile();
24567
- if (!existsSync51(lockFile)) return;
24953
+ if (!existsSync55(lockFile)) return;
24568
24954
  try {
24569
24955
  const lock2 = JSON.parse(readFileSync44(lockFile, "utf8"));
24570
24956
  if (lock2.pid && isProcessAlive2(lock2.pid)) {
@@ -24577,10 +24963,10 @@ function checkLockFile() {
24577
24963
  }
24578
24964
  }
24579
24965
  function bootstrapVenv() {
24580
- if (existsSync51(getVenvPython())) return;
24966
+ if (existsSync55(getVenvPython())) return;
24581
24967
  console.log("Setting up Python environment...");
24582
24968
  const pythonDir = getPythonDir();
24583
- execSync56(
24969
+ execSync57(
24584
24970
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
24585
24971
  {
24586
24972
  stdio: "inherit",
@@ -24590,7 +24976,7 @@ function bootstrapVenv() {
24590
24976
  }
24591
24977
  function writeLockFile(pid) {
24592
24978
  const lockFile = getLockFile();
24593
- mkdirSync20(join60(lockFile, ".."), { recursive: true });
24979
+ mkdirSync21(join63(lockFile, ".."), { recursive: true });
24594
24980
  writeFileSync39(
24595
24981
  lockFile,
24596
24982
  JSON.stringify({
@@ -24603,10 +24989,10 @@ function writeLockFile(pid) {
24603
24989
 
24604
24990
  // src/commands/voice/setup.ts
24605
24991
  function setup() {
24606
- mkdirSync21(voicePaths.dir, { recursive: true });
24992
+ mkdirSync22(voicePaths.dir, { recursive: true });
24607
24993
  bootstrapVenv();
24608
24994
  console.log("\nDownloading models...\n");
24609
- const script = join61(getPythonDir(), "setup_models.py");
24995
+ const script = join64(getPythonDir(), "setup_models.py");
24610
24996
  const result = spawnSync7(getVenvPython(), [script], {
24611
24997
  stdio: "inherit",
24612
24998
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -24619,8 +25005,8 @@ function setup() {
24619
25005
 
24620
25006
  // src/commands/voice/start.ts
24621
25007
  import { spawn as spawn7 } from "child_process";
24622
- import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync40 } from "fs";
24623
- import { join as join62 } from "path";
25008
+ import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync40 } from "fs";
25009
+ import { join as join65 } from "path";
24624
25010
 
24625
25011
  // src/commands/voice/buildDaemonEnv.ts
24626
25012
  function buildDaemonEnv(options2) {
@@ -24653,12 +25039,12 @@ function spawnBackground(python, script, env) {
24653
25039
  console.log(`Voice daemon started (PID ${pid})`);
24654
25040
  }
24655
25041
  function start2(options2) {
24656
- mkdirSync22(voicePaths.dir, { recursive: true });
25042
+ mkdirSync23(voicePaths.dir, { recursive: true });
24657
25043
  checkLockFile();
24658
25044
  bootstrapVenv();
24659
25045
  const debug = options2.debug || options2.foreground || process.platform === "win32";
24660
25046
  const env = buildDaemonEnv({ debug });
24661
- const script = join62(getPythonDir(), "voice_daemon.py");
25047
+ const script = join65(getPythonDir(), "voice_daemon.py");
24662
25048
  const python = getVenvPython();
24663
25049
  if (options2.foreground) {
24664
25050
  spawnForeground(python, script, env);
@@ -24668,7 +25054,7 @@ function start2(options2) {
24668
25054
  }
24669
25055
 
24670
25056
  // src/commands/voice/status.ts
24671
- import { existsSync as existsSync52, readFileSync as readFileSync45 } from "fs";
25057
+ import { existsSync as existsSync56, readFileSync as readFileSync45 } from "fs";
24672
25058
  function isProcessAlive3(pid) {
24673
25059
  try {
24674
25060
  process.kill(pid, 0);
@@ -24678,12 +25064,12 @@ function isProcessAlive3(pid) {
24678
25064
  }
24679
25065
  }
24680
25066
  function readRecentLogs(count7) {
24681
- if (!existsSync52(voicePaths.log)) return [];
25067
+ if (!existsSync56(voicePaths.log)) return [];
24682
25068
  const lines = readFileSync45(voicePaths.log, "utf8").trim().split("\n");
24683
25069
  return lines.slice(-count7);
24684
25070
  }
24685
25071
  function status2() {
24686
- if (!existsSync52(voicePaths.pid)) {
25072
+ if (!existsSync56(voicePaths.pid)) {
24687
25073
  console.log("Voice daemon: not running (no PID file)");
24688
25074
  return;
24689
25075
  }
@@ -24706,9 +25092,9 @@ function status2() {
24706
25092
  }
24707
25093
 
24708
25094
  // src/commands/voice/stop.ts
24709
- import { existsSync as existsSync53, readFileSync as readFileSync46, unlinkSync as unlinkSync19 } from "fs";
25095
+ import { existsSync as existsSync57, readFileSync as readFileSync46, unlinkSync as unlinkSync19 } from "fs";
24710
25096
  function stop2() {
24711
- if (!existsSync53(voicePaths.pid)) {
25097
+ if (!existsSync57(voicePaths.pid)) {
24712
25098
  console.log("Voice daemon is not running (no PID file)");
24713
25099
  return;
24714
25100
  }
@@ -24725,7 +25111,7 @@ function stop2() {
24725
25111
  }
24726
25112
  try {
24727
25113
  const lockFile = getLockFile();
24728
- if (existsSync53(lockFile)) unlinkSync19(lockFile);
25114
+ if (existsSync57(lockFile)) unlinkSync19(lockFile);
24729
25115
  } catch {
24730
25116
  }
24731
25117
  console.log("Voice daemon stopped");
@@ -24947,9 +25333,9 @@ async function auth() {
24947
25333
  }
24948
25334
 
24949
25335
  // src/commands/roam/postRoamActivity.ts
24950
- import { execFileSync as execFileSync10 } from "child_process";
25336
+ import { execFileSync as execFileSync9 } from "child_process";
24951
25337
  import { readdirSync as readdirSync11, readFileSync as readFileSync47, statSync as statSync9 } from "fs";
24952
- import { join as join63 } from "path";
25338
+ import { join as join66 } from "path";
24953
25339
  function findPortFile(roamDir) {
24954
25340
  let entries;
24955
25341
  try {
@@ -24958,7 +25344,7 @@ function findPortFile(roamDir) {
24958
25344
  return void 0;
24959
25345
  }
24960
25346
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
24961
- const path71 = join63(roamDir, name);
25347
+ const path71 = join66(roamDir, name);
24962
25348
  try {
24963
25349
  return { path: path71, mtimeMs: statSync9(path71).mtimeMs };
24964
25350
  } catch {
@@ -24970,7 +25356,7 @@ function findPortFile(roamDir) {
24970
25356
  function postRoamActivity(app, event) {
24971
25357
  const appData = process.env.APPDATA;
24972
25358
  if (!appData) return;
24973
- const portFile = findPortFile(join63(appData, "Roam"));
25359
+ const portFile = findPortFile(join66(appData, "Roam"));
24974
25360
  if (!portFile) return;
24975
25361
  let port;
24976
25362
  try {
@@ -24980,7 +25366,7 @@ function postRoamActivity(app, event) {
24980
25366
  }
24981
25367
  const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${app === "codex" ? 99998 : 99999}`;
24982
25368
  try {
24983
- execFileSync10("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
25369
+ execFileSync9("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
24984
25370
  stdio: "ignore"
24985
25371
  });
24986
25372
  } catch {
@@ -25188,11 +25574,11 @@ function resolveParams(params, cliArgs) {
25188
25574
  }
25189
25575
 
25190
25576
  // src/commands/run/runPreCommands.ts
25191
- import { execSync as execSync57 } from "child_process";
25577
+ import { execSync as execSync58 } from "child_process";
25192
25578
  function runPreCommands(pre, cwd) {
25193
25579
  for (const cmd of pre) {
25194
25580
  try {
25195
- execSync57(cmd, { stdio: "inherit", cwd });
25581
+ execSync58(cmd, { stdio: "inherit", cwd });
25196
25582
  } catch (error) {
25197
25583
  const code = error && typeof error === "object" && "status" in error ? error.status : 1;
25198
25584
  process.exit(code);
@@ -25201,16 +25587,16 @@ function runPreCommands(pre, cwd) {
25201
25587
  }
25202
25588
 
25203
25589
  // src/commands/run/spawnRunCommand.ts
25204
- import { execFileSync as execFileSync11, spawn as spawn8 } from "child_process";
25205
- import { existsSync as existsSync54 } from "fs";
25206
- import { dirname as dirname27, join as join64, resolve as resolve15 } from "path";
25590
+ import { execFileSync as execFileSync10, spawn as spawn8 } from "child_process";
25591
+ import { existsSync as existsSync58 } from "fs";
25592
+ import { dirname as dirname29, join as join67, resolve as resolve15 } from "path";
25207
25593
  function resolveCommand2(command) {
25208
25594
  if (process.platform !== "win32" || command !== "bash") return command;
25209
25595
  try {
25210
- const gitPath = execFileSync11("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
25211
- const gitRoot = resolve15(dirname27(gitPath), "..");
25212
- const gitBash = join64(gitRoot, "bin", "bash.exe");
25213
- if (existsSync54(gitBash)) return gitBash;
25596
+ const gitPath = execFileSync10("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
25597
+ const gitRoot = resolve15(dirname29(gitPath), "..");
25598
+ const gitBash = join67(gitRoot, "bin", "bash.exe");
25599
+ if (existsSync58(gitBash)) return gitBash;
25214
25600
  } catch {
25215
25601
  }
25216
25602
  return command;
@@ -25297,8 +25683,8 @@ async function run3(name, args) {
25297
25683
  }
25298
25684
 
25299
25685
  // src/commands/run/add.ts
25300
- import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync41 } from "fs";
25301
- import { join as join65 } from "path";
25686
+ import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync41 } from "fs";
25687
+ import { join as join68 } from "path";
25302
25688
 
25303
25689
  // src/commands/run/extractOption.ts
25304
25690
  function extractOption(args, flag) {
@@ -25359,15 +25745,15 @@ function saveNewRunConfig(name, command, args, cwd) {
25359
25745
  saveConfig(config);
25360
25746
  }
25361
25747
  function createCommandFile(name) {
25362
- const dir = join65(".claude", "commands");
25363
- mkdirSync23(dir, { recursive: true });
25748
+ const dir = join68(".claude", "commands");
25749
+ mkdirSync24(dir, { recursive: true });
25364
25750
  const content = `---
25365
25751
  description: Run ${name}
25366
25752
  ---
25367
25753
 
25368
25754
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
25369
25755
  `;
25370
- const filePath = join65(dir, `${name}.md`);
25756
+ const filePath = join68(dir, `${name}.md`);
25371
25757
  writeFileSync41(filePath, content);
25372
25758
  console.log(`Created command file: ${filePath}`);
25373
25759
  }
@@ -25423,8 +25809,8 @@ function link2() {
25423
25809
  }
25424
25810
 
25425
25811
  // src/commands/run/remove.ts
25426
- import { existsSync as existsSync55, unlinkSync as unlinkSync20 } from "fs";
25427
- import { join as join66 } from "path";
25812
+ import { existsSync as existsSync59, unlinkSync as unlinkSync20 } from "fs";
25813
+ import { join as join69 } from "path";
25428
25814
  function findRemoveIndex() {
25429
25815
  const idx = process.argv.indexOf("remove");
25430
25816
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -25439,8 +25825,8 @@ function parseRemoveName() {
25439
25825
  return process.argv[idx + 1];
25440
25826
  }
25441
25827
  function deleteCommandFile(name) {
25442
- const filePath = join66(".claude", "commands", `${name}.md`);
25443
- if (existsSync55(filePath)) {
25828
+ const filePath = join69(".claude", "commands", `${name}.md`);
25829
+ if (existsSync59(filePath)) {
25444
25830
  unlinkSync20(filePath);
25445
25831
  console.log(`Deleted command file: ${filePath}`);
25446
25832
  }
@@ -25493,10 +25879,10 @@ function registerRun(program2) {
25493
25879
  }
25494
25880
 
25495
25881
  // src/commands/screenshot/index.ts
25496
- import { execSync as execSync58 } from "child_process";
25497
- import { existsSync as existsSync56, mkdirSync as mkdirSync24, unlinkSync as unlinkSync21, writeFileSync as writeFileSync42 } from "fs";
25882
+ import { execSync as execSync59 } from "child_process";
25883
+ import { existsSync as existsSync60, mkdirSync as mkdirSync25, unlinkSync as unlinkSync21, writeFileSync as writeFileSync42 } from "fs";
25498
25884
  import { tmpdir as tmpdir8 } from "os";
25499
- import { join as join67, resolve as resolve17 } from "path";
25885
+ import { join as join70, resolve as resolve17 } from "path";
25500
25886
  import chalk206 from "chalk";
25501
25887
 
25502
25888
  // src/commands/screenshot/captureWindowPs1.ts
@@ -25626,17 +26012,17 @@ Write-Output $OutputPath
25626
26012
 
25627
26013
  // src/commands/screenshot/index.ts
25628
26014
  function buildOutputPath(outputDir, processName) {
25629
- if (!existsSync56(outputDir)) {
25630
- mkdirSync24(outputDir, { recursive: true });
26015
+ if (!existsSync60(outputDir)) {
26016
+ mkdirSync25(outputDir, { recursive: true });
25631
26017
  }
25632
26018
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
25633
26019
  return resolve17(outputDir, `${processName}-${timestamp6}.png`);
25634
26020
  }
25635
26021
  function runPowerShellScript(processName, outputPath) {
25636
- const scriptPath = join67(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
26022
+ const scriptPath = join70(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
25637
26023
  writeFileSync42(scriptPath, captureWindowPs1, "utf8");
25638
26024
  try {
25639
- execSync58(
26025
+ execSync59(
25640
26026
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
25641
26027
  { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }
25642
26028
  );
@@ -25660,11 +26046,11 @@ function screenshot(processName) {
25660
26046
  }
25661
26047
 
25662
26048
  // src/commands/sessions/daemon/listDaemonPids.ts
25663
- import { execFileSync as execFileSync12 } from "child_process";
26049
+ import { execFileSync as execFileSync11 } from "child_process";
25664
26050
  function listDaemonPids() {
25665
26051
  if (process.platform === "win32") return [];
25666
26052
  try {
25667
- const out = execFileSync12("ps", ["-eo", "pid=,args="], {
26053
+ const out = execFileSync11("ps", ["-eo", "pid=,args="], {
25668
26054
  encoding: "utf8"
25669
26055
  });
25670
26056
  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));
@@ -25705,167 +26091,66 @@ function applyLine(result, pending, line) {
25705
26091
  result.pid = data.pid;
25706
26092
  pending.delete("pong");
25707
26093
  }
25708
- } catch {
25709
- }
25710
- }
25711
-
25712
- // src/commands/sessions/daemon/reportStolenSocket.ts
25713
- import { readFileSync as readFileSync48 } from "fs";
25714
- function reportStolenSocket(socketPid) {
25715
- if (!socketPid) return;
25716
- const filePid = readPidFile();
25717
- if (filePid === void 0 || filePid === socketPid) return;
25718
- console.error(
25719
- `Warning: daemon.pid records PID ${filePid} but the socket is owned by PID ${socketPid} (stolen socket)`
25720
- );
25721
- }
25722
- function readPidFile() {
25723
- try {
25724
- const pid = Number.parseInt(
25725
- readFileSync48(daemonPaths.pid, "utf8").trim(),
25726
- 10
25727
- );
25728
- return Number.isInteger(pid) ? pid : void 0;
25729
- } catch {
25730
- return void 0;
25731
- }
25732
- }
25733
-
25734
- // src/commands/sessions/daemon/daemonStatus.ts
25735
- async function daemonStatus() {
25736
- let socket;
25737
- try {
25738
- socket = await connectToDaemon();
25739
- } catch {
25740
- console.log("Sessions daemon is not running");
25741
- reportStrays(listDaemonPids());
25742
- return;
25743
- }
25744
- const { pid, sessions } = await queryDaemon(socket);
25745
- socket.destroy();
25746
- console.log(`Sessions daemon is running${pid ? ` (PID ${pid})` : ""}`);
25747
- reportStolenSocket(pid);
25748
- reportStrays(listDaemonPids().filter((p) => p !== pid));
25749
- if (sessions.length === 0) {
25750
- console.log("No sessions");
25751
- return;
25752
- }
25753
- for (const session of sessions) {
25754
- const restored = session.restored === false ? " (not restored)" : "";
25755
- console.log(` [${session.status}] ${session.name}${restored}`);
25756
- }
25757
- }
25758
- function reportStrays(pids) {
25759
- if (pids.length === 0) return;
25760
- console.error(
25761
- `Warning: stray daemon process(es) detected: ${pids.join(", ")}`
25762
- );
25763
- }
25764
-
25765
- // src/commands/sessions/daemon/drainDaemon.ts
25766
- import { createInterface as createInterface6 } from "readline";
25767
-
25768
- // src/commands/sessions/daemon/daemonLog.ts
25769
- var RING_CAPACITY = 1e3;
25770
- var ring = [];
25771
- var sink;
25772
- function daemonLog(message2) {
25773
- emit3(`${(/* @__PURE__ */ new Date()).toISOString()} [${process.pid}] ${message2}`);
25774
- }
25775
- function relayDaemonLog(line) {
25776
- emit3(`[windows] ${line}`);
25777
- }
25778
- function emit3(line) {
25779
- console.log(line);
25780
- ring.push(line);
25781
- if (ring.length > RING_CAPACITY) ring.shift();
25782
- sink?.(line);
25783
- }
25784
- function setDaemonLogSink(next3) {
25785
- sink = next3;
25786
- }
25787
- function recentDaemonLogLines() {
25788
- return [...ring];
25789
- }
25790
-
25791
- // src/commands/sessions/daemon/persistedSessionSchema.ts
25792
- import { z as z6 } from "zod";
25793
- var persistedSessionSchema = z6.object({
25794
- name: z6.string(),
25795
- title: z6.string().optional(),
25796
- subtitle: z6.string().optional(),
25797
- commandType: z6.enum(["claude", "run", "assist"]),
25798
- harness: z6.enum(["claude", "codex", "pi"]).optional(),
25799
- status: z6.enum(["running", "waiting", "done", "error", "stopped"]).optional(),
25800
- cwd: z6.string(),
25801
- startedAt: z6.number(),
25802
- runningMs: z6.number().optional(),
25803
- claudeSessionId: z6.string().optional(),
25804
- initialPrompt: z6.string().optional(),
25805
- runName: z6.string().optional(),
25806
- runArgs: z6.array(z6.string()).optional(),
25807
- assistArgs: z6.array(z6.string()).optional(),
25808
- activity: activitySchema.optional(),
25809
- starred: z6.boolean().optional(),
25810
- undurable: z6.object({ reason: z6.string(), removesTree: z6.boolean().optional() }).optional()
25811
- });
25812
-
25813
- // src/commands/sessions/daemon/toPersistedSession.ts
25814
- function toPersistedSession(session) {
25815
- return {
25816
- name: session.name,
25817
- title: session.title,
25818
- subtitle: session.subtitle,
25819
- commandType: session.commandType,
25820
- harness: session.harness,
25821
- status: session.status,
25822
- cwd: session.cwd ?? process.cwd(),
25823
- startedAt: session.startedAt,
25824
- runningMs: accumulatedRunningMs(session),
25825
- claudeSessionId: session.claudeSessionId,
25826
- initialPrompt: session.initialPrompt,
25827
- runName: session.runName,
25828
- runArgs: session.runArgs,
25829
- assistArgs: session.assistArgs,
25830
- activity: session.activity,
25831
- starred: session.starred,
25832
- undurable: session.undurable
25833
- };
25834
- }
25835
- function accumulatedRunningMs(session) {
25836
- return session.runningSince != null ? session.runningMs + Date.now() - session.runningSince : session.runningMs;
26094
+ } catch {
26095
+ }
25837
26096
  }
25838
26097
 
25839
- // src/commands/sessions/daemon/loadPersistedSessions.ts
25840
- var SESSIONS_FILE = "sessions.json";
25841
- function loadPersistedSessions() {
25842
- const data = loadJson(SESSIONS_FILE);
25843
- if (!Array.isArray(data)) return [];
25844
- return data.flatMap((entry) => {
25845
- const parsed = persistedSessionSchema.safeParse(entry);
25846
- return parsed.success ? [parsed.data] : [];
25847
- });
26098
+ // src/commands/sessions/daemon/reportStolenSocket.ts
26099
+ import { readFileSync as readFileSync48 } from "fs";
26100
+ function reportStolenSocket(socketPid) {
26101
+ if (!socketPid) return;
26102
+ const filePid = readPidFile();
26103
+ if (filePid === void 0 || filePid === socketPid) return;
26104
+ console.error(
26105
+ `Warning: daemon.pid records PID ${filePid} but the socket is owned by PID ${socketPid} (stolen socket)`
26106
+ );
25848
26107
  }
25849
- function savePersistedSessions(sessions) {
25850
- saveJson(SESSIONS_FILE, sessions);
26108
+ function readPidFile() {
26109
+ try {
26110
+ const pid = Number.parseInt(
26111
+ readFileSync48(daemonPaths.pid, "utf8").trim(),
26112
+ 10
26113
+ );
26114
+ return Number.isInteger(pid) ? pid : void 0;
26115
+ } catch {
26116
+ return void 0;
26117
+ }
25851
26118
  }
25852
- function persistLiveSessions(sessions) {
25853
- const live = [...sessions.values()].filter(
25854
- (s) => (s.pty || s.status === "stopped") && s.status !== "done"
25855
- );
25856
- savePersistedSessions(live.map(toPersistedSession));
25857
- logPersist(live);
26119
+
26120
+ // src/commands/sessions/daemon/daemonStatus.ts
26121
+ async function daemonStatus() {
26122
+ let socket;
26123
+ try {
26124
+ socket = await connectToDaemon();
26125
+ } catch {
26126
+ console.log("Sessions daemon is not running");
26127
+ reportStrays(listDaemonPids());
26128
+ return;
26129
+ }
26130
+ const { pid, sessions } = await queryDaemon(socket);
26131
+ socket.destroy();
26132
+ console.log(`Sessions daemon is running${pid ? ` (PID ${pid})` : ""}`);
26133
+ reportStolenSocket(pid);
26134
+ reportStrays(listDaemonPids().filter((p) => p !== pid));
26135
+ if (sessions.length === 0) {
26136
+ console.log("No sessions");
26137
+ return;
26138
+ }
26139
+ for (const session of sessions) {
26140
+ const restored = session.restored === false ? " (not restored)" : "";
26141
+ console.log(` [${session.status}] ${session.name}${restored}`);
26142
+ }
25858
26143
  }
25859
- var lastPersistSignature = "";
25860
- function logPersist(live) {
25861
- const signature = live.map((s) => `${s.id}:${s.status}`).join(",");
25862
- if (signature === lastPersistSignature) return;
25863
- lastPersistSignature = signature;
25864
- daemonLog(
25865
- live.length > 0 ? `persisted ${live.length} session(s): ${live.map((s) => s.name).join(", ")}` : "persisted 0 sessions (sessions.json cleared)"
26144
+ function reportStrays(pids) {
26145
+ if (pids.length === 0) return;
26146
+ console.error(
26147
+ `Warning: stray daemon process(es) detected: ${pids.join(", ")}`
25866
26148
  );
25867
26149
  }
25868
26150
 
26151
+ // src/commands/sessions/daemon/drainDaemon.ts
26152
+ import { createInterface as createInterface6 } from "readline";
26153
+
25869
26154
  // src/commands/sessions/daemon/clearPersistedSessionsOnDrain.ts
25870
26155
  function clearPersistedSessionsOnDrain() {
25871
26156
  const held = loadPersistedSessions().filter((s) => s.status === "stopped");
@@ -26213,7 +26498,7 @@ function readDesignSystemPrompt() {
26213
26498
  import * as pty from "node-pty";
26214
26499
 
26215
26500
  // src/commands/sessions/daemon/ensureSpawnHelperExecutable.ts
26216
- import { chmodSync, existsSync as existsSync57, statSync as statSync10 } from "fs";
26501
+ import { chmodSync, existsSync as existsSync61, statSync as statSync10 } from "fs";
26217
26502
  import { createRequire as createRequire3 } from "module";
26218
26503
  import path59 from "path";
26219
26504
  var require4 = createRequire3(import.meta.url);
@@ -26228,7 +26513,7 @@ function ensureSpawnHelperExecutable() {
26228
26513
  `${process.platform}-${process.arch}`,
26229
26514
  "spawn-helper"
26230
26515
  );
26231
- if (!existsSync57(helper)) return;
26516
+ if (!existsSync61(helper)) return;
26232
26517
  const mode = statSync10(helper).mode;
26233
26518
  if ((mode & 73) === 0) chmodSync(helper, mode | 493);
26234
26519
  }
@@ -26387,7 +26672,8 @@ function otherTreeHolders(sessions, session) {
26387
26672
  }
26388
26673
 
26389
26674
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
26390
- import { existsSync as existsSync59 } from "fs";
26675
+ import { existsSync as existsSync62 } from "fs";
26676
+ import { basename as basename16 } from "path";
26391
26677
 
26392
26678
  // src/commands/sessions/daemon/worktree/removeTree.ts
26393
26679
  async function removeTree(clone, worktreePath, force) {
@@ -26424,63 +26710,9 @@ function reason(error) {
26424
26710
  return error instanceof Error ? error.message : String(error);
26425
26711
  }
26426
26712
 
26427
- // src/commands/sessions/daemon/worktree/treeDurability.ts
26428
- import { existsSync as existsSync58 } from "fs";
26429
- function treeDurability(state) {
26430
- if (state.dirty) return { durable: false, reason: "uncommitted changes" };
26431
- if (!state.push && state.localOnlyCommits)
26432
- return { durable: false, reason: "unpushed commits" };
26433
- return { durable: true };
26434
- }
26435
- function* durabilityProbes(cwd) {
26436
- const status3 = yield ["status", "--porcelain"];
26437
- if (!status3.ok)
26438
- return { durable: false, reason: `tree state unreadable: ${status3.error}` };
26439
- const upstream = yield [
26440
- "rev-parse",
26441
- "--abbrev-ref",
26442
- "--symbolic-full-name",
26443
- "@{upstream}"
26444
- ];
26445
- let localOnlyCommits;
26446
- if (upstream.ok && upstream.out) {
26447
- const ahead = yield ["rev-list", "--count", "@{upstream}..HEAD"];
26448
- localOnlyCommits = !ahead.ok || Number(ahead.out) > 0;
26449
- } else {
26450
- const remoteBranches = yield ["branch", "-r", "--contains", "HEAD"];
26451
- localOnlyCommits = !remoteBranches.ok || remoteBranches.out === "";
26452
- }
26453
- return treeDurability({
26454
- dirty: status3.out !== "",
26455
- push: pushOnCommit(cwd),
26456
- localOnlyCommits
26457
- });
26458
- }
26459
- function pushOnCommit(cwd) {
26460
- try {
26461
- return loadConfigFrom(cwd).commit.push;
26462
- } catch {
26463
- return false;
26464
- }
26465
- }
26466
- async function checkDurability(cwd) {
26467
- if (!existsSync58(cwd)) return { durable: true };
26468
- const probes = durabilityProbes(cwd);
26469
- let step = probes.next();
26470
- while (!step.done) step = probes.next(await gitResult(cwd, step.value));
26471
- return step.value;
26472
- }
26473
- function checkDurabilitySync(cwd) {
26474
- if (!existsSync58(cwd)) return { durable: true };
26475
- const probes = durabilityProbes(cwd);
26476
- let step = probes.next();
26477
- while (!step.done) step = probes.next(gitSyncResult(cwd, step.value));
26478
- return step.value;
26479
- }
26480
-
26481
26713
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
26482
26714
  async function reapWorktree(worktreePath, force = false) {
26483
- if (!existsSync59(worktreePath)) {
26715
+ if (!existsSync62(worktreePath)) {
26484
26716
  daemonLog(`worktree ${worktreePath} already gone; skipping reap`);
26485
26717
  return false;
26486
26718
  }
@@ -26492,23 +26724,23 @@ async function reapWorktree(worktreePath, force = false) {
26492
26724
  }
26493
26725
  }
26494
26726
  const clone = mainWorktree(worktreePath) ?? worktreePath;
26495
- const branch2 = await gitOrNull(worktreePath, [
26496
- "symbolic-ref",
26497
- "--short",
26498
- "HEAD"
26499
- ]);
26500
26727
  if (!await removeTree(clone, worktreePath, force)) return false;
26501
- if (branch2) await deleteBranch(clone, branch2);
26728
+ await deleteWorktreeBranch(clone, basename16(worktreePath));
26502
26729
  forgetWorktree(worktreePath);
26503
26730
  daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
26504
26731
  return true;
26505
26732
  }
26506
- async function deleteBranch(clone, branch2) {
26507
- const current = await gitOrNull(clone, ["symbolic-ref", "--short", "HEAD"]);
26733
+ async function deleteWorktreeBranch(clone, branch2) {
26734
+ if (!listLocalBranches(clone).includes(branch2)) return;
26735
+ const current = await gitOrNull2(clone, ["symbolic-ref", "--short", "HEAD"]);
26508
26736
  if (branch2 === current) return;
26509
26737
  try {
26510
26738
  await git2(clone, ["branch", "-D", branch2]);
26511
- } catch {
26739
+ daemonLog(`worktree branch ${branch2} deleted from clone ${clone}`);
26740
+ } catch (error) {
26741
+ daemonLog(
26742
+ `worktree branch ${branch2} retained in clone ${clone}: ${error instanceof Error ? error.message : String(error)}`
26743
+ );
26512
26744
  }
26513
26745
  }
26514
26746
 
@@ -26534,21 +26766,6 @@ function dismissSession(sessions, id) {
26534
26766
  return true;
26535
26767
  }
26536
26768
 
26537
- // src/commands/sessions/daemon/worktree/worktreeConfigFor.ts
26538
- var DISABLED = {
26539
- enabled: false,
26540
- install: true,
26541
- commitBeforeManualChecks: false,
26542
- copy: [".env", "settings.local.json", ".claude/settings.local.json"]
26543
- };
26544
- function worktreeConfigFor(cwd) {
26545
- try {
26546
- return loadConfigFrom(cwd).worktree ?? DISABLED;
26547
- } catch {
26548
- return DISABLED;
26549
- }
26550
- }
26551
-
26552
26769
  // src/commands/sessions/daemon/worktree/closeGateApplies.ts
26553
26770
  function closeGateApplies(sessions, session) {
26554
26771
  if (otherTreeHolders(sessions, session).length > 0) return false;
@@ -26570,12 +26787,12 @@ function setStatus2(session, newStatus) {
26570
26787
  }
26571
26788
 
26572
26789
  // src/commands/sessions/daemon/worktree/watchGitState.ts
26573
- import { existsSync as existsSync60, watch } from "fs";
26790
+ import { existsSync as existsSync63, watch } from "fs";
26574
26791
  var DEBOUNCE_MS = 500;
26575
26792
  var POLL_MS = 3e4;
26576
26793
  function watchGitState(cwd, onChange) {
26577
26794
  const common = gitCommonDir(cwd);
26578
- if (!common || !existsSync60(common)) return void 0;
26795
+ if (!common || !existsSync63(common)) return void 0;
26579
26796
  const watchers = [
26580
26797
  watchGitDir(common, onChange),
26581
26798
  pollGitState(cwd, onChange)
@@ -27167,10 +27384,10 @@ function emitSessionOutput(session, clients, data) {
27167
27384
  }
27168
27385
 
27169
27386
  // src/commands/sessions/daemon/exitReason.ts
27170
- import { existsSync as existsSync61 } from "fs";
27387
+ import { existsSync as existsSync64 } from "fs";
27171
27388
  function exitReason(session, exitCode) {
27172
27389
  const base = `process exited with code ${exitCode}`;
27173
- if (session.cwd && !existsSync61(session.cwd))
27390
+ if (session.cwd && !existsSync64(session.cwd))
27174
27391
  return `${base}: working directory ${session.cwd} no longer exists`;
27175
27392
  return base;
27176
27393
  }
@@ -27188,8 +27405,8 @@ function handleFailedResume(session, exitCode, onStatusChange) {
27188
27405
  }
27189
27406
 
27190
27407
  // src/commands/sessions/daemon/watchActivity.ts
27191
- import { existsSync as existsSync62, mkdirSync as mkdirSync25, watch as watch2 } from "fs";
27192
- import { dirname as dirname29 } from "path";
27408
+ import { existsSync as existsSync65, mkdirSync as mkdirSync26, watch as watch2 } from "fs";
27409
+ import { dirname as dirname31 } from "path";
27193
27410
 
27194
27411
  // src/commands/sessions/daemon/applyReviewPause.ts
27195
27412
  function applyReviewPause(session, activity2) {
@@ -27243,9 +27460,9 @@ var DEBOUNCE_MS2 = 50;
27243
27460
  function watchActivity(session, notify2, onClaudeSessionId) {
27244
27461
  if (session.commandType !== "assist" || !session.cwd) return;
27245
27462
  const path71 = activityPath(session.id);
27246
- const dir = dirname29(path71);
27463
+ const dir = dirname31(path71);
27247
27464
  try {
27248
- mkdirSync25(dir, { recursive: true });
27465
+ mkdirSync26(dir, { recursive: true });
27249
27466
  } catch {
27250
27467
  return;
27251
27468
  }
@@ -27269,7 +27486,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
27269
27486
  if (timer) clearTimeout(timer);
27270
27487
  timer = setTimeout(read, DEBOUNCE_MS2);
27271
27488
  });
27272
- if (existsSync62(path71)) read();
27489
+ if (existsSync65(path71)) read();
27273
27490
  }
27274
27491
  function refreshActivity(session) {
27275
27492
  if (session.commandType !== "assist" || !session.cwd) return;
@@ -27929,8 +28146,8 @@ function rearmStoppedSessions(sessions, notify2) {
27929
28146
  }
27930
28147
 
27931
28148
  // src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
27932
- import { existsSync as existsSync67 } from "fs";
27933
- import { basename as basename15 } from "path";
28149
+ import { existsSync as existsSync68 } from "fs";
28150
+ import { basename as basename18 } from "path";
27934
28151
 
27935
28152
  // src/commands/sessions/daemon/worktree/accountedTrees.ts
27936
28153
  function accountedTrees(sessions) {
@@ -27958,71 +28175,6 @@ function detectExistingWorktree(cwd) {
27958
28175
  return void 0;
27959
28176
  }
27960
28177
 
27961
- // src/commands/sessions/daemon/worktree/seedWorktree.ts
27962
- import { execFile as execFile8 } from "child_process";
27963
- import { copyFileSync, existsSync as existsSync65, mkdirSync as mkdirSync26 } from "fs";
27964
- import { dirname as dirname30, join as join71 } from "path";
27965
-
27966
- // src/commands/sessions/daemon/worktree/resolveInstallCommand.ts
27967
- import { existsSync as existsSync64 } from "fs";
27968
- import { join as join70 } from "path";
27969
- function detectInstallCommand(repoRoot) {
27970
- if (!existsSync64(join70(repoRoot, "package.json"))) return null;
27971
- if (existsSync64(join70(repoRoot, "pnpm-lock.yaml"))) return "pnpm install";
27972
- if (existsSync64(join70(repoRoot, "yarn.lock"))) return "yarn install";
27973
- if (existsSync64(join70(repoRoot, "bun.lockb"))) return "bun install";
27974
- return "npm install";
27975
- }
27976
- function resolveInstallCommand(repoRoot, install) {
27977
- if (install === false) return null;
27978
- if (typeof install === "string") return install;
27979
- return detectInstallCommand(repoRoot);
27980
- }
27981
-
27982
- // src/commands/sessions/daemon/worktree/seedWorktree.ts
27983
- function seedWorktree(worktreePath, clone, onSeeded = () => {
27984
- }) {
27985
- const cfg = worktreeConfigFor(clone);
27986
- copyConfigFiles(worktreePath, clone, cfg.copy);
27987
- runInstall(worktreePath, clone, cfg.install, onSeeded);
27988
- }
27989
- function copyConfigFiles(worktreePath, clone, copy) {
27990
- for (const rel of copy) {
27991
- const src = join71(clone, rel);
27992
- if (!existsSync65(src)) continue;
27993
- const dest = join71(worktreePath, rel);
27994
- try {
27995
- mkdirSync26(dirname30(dest), { recursive: true });
27996
- copyFileSync(src, dest);
27997
- daemonLog(`worktree ${worktreePath} seeded ${rel}`);
27998
- } catch (error) {
27999
- daemonLog(
28000
- `worktree ${worktreePath} failed to seed ${rel}: ${message(error)}`
28001
- );
28002
- }
28003
- }
28004
- }
28005
- function runInstall(worktreePath, clone, install, onSeeded) {
28006
- const command = resolveInstallCommand(clone, install);
28007
- if (!command) {
28008
- onSeeded();
28009
- return;
28010
- }
28011
- const windows = /^[A-Za-z]:[\\/]/.test(worktreePath);
28012
- const shell = windows ? "cmd.exe" : process.env.SHELL ?? "bash";
28013
- const shellArgs = windows ? ["/c", command] : ["-l", "-c", command];
28014
- daemonLog(`worktree ${worktreePath} installing deps: ${command}`);
28015
- execFile8(shell, shellArgs, { cwd: worktreePath }, (error) => {
28016
- daemonLog(
28017
- error ? `worktree ${worktreePath} install failed: ${error.message}` : `worktree ${worktreePath} install complete`
28018
- );
28019
- onSeeded();
28020
- });
28021
- }
28022
- function message(error) {
28023
- return error instanceof Error ? error.message : String(error);
28024
- }
28025
-
28026
28178
  // src/commands/sessions/daemon/worktree/bindNewWorktree.ts
28027
28179
  function bindNewWorktree(session, alloc, notify2, startHeld = () => {
28028
28180
  }) {
@@ -28084,9 +28236,9 @@ function capped(lines) {
28084
28236
  }
28085
28237
 
28086
28238
  // src/commands/sessions/daemon/worktree/reclaimVanishedWorktrees.ts
28087
- import { existsSync as existsSync66 } from "fs";
28239
+ import { existsSync as existsSync67 } from "fs";
28088
28240
  async function reclaimVanishedWorktrees(clone, paths) {
28089
- if (!existsSync66(clone)) {
28241
+ if (!existsSync67(clone)) {
28090
28242
  for (const { path: path71 } of paths) forgetWorktree(path71);
28091
28243
  daemonLog(
28092
28244
  `clone ${clone} is gone; forgot ${paths.length} worktree record(s) it owned`
@@ -28122,7 +28274,7 @@ async function reclaimBranch(clone, branch2) {
28122
28274
  }
28123
28275
 
28124
28276
  // src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
28125
- import { basename as basename14 } from "path";
28277
+ import { basename as basename17 } from "path";
28126
28278
  function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
28127
28279
  const { orphan, reason: reason2, held } = recovered;
28128
28280
  let id;
@@ -28145,7 +28297,7 @@ function orphanedSession(id, recovered) {
28145
28297
  const { orphan, reason: reason2, held } = recovered;
28146
28298
  return {
28147
28299
  ...sessionBase(id, "stopped"),
28148
- name: `recovered ${basename14(orphan.path)}`,
28300
+ name: `recovered ${basename17(orphan.path)}`,
28149
28301
  subtitle: `${held.summary} in ${orphan.path}`,
28150
28302
  commandType: "claude",
28151
28303
  pty: null,
@@ -28179,10 +28331,10 @@ async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
28179
28331
  const vanished = /* @__PURE__ */ new Map();
28180
28332
  for (const { path: path71, clone } of readWorktreeRegistry()) {
28181
28333
  if (accounted.has(path71)) continue;
28182
- if (!existsSync67(path71)) {
28334
+ if (!existsSync68(path71)) {
28183
28335
  vanished.set(clone, [
28184
28336
  ...vanished.get(clone) ?? [],
28185
- { path: path71, branch: basename15(path71) }
28337
+ { path: path71, branch: basename18(path71) }
28186
28338
  ]);
28187
28339
  continue;
28188
28340
  }
@@ -28358,7 +28510,7 @@ function treeSpawnContext(sessions, spawnWith, notify2, clients, onStatusChange)
28358
28510
  }
28359
28511
 
28360
28512
  // src/commands/sessions/daemon/watchTranscript.ts
28361
- import { existsSync as existsSync68, watch as watch3 } from "fs";
28513
+ import { existsSync as existsSync69, watch as watch3 } from "fs";
28362
28514
 
28363
28515
  // src/commands/sessions/daemon/reconcileTranscriptStatus.ts
28364
28516
  async function resolveTranscriptPath(session) {
@@ -28393,7 +28545,7 @@ function watchTranscript(session, onStatusChange) {
28393
28545
  if (!session.cwd || !session.claudeSessionId) return;
28394
28546
  if (session.watchedTranscriptId === session.claudeSessionId) return;
28395
28547
  const dir = projectDirForCwd(session.cwd);
28396
- if (!existsSync68(dir)) return;
28548
+ if (!existsSync69(dir)) return;
28397
28549
  if (session.transcriptWatcher) {
28398
28550
  session.transcriptWatcher.close();
28399
28551
  session.transcriptWatcher = void 0;
@@ -28544,13 +28696,13 @@ async function defaultConnect() {
28544
28696
  }
28545
28697
 
28546
28698
  // src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
28547
- import { existsSync as existsSync69, readFileSync as readFileSync50 } from "fs";
28699
+ import { existsSync as existsSync70, readFileSync as readFileSync50 } from "fs";
28548
28700
  import { posix } from "path";
28549
28701
  function hasPersistedWindowsSessions() {
28550
28702
  const sessionsFile = windowsSessionsFileFromWsl();
28551
28703
  if (!sessionsFile) return false;
28552
28704
  try {
28553
- if (!existsSync69(sessionsFile)) return false;
28705
+ if (!existsSync70(sessionsFile)) return false;
28554
28706
  const data = JSON.parse(readFileSync50(sessionsFile, "utf8"));
28555
28707
  return Array.isArray(data) && data.length > 0;
28556
28708
  } catch (error) {
@@ -29129,81 +29281,6 @@ function resumeSession(id, sessionId, cwd, name) {
29129
29281
  };
29130
29282
  }
29131
29283
 
29132
- // src/commands/sessions/daemon/worktree/createWorktree.ts
29133
- import { existsSync as existsSync70 } from "fs";
29134
- import { basename as basename17, dirname as dirname31 } from "path";
29135
-
29136
- // src/commands/sessions/daemon/worktree/planAllocation.ts
29137
- import { basename as basename16, join as join72 } from "path";
29138
- function planAllocation(clone, boundTreeRoots2) {
29139
- return boundTreeRoots2.has(clone) ? "spill" : "primary";
29140
- }
29141
- function nextWorktreePath(clone, base, isTaken) {
29142
- const name = basename16(clone);
29143
- for (let n = 2; n < 1e3; n++) {
29144
- const candidate = join72(base, `${name}-${n}`);
29145
- if (!isTaken(candidate)) return candidate;
29146
- }
29147
- throw new Error(`no free worktree suffix for ${clone}`);
29148
- }
29149
-
29150
- // src/commands/sessions/daemon/worktree/createWorktree.ts
29151
- function createWorktree(clone, root, boundTreeRoots2) {
29152
- const base = root ? expandTilde2(root) : dirname31(clone);
29153
- const registered = new Set(listWorktreePaths(clone));
29154
- const branches = new Set(listLocalBranches(clone));
29155
- const path71 = nextWorktreePath(
29156
- clone,
29157
- base,
29158
- (candidate) => registered.has(candidate) || existsSync70(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename17(candidate))
29159
- );
29160
- const trunk = cloneTrunkBranch(clone);
29161
- gitSync(clone, ["config", "push.default", "upstream"]);
29162
- gitSync(clone, [
29163
- "worktree",
29164
- "add",
29165
- "--track",
29166
- "-b",
29167
- basename17(path71),
29168
- path71,
29169
- `origin/${trunk}`
29170
- ]);
29171
- recordWorktree(path71, clone, getCurrentOrigin(clone));
29172
- daemonLog(
29173
- `worktree allocated ${path71} (branch ${basename17(path71)} tracking origin/${trunk}) for clone ${clone}`
29174
- );
29175
- return path71;
29176
- }
29177
- function cloneTrunkBranch(clone) {
29178
- const branch2 = gitSyncOrNull(clone, ["symbolic-ref", "--short", "HEAD"]);
29179
- if (branch2) return branch2;
29180
- const head = gitSyncOrNull(clone, [
29181
- "symbolic-ref",
29182
- "--short",
29183
- "refs/remotes/origin/HEAD"
29184
- ]);
29185
- if (head) {
29186
- const slash = head.indexOf("/");
29187
- return slash === -1 ? head : head.slice(slash + 1);
29188
- }
29189
- return "main";
29190
- }
29191
-
29192
- // src/commands/sessions/daemon/worktree/allocateTree.ts
29193
- function allocateTree(requestedCwd, boundTreeRoots2) {
29194
- if (!requestedCwd)
29195
- return { cwd: requestedCwd, kind: "primary", created: false };
29196
- const repoRoot = findRepoRoot(requestedCwd) ?? requestedCwd;
29197
- const cfg = worktreeConfigFor(repoRoot);
29198
- if (!cfg.enabled)
29199
- return { cwd: requestedCwd, kind: "primary", created: false };
29200
- const clone = mainWorktree(repoRoot) ?? repoRoot;
29201
- if (planAllocation(clone, boundTreeRoots2) === "primary")
29202
- return { cwd: clone, kind: "primary", created: false, clone };
29203
- const path71 = createWorktree(clone, cfg.root, boundTreeRoots2);
29204
- return { cwd: path71, kind: "worktree", created: true, clone };
29205
- }
29206
-
29207
29284
  // src/commands/sessions/daemon/worktree/boundTreeRoots.ts
29208
29285
  function boundTreeRoots(sessions) {
29209
29286
  const roots = /* @__PURE__ */ new Set();
@@ -29228,9 +29305,17 @@ function holdsTree(session, root) {
29228
29305
  return !durability.durable;
29229
29306
  }
29230
29307
 
29308
+ // src/commands/sessions/daemon/worktree/isPrCheckoutArgs.ts
29309
+ var CHECKOUT_COMMANDS = /* @__PURE__ */ new Set(["review", "review-pr-comments"]);
29310
+ function isPrCheckoutArgs(args) {
29311
+ const [command, ...rest] = args;
29312
+ if (!command || !CHECKOUT_COMMANDS.has(command)) return false;
29313
+ return rest.some((arg) => /^[1-9]\d*$/.test(arg));
29314
+ }
29315
+
29231
29316
  // src/commands/sessions/daemon/worktree/spawnInTree.ts
29232
- function allocateAndBind(ctx, cwd, create) {
29233
- const alloc = allocateTree(cwd, boundTreeRoots(ctx.sessions));
29317
+ function allocateAndBind(ctx, cwd, create, options2 = {}) {
29318
+ const alloc = allocateTree(cwd, boundTreeRoots(ctx.sessions), options2);
29234
29319
  const needsSeeding = alloc.kind === "worktree" && alloc.created === true;
29235
29320
  const id = ctx.spawnWith((sid) => create(sid, alloc.cwd, needsSeeding));
29236
29321
  bindNewWorktree(ctx.sessions.get(id), alloc, ctx.notify, ctx.startHeld);
@@ -29247,7 +29332,8 @@ function spawnAssistInTree(ctx, assistArgs, cwd, meta) {
29247
29332
  return allocateAndBind(
29248
29333
  ctx,
29249
29334
  cwd,
29250
- (sid, resolvedCwd, holdUntilSeeded) => createAssistSession(sid, assistArgs, resolvedCwd, meta, holdUntilSeeded)
29335
+ (sid, resolvedCwd, holdUntilSeeded) => createAssistSession(sid, assistArgs, resolvedCwd, meta, holdUntilSeeded),
29336
+ { forCheckout: isPrCheckoutArgs(assistArgs) }
29251
29337
  );
29252
29338
  }
29253
29339
  function resumeInTree(ctx, sessionId, cwd, name) {
@@ -29960,6 +30046,11 @@ var sessionsConfigHelp = [
29960
30046
  setter: "assist config set worktree.enabled true -g --repo",
29961
30047
  note: "opt in per repo: spill concurrent sessions into adjacent <clone>-N worktrees (default off)"
29962
30048
  },
30049
+ {
30050
+ key: "worktree.trunk",
30051
+ setter: "assist config set worktree.trunk true -g --repo",
30052
+ note: "trunk-based: a spilled worktree lands on the mainline (default off: it starts off the remote default with no mainline tracking, so the session raises its own branch and PR)"
30053
+ },
29963
30054
  {
29964
30055
  key: "worktree.root",
29965
30056
  setter: "assist config set worktree.root ~/git -g --repo",
@@ -30000,7 +30091,7 @@ function summaryPathFor(jsonlPath2) {
30000
30091
  }
30001
30092
 
30002
30093
  // src/commands/sessions/summarise/summariseSession.ts
30003
- import { execFileSync as execFileSync13 } from "child_process";
30094
+ import { execFileSync as execFileSync12 } from "child_process";
30004
30095
 
30005
30096
  // src/commands/sessions/summarise/extractFirstUserMessage.ts
30006
30097
  function extractFirstUserMessage(filePath) {
@@ -30024,7 +30115,7 @@ function summariseSession(jsonlPath2) {
30024
30115
  }
30025
30116
  const prompt = buildPrompt3(firstMessage, backlogIds);
30026
30117
  try {
30027
- const output = execFileSync13("claude", ["-p", "--model", "haiku", prompt], {
30118
+ const output = execFileSync12("claude", ["-p", "--model", "haiku", prompt], {
30028
30119
  encoding: "utf8",
30029
30120
  timeout: 3e4,
30030
30121
  stdio: ["ignore", "pipe", "ignore"]
@@ -30586,7 +30677,7 @@ function syncCommands(claudeDir, targetBase) {
30586
30677
  }
30587
30678
 
30588
30679
  // src/commands/update.ts
30589
- import { execSync as execSync59 } from "child_process";
30680
+ import { execSync as execSync60 } from "child_process";
30590
30681
  import * as path70 from "path";
30591
30682
 
30592
30683
  // src/commands/restartDaemonAfterUpdate.ts
@@ -30610,7 +30701,7 @@ function isGlobalNpmInstall(dir) {
30610
30701
  if (resolved.split(path70.sep).includes("node_modules")) {
30611
30702
  return true;
30612
30703
  }
30613
- const globalPrefix = execSync59("npm prefix -g", { stdio: "pipe" }).toString().trim();
30704
+ const globalPrefix = execSync60("npm prefix -g", { stdio: "pipe" }).toString().trim();
30614
30705
  return resolved.toLowerCase().startsWith(path70.resolve(globalPrefix).toLowerCase());
30615
30706
  } catch {
30616
30707
  return false;
@@ -30621,18 +30712,18 @@ async function update2() {
30621
30712
  console.log(`Assist is installed at: ${installDir}`);
30622
30713
  if (isGitRepo(installDir)) {
30623
30714
  console.log("Detected git repo installation, pulling latest...");
30624
- execSync59("git pull", { cwd: installDir, stdio: "inherit" });
30715
+ execSync60("git pull", { cwd: installDir, stdio: "inherit" });
30625
30716
  console.log("Installing dependencies...");
30626
- execSync59("npm i", { cwd: installDir, stdio: "inherit" });
30717
+ execSync60("npm i", { cwd: installDir, stdio: "inherit" });
30627
30718
  console.log("Building...");
30628
- execSync59("npm run build", { cwd: installDir, stdio: "inherit" });
30719
+ execSync60("npm run build", { cwd: installDir, stdio: "inherit" });
30629
30720
  console.log("Syncing commands...");
30630
- execSync59("assist sync", { stdio: "inherit" });
30721
+ execSync60("assist sync", { stdio: "inherit" });
30631
30722
  } else if (isGlobalNpmInstall(installDir)) {
30632
30723
  console.log("Detected global npm installation, updating...");
30633
- execSync59("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
30724
+ execSync60("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
30634
30725
  console.log("Syncing commands...");
30635
- execSync59("assist sync", { stdio: "inherit" });
30726
+ execSync60("assist sync", { stdio: "inherit" });
30636
30727
  } else {
30637
30728
  console.error(
30638
30729
  "Could not determine installation method. Expected a git repo or global npm install."