@staff0rd/assist 0.444.1 → 0.446.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.446.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),
@@ -502,7 +503,8 @@ var assistConfigSchema = z2.strictObject({
502
503
  windowsDaemonHost: z2.string().optional(),
503
504
  // why: TCP port the native Windows daemon listens on for the WSL bridge; defaults to 51764
504
505
  windowsDaemonPort: z2.number().optional(),
505
- windowsVersionCheck: z2.enum(["block", "warn", "off"]).default("block")
506
+ windowsVersionCheck: z2.enum(["block", "warn", "off"]).default("block"),
507
+ includeCommittedChanges: z2.boolean().default(false)
506
508
  }).optional(),
507
509
  database: z2.strictObject({
508
510
  url: z2.string().optional()
@@ -1782,17 +1784,49 @@ function git(args) {
1782
1784
  }
1783
1785
  }
1784
1786
 
1785
- // src/commands/commit/stageAndCommit.ts
1787
+ // src/commands/commit/pushCommit.ts
1786
1788
  import { execSync as execSync5 } from "child_process";
1789
+ var HEADS_PREFIX = "refs/heads/";
1790
+ function pushCommit() {
1791
+ const target = renamedUpstream();
1792
+ const command = target ? `git push ${shellQuote(target.remote)} HEAD:${shellQuote(target.branch)}` : "git push";
1793
+ execSync5(command, { stdio: "inherit" });
1794
+ }
1795
+ function renamedUpstream() {
1796
+ const branch2 = gitOrNull("git symbolic-ref --short HEAD");
1797
+ if (!branch2) return null;
1798
+ const remote = gitOrNull(
1799
+ `git config --get branch.${shellQuote(branch2)}.remote`
1800
+ );
1801
+ const merge = gitOrNull(
1802
+ `git config --get branch.${shellQuote(branch2)}.merge`
1803
+ );
1804
+ if (!remote || !merge) return null;
1805
+ const upstream = merge.startsWith(HEADS_PREFIX) ? merge.slice(HEADS_PREFIX.length) : merge;
1806
+ return upstream === branch2 ? null : { remote, branch: upstream };
1807
+ }
1808
+ function gitOrNull(command) {
1809
+ try {
1810
+ return execSync5(command, {
1811
+ encoding: "utf8",
1812
+ stdio: ["pipe", "pipe", "pipe"]
1813
+ }).trim() || null;
1814
+ } catch {
1815
+ return null;
1816
+ }
1817
+ }
1818
+
1819
+ // src/commands/commit/stageAndCommit.ts
1820
+ import { execSync as execSync6 } from "child_process";
1787
1821
  function commitStaged(message2) {
1788
- execSync5(`git commit -m ${shellQuote(message2)}`, { stdio: "inherit" });
1789
- return execSync5("git rev-parse --short=7 HEAD", {
1822
+ execSync6(`git commit -m ${shellQuote(message2)}`, { stdio: "inherit" });
1823
+ return execSync6("git rev-parse --short=7 HEAD", {
1790
1824
  encoding: "utf8"
1791
1825
  }).trim();
1792
1826
  }
1793
1827
  function stageAndCommit(files, message2) {
1794
1828
  const escaped = files.map(shellQuote).join(" ");
1795
- execSync5(`git add ${escaped}`, { stdio: "inherit" });
1829
+ execSync6(`git add ${escaped}`, { stdio: "inherit" });
1796
1830
  return commitStaged(message2);
1797
1831
  }
1798
1832
 
@@ -1920,13 +1954,13 @@ async function execCommit(files, message2, config) {
1920
1954
  warnIfUnexpectedBranch(config);
1921
1955
  const pulled = Boolean(config.commit?.pull);
1922
1956
  if (pulled) {
1923
- execSync6("git pull --autostash", { stdio: "inherit" });
1957
+ execSync7("git pull --autostash", { stdio: "inherit" });
1924
1958
  }
1925
1959
  abortOnConflicts(files, pulled);
1926
1960
  const sha = files.length > 0 ? stageAndCommit(files, message2) : commitStaged(message2);
1927
1961
  console.log(`Committed: ${sha}`);
1928
1962
  if (config.commit?.push) {
1929
- execSync6("git push", { stdio: "inherit" });
1963
+ pushCommit();
1930
1964
  console.log("Pushed to remote");
1931
1965
  }
1932
1966
  await recordCommitActivity(message2);
@@ -1941,7 +1975,7 @@ async function recordCommitActivity(message2) {
1941
1975
  }
1942
1976
  async function commit(args) {
1943
1977
  if (args[0] === "status") {
1944
- execSync6("git status && echo '---DIFF---' && git diff", {
1978
+ execSync7("git status && echo '---DIFF---' && git diff", {
1945
1979
  stdio: "inherit"
1946
1980
  });
1947
1981
  return;
@@ -1958,9 +1992,9 @@ async function commit(args) {
1958
1992
  }
1959
1993
 
1960
1994
  // src/commands/coverage.ts
1961
- import { execSync as execSync7 } from "child_process";
1995
+ import { execSync as execSync8 } from "child_process";
1962
1996
  function coverage() {
1963
- const output = execSync7(
1997
+ const output = execSync8(
1964
1998
  "npx vitest run --coverage --coverage.include='src/**/*.ts' --coverage.all --coverage.reporter=text 2>&1",
1965
1999
  { encoding: "utf8", timeout: 12e4 }
1966
2000
  );
@@ -2060,7 +2094,7 @@ function findPackageJsonWithVerifyScripts(startDir) {
2060
2094
  }
2061
2095
 
2062
2096
  // src/commands/verify/installPackage.ts
2063
- import { execSync as execSync8 } from "child_process";
2097
+ import { execSync as execSync9 } from "child_process";
2064
2098
  import { writeFileSync as writeFileSync2 } from "fs";
2065
2099
  import chalk6 from "chalk";
2066
2100
  function writePackageJson(filePath, pkg) {
@@ -2079,7 +2113,7 @@ function addScript(pkg, name, command) {
2079
2113
  function installPackage(name, cwd) {
2080
2114
  console.log(chalk6.dim(`Installing ${name}...`));
2081
2115
  try {
2082
- execSync8(`npm install -D ${name}`, { stdio: "inherit", cwd });
2116
+ execSync9(`npm install -D ${name}`, { stdio: "inherit", cwd });
2083
2117
  return true;
2084
2118
  } catch {
2085
2119
  console.error(chalk6.red(`Failed to install ${name}`));
@@ -2323,7 +2357,7 @@ import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync
2323
2357
  import chalk14 from "chalk";
2324
2358
 
2325
2359
  // src/shared/removeEslint/index.ts
2326
- import { execSync as execSync9 } from "child_process";
2360
+ import { execSync as execSync10 } from "child_process";
2327
2361
  import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
2328
2362
 
2329
2363
  // src/shared/removeEslint/removeEslintConfigFiles.ts
@@ -2358,7 +2392,7 @@ function removeEslint(options2 = {}) {
2358
2392
  const removedConfigFiles = removeEslintConfigFiles();
2359
2393
  if (removedFromPackageJson || removedConfigFiles) {
2360
2394
  console.log("Running npm install...");
2361
- execSync9("npm install", { stdio: "inherit" });
2395
+ execSync10("npm install", { stdio: "inherit" });
2362
2396
  return true;
2363
2397
  }
2364
2398
  return false;
@@ -3206,11 +3240,11 @@ function lint(options2 = {}) {
3206
3240
  }
3207
3241
 
3208
3242
  // src/commands/new/registerNew/newCli/index.ts
3209
- import { execSync as execSync18 } from "child_process";
3243
+ import { execSync as execSync19 } from "child_process";
3210
3244
  import { basename as basename2, resolve as resolve5 } from "path";
3211
3245
 
3212
3246
  // src/commands/verify/blockCodeComments/findComments.ts
3213
- import { execSync as execSync10 } from "child_process";
3247
+ import { execSync as execSync11 } from "child_process";
3214
3248
  import fs15 from "fs";
3215
3249
  import { minimatch } from "minimatch";
3216
3250
  import { Project as Project2 } from "ts-morph";
@@ -3470,7 +3504,7 @@ function shouldScan(file, ignoreGlobs) {
3470
3504
  return fs15.existsSync(file);
3471
3505
  }
3472
3506
  function findComments(options2) {
3473
- const diff3 = execSync10("git diff HEAD", {
3507
+ const diff3 = execSync11("git diff HEAD", {
3474
3508
  encoding: "utf8",
3475
3509
  maxBuffer: 64 * 1024 * 1024
3476
3510
  });
@@ -3716,13 +3750,13 @@ Total: ${violations.length} forbidden string(s).`);
3716
3750
  }
3717
3751
 
3718
3752
  // src/commands/verify/hardcodedColors.ts
3719
- import { execSync as execSync11 } from "child_process";
3753
+ import { execSync as execSync12 } from "child_process";
3720
3754
  import { minimatch as minimatch3 } from "minimatch";
3721
3755
  var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
3722
3756
  function hardcodedColors() {
3723
3757
  const ignoreGlobs = loadConfig().hardcodedColors?.ignore ?? [];
3724
3758
  try {
3725
- const output = execSync11(`grep -rEnH '${pattern}' src/`, {
3759
+ const output = execSync12(`grep -rEnH '${pattern}' src/`, {
3726
3760
  encoding: "utf8"
3727
3761
  });
3728
3762
  const lines = output.trim().split("\n").filter((line) => {
@@ -3983,14 +4017,14 @@ function listMigrationFiles(dir) {
3983
4017
  }
3984
4018
 
3985
4019
  // src/commands/verify/migrations/readBaselineMigrations.ts
3986
- import { execSync as execSync12 } from "child_process";
4020
+ import { execSync as execSync13 } from "child_process";
3987
4021
  import { basename } from "path";
3988
4022
  var MIGRATION_FILE3 = /^migration\d+[A-Za-z0-9]*\.ts$/;
3989
4023
  function readBaselineMigrations(repoRelativeDir, ref) {
3990
4024
  const baseline = /* @__PURE__ */ new Map();
3991
4025
  let listing;
3992
4026
  try {
3993
- listing = execSync12(
4027
+ listing = execSync13(
3994
4028
  `git ls-tree -r --name-only "${ref}" -- "${repoRelativeDir}"`,
3995
4029
  { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
3996
4030
  );
@@ -4000,7 +4034,7 @@ function readBaselineMigrations(repoRelativeDir, ref) {
4000
4034
  const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path71) => MIGRATION_FILE3.test(basename(path71)));
4001
4035
  for (const path71 of paths) {
4002
4036
  try {
4003
- const content = execSync12(`git show "${ref}:${path71}"`, {
4037
+ const content = execSync13(`git show "${ref}:${path71}"`, {
4004
4038
  encoding: "utf8",
4005
4039
  maxBuffer: 16 * 1024 * 1024,
4006
4040
  stdio: ["pipe", "pipe", "pipe"]
@@ -4013,10 +4047,10 @@ function readBaselineMigrations(repoRelativeDir, ref) {
4013
4047
  }
4014
4048
 
4015
4049
  // src/commands/verify/migrations/resolveBaselineRef.ts
4016
- import { execSync as execSync13 } from "child_process";
4050
+ import { execSync as execSync14 } from "child_process";
4017
4051
  function refExists(ref) {
4018
4052
  try {
4019
- execSync13(`git rev-parse --verify --quiet "${ref}"`, {
4053
+ execSync14(`git rev-parse --verify --quiet "${ref}"`, {
4020
4054
  stdio: ["pipe", "pipe", "pipe"]
4021
4055
  });
4022
4056
  return true;
@@ -4088,10 +4122,10 @@ Total: ${problems.length} violation(s).`);
4088
4122
  }
4089
4123
 
4090
4124
  // src/commands/verify/noVenv.ts
4091
- import { execSync as execSync14 } from "child_process";
4125
+ import { execSync as execSync15 } from "child_process";
4092
4126
  function noVenv() {
4093
4127
  try {
4094
- const output = execSync14(
4128
+ const output = execSync15(
4095
4129
  "find . -type d -name venv -not -path '*/node_modules/*'",
4096
4130
  {
4097
4131
  encoding: "utf8"
@@ -4123,9 +4157,9 @@ Total: ${folders.length} venv folder(s)`);
4123
4157
  import { minimatch as minimatch4 } from "minimatch";
4124
4158
 
4125
4159
  // src/commands/verify/run/getChangedFiles.ts
4126
- import { execSync as execSync15 } from "child_process";
4160
+ import { execSync as execSync16 } from "child_process";
4127
4161
  function getChangedFiles() {
4128
- const output = execSync15("git diff --name-only HEAD", {
4162
+ const output = execSync16("git diff --name-only HEAD", {
4129
4163
  encoding: "utf8"
4130
4164
  }).trim();
4131
4165
  if (output === "") return [];
@@ -4297,25 +4331,25 @@ async function run(options2 = {}) {
4297
4331
  }
4298
4332
 
4299
4333
  // src/commands/new/registerNew/initGit.ts
4300
- import { execSync as execSync16 } from "child_process";
4334
+ import { execSync as execSync17 } from "child_process";
4301
4335
  import { writeFileSync as writeFileSync10 } from "fs";
4302
4336
  function initGit() {
4303
4337
  console.log("Initializing git repository...");
4304
- execSync16("git init", { stdio: "inherit" });
4338
+ execSync17("git init", { stdio: "inherit" });
4305
4339
  writeFileSync10(".gitignore", "dist\nnode_modules\n");
4306
4340
  }
4307
4341
 
4308
4342
  // src/commands/new/registerNew/newCli/initPackageJson.ts
4309
- import { execSync as execSync17 } from "child_process";
4343
+ import { execSync as execSync18 } from "child_process";
4310
4344
  function initPackageJson(name) {
4311
4345
  console.log("Initializing package.json...");
4312
- execSync17("npm init -y", { stdio: "inherit" });
4346
+ execSync18("npm init -y", { stdio: "inherit" });
4313
4347
  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"', {
4348
+ execSync18("npm pkg delete main", { stdio: "inherit" });
4349
+ execSync18("npm pkg set type=module", { stdio: "inherit" });
4350
+ execSync18(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
4351
+ execSync18("npm pkg set scripts.build=tsup", { stdio: "inherit" });
4352
+ execSync18('npm pkg set scripts.start="node dist/index.js"', {
4319
4353
  stdio: "inherit"
4320
4354
  });
4321
4355
  }
@@ -4380,8 +4414,8 @@ async function newCli() {
4380
4414
  initGit();
4381
4415
  initPackageJson(name);
4382
4416
  console.log("Installing dependencies...");
4383
- execSync18("npm install commander", { stdio: "inherit" });
4384
- execSync18("npm install -D tsup typescript @types/node", {
4417
+ execSync19("npm install commander", { stdio: "inherit" });
4418
+ execSync19("npm install -D tsup typescript @types/node", {
4385
4419
  stdio: "inherit"
4386
4420
  });
4387
4421
  writeCliTemplate(name);
@@ -4390,11 +4424,11 @@ async function newCli() {
4390
4424
  }
4391
4425
 
4392
4426
  // src/commands/new/registerNew/newProject.ts
4393
- import { execSync as execSync20 } from "child_process";
4427
+ import { execSync as execSync21 } from "child_process";
4394
4428
  import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync13 } from "fs";
4395
4429
 
4396
4430
  // src/commands/deploy/init/index.ts
4397
- import { execSync as execSync19 } from "child_process";
4431
+ import { execSync as execSync20 } from "child_process";
4398
4432
  import chalk28 from "chalk";
4399
4433
  import enquirer3 from "enquirer";
4400
4434
 
@@ -4447,7 +4481,7 @@ Created ${WORKFLOW_PATH}`));
4447
4481
  // src/commands/deploy/init/index.ts
4448
4482
  async function ensureNetlifyCli() {
4449
4483
  try {
4450
- execSync19("netlify sites:create --disable-linking", { stdio: "inherit" });
4484
+ execSync20("netlify sites:create --disable-linking", { stdio: "inherit" });
4451
4485
  } catch (error) {
4452
4486
  if (!(error instanceof Error) || !error.message.includes("command not found"))
4453
4487
  throw error;
@@ -4462,9 +4496,9 @@ async function ensureNetlifyCli() {
4462
4496
  process.exit(1);
4463
4497
  }
4464
4498
  console.log(chalk28.dim("\nInstalling netlify-cli...\n"));
4465
- execSync19("npm install -g netlify-cli", { stdio: "inherit" });
4499
+ execSync20("npm install -g netlify-cli", { stdio: "inherit" });
4466
4500
  console.log();
4467
- execSync19("netlify sites:create --disable-linking", { stdio: "inherit" });
4501
+ execSync20("netlify sites:create --disable-linking", { stdio: "inherit" });
4468
4502
  }
4469
4503
  }
4470
4504
  function printSetupInstructions() {
@@ -4507,7 +4541,7 @@ async function init6() {
4507
4541
  // src/commands/new/registerNew/newProject.ts
4508
4542
  async function newProject() {
4509
4543
  console.log("Initializing Vite with react-ts template...");
4510
- execSync20("npm create vite@latest . -- --template react-ts", {
4544
+ execSync21("npm create vite@latest . -- --template react-ts", {
4511
4545
  stdio: "inherit"
4512
4546
  });
4513
4547
  initGit();
@@ -4698,11 +4732,11 @@ function activityChart(data, range) {
4698
4732
  }
4699
4733
 
4700
4734
  // src/commands/activity/fetchCommitsPerDay.ts
4701
- import { execSync as execSync21 } from "child_process";
4735
+ import { execSync as execSync22 } from "child_process";
4702
4736
  function fetchContributions(from, to) {
4703
4737
  const query = `{ viewer { contributionsCollection(from: "${from}T00:00:00Z", to: "${to}T23:59:59Z") { contributionCalendar { weeks { contributionDays { date contributionCount } } } } } }`;
4704
4738
  const jq = ".data.viewer.contributionsCollection.contributionCalendar.weeks[].contributionDays[]";
4705
- const raw = execSync21(`gh api graphql -f query='${query}' --jq '${jq}'`, {
4739
+ const raw = execSync22(`gh api graphql -f query='${query}' --jq '${jq}'`, {
4706
4740
  encoding: "utf8"
4707
4741
  }).trim();
4708
4742
  if (!raw) return [];
@@ -4789,10 +4823,10 @@ import { join as join10 } from "path";
4789
4823
  import chalk29 from "chalk";
4790
4824
 
4791
4825
  // src/commands/backup/readCrontab.ts
4792
- import { execSync as execSync22 } from "child_process";
4826
+ import { execSync as execSync23 } from "child_process";
4793
4827
  function readCrontab() {
4794
4828
  try {
4795
- return execSync22("crontab -l", {
4829
+ return execSync23("crontab -l", {
4796
4830
  encoding: "utf8",
4797
4831
  stdio: ["ignore", "pipe", "ignore"]
4798
4832
  });
@@ -4802,7 +4836,7 @@ function readCrontab() {
4802
4836
  }
4803
4837
  function writeCrontab(content) {
4804
4838
  try {
4805
- execSync22("crontab -", {
4839
+ execSync23("crontab -", {
4806
4840
  input: content,
4807
4841
  stdio: ["pipe", "ignore", "pipe"]
4808
4842
  });
@@ -5143,7 +5177,7 @@ import chalk46 from "chalk";
5143
5177
  import enquirer5 from "enquirer";
5144
5178
 
5145
5179
  // src/shared/pullIfConfigured.ts
5146
- import { execSync as execSync23 } from "child_process";
5180
+ import { execSync as execSync24 } from "child_process";
5147
5181
  import chalk32 from "chalk";
5148
5182
  function pullIfConfigured() {
5149
5183
  const config = loadConfig();
@@ -5157,7 +5191,7 @@ function pullIfConfigured() {
5157
5191
  return;
5158
5192
  }
5159
5193
  try {
5160
- execSync23("git pull --ff-only", { stdio: "inherit" });
5194
+ execSync24("git pull --ff-only", { stdio: "inherit" });
5161
5195
  } catch {
5162
5196
  console.error(chalk32.red("git pull --ff-only failed; aborting."));
5163
5197
  process.exit(1);
@@ -5165,7 +5199,7 @@ function pullIfConfigured() {
5165
5199
  }
5166
5200
  function hasLocalChanges() {
5167
5201
  try {
5168
- const status3 = execSync23("git status --porcelain", {
5202
+ const status3 = execSync24("git status --porcelain", {
5169
5203
  encoding: "utf8"
5170
5204
  });
5171
5205
  return status3.trim().length > 0;
@@ -5432,7 +5466,7 @@ function buildArgs(prompt, options2) {
5432
5466
  }
5433
5467
 
5434
5468
  // src/commands/branch/createBranch.ts
5435
- import { execSync as execSync25 } from "child_process";
5469
+ import { execSync as execSync26 } from "child_process";
5436
5470
 
5437
5471
  // src/commands/branch/buildBranchName.ts
5438
5472
  function buildBranchName({
@@ -5448,12 +5482,12 @@ function buildBranchName({
5448
5482
  }
5449
5483
 
5450
5484
  // src/commands/branch/resolveDefaultBranch.ts
5451
- import { execSync as execSync24 } from "child_process";
5485
+ import { execSync as execSync25 } from "child_process";
5452
5486
  var REMOTE_HEAD_REGEX = /^ref:\s+refs\/heads\/(\S+)\s+HEAD$/m;
5453
5487
  function resolveDefaultBranch(override, cwd) {
5454
5488
  if (override) return override;
5455
5489
  try {
5456
- const output = execSync24("git ls-remote --symref origin HEAD", {
5490
+ const output = execSync25("git ls-remote --symref origin HEAD", {
5457
5491
  encoding: "utf8",
5458
5492
  stdio: ["pipe", "pipe", "pipe"],
5459
5493
  cwd
@@ -5477,11 +5511,11 @@ async function createBranch({
5477
5511
  jira,
5478
5512
  slug
5479
5513
  });
5480
- execSync25("git fetch", { stdio: "inherit" });
5514
+ execSync26("git fetch", { stdio: "inherit" });
5481
5515
  let baseRef;
5482
5516
  if (from) {
5483
5517
  try {
5484
- execSync25(`git rev-parse --verify ${shellQuote(from)}`, {
5518
+ execSync26(`git rev-parse --verify ${shellQuote(from)}`, {
5485
5519
  stdio: ["pipe", "pipe", "pipe"]
5486
5520
  });
5487
5521
  } catch {
@@ -5491,7 +5525,7 @@ async function createBranch({
5491
5525
  } else {
5492
5526
  baseRef = `origin/${resolveDefaultBranch(config.branch?.defaultBranch)}`;
5493
5527
  }
5494
- execSync25(`git switch -c ${shellQuote(branchName)} ${shellQuote(baseRef)}`, {
5528
+ execSync26(`git switch -c ${shellQuote(branchName)} ${shellQuote(baseRef)}`, {
5495
5529
  stdio: "inherit"
5496
5530
  });
5497
5531
  await recordBranchActivity(branchName);
@@ -5631,11 +5665,11 @@ function backupLocalBacklogFiles(dir) {
5631
5665
  }
5632
5666
 
5633
5667
  // src/commands/backlog/gitPullBacklog.ts
5634
- import { execSync as execSync26 } from "child_process";
5668
+ import { execSync as execSync27 } from "child_process";
5635
5669
  import chalk35 from "chalk";
5636
5670
  function gitPullBacklog(dir) {
5637
5671
  try {
5638
- execSync26("git pull --ff-only", {
5672
+ execSync27("git pull --ff-only", {
5639
5673
  cwd: dir,
5640
5674
  stdio: ["pipe", "pipe", "pipe"]
5641
5675
  });
@@ -7925,7 +7959,7 @@ import chalk61 from "chalk";
7925
7959
  import { WebSocketServer } from "ws";
7926
7960
 
7927
7961
  // src/shared/getInstallDir.ts
7928
- import { execSync as execSync27 } from "child_process";
7962
+ import { execSync as execSync28 } from "child_process";
7929
7963
  import { dirname as dirname18, resolve as resolve7 } from "path";
7930
7964
  import { fileURLToPath as fileURLToPath3 } from "url";
7931
7965
  var __filename2 = fileURLToPath3(import.meta.url);
@@ -7935,7 +7969,7 @@ function getInstallDir() {
7935
7969
  }
7936
7970
  function isGitRepo(dir) {
7937
7971
  try {
7938
- const result = execSync27("git rev-parse --show-toplevel", {
7972
+ const result = execSync28("git rev-parse --show-toplevel", {
7939
7973
  cwd: dir,
7940
7974
  stdio: "pipe"
7941
7975
  }).toString().trim();
@@ -7952,11 +7986,11 @@ import {
7952
7986
  import chalk57 from "chalk";
7953
7987
 
7954
7988
  // src/lib/openBrowser.ts
7955
- import { execSync as execSync28 } from "child_process";
7989
+ import { execSync as execSync29 } from "child_process";
7956
7990
  function tryExec(commands) {
7957
7991
  for (const cmd of commands) {
7958
7992
  try {
7959
- execSync28(cmd, { stdio: "ignore" });
7993
+ execSync29(cmd, { stdio: "ignore" });
7960
7994
  return true;
7961
7995
  } catch {
7962
7996
  }
@@ -8188,7 +8222,7 @@ function git2(cwd, args) {
8188
8222
  });
8189
8223
  });
8190
8224
  }
8191
- async function gitOrNull(cwd, args) {
8225
+ async function gitOrNull2(cwd, args) {
8192
8226
  try {
8193
8227
  return (await git2(cwd, args)).trim() || null;
8194
8228
  } catch {
@@ -8847,6 +8881,61 @@ function getCwdParam(req, res) {
8847
8881
  return cwd;
8848
8882
  }
8849
8883
 
8884
+ // src/commands/sessions/web/windowsCwdToWslPath.ts
8885
+ function windowsCwdToWslPath(cwd) {
8886
+ const match = /^([A-Za-z]):[\\/](.*)$/.exec(cwd);
8887
+ if (!match) return cwd;
8888
+ const drive = match[1].toLowerCase();
8889
+ const rest = match[2].replace(/\\/g, "/");
8890
+ return `/mnt/${drive}/${rest}`;
8891
+ }
8892
+
8893
+ // src/commands/sessions/web/toGitCwd.ts
8894
+ function toGitCwd(cwd) {
8895
+ return detectPlatform() === "wsl" ? windowsCwdToWslPath(cwd) : cwd;
8896
+ }
8897
+
8898
+ // src/commands/sessions/web/resolveDiffBase.ts
8899
+ function baseCandidates(defaultBranch) {
8900
+ return [
8901
+ defaultBranch && `origin/${defaultBranch}`,
8902
+ defaultBranch,
8903
+ "origin/main",
8904
+ "origin/master",
8905
+ "main",
8906
+ "master"
8907
+ ].filter((candidate) => Boolean(candidate));
8908
+ }
8909
+ async function refExists2(cwd, ref) {
8910
+ try {
8911
+ await execGit(cwd, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]);
8912
+ return true;
8913
+ } catch {
8914
+ return false;
8915
+ }
8916
+ }
8917
+ async function resolveDiffBase(cwd) {
8918
+ let defaultBranch;
8919
+ try {
8920
+ const config = loadConfigFrom(toGitCwd(cwd));
8921
+ if (!config.sessions?.includeCommittedChanges) return "HEAD";
8922
+ defaultBranch = config.branch?.defaultBranch;
8923
+ } catch {
8924
+ return "HEAD";
8925
+ }
8926
+ for (const candidate of baseCandidates(defaultBranch)) {
8927
+ if (!await refExists2(cwd, candidate)) continue;
8928
+ try {
8929
+ const base = await execGit(cwd, ["merge-base", "HEAD", candidate]);
8930
+ const sha = base.trim();
8931
+ if (sha) return sha;
8932
+ } catch {
8933
+ }
8934
+ return "HEAD";
8935
+ }
8936
+ return "HEAD";
8937
+ }
8938
+
8850
8939
  // src/commands/sessions/web/diff.ts
8851
8940
  var MAX_DIFF_BYTES = 50 * 1024 * 1024;
8852
8941
  async function untrackedFileDiff(cwd, path71) {
@@ -8871,7 +8960,8 @@ async function diff2(req, res) {
8871
8960
  const cwd = getCwdParam(req, res);
8872
8961
  if (!cwd) return;
8873
8962
  try {
8874
- const tracked = await execGit(cwd, ["diff", "HEAD"], {
8963
+ const base = await resolveDiffBase(cwd);
8964
+ const tracked = await execGit(cwd, ["diff", base], {
8875
8965
  maxBuffer: MAX_DIFF_BYTES
8876
8966
  });
8877
8967
  const untracked = await untrackedDiff(cwd);
@@ -8886,22 +8976,6 @@ async function diff2(req, res) {
8886
8976
  // src/commands/sessions/web/fileContent.ts
8887
8977
  import { readFile, stat as stat2 } from "fs/promises";
8888
8978
  import { isAbsolute, relative as relative2, resolve as resolve9 } from "path";
8889
-
8890
- // src/commands/sessions/web/windowsCwdToWslPath.ts
8891
- function windowsCwdToWslPath(cwd) {
8892
- const match = /^([A-Za-z]):[\\/](.*)$/.exec(cwd);
8893
- if (!match) return cwd;
8894
- const drive = match[1].toLowerCase();
8895
- const rest = match[2].replace(/\\/g, "/");
8896
- return `/mnt/${drive}/${rest}`;
8897
- }
8898
-
8899
- // src/commands/sessions/web/toGitCwd.ts
8900
- function toGitCwd(cwd) {
8901
- return detectPlatform() === "wsl" ? windowsCwdToWslPath(cwd) : cwd;
8902
- }
8903
-
8904
- // src/commands/sessions/web/fileContent.ts
8905
8979
  var MAX_FILE_BYTES = 2 * 1024 * 1024;
8906
8980
  function resolveWithinCwd(cwd, path71) {
8907
8981
  const root = resolve9(toGitCwd(cwd));
@@ -9098,13 +9172,44 @@ function githubUrl(req, res) {
9098
9172
  });
9099
9173
  }
9100
9174
 
9175
+ // src/commands/sessions/web/parseDiffNameStatus.ts
9176
+ function categorize(code) {
9177
+ switch (code) {
9178
+ case "A":
9179
+ case "C":
9180
+ return "new";
9181
+ case "D":
9182
+ return "deleted";
9183
+ case "M":
9184
+ case "R":
9185
+ case "T":
9186
+ case "U":
9187
+ return "modified";
9188
+ default:
9189
+ return null;
9190
+ }
9191
+ }
9192
+ function parseDiffNameStatus(output) {
9193
+ const result = { new: [], modified: [], deleted: [] };
9194
+ for (const line of output.split("\n")) {
9195
+ const fields = line.split(" ");
9196
+ const status3 = fields[0];
9197
+ if (!status3 || fields.length < 2) continue;
9198
+ const category = categorize(status3[0]);
9199
+ if (!category) continue;
9200
+ const path71 = fields[fields.length - 1];
9201
+ if (path71) result[category].push(path71);
9202
+ }
9203
+ return result;
9204
+ }
9205
+
9101
9206
  // src/commands/sessions/web/parseGitStatus.ts
9102
9207
  function extractPath(rest) {
9103
9208
  const arrow = rest.indexOf(" -> ");
9104
9209
  return arrow === -1 ? rest : rest.slice(arrow + 4);
9105
9210
  }
9106
9211
  var UNMERGED_STATES = /* @__PURE__ */ new Set(["DD", "AU", "UD", "UA", "DU", "AA", "UU"]);
9107
- function categorize(xy) {
9212
+ function categorize2(xy) {
9108
9213
  if (xy === "??") return "new";
9109
9214
  if (UNMERGED_STATES.has(xy)) return "modified";
9110
9215
  const codes = xy.replace(/ /g, "");
@@ -9119,23 +9224,45 @@ function parseGitStatus(output) {
9119
9224
  const result = { new: [], modified: [], deleted: [] };
9120
9225
  for (const line of output.split("\n")) {
9121
9226
  if (line.length < 4) continue;
9122
- const category = categorize(line.slice(0, 2));
9227
+ const category = categorize2(line.slice(0, 2));
9123
9228
  if (category) result[category].push(extractPath(line.slice(3)));
9124
9229
  }
9125
9230
  return result;
9126
9231
  }
9127
9232
 
9128
9233
  // src/commands/sessions/web/gitStatus.ts
9234
+ async function untrackedPaths(cwd) {
9235
+ const list5 = await execGit(cwd, [
9236
+ "ls-files",
9237
+ "--others",
9238
+ "--exclude-standard"
9239
+ ]);
9240
+ return list5.split("\n").filter(Boolean);
9241
+ }
9242
+ async function branchCounts(cwd, base) {
9243
+ const output = await execGit(cwd, ["diff", "--name-status", base]);
9244
+ const counts = parseDiffNameStatus(output);
9245
+ counts.new.push(...await untrackedPaths(cwd));
9246
+ return counts;
9247
+ }
9248
+ async function workingTreeCounts(cwd) {
9249
+ const output = await execGit(cwd, [
9250
+ "status",
9251
+ "--porcelain",
9252
+ "--untracked-files=all"
9253
+ ]);
9254
+ return parseGitStatus(output);
9255
+ }
9129
9256
  async function gitStatus(req, res) {
9130
9257
  const cwd = getCwdParam(req, res);
9131
9258
  if (!cwd) return;
9132
9259
  try {
9133
- const output = await execGit(cwd, [
9134
- "status",
9135
- "--porcelain",
9136
- "--untracked-files=all"
9137
- ]);
9138
- respondJson(res, 200, parseGitStatus(output));
9260
+ const base = await resolveDiffBase(cwd);
9261
+ respondJson(
9262
+ res,
9263
+ 200,
9264
+ base === "HEAD" ? await workingTreeCounts(cwd) : await branchCounts(cwd, base)
9265
+ );
9139
9266
  } catch {
9140
9267
  respondJson(res, 200, { new: [], modified: [], deleted: [] });
9141
9268
  }
@@ -9146,7 +9273,7 @@ import * as os3 from "os";
9146
9273
  import * as path25 from "path";
9147
9274
 
9148
9275
  // src/shared/checkCliAvailable.ts
9149
- import { execSync as execSync29 } from "child_process";
9276
+ import { execSync as execSync30 } from "child_process";
9150
9277
  function checkCliAvailable(cli) {
9151
9278
  const binary = cli.split(/\s+/)[0];
9152
9279
  const opts = {
@@ -9154,11 +9281,11 @@ function checkCliAvailable(cli) {
9154
9281
  stdio: ["ignore", "pipe", "pipe"]
9155
9282
  };
9156
9283
  try {
9157
- execSync29(`command -v ${binary}`, opts);
9284
+ execSync30(`command -v ${binary}`, opts);
9158
9285
  return true;
9159
9286
  } catch {
9160
9287
  try {
9161
- execSync29(`where ${binary}`, opts);
9288
+ execSync30(`where ${binary}`, opts);
9162
9289
  return true;
9163
9290
  } catch {
9164
9291
  return false;
@@ -9249,8 +9376,8 @@ function subsequenceScore(text17, query) {
9249
9376
  function scoreFilePath(path71, query) {
9250
9377
  const needle = query.trim().toLowerCase();
9251
9378
  if (!needle) return 0;
9252
- const basename18 = path71.slice(path71.lastIndexOf("/") + 1);
9253
- const inBasename = subsequenceScore(basename18, needle);
9379
+ const basename19 = path71.slice(path71.lastIndexOf("/") + 1);
9380
+ const inBasename = subsequenceScore(basename19, needle);
9254
9381
  if (inBasename !== null) return BASENAME_WEIGHT + inBasename;
9255
9382
  return subsequenceScore(path71, needle);
9256
9383
  }
@@ -10561,13 +10688,13 @@ async function beginAssociation(id, options2, clearPatch, label2) {
10561
10688
  }
10562
10689
 
10563
10690
  // src/commands/backlog/associate-github/fetchGithubIssueTitle.ts
10564
- import { execSync as execSync30 } from "child_process";
10691
+ import { execSync as execSync31 } from "child_process";
10565
10692
  function fetchGithubIssueTitle(issue) {
10566
10693
  const match = /^([^/]+)\/([^#]+)#(\d+)$/.exec(issue);
10567
10694
  if (!match) return void 0;
10568
10695
  const [, owner, repo, number] = match;
10569
10696
  try {
10570
- const result = execSync30(
10697
+ const result = execSync31(
10571
10698
  `gh issue view ${number} -R ${owner}/${repo} --json title`,
10572
10699
  { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
10573
10700
  );
@@ -10634,12 +10761,12 @@ import chalk66 from "chalk";
10634
10761
  import { eq as eq19 } from "drizzle-orm";
10635
10762
 
10636
10763
  // src/commands/jira/fetchIssue.ts
10637
- import { execSync as execSync31 } from "child_process";
10764
+ import { execSync as execSync32 } from "child_process";
10638
10765
  import chalk65 from "chalk";
10639
10766
  function fetchIssue(issueKey, fields) {
10640
10767
  let result;
10641
10768
  try {
10642
- result = execSync31(
10769
+ result = execSync32(
10643
10770
  `acli jira workitem view ${issueKey} -f ${fields} --json`,
10644
10771
  { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
10645
10772
  );
@@ -14721,10 +14848,10 @@ function formatResultLine(entry, failing) {
14721
14848
  }
14722
14849
 
14723
14850
  // src/commands/complexity/maintainability/getMaintainabilityGitState.ts
14724
- import { execSync as execSync32 } from "child_process";
14851
+ import { execSync as execSync33 } from "child_process";
14725
14852
  import path28 from "path";
14726
14853
  function git3(command) {
14727
- return execSync32(command, { encoding: "utf8" });
14854
+ return execSync33(command, { encoding: "utf8" });
14728
14855
  }
14729
14856
  function toAbsolute(root, repoRelative) {
14730
14857
  return path28.resolve(root, repoRelative);
@@ -15298,7 +15425,7 @@ function loadBlogSkipDays(repoName) {
15298
15425
  }
15299
15426
 
15300
15427
  // src/commands/devlog/shared.ts
15301
- import { execSync as execSync33 } from "child_process";
15428
+ import { execSync as execSync34 } from "child_process";
15302
15429
  import chalk134 from "chalk";
15303
15430
 
15304
15431
  // src/shared/getRepoName.ts
@@ -15390,7 +15517,7 @@ function loadAllDevlogLatestDates() {
15390
15517
  // src/commands/devlog/shared.ts
15391
15518
  function getCommitFiles(hash) {
15392
15519
  try {
15393
- const output = execSync33(`git show --name-only --format="" ${hash}`, {
15520
+ const output = execSync34(`git show --name-only --format="" ${hash}`, {
15394
15521
  encoding: "utf8"
15395
15522
  });
15396
15523
  return output.trim().split("\n").filter(Boolean);
@@ -15486,11 +15613,11 @@ function list3(options2) {
15486
15613
  }
15487
15614
 
15488
15615
  // src/commands/devlog/getLastVersionInfo.ts
15489
- import { execFileSync as execFileSync4, execSync as execSync34 } from "child_process";
15616
+ import { execFileSync as execFileSync4, execSync as execSync35 } from "child_process";
15490
15617
  import semver from "semver";
15491
15618
  function getVersionAtCommit(hash) {
15492
15619
  try {
15493
- const content = execSync34(`git show ${hash}:package.json`, {
15620
+ const content = execSync35(`git show ${hash}:package.json`, {
15494
15621
  encoding: "utf8"
15495
15622
  });
15496
15623
  const pkg = JSON.parse(content);
@@ -15663,7 +15790,7 @@ function next2(options2) {
15663
15790
  }
15664
15791
 
15665
15792
  // src/commands/devlog/repos/index.ts
15666
- import { execSync as execSync35 } from "child_process";
15793
+ import { execSync as execSync36 } from "child_process";
15667
15794
 
15668
15795
  // src/commands/devlog/repos/printReposTable.ts
15669
15796
  import chalk138 from "chalk";
@@ -15698,7 +15825,7 @@ function getStatus(lastPush, lastDevlog) {
15698
15825
  return lastDevlog < lastPush ? "outdated" : "ok";
15699
15826
  }
15700
15827
  function fetchRepos(days, all) {
15701
- const json = execSync35(
15828
+ const json = execSync36(
15702
15829
  "gh repo list staff0rd --json name,pushedAt,isArchived --limit 200",
15703
15830
  { encoding: "utf8" }
15704
15831
  );
@@ -16078,7 +16205,7 @@ async function deps(csprojPath, options2) {
16078
16205
  }
16079
16206
 
16080
16207
  // src/commands/dotnet/getChangedCsFiles.ts
16081
- import { execSync as execSync36 } from "child_process";
16208
+ import { execSync as execSync37 } from "child_process";
16082
16209
  var SCOPE_ALL = "all";
16083
16210
  var SCOPE_BASE = "base:";
16084
16211
  var SCOPE_COMMIT = "commit:";
@@ -16102,7 +16229,7 @@ function getChangedCsFiles(scope) {
16102
16229
  } else {
16103
16230
  cmd = "git diff --name-only HEAD";
16104
16231
  }
16105
- const output = execSync36(cmd, { encoding: "utf8" }).trim();
16232
+ const output = execSync37(cmd, { encoding: "utf8" }).trim();
16106
16233
  if (output === "") return [];
16107
16234
  return output.split("\n").filter((f) => f.toLowerCase().endsWith(".cs"));
16108
16235
  }
@@ -16300,14 +16427,14 @@ function parseInspectReport(json) {
16300
16427
  }
16301
16428
 
16302
16429
  // src/commands/dotnet/runInspectCode.ts
16303
- import { execSync as execSync37 } from "child_process";
16430
+ import { execSync as execSync38 } from "child_process";
16304
16431
  import { existsSync as existsSync40, readFileSync as readFileSync35, unlinkSync as unlinkSync10 } from "fs";
16305
16432
  import { tmpdir as tmpdir4 } from "os";
16306
16433
  import path35 from "path";
16307
16434
  import chalk148 from "chalk";
16308
16435
  function assertJbInstalled() {
16309
16436
  try {
16310
- execSync37("jb inspectcode --version", { stdio: "pipe" });
16437
+ execSync38("jb inspectcode --version", { stdio: "pipe" });
16311
16438
  } catch {
16312
16439
  console.error(chalk148.red("jb is not installed. Install with:"));
16313
16440
  console.error(
@@ -16321,7 +16448,7 @@ function runInspectCode(slnPath, include, swea) {
16321
16448
  const includeFlag = include ? ` --include="${include}"` : "";
16322
16449
  const sweaFlag = swea ? " --swea" : "";
16323
16450
  try {
16324
- execSync37(
16451
+ execSync38(
16325
16452
  `jb inspectcode "${slnPath}" -o="${reportPath}"${includeFlag}${sweaFlag} --verbosity=OFF`,
16326
16453
  { stdio: "pipe" }
16327
16454
  );
@@ -16342,7 +16469,7 @@ function runInspectCode(slnPath, include, swea) {
16342
16469
  }
16343
16470
 
16344
16471
  // src/commands/dotnet/runRoslynInspect.ts
16345
- import { execSync as execSync38 } from "child_process";
16472
+ import { execSync as execSync39 } from "child_process";
16346
16473
  import chalk149 from "chalk";
16347
16474
  function resolveMsbuildPath() {
16348
16475
  const { run: run4 } = loadConfig();
@@ -16353,7 +16480,7 @@ function resolveMsbuildPath() {
16353
16480
  function assertMsbuildInstalled() {
16354
16481
  const msbuild = resolveMsbuildPath();
16355
16482
  try {
16356
- execSync38(`"${msbuild}" -version`, { stdio: "pipe" });
16483
+ execSync39(`"${msbuild}" -version`, { stdio: "pipe" });
16357
16484
  } catch {
16358
16485
  console.error(chalk149.red(`msbuild not found at: ${msbuild}`));
16359
16486
  console.error(
@@ -16379,7 +16506,7 @@ function runRoslynInspect(slnPath) {
16379
16506
  const msbuild = resolveMsbuildPath();
16380
16507
  let output;
16381
16508
  try {
16382
- output = execSync38(
16509
+ output = execSync39(
16383
16510
  `"${msbuild}" "${slnPath}" -t:Build -v:minimal -maxcpucount -p:EnforceCodeStyleInBuild=true -p:RunAnalyzersDuringBuild=true 2>&1`,
16384
16511
  { encoding: "utf8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
16385
16512
  );
@@ -17226,7 +17353,7 @@ function acceptanceCriteria(issueKey) {
17226
17353
  }
17227
17354
 
17228
17355
  // src/commands/jira/jiraAuth.ts
17229
- import { execSync as execSync39 } from "child_process";
17356
+ import { execSync as execSync40 } from "child_process";
17230
17357
 
17231
17358
  // src/shared/promptInput.ts
17232
17359
  import Enquirer from "enquirer";
@@ -17261,7 +17388,7 @@ async function jiraAuth() {
17261
17388
  console.error("All fields are required.");
17262
17389
  process.exit(1);
17263
17390
  }
17264
- execSync39(`acli jira auth login --site ${site} --email "${email}" --token`, {
17391
+ execSync40(`acli jira auth login --site ${site} --email "${email}" --token`, {
17265
17392
  encoding: "utf8",
17266
17393
  input: token,
17267
17394
  stdio: ["pipe", "inherit", "inherit"]
@@ -17352,71 +17479,434 @@ function registerRefineLaunch(program2, resumeFlag) {
17352
17479
  }
17353
17480
 
17354
17481
  // src/commands/reviewPrComments.ts
17355
- import { execFileSync as execFileSync6 } from "child_process";
17356
17482
  import { randomUUID as randomUUID4 } from "crypto";
17483
+
17484
+ // src/commands/review/checkoutPr.ts
17485
+ import { execFileSync as execFileSync6 } from "child_process";
17357
17486
  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
- }
17487
+
17488
+ // src/commands/sessions/daemon/daemonLog.ts
17489
+ var RING_CAPACITY = 1e3;
17490
+ var ring = [];
17491
+ var sink;
17492
+ function daemonLog(message2) {
17493
+ emit3(`${(/* @__PURE__ */ new Date()).toISOString()} [${process.pid}] ${message2}`);
17494
+ }
17495
+ function relayDaemonLog(line) {
17496
+ emit3(`[windows] ${line}`);
17497
+ }
17498
+ function emit3(line) {
17499
+ console.log(line);
17500
+ ring.push(line);
17501
+ if (ring.length > RING_CAPACITY) ring.shift();
17502
+ sink?.(line);
17503
+ }
17504
+ function setDaemonLogSink(next3) {
17505
+ sink = next3;
17506
+ }
17507
+ function recentDaemonLogLines() {
17508
+ return [...ring];
17509
+ }
17510
+
17511
+ // src/commands/sessions/daemon/worktree/createWorktree.ts
17512
+ import { existsSync as existsSync43 } from "fs";
17513
+ import { basename as basename12, dirname as dirname23 } from "path";
17514
+
17515
+ // src/commands/sessions/daemon/worktree/planAllocation.ts
17516
+ import { basename as basename11, join as join46 } from "path";
17517
+ function planAllocation(clone, boundTreeRoots2) {
17518
+ return boundTreeRoots2.has(clone) ? "spill" : "primary";
17519
+ }
17520
+ function nextWorktreePath(clone, base, isTaken) {
17521
+ const name = basename11(clone);
17522
+ for (let n = 2; n < 1e3; n++) {
17523
+ const candidate = join46(base, `${name}-${n}`);
17524
+ if (!isTaken(candidate)) return candidate;
17366
17525
  }
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;
17526
+ throw new Error(`no free worktree suffix for ${clone}`);
17378
17527
  }
17379
17528
 
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
- );
17529
+ // src/commands/sessions/daemon/worktree/worktreeStartPoint.ts
17530
+ function worktreeStartPoint(clone, trunk) {
17531
+ const branch2 = trunk ? cloneTrunkBranch(clone) : remoteDefaultBranch(clone);
17532
+ const ref = `origin/${branch2}`;
17533
+ if (gitSyncOrNull(clone, ["rev-parse", "--verify", "--quiet", ref]))
17534
+ return { ref, track: trunk };
17535
+ return { ref: "HEAD", track: false };
17386
17536
  }
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);
17537
+ function cloneTrunkBranch(clone) {
17538
+ return cloneHead(clone) ?? remoteDefaultBranch(clone);
17399
17539
  }
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));
17540
+ function remoteDefaultBranch(clone) {
17541
+ const head = gitSyncOrNull(clone, [
17542
+ "symbolic-ref",
17543
+ "--short",
17544
+ "refs/remotes/origin/HEAD"
17545
+ ]);
17546
+ if (!head) return cloneHead(clone) ?? "main";
17547
+ const slash = head.indexOf("/");
17548
+ return slash === -1 ? head : head.slice(slash + 1);
17402
17549
  }
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"
17550
+ function cloneHead(clone) {
17551
+ return gitSyncOrNull(clone, ["symbolic-ref", "--short", "HEAD"]);
17552
+ }
17553
+
17554
+ // src/commands/sessions/daemon/worktree/createWorktree.ts
17555
+ function createWorktree(clone, strategy, boundTreeRoots2) {
17556
+ const base = strategy.root ? expandTilde2(strategy.root) : dirname23(clone);
17557
+ const registered = new Set(listWorktreePaths(clone));
17558
+ const branches = new Set(listLocalBranches(clone));
17559
+ const path71 = nextWorktreePath(
17560
+ clone,
17561
+ base,
17562
+ (candidate) => registered.has(candidate) || existsSync43(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename12(candidate))
17411
17563
  );
17412
- registerDescriptionLaunch(
17413
- program2,
17414
- "bug",
17415
- "bug",
17416
- "Launch Claude in /bug mode, chain into next on /next signal"
17564
+ const start3 = worktreeStartPoint(clone, strategy.trunk);
17565
+ gitSync(clone, [
17566
+ "worktree",
17567
+ "add",
17568
+ start3.track ? "--track" : "--no-track",
17569
+ "-b",
17570
+ basename12(path71),
17571
+ path71,
17572
+ start3.ref
17573
+ ]);
17574
+ recordWorktree(path71, clone, getCurrentOrigin(clone));
17575
+ daemonLog(
17576
+ 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}`
17417
17577
  );
17418
- registerReviewPrComments(program2);
17419
- registerRefineLaunch(program2, RESUME_SESSION_FLAG);
17578
+ return path71;
17579
+ }
17580
+
17581
+ // src/commands/sessions/daemon/worktree/treeDurability.ts
17582
+ import { existsSync as existsSync44 } from "fs";
17583
+ function treeDurability(state) {
17584
+ if (state.dirty) return { durable: false, reason: "uncommitted changes" };
17585
+ if (state.localOnlyCommits)
17586
+ return { durable: false, reason: "unpushed commits" };
17587
+ return { durable: true };
17588
+ }
17589
+ function* durabilityProbes() {
17590
+ const status3 = yield ["status", "--porcelain"];
17591
+ if (!status3.ok)
17592
+ return { durable: false, reason: `tree state unreadable: ${status3.error}` };
17593
+ const upstream = yield [
17594
+ "rev-parse",
17595
+ "--abbrev-ref",
17596
+ "--symbolic-full-name",
17597
+ "@{upstream}"
17598
+ ];
17599
+ let localOnlyCommits;
17600
+ if (upstream.ok && upstream.out) {
17601
+ const ahead = yield ["rev-list", "--count", "@{upstream}..HEAD"];
17602
+ localOnlyCommits = !ahead.ok || Number(ahead.out) > 0;
17603
+ } else {
17604
+ const remoteBranches = yield ["branch", "-r", "--contains", "HEAD"];
17605
+ localOnlyCommits = !remoteBranches.ok || remoteBranches.out === "";
17606
+ }
17607
+ return treeDurability({ dirty: status3.out !== "", localOnlyCommits });
17608
+ }
17609
+ async function checkDurability(cwd) {
17610
+ if (!existsSync44(cwd)) return { durable: true };
17611
+ const probes = durabilityProbes();
17612
+ let step = probes.next();
17613
+ while (!step.done) step = probes.next(await gitResult(cwd, step.value));
17614
+ return step.value;
17615
+ }
17616
+ function checkDurabilitySync(cwd) {
17617
+ if (!existsSync44(cwd)) return { durable: true };
17618
+ const probes = durabilityProbes();
17619
+ let step = probes.next();
17620
+ while (!step.done) step = probes.next(gitSyncResult(cwd, step.value));
17621
+ return step.value;
17622
+ }
17623
+
17624
+ // src/commands/sessions/daemon/worktree/worktreeConfigFor.ts
17625
+ var DISABLED = {
17626
+ enabled: false,
17627
+ trunk: false,
17628
+ install: true,
17629
+ commitBeforeManualChecks: false,
17630
+ copy: [".env", "settings.local.json", ".claude/settings.local.json"]
17631
+ };
17632
+ function worktreeConfigFor(cwd) {
17633
+ try {
17634
+ return loadConfigFrom(cwd).worktree ?? DISABLED;
17635
+ } catch {
17636
+ return DISABLED;
17637
+ }
17638
+ }
17639
+
17640
+ // src/commands/sessions/daemon/worktree/allocateTree.ts
17641
+ function allocateTree(requestedCwd, boundTreeRoots2, options2 = {}) {
17642
+ if (!requestedCwd)
17643
+ return { cwd: requestedCwd, kind: "primary", created: false };
17644
+ const repoRoot = findRepoRoot(requestedCwd) ?? requestedCwd;
17645
+ const cfg = worktreeConfigFor(repoRoot);
17646
+ if (!cfg.enabled)
17647
+ return { cwd: requestedCwd, kind: "primary", created: false };
17648
+ const clone = mainWorktree(repoRoot) ?? repoRoot;
17649
+ if (planAllocation(clone, boundTreeRoots2) === "primary" && !wouldDisturbWorkInProgress(clone, options2.forCheckout === true))
17650
+ return { cwd: clone, kind: "primary", created: false, clone };
17651
+ const path71 = createWorktree(
17652
+ clone,
17653
+ { root: cfg.root, trunk: cfg.trunk },
17654
+ boundTreeRoots2
17655
+ );
17656
+ return { cwd: path71, kind: "worktree", created: true, clone };
17657
+ }
17658
+ function wouldDisturbWorkInProgress(clone, forCheckout) {
17659
+ if (!forCheckout) return false;
17660
+ const durability = checkDurabilitySync(clone);
17661
+ if (durability.durable) return false;
17662
+ daemonLog(
17663
+ `tree ${clone} not used for a PR checkout: ${durability.reason} \u2014 spilling to a worktree`
17664
+ );
17665
+ return true;
17666
+ }
17667
+
17668
+ // src/commands/sessions/daemon/persistedSessionSchema.ts
17669
+ import { z as z6 } from "zod";
17670
+ var persistedSessionSchema = z6.object({
17671
+ name: z6.string(),
17672
+ title: z6.string().optional(),
17673
+ subtitle: z6.string().optional(),
17674
+ commandType: z6.enum(["claude", "run", "assist"]),
17675
+ harness: z6.enum(["claude", "codex", "pi"]).optional(),
17676
+ status: z6.enum(["running", "waiting", "done", "error", "stopped"]).optional(),
17677
+ cwd: z6.string(),
17678
+ startedAt: z6.number(),
17679
+ runningMs: z6.number().optional(),
17680
+ claudeSessionId: z6.string().optional(),
17681
+ initialPrompt: z6.string().optional(),
17682
+ runName: z6.string().optional(),
17683
+ runArgs: z6.array(z6.string()).optional(),
17684
+ assistArgs: z6.array(z6.string()).optional(),
17685
+ activity: activitySchema.optional(),
17686
+ starred: z6.boolean().optional(),
17687
+ undurable: z6.object({ reason: z6.string(), removesTree: z6.boolean().optional() }).optional()
17688
+ });
17689
+
17690
+ // src/commands/sessions/daemon/toPersistedSession.ts
17691
+ function toPersistedSession(session) {
17692
+ return {
17693
+ name: session.name,
17694
+ title: session.title,
17695
+ subtitle: session.subtitle,
17696
+ commandType: session.commandType,
17697
+ harness: session.harness,
17698
+ status: session.status,
17699
+ cwd: session.cwd ?? process.cwd(),
17700
+ startedAt: session.startedAt,
17701
+ runningMs: accumulatedRunningMs(session),
17702
+ claudeSessionId: session.claudeSessionId,
17703
+ initialPrompt: session.initialPrompt,
17704
+ runName: session.runName,
17705
+ runArgs: session.runArgs,
17706
+ assistArgs: session.assistArgs,
17707
+ activity: session.activity,
17708
+ starred: session.starred,
17709
+ undurable: session.undurable
17710
+ };
17711
+ }
17712
+ function accumulatedRunningMs(session) {
17713
+ return session.runningSince != null ? session.runningMs + Date.now() - session.runningSince : session.runningMs;
17714
+ }
17715
+
17716
+ // src/commands/sessions/daemon/loadPersistedSessions.ts
17717
+ var SESSIONS_FILE = "sessions.json";
17718
+ function loadPersistedSessions() {
17719
+ const data = loadJson(SESSIONS_FILE);
17720
+ if (!Array.isArray(data)) return [];
17721
+ return data.flatMap((entry) => {
17722
+ const parsed = persistedSessionSchema.safeParse(entry);
17723
+ return parsed.success ? [parsed.data] : [];
17724
+ });
17725
+ }
17726
+ function savePersistedSessions(sessions) {
17727
+ saveJson(SESSIONS_FILE, sessions);
17728
+ }
17729
+ function persistLiveSessions(sessions) {
17730
+ const live = [...sessions.values()].filter(
17731
+ (s) => (s.pty || s.status === "stopped") && s.status !== "done"
17732
+ );
17733
+ savePersistedSessions(live.map(toPersistedSession));
17734
+ logPersist(live);
17735
+ }
17736
+ var lastPersistSignature = "";
17737
+ function logPersist(live) {
17738
+ const signature = live.map((s) => `${s.id}:${s.status}`).join(",");
17739
+ if (signature === lastPersistSignature) return;
17740
+ lastPersistSignature = signature;
17741
+ daemonLog(
17742
+ live.length > 0 ? `persisted ${live.length} session(s): ${live.map((s) => s.name).join(", ")}` : "persisted 0 sessions (sessions.json cleared)"
17743
+ );
17744
+ }
17745
+
17746
+ // src/commands/sessions/daemon/worktree/persistedTreeRoots.ts
17747
+ function persistedTreeRoots() {
17748
+ const roots = /* @__PURE__ */ new Set();
17749
+ for (const { cwd } of loadPersistedSessions()) {
17750
+ if (cwd) roots.add(findRepoRoot(cwd) ?? cwd);
17751
+ }
17752
+ return roots;
17753
+ }
17754
+
17755
+ // src/commands/sessions/daemon/worktree/seedWorktree.ts
17756
+ import { execFile as execFile8 } from "child_process";
17757
+ import { copyFileSync, existsSync as existsSync46, mkdirSync as mkdirSync16 } from "fs";
17758
+ import { dirname as dirname24, join as join48 } from "path";
17759
+
17760
+ // src/commands/sessions/daemon/worktree/resolveInstallCommand.ts
17761
+ import { existsSync as existsSync45 } from "fs";
17762
+ import { join as join47 } from "path";
17763
+ function detectInstallCommand(repoRoot) {
17764
+ if (!existsSync45(join47(repoRoot, "package.json"))) return null;
17765
+ if (existsSync45(join47(repoRoot, "pnpm-lock.yaml"))) return "pnpm install";
17766
+ if (existsSync45(join47(repoRoot, "yarn.lock"))) return "yarn install";
17767
+ if (existsSync45(join47(repoRoot, "bun.lockb"))) return "bun install";
17768
+ return "npm install";
17769
+ }
17770
+ function resolveInstallCommand(repoRoot, install) {
17771
+ if (install === false) return null;
17772
+ if (typeof install === "string") return install;
17773
+ return detectInstallCommand(repoRoot);
17774
+ }
17775
+
17776
+ // src/commands/sessions/daemon/worktree/seedWorktree.ts
17777
+ function seedWorktree(worktreePath, clone, onSeeded = () => {
17778
+ }) {
17779
+ const cfg = worktreeConfigFor(clone);
17780
+ copyConfigFiles(worktreePath, clone, cfg.copy);
17781
+ runInstall(worktreePath, clone, cfg.install, onSeeded);
17782
+ }
17783
+ function copyConfigFiles(worktreePath, clone, copy) {
17784
+ for (const rel of copy) {
17785
+ const src = join48(clone, rel);
17786
+ if (!existsSync46(src)) continue;
17787
+ const dest = join48(worktreePath, rel);
17788
+ try {
17789
+ mkdirSync16(dirname24(dest), { recursive: true });
17790
+ copyFileSync(src, dest);
17791
+ daemonLog(`worktree ${worktreePath} seeded ${rel}`);
17792
+ } catch (error) {
17793
+ daemonLog(
17794
+ `worktree ${worktreePath} failed to seed ${rel}: ${message(error)}`
17795
+ );
17796
+ }
17797
+ }
17798
+ }
17799
+ function runInstall(worktreePath, clone, install, onSeeded) {
17800
+ const command = resolveInstallCommand(clone, install);
17801
+ if (!command) {
17802
+ onSeeded();
17803
+ return;
17804
+ }
17805
+ const windows = /^[A-Za-z]:[\\/]/.test(worktreePath);
17806
+ const shell = windows ? "cmd.exe" : process.env.SHELL ?? "bash";
17807
+ const shellArgs = windows ? ["/c", command] : ["-l", "-c", command];
17808
+ daemonLog(`worktree ${worktreePath} installing deps: ${command}`);
17809
+ execFile8(shell, shellArgs, { cwd: worktreePath }, (error) => {
17810
+ daemonLog(
17811
+ error ? `worktree ${worktreePath} install failed: ${error.message}` : `worktree ${worktreePath} install complete`
17812
+ );
17813
+ onSeeded();
17814
+ });
17815
+ }
17816
+ function message(error) {
17817
+ return error instanceof Error ? error.message : String(error);
17818
+ }
17819
+
17820
+ // src/commands/review/moveToPrCheckoutTree.ts
17821
+ function placedByDaemon() {
17822
+ return process.env.ASSIST_SESSION === "1";
17823
+ }
17824
+ function seed(worktreePath, clone) {
17825
+ console.log(`Preparing ${worktreePath}\u2026`);
17826
+ return new Promise(
17827
+ (resolve20) => seedWorktree(worktreePath, clone, resolve20)
17828
+ );
17829
+ }
17830
+ async function moveToPrCheckoutTree() {
17831
+ if (placedByDaemon()) return;
17832
+ const from = process.cwd();
17833
+ const alloc = allocateTree(from, persistedTreeRoots(), {
17834
+ forCheckout: true
17835
+ });
17836
+ if (!alloc.cwd || alloc.cwd === from) return;
17837
+ process.chdir(alloc.cwd);
17838
+ console.log(`Checking the PR out in ${alloc.cwd}`);
17839
+ appendDaemonLog(`pr checkout placed in ${alloc.cwd} (invoked from ${from})`);
17840
+ if (alloc.created && alloc.clone) await seed(alloc.cwd, alloc.clone);
17841
+ }
17842
+
17843
+ // src/commands/review/checkoutPr.ts
17844
+ async function checkoutPr(number) {
17845
+ await moveToPrCheckoutTree();
17846
+ try {
17847
+ execFileSync6("gh", ["pr", "checkout", number], { stdio: "inherit" });
17848
+ } catch {
17849
+ console.error(chalk155.red(`gh pr checkout ${number} failed; aborting.`));
17850
+ process.exit(1);
17851
+ }
17852
+ }
17853
+
17854
+ // src/commands/reviewPrComments.ts
17855
+ async function reviewPrComments(number) {
17856
+ if (number) await checkoutPr(number);
17857
+ const claudeSessionId = randomUUID4();
17858
+ emitActivity({
17859
+ kind: "command",
17860
+ name: "review-pr-comments",
17861
+ claudeSessionId
17862
+ });
17863
+ const { done: done2 } = spawnClaude("/review-pr-comments", {
17864
+ permissionMode: "acceptEdits",
17865
+ sessionId: claudeSessionId
17866
+ });
17867
+ await done2;
17868
+ }
17869
+
17870
+ // src/commands/registerLaunch.ts
17871
+ var RESUME_SESSION_FLAG = "Resume an interrupted Claude session (used by the sessions daemon on restart)";
17872
+ function registerNext(program2) {
17873
+ 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(
17874
+ (id, opts) => next({ allowEdits: true, once: opts.once }, id)
17875
+ );
17876
+ }
17877
+ function registerDescriptionLaunch(program2, name, slashCommand, description, alias) {
17878
+ const command = program2.command(name).argument(
17879
+ "[description]",
17880
+ `Text to forward to the /${slashCommand} slash command`
17881
+ ).description(description).option("--once", "Exit when the initial task completes").option("--resume-session <id>", RESUME_SESSION_FLAG).action(
17882
+ (text17, opts) => launchMode(slashCommand, {
17883
+ once: opts.once,
17884
+ description: text17,
17885
+ resumeSessionId: opts.resumeSession
17886
+ })
17887
+ );
17888
+ if (alias) command.alias(alias);
17889
+ }
17890
+ function registerReviewPrComments(program2) {
17891
+ 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));
17892
+ }
17893
+ function registerLaunch(program2) {
17894
+ registerNext(program2);
17895
+ registerDescriptionLaunch(
17896
+ program2,
17897
+ "draft",
17898
+ "draft",
17899
+ "Launch Claude in /draft mode, chain into next on /next signal",
17900
+ "feat"
17901
+ );
17902
+ registerDescriptionLaunch(
17903
+ program2,
17904
+ "bug",
17905
+ "bug",
17906
+ "Launch Claude in /bug mode, chain into next on /next signal"
17907
+ );
17908
+ registerReviewPrComments(program2);
17909
+ registerRefineLaunch(program2, RESUME_SESSION_FLAG);
17420
17910
  }
17421
17911
 
17422
17912
  // src/commands/registerList.ts
@@ -17431,13 +17921,13 @@ function registerList(program2) {
17431
17921
  }
17432
17922
 
17433
17923
  // src/commands/mermaid/index.ts
17434
- import { mkdirSync as mkdirSync16, readdirSync as readdirSync9 } from "fs";
17924
+ import { mkdirSync as mkdirSync17, readdirSync as readdirSync9 } from "fs";
17435
17925
  import { resolve as resolve13 } from "path";
17436
17926
  import chalk158 from "chalk";
17437
17927
 
17438
17928
  // src/commands/mermaid/exportFile.ts
17439
17929
  import { readFileSync as readFileSync37, writeFileSync as writeFileSync31 } from "fs";
17440
- import { basename as basename11, extname as extname2, resolve as resolve12 } from "path";
17930
+ import { basename as basename13, extname as extname2, resolve as resolve12 } from "path";
17441
17931
  import chalk157 from "chalk";
17442
17932
 
17443
17933
  // src/commands/mermaid/renderBlock.ts
@@ -17464,7 +17954,7 @@ async function renderBlock(krokiUrl, source) {
17464
17954
  async function exportFile(file, outDir, krokiUrl, onlyIndex) {
17465
17955
  const content = readFileSync37(file, "utf8");
17466
17956
  const blocks = extractMermaidBlocks(content);
17467
- const stem = basename11(file, extname2(file));
17957
+ const stem = basename13(file, extname2(file));
17468
17958
  if (onlyIndex !== void 0) {
17469
17959
  if (onlyIndex < 1 || onlyIndex > blocks.length) {
17470
17960
  console.error(
@@ -17500,7 +17990,7 @@ function extractMermaidBlocks(markdown) {
17500
17990
  async function mermaidExport(file, options2 = {}) {
17501
17991
  const { mermaid } = loadConfig();
17502
17992
  const outDir = resolve13(process.cwd(), options2.out ?? ".");
17503
- mkdirSync16(outDir, { recursive: true });
17993
+ mkdirSync17(outDir, { recursive: true });
17504
17994
  if (options2.index !== void 0) {
17505
17995
  if (!Number.isInteger(options2.index) || options2.index < 1) {
17506
17996
  console.error(
@@ -17547,7 +18037,7 @@ function registerMermaid(program2) {
17547
18037
  // src/commands/netcap/netcap.ts
17548
18038
  import { mkdir as mkdir4 } from "fs/promises";
17549
18039
  import { createServer as createServer2 } from "http";
17550
- import { dirname as dirname24 } from "path";
18040
+ import { dirname as dirname26 } from "path";
17551
18041
  import chalk160 from "chalk";
17552
18042
 
17553
18043
  // src/commands/netcap/corsHeaders.ts
@@ -17626,15 +18116,15 @@ function createNetcapHandler(options2) {
17626
18116
  // src/commands/netcap/prepareExtensionForLoad.ts
17627
18117
  import { cp, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
17628
18118
  import { networkInterfaces } from "os";
17629
- import { join as join47 } from "path";
18119
+ import { join as join50 } from "path";
17630
18120
  import chalk159 from "chalk";
17631
18121
 
17632
18122
  // src/commands/netcap/netcapExtensionDir.ts
17633
- import { dirname as dirname23, join as join46 } from "path";
18123
+ import { dirname as dirname25, join as join49 } from "path";
17634
18124
  import { fileURLToPath as fileURLToPath6 } from "url";
17635
- var moduleDir = dirname23(fileURLToPath6(import.meta.url));
18125
+ var moduleDir = dirname25(fileURLToPath6(import.meta.url));
17636
18126
  function netcapExtensionDir() {
17637
- return join46(moduleDir, "commands", "netcap", "netcap-extension");
18127
+ return join49(moduleDir, "commands", "netcap", "netcap-extension");
17638
18128
  }
17639
18129
 
17640
18130
  // src/commands/netcap/prepareExtensionForLoad.ts
@@ -17649,7 +18139,7 @@ function lanIPv4() {
17649
18139
  return void 0;
17650
18140
  }
17651
18141
  async function configureBackground(dir, host, port, filter) {
17652
- const file = join47(dir, "background.js");
18142
+ const file = join50(dir, "background.js");
17653
18143
  const source = await readFile3(file, "utf8");
17654
18144
  await writeFile3(
17655
18145
  file,
@@ -17689,20 +18179,20 @@ async function prepareExtensionForLoad(port, filter = "") {
17689
18179
  }
17690
18180
 
17691
18181
  // src/commands/netcap/resolveNetcapOutPath.ts
17692
- import { isAbsolute as isAbsolute2, join as join49, resolve as resolve14 } from "path";
18182
+ import { isAbsolute as isAbsolute2, join as join52, resolve as resolve14 } from "path";
17693
18183
 
17694
18184
  // src/commands/netcap/defaultCapturePath.ts
17695
18185
  import { homedir as homedir19 } from "os";
17696
- import { join as join48 } from "path";
18186
+ import { join as join51 } from "path";
17697
18187
  function defaultCapturePath() {
17698
- return join48(homedir19(), ".assist", "netcap", "capture.jsonl");
18188
+ return join51(homedir19(), ".assist", "netcap", "capture.jsonl");
17699
18189
  }
17700
18190
 
17701
18191
  // src/commands/netcap/resolveNetcapOutPath.ts
17702
18192
  function resolveNetcapOutPath(out) {
17703
18193
  if (!out) return defaultCapturePath();
17704
18194
  const dir = isAbsolute2(out) ? out : resolve14(process.cwd(), out);
17705
- return join49(dir, "capture.jsonl");
18195
+ return join52(dir, "capture.jsonl");
17706
18196
  }
17707
18197
 
17708
18198
  // src/commands/netcap/netcap.ts
@@ -17710,7 +18200,7 @@ async function netcap(options2) {
17710
18200
  const port = Number(options2.port);
17711
18201
  const outPath = resolveNetcapOutPath(options2.out);
17712
18202
  const filter = options2.filter ?? "";
17713
- await mkdir4(dirname24(outPath), { recursive: true });
18203
+ await mkdir4(dirname26(outPath), { recursive: true });
17714
18204
  const extensionPath = await prepareExtensionForLoad(port, filter);
17715
18205
  let count7 = 0;
17716
18206
  const handler = createNetcapHandler({
@@ -17749,7 +18239,7 @@ netcap stopped \u2014 captured ${count7} ${count7 === 1 ? "entry" : "entries"} t
17749
18239
 
17750
18240
  // src/commands/netcap/netcapExtract.ts
17751
18241
  import { writeFileSync as writeFileSync32 } from "fs";
17752
- import { join as join50 } from "path";
18242
+ import { join as join53 } from "path";
17753
18243
  import chalk161 from "chalk";
17754
18244
 
17755
18245
  // src/commands/netcap/extractPostsFromCapture.ts
@@ -18194,7 +18684,7 @@ function extractPostsFromCapture(captureFile) {
18194
18684
  function netcapExtract(file) {
18195
18685
  const captureFile = file ?? defaultCapturePath();
18196
18686
  const posts = extractPostsFromCapture(captureFile);
18197
- const outFile = join50(captureFile, "..", "posts.json");
18687
+ const outFile = join53(captureFile, "..", "posts.json");
18198
18688
  writeFileSync32(outFile, `${JSON.stringify(posts, null, 2)}
18199
18689
  `);
18200
18690
  console.log(
@@ -18346,7 +18836,7 @@ function registerPrompts(program2) {
18346
18836
  }
18347
18837
 
18348
18838
  // src/commands/prs/shared.ts
18349
- import { execSync as execSync40 } from "child_process";
18839
+ import { execSync as execSync41 } from "child_process";
18350
18840
  function isGhNotInstalled(error) {
18351
18841
  if (error instanceof Error) {
18352
18842
  const msg = error.message.toLowerCase();
@@ -18364,12 +18854,12 @@ function getRepoInfo() {
18364
18854
  const preferred = getPreferredRemoteRepo();
18365
18855
  if (preferred) return preferred;
18366
18856
  const repoInfo = JSON.parse(
18367
- execSync40("gh repo view --json owner,name", { encoding: "utf8" })
18857
+ execSync41("gh repo view --json owner,name", { encoding: "utf8" })
18368
18858
  );
18369
18859
  return { org: repoInfo.owner.login, repo: repoInfo.name };
18370
18860
  }
18371
18861
  function getCurrentBranch2() {
18372
- return execSync40("git rev-parse --abbrev-ref HEAD", {
18862
+ return execSync41("git rev-parse --abbrev-ref HEAD", {
18373
18863
  encoding: "utf8"
18374
18864
  }).trim();
18375
18865
  }
@@ -18377,7 +18867,7 @@ function viewCurrentPr(fields) {
18377
18867
  const { org, repo } = getRepoInfo();
18378
18868
  const branch2 = getCurrentBranch2();
18379
18869
  return JSON.parse(
18380
- execSync40(`gh pr view ${branch2} --json ${fields} -R ${org}/${repo}`, {
18870
+ execSync41(`gh pr view ${branch2} --json ${fields} -R ${org}/${repo}`, {
18381
18871
  encoding: "utf8"
18382
18872
  })
18383
18873
  );
@@ -18679,24 +19169,24 @@ function edit(options2) {
18679
19169
  }
18680
19170
 
18681
19171
  // src/commands/prs/fixed.ts
18682
- import { execSync as execSync43 } from "child_process";
19172
+ import { execSync as execSync44 } from "child_process";
18683
19173
 
18684
19174
  // src/commands/prs/resolveCommentWithReply.ts
18685
- import { execSync as execSync42 } from "child_process";
19175
+ import { execSync as execSync43 } from "child_process";
18686
19176
  import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync33 } from "fs";
18687
19177
  import { tmpdir as tmpdir6 } from "os";
18688
- import { join as join52 } from "path";
19178
+ import { join as join55 } from "path";
18689
19179
 
18690
19180
  // 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";
19181
+ import { existsSync as existsSync47, readFileSync as readFileSync39, unlinkSync as unlinkSync13 } from "fs";
19182
+ import { join as join54 } from "path";
18693
19183
  import { parse as parse2 } from "yaml";
18694
19184
  function getCachePath(prNumber) {
18695
- return join51(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
19185
+ return join54(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
18696
19186
  }
18697
19187
  function loadCommentsCache(prNumber) {
18698
19188
  const cachePath = getCachePath(prNumber);
18699
- if (!existsSync43(cachePath)) {
19189
+ if (!existsSync47(cachePath)) {
18700
19190
  return null;
18701
19191
  }
18702
19192
  const content = readFileSync39(cachePath, "utf8");
@@ -18704,16 +19194,16 @@ function loadCommentsCache(prNumber) {
18704
19194
  }
18705
19195
  function deleteCommentsCache(prNumber) {
18706
19196
  const cachePath = getCachePath(prNumber);
18707
- if (existsSync43(cachePath)) {
19197
+ if (existsSync47(cachePath)) {
18708
19198
  unlinkSync13(cachePath);
18709
19199
  console.log("No more unresolved line comments. Cache dropped.");
18710
19200
  }
18711
19201
  }
18712
19202
 
18713
19203
  // src/commands/prs/replyToComment.ts
18714
- import { execSync as execSync41 } from "child_process";
19204
+ import { execSync as execSync42 } from "child_process";
18715
19205
  function replyToComment(org, repo, prNumber, commentId, message2) {
18716
- execSync41(
19206
+ execSync42(
18717
19207
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message2.replace(/"/g, String.raw`\"`)}" -F in_reply_to=${commentId}`,
18718
19208
  { stdio: ["inherit", "pipe", "inherit"] }
18719
19209
  );
@@ -18722,10 +19212,10 @@ function replyToComment(org, repo, prNumber, commentId, message2) {
18722
19212
  // src/commands/prs/resolveCommentWithReply.ts
18723
19213
  function resolveThread(threadId) {
18724
19214
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
18725
- const queryFile = join52(tmpdir6(), `gh-mutation-${Date.now()}.graphql`);
19215
+ const queryFile = join55(tmpdir6(), `gh-mutation-${Date.now()}.graphql`);
18726
19216
  writeFileSync33(queryFile, mutation);
18727
19217
  try {
18728
- execSync42(
19218
+ execSync43(
18729
19219
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
18730
19220
  { stdio: ["inherit", "pipe", "inherit"] }
18731
19221
  );
@@ -18777,7 +19267,7 @@ function resolveCommentWithReply(commentId, message2) {
18777
19267
  // src/commands/prs/fixed.ts
18778
19268
  function verifySha(sha) {
18779
19269
  try {
18780
- return execSync43(`git rev-parse --verify ${sha}`, {
19270
+ return execSync44(`git rev-parse --verify ${sha}`, {
18781
19271
  encoding: "utf8"
18782
19272
  }).trim();
18783
19273
  } catch {
@@ -18791,7 +19281,7 @@ function fixed(commentId, sha) {
18791
19281
  const { org, repo } = getRepoInfo();
18792
19282
  const repoUrl = `https://github.com/${org}/${repo}`;
18793
19283
  const message2 = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
18794
- execSync43("git push", { stdio: "inherit" });
19284
+ pushCommit();
18795
19285
  resolveCommentWithReply(commentId, message2);
18796
19286
  } catch (error) {
18797
19287
  if (isGhNotInstalled(error)) {
@@ -18804,21 +19294,21 @@ function fixed(commentId, sha) {
18804
19294
  }
18805
19295
 
18806
19296
  // 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";
19297
+ import { existsSync as existsSync48, mkdirSync as mkdirSync18, writeFileSync as writeFileSync35 } from "fs";
19298
+ import { join as join57 } from "path";
18809
19299
  import { stringify } from "yaml";
18810
19300
 
18811
19301
  // src/commands/prs/fetchThreadIds.ts
18812
- import { execSync as execSync44 } from "child_process";
19302
+ import { execSync as execSync45 } from "child_process";
18813
19303
  import { unlinkSync as unlinkSync15, writeFileSync as writeFileSync34 } from "fs";
18814
19304
  import { tmpdir as tmpdir7 } from "os";
18815
- import { join as join53 } from "path";
19305
+ import { join as join56 } from "path";
18816
19306
  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
19307
  function fetchThreadIds(org, repo, prNumber) {
18818
- const queryFile = join53(tmpdir7(), `gh-query-${Date.now()}.graphql`);
19308
+ const queryFile = join56(tmpdir7(), `gh-query-${Date.now()}.graphql`);
18819
19309
  writeFileSync34(queryFile, THREAD_QUERY);
18820
19310
  try {
18821
- const result = execSync44(
19311
+ const result = execSync45(
18822
19312
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
18823
19313
  { encoding: "utf8" }
18824
19314
  );
@@ -18840,9 +19330,9 @@ function fetchThreadIds(org, repo, prNumber) {
18840
19330
  }
18841
19331
 
18842
19332
  // src/commands/prs/listComments/fetchReviewComments.ts
18843
- import { execSync as execSync45 } from "child_process";
19333
+ import { execSync as execSync46 } from "child_process";
18844
19334
  function fetchJson(endpoint) {
18845
- const result = execSync45(`gh api --paginate ${endpoint}`, {
19335
+ const result = execSync46(`gh api --paginate ${endpoint}`, {
18846
19336
  encoding: "utf8"
18847
19337
  });
18848
19338
  if (!result.trim()) return [];
@@ -18929,16 +19419,16 @@ function printComments2(result) {
18929
19419
 
18930
19420
  // src/commands/prs/listComments/index.ts
18931
19421
  function writeCommentsCache(prNumber, comments3) {
18932
- const assistDir = join54(process.cwd(), ".assist");
18933
- if (!existsSync44(assistDir)) {
18934
- mkdirSync17(assistDir, { recursive: true });
19422
+ const assistDir = join57(process.cwd(), ".assist");
19423
+ if (!existsSync48(assistDir)) {
19424
+ mkdirSync18(assistDir, { recursive: true });
18935
19425
  }
18936
19426
  const cacheData = {
18937
19427
  prNumber,
18938
19428
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
18939
19429
  comments: comments3
18940
19430
  };
18941
- const cachePath = join54(assistDir, `pr-${prNumber}-comments.yaml`);
19431
+ const cachePath = join57(assistDir, `pr-${prNumber}-comments.yaml`);
18942
19432
  writeFileSync35(cachePath, stringify(cacheData));
18943
19433
  }
18944
19434
  function handleKnownErrors(error) {
@@ -18971,7 +19461,7 @@ async function listComments() {
18971
19461
  ];
18972
19462
  updateCache(prNumber, allComments);
18973
19463
  const hasLineComments = allComments.some((c) => c.type === "line");
18974
- const cachePath = hasLineComments ? join54(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
19464
+ const cachePath = hasLineComments ? join57(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
18975
19465
  return { comments: allComments, cachePath };
18976
19466
  } catch (error) {
18977
19467
  const handled = handleKnownErrors(error);
@@ -18981,7 +19471,7 @@ async function listComments() {
18981
19471
  }
18982
19472
 
18983
19473
  // src/commands/prs/prs/index.ts
18984
- import { execSync as execSync46 } from "child_process";
19474
+ import { execSync as execSync47 } from "child_process";
18985
19475
 
18986
19476
  // src/commands/prs/prs/displayPaginated/index.ts
18987
19477
  import enquirer9 from "enquirer";
@@ -19088,7 +19578,7 @@ async function prs(options2) {
19088
19578
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
19089
19579
  try {
19090
19580
  const { org, repo } = getRepoInfo();
19091
- const result = execSync46(
19581
+ const result = execSync47(
19092
19582
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100 -R ${org}/${repo}`,
19093
19583
  { encoding: "utf8" }
19094
19584
  );
@@ -19159,16 +19649,16 @@ function buildCreateArgs(title, body, options2) {
19159
19649
  }
19160
19650
 
19161
19651
  // src/commands/prs/readSessionPrRef.ts
19162
- import { execSync as execSync47 } from "child_process";
19652
+ import { execSync as execSync48 } from "child_process";
19163
19653
  function readSessionPrRef() {
19164
19654
  try {
19165
- const branch2 = execSync47("git rev-parse --abbrev-ref HEAD", {
19655
+ const branch2 = execSync48("git rev-parse --abbrev-ref HEAD", {
19166
19656
  encoding: "utf8",
19167
19657
  stdio: ["pipe", "pipe", "pipe"]
19168
19658
  }).trim();
19169
19659
  if (!branch2 || branch2 === "HEAD") return null;
19170
19660
  const pr = JSON.parse(
19171
- execSync47(`gh pr view ${branch2} --json number,title,url,state`, {
19661
+ execSync48(`gh pr view ${branch2} --json number,title,url,state`, {
19172
19662
  encoding: "utf8",
19173
19663
  stdio: ["pipe", "pipe", "pipe"]
19174
19664
  })
@@ -19296,7 +19786,7 @@ function reply(commentId, body) {
19296
19786
  }
19297
19787
 
19298
19788
  // src/commands/prs/wontfix.ts
19299
- import { execSync as execSync48 } from "child_process";
19789
+ import { execSync as execSync49 } from "child_process";
19300
19790
  function validateReason(reason2) {
19301
19791
  const lowerReason = reason2.toLowerCase();
19302
19792
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -19313,7 +19803,7 @@ function validateShaReferences(reason2) {
19313
19803
  const invalidShas = [];
19314
19804
  for (const sha of shas) {
19315
19805
  try {
19316
- execSync48(`git cat-file -t ${sha}`, { stdio: "pipe" });
19806
+ execSync49(`git cat-file -t ${sha}`, { stdio: "pipe" });
19317
19807
  } catch {
19318
19808
  invalidShas.push(sha);
19319
19809
  }
@@ -19590,10 +20080,10 @@ import chalk168 from "chalk";
19590
20080
  import Enquirer2 from "enquirer";
19591
20081
 
19592
20082
  // src/commands/ravendb/searchItems.ts
19593
- import { execSync as execSync49 } from "child_process";
20083
+ import { execSync as execSync50 } from "child_process";
19594
20084
  import chalk167 from "chalk";
19595
20085
  function opExec(args) {
19596
- return execSync49(`op ${args}`, {
20086
+ return execSync50(`op ${args}`, {
19597
20087
  encoding: "utf8",
19598
20088
  stdio: ["pipe", "pipe", "pipe"]
19599
20089
  }).trim();
@@ -19745,7 +20235,7 @@ ${errorText}`
19745
20235
  }
19746
20236
 
19747
20237
  // src/commands/ravendb/resolveOpSecret.ts
19748
- import { execSync as execSync50 } from "child_process";
20238
+ import { execSync as execSync51 } from "child_process";
19749
20239
  import chalk172 from "chalk";
19750
20240
  function resolveOpSecret(reference) {
19751
20241
  if (!reference.startsWith("op://")) {
@@ -19753,7 +20243,7 @@ function resolveOpSecret(reference) {
19753
20243
  process.exit(1);
19754
20244
  }
19755
20245
  try {
19756
- return execSync50(`op read "${reference}"`, {
20246
+ return execSync51(`op read "${reference}"`, {
19757
20247
  encoding: "utf8",
19758
20248
  stdio: ["pipe", "pipe", "pipe"]
19759
20249
  }).trim();
@@ -20017,7 +20507,7 @@ Refactor check failed:
20017
20507
  }
20018
20508
 
20019
20509
  // src/commands/refactor/check/getViolations/index.ts
20020
- import { execSync as execSync51 } from "child_process";
20510
+ import { execSync as execSync52 } from "child_process";
20021
20511
  import fs25 from "fs";
20022
20512
  import { minimatch as minimatch6 } from "minimatch";
20023
20513
 
@@ -20067,7 +20557,7 @@ function getGitFiles(options2) {
20067
20557
  }
20068
20558
  const files = /* @__PURE__ */ new Set();
20069
20559
  if (options2.staged || options2.modified) {
20070
- const staged = execSync51("git diff --cached --name-only", {
20560
+ const staged = execSync52("git diff --cached --name-only", {
20071
20561
  encoding: "utf8"
20072
20562
  });
20073
20563
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -20075,7 +20565,7 @@ function getGitFiles(options2) {
20075
20565
  }
20076
20566
  }
20077
20567
  if (options2.unstaged || options2.modified) {
20078
- const unstaged = execSync51("git diff --name-only", { encoding: "utf8" });
20568
+ const unstaged = execSync52("git diff --name-only", { encoding: "utf8" });
20079
20569
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
20080
20570
  files.add(file);
20081
20571
  }
@@ -21342,8 +21832,8 @@ function findRootParent(file, importedBy, visited) {
21342
21832
  function clusterFiles(graph) {
21343
21833
  const clusters = /* @__PURE__ */ new Map();
21344
21834
  for (const file of graph.files) {
21345
- const basename18 = path52.basename(file, path52.extname(file));
21346
- if (basename18 === "index") continue;
21835
+ const basename19 = path52.basename(file, path52.extname(file));
21836
+ if (basename19 === "index") continue;
21347
21837
  const importers = graph.importedBy.get(file);
21348
21838
  if (!importers || importers.size !== 1) continue;
21349
21839
  const parent = [...importers][0];
@@ -21649,9 +22139,6 @@ function registerRefactor(program2) {
21649
22139
  registerRestructure(refactorCommand);
21650
22140
  }
21651
22141
 
21652
- // src/commands/review/review.ts
21653
- import { execFileSync as execFileSync9 } from "child_process";
21654
-
21655
22142
  // src/commands/review/annotateDiffWithLineNumbers.ts
21656
22143
  var FILE_HEADER2 = /^\+\+\+ (?:b\/)?(.+)$/;
21657
22144
  var HUNK_HEADER2 = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
@@ -21766,28 +22253,28 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
21766
22253
 
21767
22254
  // src/commands/review/buildReviewPaths.ts
21768
22255
  import { homedir as homedir20 } from "os";
21769
- import { basename as basename12, join as join55 } from "path";
22256
+ import { basename as basename14, join as join58 } from "path";
21770
22257
  function buildReviewPaths(repoRoot, key) {
21771
- const reviewDir = join55(
22258
+ const reviewDir = join58(
21772
22259
  homedir20(),
21773
22260
  ".assist",
21774
22261
  "reviews",
21775
- basename12(repoRoot),
22262
+ basename14(repoRoot),
21776
22263
  key
21777
22264
  );
21778
22265
  return {
21779
22266
  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")
22267
+ requestPath: join58(reviewDir, "request.md"),
22268
+ claudePath: join58(reviewDir, "claude.md"),
22269
+ codexPath: join58(reviewDir, "codex.md"),
22270
+ synthesisPath: join58(reviewDir, "synthesis.md")
21784
22271
  };
21785
22272
  }
21786
22273
 
21787
22274
  // src/commands/review/fetchExistingComments.ts
21788
- import { execSync as execSync52 } from "child_process";
22275
+ import { execSync as execSync53 } from "child_process";
21789
22276
  function fetchRawComments(org, repo, prNumber) {
21790
- const out = execSync52(
22277
+ const out = execSync53(
21791
22278
  `gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
21792
22279
  { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }
21793
22280
  );
@@ -21818,14 +22305,14 @@ function fetchExistingComments() {
21818
22305
  }
21819
22306
 
21820
22307
  // src/commands/review/gatherContext.ts
21821
- import { execSync as execSync55 } from "child_process";
22308
+ import { execSync as execSync56 } from "child_process";
21822
22309
 
21823
22310
  // src/commands/review/fetchPrDiff.ts
21824
- import { execSync as execSync53 } from "child_process";
22311
+ import { execSync as execSync54 } from "child_process";
21825
22312
  function fetchPrDiff(prNumber, baseSha, headSha) {
21826
22313
  const { org, repo } = getRepoInfo();
21827
22314
  try {
21828
- return execSync53(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
22315
+ return execSync54(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
21829
22316
  encoding: "utf8",
21830
22317
  maxBuffer: 256 * 1024 * 1024,
21831
22318
  stdio: ["ignore", "pipe", "pipe"]
@@ -21840,19 +22327,19 @@ function isDiffTooLarge(error) {
21840
22327
  }
21841
22328
  function fetchDiffViaGit(baseSha, headSha) {
21842
22329
  try {
21843
- execSync53(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
22330
+ execSync54(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
21844
22331
  } catch {
21845
22332
  }
21846
- return execSync53(`git diff ${baseSha}...${headSha}`, {
22333
+ return execSync54(`git diff ${baseSha}...${headSha}`, {
21847
22334
  encoding: "utf8",
21848
22335
  maxBuffer: 256 * 1024 * 1024
21849
22336
  });
21850
22337
  }
21851
22338
 
21852
22339
  // src/commands/review/fetchPrDiffInfo.ts
21853
- import { execSync as execSync54 } from "child_process";
22340
+ import { execSync as execSync55 } from "child_process";
21854
22341
  function getCurrentBranch3() {
21855
- return execSync54("git rev-parse --abbrev-ref HEAD", {
22342
+ return execSync55("git rev-parse --abbrev-ref HEAD", {
21856
22343
  encoding: "utf8"
21857
22344
  }).trim();
21858
22345
  }
@@ -21860,7 +22347,7 @@ function fetchPrDiffInfo() {
21860
22347
  const { org, repo } = getRepoInfo();
21861
22348
  const branch2 = getCurrentBranch3();
21862
22349
  const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
21863
- const raw = execSync54(
22350
+ const raw = execSync55(
21864
22351
  `gh pr list --state open --head ${branch2} --json ${fields} -R ${org}/${repo}`,
21865
22352
  {
21866
22353
  encoding: "utf8",
@@ -21885,7 +22372,7 @@ function fetchPrDiffInfo() {
21885
22372
  }
21886
22373
  function fetchPrChangedFiles(prNumber) {
21887
22374
  const { org, repo } = getRepoInfo();
21888
- const out = execSync54(
22375
+ const out = execSync55(
21889
22376
  `gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
21890
22377
  {
21891
22378
  encoding: "utf8",
@@ -21897,11 +22384,11 @@ function fetchPrChangedFiles(prNumber) {
21897
22384
 
21898
22385
  // src/commands/review/gatherContext.ts
21899
22386
  function gatherContext() {
21900
- const branch2 = execSync55("git rev-parse --abbrev-ref HEAD", {
22387
+ const branch2 = execSync56("git rev-parse --abbrev-ref HEAD", {
21901
22388
  encoding: "utf8"
21902
22389
  }).trim();
21903
- const sha = execSync55("git rev-parse HEAD", { encoding: "utf8" }).trim();
21904
- const shortSha = execSync55("git rev-parse --short=7 HEAD", {
22390
+ const sha = execSync56("git rev-parse HEAD", { encoding: "utf8" }).trim();
22391
+ const shortSha = execSync56("git rev-parse --short=7 HEAD", {
21905
22392
  encoding: "utf8"
21906
22393
  }).trim();
21907
22394
  const prInfo = fetchPrDiffInfo();
@@ -22319,14 +22806,14 @@ async function handlePostSynthesis(synthesisPath, options2) {
22319
22806
  }
22320
22807
 
22321
22808
  // src/commands/review/prepareReviewDir.ts
22322
- import { existsSync as existsSync45, mkdirSync as mkdirSync18, unlinkSync as unlinkSync16, writeFileSync as writeFileSync36 } from "fs";
22809
+ import { existsSync as existsSync49, mkdirSync as mkdirSync19, unlinkSync as unlinkSync16, writeFileSync as writeFileSync36 } from "fs";
22323
22810
  function clearReviewFiles(paths) {
22324
22811
  for (const path71 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
22325
- if (existsSync45(path71)) unlinkSync16(path71);
22812
+ if (existsSync49(path71)) unlinkSync16(path71);
22326
22813
  }
22327
22814
  }
22328
22815
  function prepareReviewDir(paths, requestBody, force) {
22329
- mkdirSync18(paths.reviewDir, { recursive: true });
22816
+ mkdirSync19(paths.reviewDir, { recursive: true });
22330
22817
  if (force) clearReviewFiles(paths);
22331
22818
  writeFileSync36(paths.requestPath, requestBody);
22332
22819
  }
@@ -22607,7 +23094,7 @@ function printReviewerFailures(results) {
22607
23094
  }
22608
23095
 
22609
23096
  // src/commands/review/runAndSynthesise.ts
22610
- import { existsSync as existsSync47, unlinkSync as unlinkSync18 } from "fs";
23097
+ import { existsSync as existsSync51, unlinkSync as unlinkSync18 } from "fs";
22611
23098
 
22612
23099
  // src/commands/review/buildReviewerStdin.ts
22613
23100
  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 +23514,7 @@ function resolveClaude(args) {
23027
23514
  }
23028
23515
 
23029
23516
  // src/commands/review/runCodexReviewer.ts
23030
- import { existsSync as existsSync46, unlinkSync as unlinkSync17 } from "fs";
23517
+ import { existsSync as existsSync50, unlinkSync as unlinkSync17 } from "fs";
23031
23518
 
23032
23519
  // src/commands/review/parseCodexEvent.ts
23033
23520
  function isItemStarted(value) {
@@ -23079,7 +23566,7 @@ async function runCodexReviewer(spec) {
23079
23566
  reportReviewerToolUse(spec.name, event, spinner);
23080
23567
  }
23081
23568
  });
23082
- if (result.exitCode !== 0 && existsSync46(spec.outputPath)) {
23569
+ if (result.exitCode !== 0 && existsSync50(spec.outputPath)) {
23083
23570
  unlinkSync17(spec.outputPath);
23084
23571
  }
23085
23572
  return finaliseReviewerRun({ ...spec, command }, spinner, result);
@@ -23225,7 +23712,7 @@ async function runAndSynthesise(args) {
23225
23712
  console.error("Both reviewers failed; skipping synthesis.");
23226
23713
  return { ok: false, failures };
23227
23714
  }
23228
- if (anyFresh && existsSync47(paths.synthesisPath)) {
23715
+ if (anyFresh && existsSync51(paths.synthesisPath)) {
23229
23716
  unlinkSync18(paths.synthesisPath);
23230
23717
  }
23231
23718
  const synthesisResult = await synthesise(paths, { multi });
@@ -23346,20 +23833,13 @@ function validateOptions(options2) {
23346
23833
  process.exit(1);
23347
23834
  }
23348
23835
  }
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
23836
  async function review(options2 = {}) {
23358
23837
  validateOptions(options2);
23359
- const repoRoot = resolveRepoRoot();
23838
+ const invokedIn = resolveRepoRoot();
23360
23839
  emitActivity({ kind: "command", name: "review" });
23361
- if (options2.number) checkoutPr(options2.number);
23362
- await reviewPr(repoRoot, options2);
23840
+ if (!options2.number) return reviewPr(invokedIn, options2);
23841
+ await checkoutPr(options2.number);
23842
+ return reviewPr(resolveRepoRoot(), options2);
23363
23843
  }
23364
23844
 
23365
23845
  // src/commands/registerReview.ts
@@ -24105,27 +24585,27 @@ async function configure() {
24105
24585
  }
24106
24586
 
24107
24587
  // 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";
24588
+ import { existsSync as existsSync52, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
24589
+ import { join as join59 } from "path";
24110
24590
  function list4() {
24111
24591
  const { vttDir } = getTranscriptConfig();
24112
- if (!existsSync48(vttDir)) return;
24592
+ if (!existsSync52(vttDir)) return;
24113
24593
  for (const entry of readdirSync10(vttDir)) {
24114
24594
  if (!entry.endsWith(".vtt")) continue;
24115
- if (statSync8(join56(vttDir, entry)).isDirectory()) continue;
24595
+ if (statSync8(join59(vttDir, entry)).isDirectory()) continue;
24116
24596
  console.log(entry);
24117
24597
  }
24118
24598
  }
24119
24599
 
24120
24600
  // src/commands/transcript/move.ts
24121
24601
  import {
24122
- existsSync as existsSync49,
24123
- mkdirSync as mkdirSync19,
24602
+ existsSync as existsSync53,
24603
+ mkdirSync as mkdirSync20,
24124
24604
  readFileSync as readFileSync42,
24125
24605
  renameSync as renameSync2,
24126
24606
  writeFileSync as writeFileSync38
24127
24607
  } from "fs";
24128
- import { basename as basename13, join as join57 } from "path";
24608
+ import { basename as basename15, join as join60 } from "path";
24129
24609
 
24130
24610
  // src/commands/transcript/cleanText.ts
24131
24611
  function cleanText(text17) {
@@ -24338,9 +24818,9 @@ function convertVttToMarkdown(inputPath) {
24338
24818
  return formatChatLog(messages);
24339
24819
  }
24340
24820
  function archiveRawVtt(vttDir, sourcePath, filename) {
24341
- const processedDir = join57(vttDir, "processed");
24342
- mkdirSync19(processedDir, { recursive: true });
24343
- renameSync2(sourcePath, join57(processedDir, filename));
24821
+ const processedDir = join60(vttDir, "processed");
24822
+ mkdirSync20(processedDir, { recursive: true });
24823
+ renameSync2(sourcePath, join60(processedDir, filename));
24344
24824
  }
24345
24825
  function move(file, options2) {
24346
24826
  const { date, client } = options2;
@@ -24349,20 +24829,20 @@ function move(file, options2) {
24349
24829
  process.exit(1);
24350
24830
  }
24351
24831
  const { vttDir, transcriptsDir, summaryDir } = getTranscriptConfig();
24352
- const filename = basename13(file);
24353
- const sourcePath = join57(vttDir, filename);
24354
- if (!existsSync49(sourcePath)) {
24832
+ const filename = basename15(file);
24833
+ const sourcePath = join60(vttDir, filename);
24834
+ if (!existsSync53(sourcePath)) {
24355
24835
  console.error(`Error: VTT file not found: ${sourcePath}`);
24356
24836
  process.exit(1);
24357
24837
  }
24358
- const base = basename13(filename, ".vtt").replace(/ Transcription$/, "");
24838
+ const base = basename15(filename, ".vtt").replace(/ Transcription$/, "");
24359
24839
  const outputName = `${date} ${base}.md`;
24360
- const formattedDir = join57(transcriptsDir, client);
24361
- mkdirSync19(formattedDir, { recursive: true });
24362
- const formattedPath = join57(formattedDir, outputName);
24840
+ const formattedDir = join60(transcriptsDir, client);
24841
+ mkdirSync20(formattedDir, { recursive: true });
24842
+ const formattedPath = join60(formattedDir, outputName);
24363
24843
  writeFileSync38(formattedPath, convertVttToMarkdown(sourcePath), "utf8");
24364
24844
  archiveRawVtt(vttDir, sourcePath, filename);
24365
- const summaryPath = join57(summaryDir, client, outputName);
24845
+ const summaryPath = join60(summaryDir, client, outputName);
24366
24846
  console.log(`Formatted transcript: ${formattedPath}`);
24367
24847
  console.log(`Summary target: ${summaryPath}`);
24368
24848
  }
@@ -24482,45 +24962,45 @@ function registerVerify(program2) {
24482
24962
 
24483
24963
  // src/commands/voice/devices.ts
24484
24964
  import { spawnSync as spawnSync6 } from "child_process";
24485
- import { join as join59 } from "path";
24965
+ import { join as join62 } from "path";
24486
24966
 
24487
24967
  // src/commands/voice/shared.ts
24488
24968
  import { homedir as homedir21 } from "os";
24489
- import { dirname as dirname26, join as join58 } from "path";
24969
+ import { dirname as dirname28, join as join61 } from "path";
24490
24970
  import { fileURLToPath as fileURLToPath7 } from "url";
24491
- var __dirname5 = dirname26(fileURLToPath7(import.meta.url));
24492
- var VOICE_DIR = join58(homedir21(), ".assist", "voice");
24971
+ var __dirname5 = dirname28(fileURLToPath7(import.meta.url));
24972
+ var VOICE_DIR = join61(homedir21(), ".assist", "voice");
24493
24973
  var voicePaths = {
24494
24974
  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")
24975
+ pid: join61(VOICE_DIR, "voice.pid"),
24976
+ log: join61(VOICE_DIR, "voice.log"),
24977
+ venv: join61(VOICE_DIR, ".venv"),
24978
+ lock: join61(VOICE_DIR, "voice.lock")
24499
24979
  };
24500
24980
  function getPythonDir() {
24501
- return join58(__dirname5, "commands", "voice", "python");
24981
+ return join61(__dirname5, "commands", "voice", "python");
24502
24982
  }
24503
24983
  function getVenvPython() {
24504
- return process.platform === "win32" ? join58(voicePaths.venv, "Scripts", "python.exe") : join58(voicePaths.venv, "bin", "python");
24984
+ return process.platform === "win32" ? join61(voicePaths.venv, "Scripts", "python.exe") : join61(voicePaths.venv, "bin", "python");
24505
24985
  }
24506
24986
  function getLockDir() {
24507
24987
  const config = loadConfig();
24508
24988
  return config.voice?.lockDir ?? VOICE_DIR;
24509
24989
  }
24510
24990
  function getLockFile() {
24511
- return join58(getLockDir(), "voice.lock");
24991
+ return join61(getLockDir(), "voice.lock");
24512
24992
  }
24513
24993
 
24514
24994
  // src/commands/voice/devices.ts
24515
24995
  function devices() {
24516
- const script = join59(getPythonDir(), "list_devices.py");
24996
+ const script = join62(getPythonDir(), "list_devices.py");
24517
24997
  spawnSync6(getVenvPython(), [script], { stdio: "inherit" });
24518
24998
  }
24519
24999
 
24520
25000
  // src/commands/voice/logs.ts
24521
- import { existsSync as existsSync50, readFileSync as readFileSync43 } from "fs";
25001
+ import { existsSync as existsSync54, readFileSync as readFileSync43 } from "fs";
24522
25002
  function logs(options2) {
24523
- if (!existsSync50(voicePaths.log)) {
25003
+ if (!existsSync54(voicePaths.log)) {
24524
25004
  console.log("No voice log file found");
24525
25005
  return;
24526
25006
  }
@@ -24547,13 +25027,13 @@ function logs(options2) {
24547
25027
 
24548
25028
  // src/commands/voice/setup.ts
24549
25029
  import { spawnSync as spawnSync7 } from "child_process";
24550
- import { mkdirSync as mkdirSync21 } from "fs";
24551
- import { join as join61 } from "path";
25030
+ import { mkdirSync as mkdirSync22 } from "fs";
25031
+ import { join as join64 } from "path";
24552
25032
 
24553
25033
  // 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";
25034
+ import { execSync as execSync57 } from "child_process";
25035
+ import { existsSync as existsSync55, mkdirSync as mkdirSync21, readFileSync as readFileSync44, writeFileSync as writeFileSync39 } from "fs";
25036
+ import { join as join63 } from "path";
24557
25037
  function isProcessAlive2(pid) {
24558
25038
  try {
24559
25039
  process.kill(pid, 0);
@@ -24564,7 +25044,7 @@ function isProcessAlive2(pid) {
24564
25044
  }
24565
25045
  function checkLockFile() {
24566
25046
  const lockFile = getLockFile();
24567
- if (!existsSync51(lockFile)) return;
25047
+ if (!existsSync55(lockFile)) return;
24568
25048
  try {
24569
25049
  const lock2 = JSON.parse(readFileSync44(lockFile, "utf8"));
24570
25050
  if (lock2.pid && isProcessAlive2(lock2.pid)) {
@@ -24577,10 +25057,10 @@ function checkLockFile() {
24577
25057
  }
24578
25058
  }
24579
25059
  function bootstrapVenv() {
24580
- if (existsSync51(getVenvPython())) return;
25060
+ if (existsSync55(getVenvPython())) return;
24581
25061
  console.log("Setting up Python environment...");
24582
25062
  const pythonDir = getPythonDir();
24583
- execSync56(
25063
+ execSync57(
24584
25064
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
24585
25065
  {
24586
25066
  stdio: "inherit",
@@ -24590,7 +25070,7 @@ function bootstrapVenv() {
24590
25070
  }
24591
25071
  function writeLockFile(pid) {
24592
25072
  const lockFile = getLockFile();
24593
- mkdirSync20(join60(lockFile, ".."), { recursive: true });
25073
+ mkdirSync21(join63(lockFile, ".."), { recursive: true });
24594
25074
  writeFileSync39(
24595
25075
  lockFile,
24596
25076
  JSON.stringify({
@@ -24603,10 +25083,10 @@ function writeLockFile(pid) {
24603
25083
 
24604
25084
  // src/commands/voice/setup.ts
24605
25085
  function setup() {
24606
- mkdirSync21(voicePaths.dir, { recursive: true });
25086
+ mkdirSync22(voicePaths.dir, { recursive: true });
24607
25087
  bootstrapVenv();
24608
25088
  console.log("\nDownloading models...\n");
24609
- const script = join61(getPythonDir(), "setup_models.py");
25089
+ const script = join64(getPythonDir(), "setup_models.py");
24610
25090
  const result = spawnSync7(getVenvPython(), [script], {
24611
25091
  stdio: "inherit",
24612
25092
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -24619,8 +25099,8 @@ function setup() {
24619
25099
 
24620
25100
  // src/commands/voice/start.ts
24621
25101
  import { spawn as spawn7 } from "child_process";
24622
- import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync40 } from "fs";
24623
- import { join as join62 } from "path";
25102
+ import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync40 } from "fs";
25103
+ import { join as join65 } from "path";
24624
25104
 
24625
25105
  // src/commands/voice/buildDaemonEnv.ts
24626
25106
  function buildDaemonEnv(options2) {
@@ -24653,12 +25133,12 @@ function spawnBackground(python, script, env) {
24653
25133
  console.log(`Voice daemon started (PID ${pid})`);
24654
25134
  }
24655
25135
  function start2(options2) {
24656
- mkdirSync22(voicePaths.dir, { recursive: true });
25136
+ mkdirSync23(voicePaths.dir, { recursive: true });
24657
25137
  checkLockFile();
24658
25138
  bootstrapVenv();
24659
25139
  const debug = options2.debug || options2.foreground || process.platform === "win32";
24660
25140
  const env = buildDaemonEnv({ debug });
24661
- const script = join62(getPythonDir(), "voice_daemon.py");
25141
+ const script = join65(getPythonDir(), "voice_daemon.py");
24662
25142
  const python = getVenvPython();
24663
25143
  if (options2.foreground) {
24664
25144
  spawnForeground(python, script, env);
@@ -24668,7 +25148,7 @@ function start2(options2) {
24668
25148
  }
24669
25149
 
24670
25150
  // src/commands/voice/status.ts
24671
- import { existsSync as existsSync52, readFileSync as readFileSync45 } from "fs";
25151
+ import { existsSync as existsSync56, readFileSync as readFileSync45 } from "fs";
24672
25152
  function isProcessAlive3(pid) {
24673
25153
  try {
24674
25154
  process.kill(pid, 0);
@@ -24678,12 +25158,12 @@ function isProcessAlive3(pid) {
24678
25158
  }
24679
25159
  }
24680
25160
  function readRecentLogs(count7) {
24681
- if (!existsSync52(voicePaths.log)) return [];
25161
+ if (!existsSync56(voicePaths.log)) return [];
24682
25162
  const lines = readFileSync45(voicePaths.log, "utf8").trim().split("\n");
24683
25163
  return lines.slice(-count7);
24684
25164
  }
24685
25165
  function status2() {
24686
- if (!existsSync52(voicePaths.pid)) {
25166
+ if (!existsSync56(voicePaths.pid)) {
24687
25167
  console.log("Voice daemon: not running (no PID file)");
24688
25168
  return;
24689
25169
  }
@@ -24706,9 +25186,9 @@ function status2() {
24706
25186
  }
24707
25187
 
24708
25188
  // src/commands/voice/stop.ts
24709
- import { existsSync as existsSync53, readFileSync as readFileSync46, unlinkSync as unlinkSync19 } from "fs";
25189
+ import { existsSync as existsSync57, readFileSync as readFileSync46, unlinkSync as unlinkSync19 } from "fs";
24710
25190
  function stop2() {
24711
- if (!existsSync53(voicePaths.pid)) {
25191
+ if (!existsSync57(voicePaths.pid)) {
24712
25192
  console.log("Voice daemon is not running (no PID file)");
24713
25193
  return;
24714
25194
  }
@@ -24725,7 +25205,7 @@ function stop2() {
24725
25205
  }
24726
25206
  try {
24727
25207
  const lockFile = getLockFile();
24728
- if (existsSync53(lockFile)) unlinkSync19(lockFile);
25208
+ if (existsSync57(lockFile)) unlinkSync19(lockFile);
24729
25209
  } catch {
24730
25210
  }
24731
25211
  console.log("Voice daemon stopped");
@@ -24947,9 +25427,9 @@ async function auth() {
24947
25427
  }
24948
25428
 
24949
25429
  // src/commands/roam/postRoamActivity.ts
24950
- import { execFileSync as execFileSync10 } from "child_process";
25430
+ import { execFileSync as execFileSync9 } from "child_process";
24951
25431
  import { readdirSync as readdirSync11, readFileSync as readFileSync47, statSync as statSync9 } from "fs";
24952
- import { join as join63 } from "path";
25432
+ import { join as join66 } from "path";
24953
25433
  function findPortFile(roamDir) {
24954
25434
  let entries;
24955
25435
  try {
@@ -24958,7 +25438,7 @@ function findPortFile(roamDir) {
24958
25438
  return void 0;
24959
25439
  }
24960
25440
  const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
24961
- const path71 = join63(roamDir, name);
25441
+ const path71 = join66(roamDir, name);
24962
25442
  try {
24963
25443
  return { path: path71, mtimeMs: statSync9(path71).mtimeMs };
24964
25444
  } catch {
@@ -24970,7 +25450,7 @@ function findPortFile(roamDir) {
24970
25450
  function postRoamActivity(app, event) {
24971
25451
  const appData = process.env.APPDATA;
24972
25452
  if (!appData) return;
24973
- const portFile = findPortFile(join63(appData, "Roam"));
25453
+ const portFile = findPortFile(join66(appData, "Roam"));
24974
25454
  if (!portFile) return;
24975
25455
  let port;
24976
25456
  try {
@@ -24980,7 +25460,7 @@ function postRoamActivity(app, event) {
24980
25460
  }
24981
25461
  const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${app === "codex" ? 99998 : 99999}`;
24982
25462
  try {
24983
- execFileSync10("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
25463
+ execFileSync9("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
24984
25464
  stdio: "ignore"
24985
25465
  });
24986
25466
  } catch {
@@ -25188,11 +25668,11 @@ function resolveParams(params, cliArgs) {
25188
25668
  }
25189
25669
 
25190
25670
  // src/commands/run/runPreCommands.ts
25191
- import { execSync as execSync57 } from "child_process";
25671
+ import { execSync as execSync58 } from "child_process";
25192
25672
  function runPreCommands(pre, cwd) {
25193
25673
  for (const cmd of pre) {
25194
25674
  try {
25195
- execSync57(cmd, { stdio: "inherit", cwd });
25675
+ execSync58(cmd, { stdio: "inherit", cwd });
25196
25676
  } catch (error) {
25197
25677
  const code = error && typeof error === "object" && "status" in error ? error.status : 1;
25198
25678
  process.exit(code);
@@ -25201,16 +25681,16 @@ function runPreCommands(pre, cwd) {
25201
25681
  }
25202
25682
 
25203
25683
  // 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";
25684
+ import { execFileSync as execFileSync10, spawn as spawn8 } from "child_process";
25685
+ import { existsSync as existsSync58 } from "fs";
25686
+ import { dirname as dirname29, join as join67, resolve as resolve15 } from "path";
25207
25687
  function resolveCommand2(command) {
25208
25688
  if (process.platform !== "win32" || command !== "bash") return command;
25209
25689
  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;
25690
+ const gitPath = execFileSync10("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
25691
+ const gitRoot = resolve15(dirname29(gitPath), "..");
25692
+ const gitBash = join67(gitRoot, "bin", "bash.exe");
25693
+ if (existsSync58(gitBash)) return gitBash;
25214
25694
  } catch {
25215
25695
  }
25216
25696
  return command;
@@ -25297,8 +25777,8 @@ async function run3(name, args) {
25297
25777
  }
25298
25778
 
25299
25779
  // src/commands/run/add.ts
25300
- import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync41 } from "fs";
25301
- import { join as join65 } from "path";
25780
+ import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync41 } from "fs";
25781
+ import { join as join68 } from "path";
25302
25782
 
25303
25783
  // src/commands/run/extractOption.ts
25304
25784
  function extractOption(args, flag) {
@@ -25359,15 +25839,15 @@ function saveNewRunConfig(name, command, args, cwd) {
25359
25839
  saveConfig(config);
25360
25840
  }
25361
25841
  function createCommandFile(name) {
25362
- const dir = join65(".claude", "commands");
25363
- mkdirSync23(dir, { recursive: true });
25842
+ const dir = join68(".claude", "commands");
25843
+ mkdirSync24(dir, { recursive: true });
25364
25844
  const content = `---
25365
25845
  description: Run ${name}
25366
25846
  ---
25367
25847
 
25368
25848
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
25369
25849
  `;
25370
- const filePath = join65(dir, `${name}.md`);
25850
+ const filePath = join68(dir, `${name}.md`);
25371
25851
  writeFileSync41(filePath, content);
25372
25852
  console.log(`Created command file: ${filePath}`);
25373
25853
  }
@@ -25423,8 +25903,8 @@ function link2() {
25423
25903
  }
25424
25904
 
25425
25905
  // src/commands/run/remove.ts
25426
- import { existsSync as existsSync55, unlinkSync as unlinkSync20 } from "fs";
25427
- import { join as join66 } from "path";
25906
+ import { existsSync as existsSync59, unlinkSync as unlinkSync20 } from "fs";
25907
+ import { join as join69 } from "path";
25428
25908
  function findRemoveIndex() {
25429
25909
  const idx = process.argv.indexOf("remove");
25430
25910
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -25439,8 +25919,8 @@ function parseRemoveName() {
25439
25919
  return process.argv[idx + 1];
25440
25920
  }
25441
25921
  function deleteCommandFile(name) {
25442
- const filePath = join66(".claude", "commands", `${name}.md`);
25443
- if (existsSync55(filePath)) {
25922
+ const filePath = join69(".claude", "commands", `${name}.md`);
25923
+ if (existsSync59(filePath)) {
25444
25924
  unlinkSync20(filePath);
25445
25925
  console.log(`Deleted command file: ${filePath}`);
25446
25926
  }
@@ -25493,10 +25973,10 @@ function registerRun(program2) {
25493
25973
  }
25494
25974
 
25495
25975
  // 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";
25976
+ import { execSync as execSync59 } from "child_process";
25977
+ import { existsSync as existsSync60, mkdirSync as mkdirSync25, unlinkSync as unlinkSync21, writeFileSync as writeFileSync42 } from "fs";
25498
25978
  import { tmpdir as tmpdir8 } from "os";
25499
- import { join as join67, resolve as resolve17 } from "path";
25979
+ import { join as join70, resolve as resolve17 } from "path";
25500
25980
  import chalk206 from "chalk";
25501
25981
 
25502
25982
  // src/commands/screenshot/captureWindowPs1.ts
@@ -25626,17 +26106,17 @@ Write-Output $OutputPath
25626
26106
 
25627
26107
  // src/commands/screenshot/index.ts
25628
26108
  function buildOutputPath(outputDir, processName) {
25629
- if (!existsSync56(outputDir)) {
25630
- mkdirSync24(outputDir, { recursive: true });
26109
+ if (!existsSync60(outputDir)) {
26110
+ mkdirSync25(outputDir, { recursive: true });
25631
26111
  }
25632
26112
  const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
25633
26113
  return resolve17(outputDir, `${processName}-${timestamp6}.png`);
25634
26114
  }
25635
26115
  function runPowerShellScript(processName, outputPath) {
25636
- const scriptPath = join67(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
26116
+ const scriptPath = join70(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
25637
26117
  writeFileSync42(scriptPath, captureWindowPs1, "utf8");
25638
26118
  try {
25639
- execSync58(
26119
+ execSync59(
25640
26120
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
25641
26121
  { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }
25642
26122
  );
@@ -25660,11 +26140,11 @@ function screenshot(processName) {
25660
26140
  }
25661
26141
 
25662
26142
  // src/commands/sessions/daemon/listDaemonPids.ts
25663
- import { execFileSync as execFileSync12 } from "child_process";
26143
+ import { execFileSync as execFileSync11 } from "child_process";
25664
26144
  function listDaemonPids() {
25665
26145
  if (process.platform === "win32") return [];
25666
26146
  try {
25667
- const out = execFileSync12("ps", ["-eo", "pid=,args="], {
26147
+ const out = execFileSync11("ps", ["-eo", "pid=,args="], {
25668
26148
  encoding: "utf8"
25669
26149
  });
25670
26150
  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));
@@ -25709,163 +26189,62 @@ function applyLine(result, pending, line) {
25709
26189
  }
25710
26190
  }
25711
26191
 
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;
25837
- }
25838
-
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
- });
26192
+ // src/commands/sessions/daemon/reportStolenSocket.ts
26193
+ import { readFileSync as readFileSync48 } from "fs";
26194
+ function reportStolenSocket(socketPid) {
26195
+ if (!socketPid) return;
26196
+ const filePid = readPidFile();
26197
+ if (filePid === void 0 || filePid === socketPid) return;
26198
+ console.error(
26199
+ `Warning: daemon.pid records PID ${filePid} but the socket is owned by PID ${socketPid} (stolen socket)`
26200
+ );
25848
26201
  }
25849
- function savePersistedSessions(sessions) {
25850
- saveJson(SESSIONS_FILE, sessions);
26202
+ function readPidFile() {
26203
+ try {
26204
+ const pid = Number.parseInt(
26205
+ readFileSync48(daemonPaths.pid, "utf8").trim(),
26206
+ 10
26207
+ );
26208
+ return Number.isInteger(pid) ? pid : void 0;
26209
+ } catch {
26210
+ return void 0;
26211
+ }
25851
26212
  }
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);
26213
+
26214
+ // src/commands/sessions/daemon/daemonStatus.ts
26215
+ async function daemonStatus() {
26216
+ let socket;
26217
+ try {
26218
+ socket = await connectToDaemon();
26219
+ } catch {
26220
+ console.log("Sessions daemon is not running");
26221
+ reportStrays(listDaemonPids());
26222
+ return;
26223
+ }
26224
+ const { pid, sessions } = await queryDaemon(socket);
26225
+ socket.destroy();
26226
+ console.log(`Sessions daemon is running${pid ? ` (PID ${pid})` : ""}`);
26227
+ reportStolenSocket(pid);
26228
+ reportStrays(listDaemonPids().filter((p) => p !== pid));
26229
+ if (sessions.length === 0) {
26230
+ console.log("No sessions");
26231
+ return;
26232
+ }
26233
+ for (const session of sessions) {
26234
+ const restored = session.restored === false ? " (not restored)" : "";
26235
+ console.log(` [${session.status}] ${session.name}${restored}`);
26236
+ }
25858
26237
  }
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)"
26238
+ function reportStrays(pids) {
26239
+ if (pids.length === 0) return;
26240
+ console.error(
26241
+ `Warning: stray daemon process(es) detected: ${pids.join(", ")}`
25866
26242
  );
25867
26243
  }
25868
26244
 
26245
+ // src/commands/sessions/daemon/drainDaemon.ts
26246
+ import { createInterface as createInterface6 } from "readline";
26247
+
25869
26248
  // src/commands/sessions/daemon/clearPersistedSessionsOnDrain.ts
25870
26249
  function clearPersistedSessionsOnDrain() {
25871
26250
  const held = loadPersistedSessions().filter((s) => s.status === "stopped");
@@ -26213,7 +26592,7 @@ function readDesignSystemPrompt() {
26213
26592
  import * as pty from "node-pty";
26214
26593
 
26215
26594
  // src/commands/sessions/daemon/ensureSpawnHelperExecutable.ts
26216
- import { chmodSync, existsSync as existsSync57, statSync as statSync10 } from "fs";
26595
+ import { chmodSync, existsSync as existsSync61, statSync as statSync10 } from "fs";
26217
26596
  import { createRequire as createRequire3 } from "module";
26218
26597
  import path59 from "path";
26219
26598
  var require4 = createRequire3(import.meta.url);
@@ -26228,7 +26607,7 @@ function ensureSpawnHelperExecutable() {
26228
26607
  `${process.platform}-${process.arch}`,
26229
26608
  "spawn-helper"
26230
26609
  );
26231
- if (!existsSync57(helper)) return;
26610
+ if (!existsSync61(helper)) return;
26232
26611
  const mode = statSync10(helper).mode;
26233
26612
  if ((mode & 73) === 0) chmodSync(helper, mode | 493);
26234
26613
  }
@@ -26387,7 +26766,8 @@ function otherTreeHolders(sessions, session) {
26387
26766
  }
26388
26767
 
26389
26768
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
26390
- import { existsSync as existsSync59 } from "fs";
26769
+ import { existsSync as existsSync62 } from "fs";
26770
+ import { basename as basename16 } from "path";
26391
26771
 
26392
26772
  // src/commands/sessions/daemon/worktree/removeTree.ts
26393
26773
  async function removeTree(clone, worktreePath, force) {
@@ -26424,63 +26804,9 @@ function reason(error) {
26424
26804
  return error instanceof Error ? error.message : String(error);
26425
26805
  }
26426
26806
 
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
26807
  // src/commands/sessions/daemon/worktree/reapWorktree.ts
26482
26808
  async function reapWorktree(worktreePath, force = false) {
26483
- if (!existsSync59(worktreePath)) {
26809
+ if (!existsSync62(worktreePath)) {
26484
26810
  daemonLog(`worktree ${worktreePath} already gone; skipping reap`);
26485
26811
  return false;
26486
26812
  }
@@ -26492,23 +26818,23 @@ async function reapWorktree(worktreePath, force = false) {
26492
26818
  }
26493
26819
  }
26494
26820
  const clone = mainWorktree(worktreePath) ?? worktreePath;
26495
- const branch2 = await gitOrNull(worktreePath, [
26496
- "symbolic-ref",
26497
- "--short",
26498
- "HEAD"
26499
- ]);
26500
26821
  if (!await removeTree(clone, worktreePath, force)) return false;
26501
- if (branch2) await deleteBranch(clone, branch2);
26822
+ await deleteWorktreeBranch(clone, basename16(worktreePath));
26502
26823
  forgetWorktree(worktreePath);
26503
26824
  daemonLog(`worktree ${worktreePath} reaped${force ? " (forced)" : ""}`);
26504
26825
  return true;
26505
26826
  }
26506
- async function deleteBranch(clone, branch2) {
26507
- const current = await gitOrNull(clone, ["symbolic-ref", "--short", "HEAD"]);
26827
+ async function deleteWorktreeBranch(clone, branch2) {
26828
+ if (!listLocalBranches(clone).includes(branch2)) return;
26829
+ const current = await gitOrNull2(clone, ["symbolic-ref", "--short", "HEAD"]);
26508
26830
  if (branch2 === current) return;
26509
26831
  try {
26510
26832
  await git2(clone, ["branch", "-D", branch2]);
26511
- } catch {
26833
+ daemonLog(`worktree branch ${branch2} deleted from clone ${clone}`);
26834
+ } catch (error) {
26835
+ daemonLog(
26836
+ `worktree branch ${branch2} retained in clone ${clone}: ${error instanceof Error ? error.message : String(error)}`
26837
+ );
26512
26838
  }
26513
26839
  }
26514
26840
 
@@ -26534,21 +26860,6 @@ function dismissSession(sessions, id) {
26534
26860
  return true;
26535
26861
  }
26536
26862
 
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
26863
  // src/commands/sessions/daemon/worktree/closeGateApplies.ts
26553
26864
  function closeGateApplies(sessions, session) {
26554
26865
  if (otherTreeHolders(sessions, session).length > 0) return false;
@@ -26570,12 +26881,12 @@ function setStatus2(session, newStatus) {
26570
26881
  }
26571
26882
 
26572
26883
  // src/commands/sessions/daemon/worktree/watchGitState.ts
26573
- import { existsSync as existsSync60, watch } from "fs";
26884
+ import { existsSync as existsSync63, watch } from "fs";
26574
26885
  var DEBOUNCE_MS = 500;
26575
26886
  var POLL_MS = 3e4;
26576
26887
  function watchGitState(cwd, onChange) {
26577
26888
  const common = gitCommonDir(cwd);
26578
- if (!common || !existsSync60(common)) return void 0;
26889
+ if (!common || !existsSync63(common)) return void 0;
26579
26890
  const watchers = [
26580
26891
  watchGitDir(common, onChange),
26581
26892
  pollGitState(cwd, onChange)
@@ -27167,10 +27478,10 @@ function emitSessionOutput(session, clients, data) {
27167
27478
  }
27168
27479
 
27169
27480
  // src/commands/sessions/daemon/exitReason.ts
27170
- import { existsSync as existsSync61 } from "fs";
27481
+ import { existsSync as existsSync64 } from "fs";
27171
27482
  function exitReason(session, exitCode) {
27172
27483
  const base = `process exited with code ${exitCode}`;
27173
- if (session.cwd && !existsSync61(session.cwd))
27484
+ if (session.cwd && !existsSync64(session.cwd))
27174
27485
  return `${base}: working directory ${session.cwd} no longer exists`;
27175
27486
  return base;
27176
27487
  }
@@ -27188,8 +27499,8 @@ function handleFailedResume(session, exitCode, onStatusChange) {
27188
27499
  }
27189
27500
 
27190
27501
  // 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";
27502
+ import { existsSync as existsSync65, mkdirSync as mkdirSync26, watch as watch2 } from "fs";
27503
+ import { dirname as dirname31 } from "path";
27193
27504
 
27194
27505
  // src/commands/sessions/daemon/applyReviewPause.ts
27195
27506
  function applyReviewPause(session, activity2) {
@@ -27243,9 +27554,9 @@ var DEBOUNCE_MS2 = 50;
27243
27554
  function watchActivity(session, notify2, onClaudeSessionId) {
27244
27555
  if (session.commandType !== "assist" || !session.cwd) return;
27245
27556
  const path71 = activityPath(session.id);
27246
- const dir = dirname29(path71);
27557
+ const dir = dirname31(path71);
27247
27558
  try {
27248
- mkdirSync25(dir, { recursive: true });
27559
+ mkdirSync26(dir, { recursive: true });
27249
27560
  } catch {
27250
27561
  return;
27251
27562
  }
@@ -27269,7 +27580,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
27269
27580
  if (timer) clearTimeout(timer);
27270
27581
  timer = setTimeout(read, DEBOUNCE_MS2);
27271
27582
  });
27272
- if (existsSync62(path71)) read();
27583
+ if (existsSync65(path71)) read();
27273
27584
  }
27274
27585
  function refreshActivity(session) {
27275
27586
  if (session.commandType !== "assist" || !session.cwd) return;
@@ -27929,8 +28240,8 @@ function rearmStoppedSessions(sessions, notify2) {
27929
28240
  }
27930
28241
 
27931
28242
  // src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
27932
- import { existsSync as existsSync67 } from "fs";
27933
- import { basename as basename15 } from "path";
28243
+ import { existsSync as existsSync68 } from "fs";
28244
+ import { basename as basename18 } from "path";
27934
28245
 
27935
28246
  // src/commands/sessions/daemon/worktree/accountedTrees.ts
27936
28247
  function accountedTrees(sessions) {
@@ -27958,71 +28269,6 @@ function detectExistingWorktree(cwd) {
27958
28269
  return void 0;
27959
28270
  }
27960
28271
 
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
28272
  // src/commands/sessions/daemon/worktree/bindNewWorktree.ts
28027
28273
  function bindNewWorktree(session, alloc, notify2, startHeld = () => {
28028
28274
  }) {
@@ -28084,9 +28330,9 @@ function capped(lines) {
28084
28330
  }
28085
28331
 
28086
28332
  // src/commands/sessions/daemon/worktree/reclaimVanishedWorktrees.ts
28087
- import { existsSync as existsSync66 } from "fs";
28333
+ import { existsSync as existsSync67 } from "fs";
28088
28334
  async function reclaimVanishedWorktrees(clone, paths) {
28089
- if (!existsSync66(clone)) {
28335
+ if (!existsSync67(clone)) {
28090
28336
  for (const { path: path71 } of paths) forgetWorktree(path71);
28091
28337
  daemonLog(
28092
28338
  `clone ${clone} is gone; forgot ${paths.length} worktree record(s) it owned`
@@ -28122,7 +28368,7 @@ async function reclaimBranch(clone, branch2) {
28122
28368
  }
28123
28369
 
28124
28370
  // src/commands/sessions/daemon/worktree/resurfaceOrphanedWorktree.ts
28125
- import { basename as basename14 } from "path";
28371
+ import { basename as basename17 } from "path";
28126
28372
  function resurfaceOrphanedWorktree(sessions, spawnWith, recovered, notify2) {
28127
28373
  const { orphan, reason: reason2, held } = recovered;
28128
28374
  let id;
@@ -28145,7 +28391,7 @@ function orphanedSession(id, recovered) {
28145
28391
  const { orphan, reason: reason2, held } = recovered;
28146
28392
  return {
28147
28393
  ...sessionBase(id, "stopped"),
28148
- name: `recovered ${basename14(orphan.path)}`,
28394
+ name: `recovered ${basename17(orphan.path)}`,
28149
28395
  subtitle: `${held.summary} in ${orphan.path}`,
28150
28396
  commandType: "claude",
28151
28397
  pty: null,
@@ -28179,10 +28425,10 @@ async function recoverOrphanedWorktrees(sessions, spawnWith, notify2) {
28179
28425
  const vanished = /* @__PURE__ */ new Map();
28180
28426
  for (const { path: path71, clone } of readWorktreeRegistry()) {
28181
28427
  if (accounted.has(path71)) continue;
28182
- if (!existsSync67(path71)) {
28428
+ if (!existsSync68(path71)) {
28183
28429
  vanished.set(clone, [
28184
28430
  ...vanished.get(clone) ?? [],
28185
- { path: path71, branch: basename15(path71) }
28431
+ { path: path71, branch: basename18(path71) }
28186
28432
  ]);
28187
28433
  continue;
28188
28434
  }
@@ -28358,7 +28604,7 @@ function treeSpawnContext(sessions, spawnWith, notify2, clients, onStatusChange)
28358
28604
  }
28359
28605
 
28360
28606
  // src/commands/sessions/daemon/watchTranscript.ts
28361
- import { existsSync as existsSync68, watch as watch3 } from "fs";
28607
+ import { existsSync as existsSync69, watch as watch3 } from "fs";
28362
28608
 
28363
28609
  // src/commands/sessions/daemon/reconcileTranscriptStatus.ts
28364
28610
  async function resolveTranscriptPath(session) {
@@ -28393,7 +28639,7 @@ function watchTranscript(session, onStatusChange) {
28393
28639
  if (!session.cwd || !session.claudeSessionId) return;
28394
28640
  if (session.watchedTranscriptId === session.claudeSessionId) return;
28395
28641
  const dir = projectDirForCwd(session.cwd);
28396
- if (!existsSync68(dir)) return;
28642
+ if (!existsSync69(dir)) return;
28397
28643
  if (session.transcriptWatcher) {
28398
28644
  session.transcriptWatcher.close();
28399
28645
  session.transcriptWatcher = void 0;
@@ -28544,13 +28790,13 @@ async function defaultConnect() {
28544
28790
  }
28545
28791
 
28546
28792
  // src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
28547
- import { existsSync as existsSync69, readFileSync as readFileSync50 } from "fs";
28793
+ import { existsSync as existsSync70, readFileSync as readFileSync50 } from "fs";
28548
28794
  import { posix } from "path";
28549
28795
  function hasPersistedWindowsSessions() {
28550
28796
  const sessionsFile = windowsSessionsFileFromWsl();
28551
28797
  if (!sessionsFile) return false;
28552
28798
  try {
28553
- if (!existsSync69(sessionsFile)) return false;
28799
+ if (!existsSync70(sessionsFile)) return false;
28554
28800
  const data = JSON.parse(readFileSync50(sessionsFile, "utf8"));
28555
28801
  return Array.isArray(data) && data.length > 0;
28556
28802
  } catch (error) {
@@ -29129,81 +29375,6 @@ function resumeSession(id, sessionId, cwd, name) {
29129
29375
  };
29130
29376
  }
29131
29377
 
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
29378
  // src/commands/sessions/daemon/worktree/boundTreeRoots.ts
29208
29379
  function boundTreeRoots(sessions) {
29209
29380
  const roots = /* @__PURE__ */ new Set();
@@ -29228,9 +29399,17 @@ function holdsTree(session, root) {
29228
29399
  return !durability.durable;
29229
29400
  }
29230
29401
 
29402
+ // src/commands/sessions/daemon/worktree/isPrCheckoutArgs.ts
29403
+ var CHECKOUT_COMMANDS = /* @__PURE__ */ new Set(["review", "review-pr-comments"]);
29404
+ function isPrCheckoutArgs(args) {
29405
+ const [command, ...rest] = args;
29406
+ if (!command || !CHECKOUT_COMMANDS.has(command)) return false;
29407
+ return rest.some((arg) => /^[1-9]\d*$/.test(arg));
29408
+ }
29409
+
29231
29410
  // src/commands/sessions/daemon/worktree/spawnInTree.ts
29232
- function allocateAndBind(ctx, cwd, create) {
29233
- const alloc = allocateTree(cwd, boundTreeRoots(ctx.sessions));
29411
+ function allocateAndBind(ctx, cwd, create, options2 = {}) {
29412
+ const alloc = allocateTree(cwd, boundTreeRoots(ctx.sessions), options2);
29234
29413
  const needsSeeding = alloc.kind === "worktree" && alloc.created === true;
29235
29414
  const id = ctx.spawnWith((sid) => create(sid, alloc.cwd, needsSeeding));
29236
29415
  bindNewWorktree(ctx.sessions.get(id), alloc, ctx.notify, ctx.startHeld);
@@ -29247,7 +29426,8 @@ function spawnAssistInTree(ctx, assistArgs, cwd, meta) {
29247
29426
  return allocateAndBind(
29248
29427
  ctx,
29249
29428
  cwd,
29250
- (sid, resolvedCwd, holdUntilSeeded) => createAssistSession(sid, assistArgs, resolvedCwd, meta, holdUntilSeeded)
29429
+ (sid, resolvedCwd, holdUntilSeeded) => createAssistSession(sid, assistArgs, resolvedCwd, meta, holdUntilSeeded),
29430
+ { forCheckout: isPrCheckoutArgs(assistArgs) }
29251
29431
  );
29252
29432
  }
29253
29433
  function resumeInTree(ctx, sessionId, cwd, name) {
@@ -29955,11 +30135,21 @@ var sessionsConfigHelp = [
29955
30135
  setter: "assist config set sessions.windowsVersionCheck block",
29956
30136
  note: "Windows daemon version mismatch handling: block | warn | off"
29957
30137
  },
30138
+ {
30139
+ key: "sessions.includeCommittedChanges",
30140
+ setter: "assist config set sessions.includeCommittedChanges true -g",
30141
+ note: "session card counts and /diff span the whole branch (merge-base with the default branch) instead of just uncommitted work (default off)"
30142
+ },
29958
30143
  {
29959
30144
  key: "worktree.enabled",
29960
30145
  setter: "assist config set worktree.enabled true -g --repo",
29961
30146
  note: "opt in per repo: spill concurrent sessions into adjacent <clone>-N worktrees (default off)"
29962
30147
  },
30148
+ {
30149
+ key: "worktree.trunk",
30150
+ setter: "assist config set worktree.trunk true -g --repo",
30151
+ 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)"
30152
+ },
29963
30153
  {
29964
30154
  key: "worktree.root",
29965
30155
  setter: "assist config set worktree.root ~/git -g --repo",
@@ -30000,7 +30190,7 @@ function summaryPathFor(jsonlPath2) {
30000
30190
  }
30001
30191
 
30002
30192
  // src/commands/sessions/summarise/summariseSession.ts
30003
- import { execFileSync as execFileSync13 } from "child_process";
30193
+ import { execFileSync as execFileSync12 } from "child_process";
30004
30194
 
30005
30195
  // src/commands/sessions/summarise/extractFirstUserMessage.ts
30006
30196
  function extractFirstUserMessage(filePath) {
@@ -30024,7 +30214,7 @@ function summariseSession(jsonlPath2) {
30024
30214
  }
30025
30215
  const prompt = buildPrompt3(firstMessage, backlogIds);
30026
30216
  try {
30027
- const output = execFileSync13("claude", ["-p", "--model", "haiku", prompt], {
30217
+ const output = execFileSync12("claude", ["-p", "--model", "haiku", prompt], {
30028
30218
  encoding: "utf8",
30029
30219
  timeout: 3e4,
30030
30220
  stdio: ["ignore", "pipe", "ignore"]
@@ -30586,7 +30776,7 @@ function syncCommands(claudeDir, targetBase) {
30586
30776
  }
30587
30777
 
30588
30778
  // src/commands/update.ts
30589
- import { execSync as execSync59 } from "child_process";
30779
+ import { execSync as execSync60 } from "child_process";
30590
30780
  import * as path70 from "path";
30591
30781
 
30592
30782
  // src/commands/restartDaemonAfterUpdate.ts
@@ -30610,7 +30800,7 @@ function isGlobalNpmInstall(dir) {
30610
30800
  if (resolved.split(path70.sep).includes("node_modules")) {
30611
30801
  return true;
30612
30802
  }
30613
- const globalPrefix = execSync59("npm prefix -g", { stdio: "pipe" }).toString().trim();
30803
+ const globalPrefix = execSync60("npm prefix -g", { stdio: "pipe" }).toString().trim();
30614
30804
  return resolved.toLowerCase().startsWith(path70.resolve(globalPrefix).toLowerCase());
30615
30805
  } catch {
30616
30806
  return false;
@@ -30621,18 +30811,18 @@ async function update2() {
30621
30811
  console.log(`Assist is installed at: ${installDir}`);
30622
30812
  if (isGitRepo(installDir)) {
30623
30813
  console.log("Detected git repo installation, pulling latest...");
30624
- execSync59("git pull", { cwd: installDir, stdio: "inherit" });
30814
+ execSync60("git pull", { cwd: installDir, stdio: "inherit" });
30625
30815
  console.log("Installing dependencies...");
30626
- execSync59("npm i", { cwd: installDir, stdio: "inherit" });
30816
+ execSync60("npm i", { cwd: installDir, stdio: "inherit" });
30627
30817
  console.log("Building...");
30628
- execSync59("npm run build", { cwd: installDir, stdio: "inherit" });
30818
+ execSync60("npm run build", { cwd: installDir, stdio: "inherit" });
30629
30819
  console.log("Syncing commands...");
30630
- execSync59("assist sync", { stdio: "inherit" });
30820
+ execSync60("assist sync", { stdio: "inherit" });
30631
30821
  } else if (isGlobalNpmInstall(installDir)) {
30632
30822
  console.log("Detected global npm installation, updating...");
30633
- execSync59("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
30823
+ execSync60("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
30634
30824
  console.log("Syncing commands...");
30635
- execSync59("assist sync", { stdio: "inherit" });
30825
+ execSync60("assist sync", { stdio: "inherit" });
30636
30826
  } else {
30637
30827
  console.error(
30638
30828
  "Could not determine installation method. Expected a git repo or global npm install."