@staff0rd/assist 0.188.0 → 0.189.1

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +405 -235
  3. package/package.json +1 -1
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.188.0",
9
+ version: "0.189.1",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -973,8 +973,8 @@ function spawnClaude(prompt, options2 = {}) {
973
973
  const child = spawn("claude", args, {
974
974
  stdio: "inherit"
975
975
  });
976
- const done2 = new Promise((resolve8, reject) => {
977
- child.on("close", (code) => resolve8(code ?? 0));
976
+ const done2 = new Promise((resolve13, reject) => {
977
+ child.on("close", (code) => resolve13(code ?? 0));
978
978
  child.on("error", reject);
979
979
  });
980
980
  return { child, done: done2 };
@@ -1247,16 +1247,16 @@ function printLinks(item, items) {
1247
1247
  const links = item.links ?? [];
1248
1248
  if (links.length === 0) return;
1249
1249
  console.log(chalk12.bold("Links"));
1250
- for (const link2 of links) {
1251
- const target = items.find((i) => i.id === link2.targetId);
1252
- const typeLabel2 = link2.type === "depends-on" ? chalk12.red("depends-on") : chalk12.blue("relates-to");
1250
+ for (const link3 of links) {
1251
+ const target = items.find((i) => i.id === link3.targetId);
1252
+ const typeLabel2 = link3.type === "depends-on" ? chalk12.red("depends-on") : chalk12.blue("relates-to");
1253
1253
  if (target) {
1254
1254
  console.log(
1255
1255
  ` ${typeLabel2} #${target.id} ${target.name} ${chalk12.dim(`(${target.status})`)}`
1256
1256
  );
1257
1257
  } else {
1258
1258
  console.log(
1259
- ` ${typeLabel2} #${link2.targetId} ${chalk12.dim("(not found)")}`
1259
+ ` ${typeLabel2} #${link3.targetId} ${chalk12.dim("(not found)")}`
1260
1260
  );
1261
1261
  }
1262
1262
  }
@@ -1420,12 +1420,12 @@ function getHtml() {
1420
1420
 
1421
1421
  // src/commands/backlog/web/parseItemBody.ts
1422
1422
  function readBody(req) {
1423
- return new Promise((resolve8, reject) => {
1423
+ return new Promise((resolve13, reject) => {
1424
1424
  let body = "";
1425
1425
  req.on("data", (chunk) => {
1426
1426
  body += chunk.toString();
1427
1427
  });
1428
- req.on("end", () => resolve8(body));
1428
+ req.on("end", () => resolve13(body));
1429
1429
  req.on("error", reject);
1430
1430
  });
1431
1431
  }
@@ -1641,6 +1641,10 @@ var runConfigSchema = z2.strictObject({
1641
1641
  pre: z2.array(z2.string()).optional(),
1642
1642
  cwd: z2.string().optional()
1643
1643
  });
1644
+ var runLinkSchema = z2.strictObject({
1645
+ link: z2.string(),
1646
+ prefix: z2.string()
1647
+ });
1644
1648
  var transcriptConfigSchema = z2.strictObject({
1645
1649
  vttDir: z2.string(),
1646
1650
  transcriptsDir: z2.string(),
@@ -1681,7 +1685,7 @@ var assistConfigSchema = z2.strictObject({
1681
1685
  refreshToken: z2.string().optional(),
1682
1686
  tokenExpiresAt: z2.number().optional()
1683
1687
  }).optional(),
1684
- run: z2.array(runConfigSchema).optional(),
1688
+ run: z2.array(z2.union([runConfigSchema, runLinkSchema])).optional(),
1685
1689
  transcript: transcriptConfigSchema.optional(),
1686
1690
  cliReadVerbs: z2.record(z2.string(), z2.array(z2.string())).optional(),
1687
1691
  news: z2.strictObject({
@@ -1745,6 +1749,9 @@ var assistConfigSchema = z2.strictObject({
1745
1749
  models: {}
1746
1750
  })
1747
1751
  });
1752
+ function isRunLink(entry) {
1753
+ return "link" in entry;
1754
+ }
1748
1755
 
1749
1756
  // src/shared/loadConfig.ts
1750
1757
  function findConfigUp(startDir) {
@@ -2388,8 +2395,8 @@ function toolStatus(pkg, scriptName, hasPackage, configScriptNames) {
2388
2395
  };
2389
2396
  }
2390
2397
  function loadConfigScriptNames() {
2391
- const config = loadConfig();
2392
- return new Set((config.run ?? []).map((r) => r.name));
2398
+ const entries = loadConfig().run ?? [];
2399
+ return new Set(entries.flatMap((r) => "name" in r ? [r.name] : []));
2393
2400
  }
2394
2401
  function buildToolStatuses(pkg, configScriptNames) {
2395
2402
  const status2 = (script, has) => toolStatus(pkg, script, has, configScriptNames);
@@ -3034,7 +3041,7 @@ function lint(options2 = {}) {
3034
3041
 
3035
3042
  // src/commands/new/registerNew/newCli/index.ts
3036
3043
  import { execSync as execSync11 } from "child_process";
3037
- import { basename, resolve } from "path";
3044
+ import { basename, resolve as resolve5 } from "path";
3038
3045
 
3039
3046
  // src/commands/verify/hardcodedColors.ts
3040
3047
  import { execSync as execSync6 } from "child_process";
@@ -3082,15 +3089,111 @@ Total: ${lines.length} hardcoded color(s)`);
3082
3089
 
3083
3090
  // src/commands/verify/run/resolveEntries.ts
3084
3091
  import * as path17 from "path";
3092
+
3093
+ // src/shared/resolveRunConfigs.ts
3094
+ import { dirname as dirname12, relative, resolve as resolve3 } from "path";
3095
+
3096
+ // src/shared/assertNoDuplicateRunNames.ts
3097
+ function findDuplicateNames(configs) {
3098
+ const seen = /* @__PURE__ */ new Set();
3099
+ const dupes = /* @__PURE__ */ new Set();
3100
+ for (const c of configs) {
3101
+ if (seen.has(c.name)) dupes.add(c.name);
3102
+ seen.add(c.name);
3103
+ }
3104
+ return [...dupes];
3105
+ }
3106
+ function assertNoDuplicateRunNames(configs) {
3107
+ const duplicates = findDuplicateNames(configs);
3108
+ if (duplicates.length > 0) {
3109
+ throw new Error(
3110
+ `Duplicate run command names: ${duplicates.join(", ")}. Use the prefix option on link entries to namespace linked commands.`
3111
+ );
3112
+ }
3113
+ }
3114
+
3115
+ // src/shared/findLinkedConfigPath.ts
3116
+ import { existsSync as existsSync17 } from "fs";
3117
+ import { join as join14, resolve } from "path";
3118
+ function findLinkedConfigPath(linkPath, fromDir) {
3119
+ const resolved = resolve(fromDir, linkPath);
3120
+ const claudePath = join14(resolved, ".claude", "assist.yml");
3121
+ if (existsSync17(claudePath)) return claudePath;
3122
+ const rootPath = join14(resolved, "assist.yml");
3123
+ if (existsSync17(rootPath)) return rootPath;
3124
+ throw new Error(`No assist.yml found in linked project: ${resolved}`);
3125
+ }
3126
+
3127
+ // src/shared/loadLinkedEntries.ts
3128
+ import { resolve as resolve2 } from "path";
3129
+ function loadLinkedEntries(configPath, visited) {
3130
+ const canonical = resolve2(configPath);
3131
+ if (visited.has(canonical)) {
3132
+ throw new Error(
3133
+ `Circular link detected: ${canonical} has already been visited`
3134
+ );
3135
+ }
3136
+ visited.add(canonical);
3137
+ const raw = loadRawYaml(configPath);
3138
+ return assistConfigSchema.parse(raw).run;
3139
+ }
3140
+
3141
+ // src/shared/resolveRunConfigs.ts
3142
+ function resolveRunConfigs(entries, configDir) {
3143
+ const ctx = { rootConfigDir: configDir, visited: /* @__PURE__ */ new Set() };
3144
+ return resolveRecursive(entries, configDir, ctx);
3145
+ }
3146
+ function applyPrefix(configs, prefix2) {
3147
+ return configs.map((c) => ({ ...c, name: `${prefix2}:${c.name}` }));
3148
+ }
3149
+ function setDefaultCwd(configs, defaultCwd) {
3150
+ return configs.map((c) => c.cwd ? c : { ...c, cwd: defaultCwd });
3151
+ }
3152
+ function relativeToRoot(ctx, absolute) {
3153
+ return relative(ctx.rootConfigDir, absolute);
3154
+ }
3155
+ function loadAndResolveLink(linkPath, configDir, ctx) {
3156
+ const configPath = findLinkedConfigPath(linkPath, configDir);
3157
+ const entries = loadLinkedEntries(configPath, ctx.visited);
3158
+ const defaultCwd = relativeToRoot(ctx, resolve3(configDir, linkPath));
3159
+ return setDefaultCwd(
3160
+ resolveRecursive(entries, dirname12(configPath), ctx),
3161
+ defaultCwd
3162
+ );
3163
+ }
3164
+ function resolveLink(entry, configDir, ctx) {
3165
+ const configs = loadAndResolveLink(entry.link, configDir, ctx);
3166
+ return applyPrefix(configs, entry.prefix);
3167
+ }
3168
+ function resolveEntry(entry, configDir, ctx) {
3169
+ if (isRunLink(entry)) return resolveLink(entry, configDir, ctx);
3170
+ return [resolveLocalCwd(entry, configDir, ctx)];
3171
+ }
3172
+ function resolveRecursive(entries, configDir, ctx) {
3173
+ if (!entries || entries.length === 0) return [];
3174
+ const result = entries.flatMap((e) => resolveEntry(e, configDir, ctx));
3175
+ assertNoDuplicateRunNames(result);
3176
+ return result;
3177
+ }
3178
+ function resolveLocalCwd(config, configDir, ctx) {
3179
+ if (!config.cwd || configDir === ctx.rootConfigDir) return config;
3180
+ return {
3181
+ ...config,
3182
+ cwd: relativeToRoot(ctx, resolve3(configDir, config.cwd))
3183
+ };
3184
+ }
3185
+
3186
+ // src/commands/verify/run/resolveEntries.ts
3085
3187
  function buildFullCommand(command, args) {
3086
3188
  return [shellQuote(command), ...(args ?? []).map(shellQuote)].join(" ");
3087
3189
  }
3088
3190
  function getRunEntries() {
3089
3191
  const { run: run4 } = loadConfig();
3090
- if (!run4) return [];
3091
- return run4.filter((r) => r.name.startsWith("verify:")).map((r) => ({
3192
+ const configs = resolveRunConfigs(run4, getConfigDir());
3193
+ return configs.filter((r) => r.name.startsWith("verify:")).map((r) => ({
3092
3194
  name: r.name,
3093
3195
  fullCommand: buildFullCommand(r.command, r.args),
3196
+ cwd: r.cwd ? path17.resolve(getConfigDir(), r.cwd) : void 0,
3094
3197
  env: r.env,
3095
3198
  filter: r.filter
3096
3199
  }));
@@ -3263,14 +3366,14 @@ function flushIfFailed(exitCode, chunks) {
3263
3366
 
3264
3367
  // src/commands/verify/run/runAllEntries.ts
3265
3368
  function runEntry(entry, onComplete) {
3266
- return new Promise((resolve8) => {
3369
+ return new Promise((resolve13) => {
3267
3370
  const child = spawnCommand(entry.fullCommand, entry.cwd, entry.env);
3268
3371
  const chunks = collectOutput(child);
3269
3372
  child.on("close", (code) => {
3270
3373
  const exitCode = code ?? 1;
3271
3374
  flushIfFailed(exitCode, chunks);
3272
3375
  onComplete?.(exitCode);
3273
- resolve8({ script: entry.name, code: exitCode });
3376
+ resolve13({ script: entry.name, code: exitCode });
3274
3377
  });
3275
3378
  });
3276
3379
  }
@@ -3400,7 +3503,7 @@ program.parse();
3400
3503
 
3401
3504
  // src/commands/new/registerNew/newCli/index.ts
3402
3505
  async function newCli() {
3403
- const name = basename(resolve("."));
3506
+ const name = basename(resolve5("."));
3404
3507
  initGit();
3405
3508
  initPackageJson(name);
3406
3509
  console.log("Installing dependencies...");
@@ -3415,7 +3518,7 @@ async function newCli() {
3415
3518
 
3416
3519
  // src/commands/new/registerNew/newProject.ts
3417
3520
  import { execSync as execSync13 } from "child_process";
3418
- import { existsSync as existsSync18, readFileSync as readFileSync14, writeFileSync as writeFileSync14 } from "fs";
3521
+ import { existsSync as existsSync19, readFileSync as readFileSync14, writeFileSync as writeFileSync14 } from "fs";
3419
3522
 
3420
3523
  // src/commands/deploy/init/index.ts
3421
3524
  import { execSync as execSync12 } from "child_process";
@@ -3423,14 +3526,14 @@ import chalk40 from "chalk";
3423
3526
  import enquirer6 from "enquirer";
3424
3527
 
3425
3528
  // src/commands/deploy/init/updateWorkflow.ts
3426
- import { existsSync as existsSync17, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
3427
- import { dirname as dirname13, join as join14 } from "path";
3529
+ import { existsSync as existsSync18, mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
3530
+ import { dirname as dirname14, join as join15 } from "path";
3428
3531
  import { fileURLToPath as fileURLToPath3 } from "url";
3429
3532
  import chalk39 from "chalk";
3430
3533
  var WORKFLOW_PATH = ".github/workflows/build.yml";
3431
- var __dirname3 = dirname13(fileURLToPath3(import.meta.url));
3534
+ var __dirname3 = dirname14(fileURLToPath3(import.meta.url));
3432
3535
  function getExistingSiteId() {
3433
- if (!existsSync17(WORKFLOW_PATH)) {
3536
+ if (!existsSync18(WORKFLOW_PATH)) {
3434
3537
  return null;
3435
3538
  }
3436
3539
  const content = readFileSync13(WORKFLOW_PATH, "utf-8");
@@ -3438,17 +3541,17 @@ function getExistingSiteId() {
3438
3541
  return match ? match[1] : null;
3439
3542
  }
3440
3543
  function getTemplateContent(siteId) {
3441
- const templatePath = join14(__dirname3, "commands/deploy/build.yml");
3544
+ const templatePath = join15(__dirname3, "commands/deploy/build.yml");
3442
3545
  const template = readFileSync13(templatePath, "utf-8");
3443
3546
  return template.replace("{{NETLIFY_SITE_ID}}", siteId);
3444
3547
  }
3445
3548
  async function updateWorkflow(siteId) {
3446
3549
  const newContent = getTemplateContent(siteId);
3447
3550
  const workflowDir = ".github/workflows";
3448
- if (!existsSync17(workflowDir)) {
3551
+ if (!existsSync18(workflowDir)) {
3449
3552
  mkdirSync4(workflowDir, { recursive: true });
3450
3553
  }
3451
- if (existsSync17(WORKFLOW_PATH)) {
3554
+ if (existsSync18(WORKFLOW_PATH)) {
3452
3555
  const oldContent = readFileSync13(WORKFLOW_PATH, "utf-8");
3453
3556
  if (oldContent === newContent) {
3454
3557
  console.log(chalk39.green("build.yml is already up to date"));
@@ -3543,7 +3646,7 @@ async function newProject() {
3543
3646
  }
3544
3647
  function addViteBaseConfig() {
3545
3648
  const viteConfigPath = "vite.config.ts";
3546
- if (!existsSync18(viteConfigPath)) {
3649
+ if (!existsSync19(viteConfigPath)) {
3547
3650
  console.log("No vite.config.ts found, skipping base config");
3548
3651
  return;
3549
3652
  }
@@ -3877,7 +3980,7 @@ import chalk45 from "chalk";
3877
3980
 
3878
3981
  // src/commands/backlog/commitBacklog.ts
3879
3982
  import { execSync as execSync15 } from "child_process";
3880
- import { join as join15 } from "path";
3983
+ import { join as join16 } from "path";
3881
3984
  import chalk44 from "chalk";
3882
3985
  function commitBacklog(id, name) {
3883
3986
  const config = loadConfig();
@@ -3890,7 +3993,7 @@ function commitBacklog(id, name) {
3890
3993
  return;
3891
3994
  }
3892
3995
  try {
3893
- const jsonlPath = join15(getBacklogDir(), ".assist", "backlog.jsonl");
3996
+ const jsonlPath = join16(getBacklogDir(), ".assist", "backlog.jsonl");
3894
3997
  const message = `chore: add backlog item #${id} \u2014 ${name}`;
3895
3998
  execSync15(`git add ${shellQuote(jsonlPath)}`, { stdio: "ignore" });
3896
3999
  execSync15(`git commit -m ${shellQuote(message)}`, { stdio: "ignore" });
@@ -3903,7 +4006,7 @@ function commitBacklog(id, name) {
3903
4006
  import { spawnSync } from "child_process";
3904
4007
  import { mkdtempSync, readFileSync as readFileSync15, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "fs";
3905
4008
  import { tmpdir } from "os";
3906
- import { join as join16 } from "path";
4009
+ import { join as join17 } from "path";
3907
4010
  import enquirer7 from "enquirer";
3908
4011
  async function promptType() {
3909
4012
  const { type } = await enquirer7.prompt({
@@ -3943,8 +4046,8 @@ async function promptDescription() {
3943
4046
  }
3944
4047
  function openEditor() {
3945
4048
  const editor = process.env.EDITOR || process.env.VISUAL || "vi";
3946
- const dir = mkdtempSync(join16(tmpdir(), "assist-"));
3947
- const filePath = join16(dir, "description.md");
4049
+ const dir = mkdtempSync(join17(tmpdir(), "assist-"));
4050
+ const filePath = join17(dir, "description.md");
3948
4051
  writeFileSync15(filePath, "");
3949
4052
  const result = spawnSync(editor, [filePath], { stdio: "inherit" });
3950
4053
  if (result.status !== 0) {
@@ -4170,9 +4273,9 @@ function hasCycle(items, fromId, toId) {
4170
4273
  visited.add(current);
4171
4274
  const item = items.find((i) => i.id === current);
4172
4275
  if (!item?.links) continue;
4173
- for (const link2 of item.links) {
4174
- if (link2.type === "depends-on") {
4175
- stack.push(link2.targetId);
4276
+ for (const link3 of item.links) {
4277
+ if (link3.type === "depends-on") {
4278
+ stack.push(link3.targetId);
4176
4279
  }
4177
4280
  }
4178
4281
  }
@@ -4742,7 +4845,7 @@ function stripEnvPrefix(parts) {
4742
4845
  }
4743
4846
 
4744
4847
  // src/shared/isApprovedRead.ts
4745
- import { resolve as resolve3 } from "path";
4848
+ import { resolve as resolve7 } from "path";
4746
4849
 
4747
4850
  // src/shared/tokenize.ts
4748
4851
  function tokenize(command) {
@@ -4823,29 +4926,29 @@ function extractGraphqlQuery(args) {
4823
4926
  }
4824
4927
 
4825
4928
  // src/shared/loadCliReads.ts
4826
- import { existsSync as existsSync19, readFileSync as readFileSync16, writeFileSync as writeFileSync16 } from "fs";
4827
- import { dirname as dirname14, resolve as resolve2 } from "path";
4929
+ import { existsSync as existsSync20, readFileSync as readFileSync16, writeFileSync as writeFileSync16 } from "fs";
4930
+ import { dirname as dirname15, resolve as resolve6 } from "path";
4828
4931
  import { fileURLToPath as fileURLToPath4 } from "url";
4829
4932
  var __filename2 = fileURLToPath4(import.meta.url);
4830
- var __dirname4 = dirname14(__filename2);
4933
+ var __dirname4 = dirname15(__filename2);
4831
4934
  function packageRoot() {
4832
4935
  return __dirname4;
4833
4936
  }
4834
4937
  function readLines(path50) {
4835
- if (!existsSync19(path50)) return [];
4938
+ if (!existsSync20(path50)) return [];
4836
4939
  return readFileSync16(path50, "utf-8").split("\n").filter((line) => line.trim() !== "");
4837
4940
  }
4838
4941
  var cachedReads;
4839
4942
  var cachedWrites;
4840
4943
  function getCliReadsLines() {
4841
4944
  if (!cachedReads) {
4842
- cachedReads = readLines(resolve2(packageRoot(), "allowed.cli-reads"));
4945
+ cachedReads = readLines(resolve6(packageRoot(), "allowed.cli-reads"));
4843
4946
  }
4844
4947
  return cachedReads;
4845
4948
  }
4846
4949
  function getCliWritesLines() {
4847
4950
  if (!cachedWrites) {
4848
- cachedWrites = readLines(resolve2(packageRoot(), "allowed.cli-writes"));
4951
+ cachedWrites = readLines(resolve6(packageRoot(), "allowed.cli-writes"));
4849
4952
  }
4850
4953
  return cachedWrites;
4851
4954
  }
@@ -4854,7 +4957,7 @@ function loadCliReads() {
4854
4957
  }
4855
4958
  function saveCliReads(commands) {
4856
4959
  writeFileSync16(
4857
- resolve2(packageRoot(), "allowed.cli-reads"),
4960
+ resolve6(packageRoot(), "allowed.cli-reads"),
4858
4961
  `${commands.join("\n")}
4859
4962
  `
4860
4963
  );
@@ -4879,14 +4982,14 @@ function findCliWrite(command) {
4879
4982
  }
4880
4983
 
4881
4984
  // src/shared/readSettingsPerms.ts
4882
- import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
4985
+ import { existsSync as existsSync21, readFileSync as readFileSync17 } from "fs";
4883
4986
  import { homedir as homedir3 } from "os";
4884
- import { join as join17 } from "path";
4987
+ import { join as join18 } from "path";
4885
4988
  function readSettingsPerms(key) {
4886
4989
  const paths = [
4887
- join17(homedir3(), ".claude", "settings.json"),
4888
- join17(process.cwd(), ".claude", "settings.json"),
4889
- join17(process.cwd(), ".claude", "settings.local.json")
4990
+ join18(homedir3(), ".claude", "settings.json"),
4991
+ join18(process.cwd(), ".claude", "settings.json"),
4992
+ join18(process.cwd(), ".claude", "settings.local.json")
4890
4993
  ];
4891
4994
  const entries = [];
4892
4995
  for (const p of paths) {
@@ -4895,7 +4998,7 @@ function readSettingsPerms(key) {
4895
4998
  return entries;
4896
4999
  }
4897
5000
  function readPermissionArray(filePath, key) {
4898
- if (!existsSync20(filePath)) return [];
5001
+ if (!existsSync21(filePath)) return [];
4899
5002
  try {
4900
5003
  const data = JSON.parse(readFileSync17(filePath, "utf-8"));
4901
5004
  const arr = data?.permissions?.[key];
@@ -4971,8 +5074,8 @@ function isCdToCwd(command) {
4971
5074
  const parts = command.split(/\s+/);
4972
5075
  if (parts[0] !== "cd" || parts.length > 2) return false;
4973
5076
  if (parts.length === 1) return false;
4974
- const resolved = resolve3(normalizeMsysPath(parts[1]));
4975
- return resolved === resolve3(process.cwd());
5077
+ const resolved = resolve7(normalizeMsysPath(parts[1]));
5078
+ return resolved === resolve7(process.cwd());
4976
5079
  }
4977
5080
  function normalizeMsysPath(p) {
4978
5081
  const m = p.match(/^\/([a-zA-Z])(\/.*)/);
@@ -5089,18 +5192,18 @@ ${reasons.join("\n")}`);
5089
5192
  }
5090
5193
 
5091
5194
  // src/commands/permitCliReads/index.ts
5092
- import { existsSync as existsSync21, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "fs";
5195
+ import { existsSync as existsSync22, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "fs";
5093
5196
  import { homedir as homedir4 } from "os";
5094
- import { join as join18 } from "path";
5197
+ import { join as join19 } from "path";
5095
5198
 
5096
5199
  // src/shared/getInstallDir.ts
5097
5200
  import { execSync as execSync16 } from "child_process";
5098
- import { dirname as dirname15, resolve as resolve4 } from "path";
5201
+ import { dirname as dirname16, resolve as resolve8 } from "path";
5099
5202
  import { fileURLToPath as fileURLToPath5 } from "url";
5100
5203
  var __filename3 = fileURLToPath5(import.meta.url);
5101
- var __dirname5 = dirname15(__filename3);
5204
+ var __dirname5 = dirname16(__filename3);
5102
5205
  function getInstallDir() {
5103
- return resolve4(__dirname5, "..");
5206
+ return resolve8(__dirname5, "..");
5104
5207
  }
5105
5208
  function isGitRepo(dir) {
5106
5209
  try {
@@ -5108,7 +5211,7 @@ function isGitRepo(dir) {
5108
5211
  cwd: dir,
5109
5212
  stdio: "pipe"
5110
5213
  }).toString().trim();
5111
- return resolve4(result) === resolve4(dir);
5214
+ return resolve8(result) === resolve8(dir);
5112
5215
  } catch {
5113
5216
  return false;
5114
5217
  }
@@ -5221,12 +5324,12 @@ function hasSubcommands(helpText) {
5221
5324
  // src/commands/permitCliReads/runHelp.ts
5222
5325
  import { exec as exec2 } from "child_process";
5223
5326
  function runHelp(args) {
5224
- return new Promise((resolve8) => {
5327
+ return new Promise((resolve13) => {
5225
5328
  exec2(
5226
5329
  `${args.join(" ")} --help`,
5227
5330
  { encoding: "utf-8", timeout: 3e4 },
5228
5331
  (_err, stdout, stderr) => {
5229
- resolve8(stdout || stderr || "");
5332
+ resolve13(stdout || stderr || "");
5230
5333
  }
5231
5334
  );
5232
5335
  });
@@ -5393,15 +5496,15 @@ function updateSettings(cli, commands) {
5393
5496
  // src/commands/permitCliReads/index.ts
5394
5497
  function logPath(cli) {
5395
5498
  const safeName = cli.replace(/\s+/g, "-");
5396
- return join18(homedir4(), ".assist", `cli-discover-${safeName}.log`);
5499
+ return join19(homedir4(), ".assist", `cli-discover-${safeName}.log`);
5397
5500
  }
5398
5501
  function readCache(cli) {
5399
5502
  const path50 = logPath(cli);
5400
- if (!existsSync21(path50)) return void 0;
5503
+ if (!existsSync22(path50)) return void 0;
5401
5504
  return readFileSync18(path50, "utf-8");
5402
5505
  }
5403
5506
  function writeCache(cli, output) {
5404
- const dir = join18(homedir4(), ".assist");
5507
+ const dir = join19(homedir4(), ".assist");
5405
5508
  mkdirSync5(dir, { recursive: true });
5406
5509
  writeFileSync17(logPath(cli), output);
5407
5510
  }
@@ -6157,7 +6260,7 @@ function registerConfig(program2) {
6157
6260
  }
6158
6261
 
6159
6262
  // src/commands/deploy/redirect.ts
6160
- import { existsSync as existsSync22, readFileSync as readFileSync19, writeFileSync as writeFileSync18 } from "fs";
6263
+ import { existsSync as existsSync23, readFileSync as readFileSync19, writeFileSync as writeFileSync18 } from "fs";
6161
6264
  import chalk76 from "chalk";
6162
6265
  var TRAILING_SLASH_SCRIPT = ` <script>
6163
6266
  if (!window.location.pathname.endsWith('/')) {
@@ -6166,7 +6269,7 @@ var TRAILING_SLASH_SCRIPT = ` <script>
6166
6269
  </script>`;
6167
6270
  function redirect() {
6168
6271
  const indexPath = "index.html";
6169
- if (!existsSync22(indexPath)) {
6272
+ if (!existsSync23(indexPath)) {
6170
6273
  console.log(chalk76.yellow("No index.html found"));
6171
6274
  return;
6172
6275
  }
@@ -6198,10 +6301,10 @@ import { basename as basename3 } from "path";
6198
6301
 
6199
6302
  // src/commands/devlog/loadBlogSkipDays.ts
6200
6303
  import { homedir as homedir5 } from "os";
6201
- import { join as join19 } from "path";
6202
- var BLOG_REPO_ROOT = join19(homedir5(), "git/blog");
6304
+ import { join as join20 } from "path";
6305
+ var BLOG_REPO_ROOT = join20(homedir5(), "git/blog");
6203
6306
  function loadBlogSkipDays(repoName) {
6204
- const config = loadRawYaml(join19(BLOG_REPO_ROOT, "assist.yml"));
6307
+ const config = loadRawYaml(join20(BLOG_REPO_ROOT, "assist.yml"));
6205
6308
  const devlog = config.devlog;
6206
6309
  const skip2 = devlog?.skip;
6207
6310
  return new Set(skip2?.[repoName] ?? []);
@@ -6212,15 +6315,15 @@ import { execSync as execSync18 } from "child_process";
6212
6315
  import chalk77 from "chalk";
6213
6316
 
6214
6317
  // src/shared/getRepoName.ts
6215
- import { existsSync as existsSync23, readFileSync as readFileSync20 } from "fs";
6216
- import { basename as basename2, join as join20 } from "path";
6318
+ import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
6319
+ import { basename as basename2, join as join21 } from "path";
6217
6320
  function getRepoName() {
6218
6321
  const config = loadConfig();
6219
6322
  if (config.devlog?.name) {
6220
6323
  return config.devlog.name;
6221
6324
  }
6222
- const packageJsonPath = join20(process.cwd(), "package.json");
6223
- if (existsSync23(packageJsonPath)) {
6325
+ const packageJsonPath = join21(process.cwd(), "package.json");
6326
+ if (existsSync24(packageJsonPath)) {
6224
6327
  try {
6225
6328
  const content = readFileSync20(packageJsonPath, "utf-8");
6226
6329
  const pkg = JSON.parse(content);
@@ -6235,8 +6338,8 @@ function getRepoName() {
6235
6338
 
6236
6339
  // src/commands/devlog/loadDevlogEntries.ts
6237
6340
  import { readdirSync, readFileSync as readFileSync21 } from "fs";
6238
- import { join as join21 } from "path";
6239
- var DEVLOG_DIR = join21(BLOG_REPO_ROOT, "src/content/devlog");
6341
+ import { join as join22 } from "path";
6342
+ var DEVLOG_DIR = join22(BLOG_REPO_ROOT, "src/content/devlog");
6240
6343
  function extractFrontmatter(content) {
6241
6344
  const fm = content.match(/^---\n([\s\S]*?)\n---/);
6242
6345
  return fm?.[1] ?? null;
@@ -6264,7 +6367,7 @@ function readDevlogFiles(callback) {
6264
6367
  try {
6265
6368
  const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
6266
6369
  for (const file of files) {
6267
- const content = readFileSync21(join21(DEVLOG_DIR, file), "utf-8");
6370
+ const content = readFileSync21(join22(DEVLOG_DIR, file), "utf-8");
6268
6371
  const parsed = parseFrontmatter(content, file);
6269
6372
  if (parsed) callback(parsed);
6270
6373
  }
@@ -6651,11 +6754,11 @@ function repos(options2) {
6651
6754
 
6652
6755
  // src/commands/devlog/skip.ts
6653
6756
  import { writeFileSync as writeFileSync19 } from "fs";
6654
- import { join as join22 } from "path";
6757
+ import { join as join23 } from "path";
6655
6758
  import chalk82 from "chalk";
6656
6759
  import { stringify as stringifyYaml3 } from "yaml";
6657
6760
  function getBlogConfigPath() {
6658
- return join22(BLOG_REPO_ROOT, "assist.yml");
6761
+ return join23(BLOG_REPO_ROOT, "assist.yml");
6659
6762
  }
6660
6763
  function skip(date) {
6661
6764
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
@@ -6716,16 +6819,16 @@ function registerDevlog(program2) {
6716
6819
 
6717
6820
  // src/commands/dotnet/checkBuildLocks.ts
6718
6821
  import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
6719
- import { join as join23 } from "path";
6822
+ import { join as join24 } from "path";
6720
6823
  import chalk84 from "chalk";
6721
6824
 
6722
6825
  // src/shared/findRepoRoot.ts
6723
- import { existsSync as existsSync24 } from "fs";
6826
+ import { existsSync as existsSync25 } from "fs";
6724
6827
  import path21 from "path";
6725
6828
  function findRepoRoot(dir) {
6726
6829
  let current = dir;
6727
6830
  while (current !== path21.dirname(current)) {
6728
- if (existsSync24(path21.join(current, ".git"))) {
6831
+ if (existsSync25(path21.join(current, ".git"))) {
6729
6832
  return current;
6730
6833
  }
6731
6834
  current = path21.dirname(current);
@@ -6744,7 +6847,7 @@ function isLockedDll(debugDir) {
6744
6847
  }
6745
6848
  for (const file of files) {
6746
6849
  if (!file.toLowerCase().endsWith(".dll")) continue;
6747
- const dllPath = join23(debugDir, file);
6850
+ const dllPath = join24(debugDir, file);
6748
6851
  try {
6749
6852
  const fd = openSync(dllPath, "r+");
6750
6853
  closeSync(fd);
@@ -6762,13 +6865,13 @@ function findFirstLockedDll(dir) {
6762
6865
  return null;
6763
6866
  }
6764
6867
  if (entries.includes("bin")) {
6765
- const locked = isLockedDll(join23(dir, "bin", "Debug"));
6868
+ const locked = isLockedDll(join24(dir, "bin", "Debug"));
6766
6869
  if (locked) return locked;
6767
6870
  }
6768
6871
  for (const entry of entries) {
6769
6872
  if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
6770
6873
  continue;
6771
- const found = findFirstLockedDll(join23(dir, entry));
6874
+ const found = findFirstLockedDll(join24(dir, entry));
6772
6875
  if (found) return found;
6773
6876
  }
6774
6877
  return null;
@@ -6936,12 +7039,12 @@ function printJson(tree, totalCount, solutions) {
6936
7039
  }
6937
7040
 
6938
7041
  // src/commands/dotnet/resolveCsproj.ts
6939
- import { existsSync as existsSync25 } from "fs";
7042
+ import { existsSync as existsSync26 } from "fs";
6940
7043
  import path24 from "path";
6941
7044
  import chalk86 from "chalk";
6942
7045
  function resolveCsproj(csprojPath) {
6943
7046
  const resolved = path24.resolve(csprojPath);
6944
- if (!existsSync25(resolved)) {
7047
+ if (!existsSync26(resolved)) {
6945
7048
  console.error(chalk86.red(`File not found: ${resolved}`));
6946
7049
  process.exit(1);
6947
7050
  }
@@ -7109,17 +7212,17 @@ function filterIssues(issues, all, cliOnly, cliSuppress) {
7109
7212
  }
7110
7213
 
7111
7214
  // src/commands/dotnet/resolveSolution.ts
7112
- import { existsSync as existsSync26 } from "fs";
7215
+ import { existsSync as existsSync27 } from "fs";
7113
7216
  import path25 from "path";
7114
7217
  import chalk90 from "chalk";
7115
7218
 
7116
7219
  // src/commands/dotnet/findSolution.ts
7117
7220
  import { readdirSync as readdirSync4 } from "fs";
7118
- import { dirname as dirname16, join as join24 } from "path";
7221
+ import { dirname as dirname17, join as join25 } from "path";
7119
7222
  import chalk89 from "chalk";
7120
7223
  function findSlnInDir(dir) {
7121
7224
  try {
7122
- return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join24(dir, f));
7225
+ return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join25(dir, f));
7123
7226
  } catch {
7124
7227
  return [];
7125
7228
  }
@@ -7140,7 +7243,7 @@ function findSolution() {
7140
7243
  process.exit(1);
7141
7244
  }
7142
7245
  if (current === ceiling) break;
7143
- current = dirname16(current);
7246
+ current = dirname17(current);
7144
7247
  }
7145
7248
  console.error(chalk89.red("No .sln file found between cwd and repo root"));
7146
7249
  process.exit(1);
@@ -7150,7 +7253,7 @@ function findSolution() {
7150
7253
  function resolveSolution(sln) {
7151
7254
  if (sln) {
7152
7255
  const resolved = path25.resolve(sln);
7153
- if (!existsSync26(resolved)) {
7256
+ if (!existsSync27(resolved)) {
7154
7257
  console.error(chalk90.red(`Solution file not found: ${resolved}`));
7155
7258
  process.exit(1);
7156
7259
  }
@@ -7190,7 +7293,7 @@ function parseInspectReport(json) {
7190
7293
 
7191
7294
  // src/commands/dotnet/runInspectCode.ts
7192
7295
  import { execSync as execSync24 } from "child_process";
7193
- import { existsSync as existsSync27, readFileSync as readFileSync24, unlinkSync as unlinkSync5 } from "fs";
7296
+ import { existsSync as existsSync28, readFileSync as readFileSync24, unlinkSync as unlinkSync5 } from "fs";
7194
7297
  import { tmpdir as tmpdir2 } from "os";
7195
7298
  import path26 from "path";
7196
7299
  import chalk91 from "chalk";
@@ -7221,7 +7324,7 @@ function runInspectCode(slnPath, include, swea) {
7221
7324
  console.error(chalk91.red("jb inspectcode failed"));
7222
7325
  process.exit(1);
7223
7326
  }
7224
- if (!existsSync27(reportPath)) {
7327
+ if (!existsSync28(reportPath)) {
7225
7328
  console.error(chalk91.red("Report file not generated"));
7226
7329
  process.exit(1);
7227
7330
  }
@@ -7234,8 +7337,9 @@ function runInspectCode(slnPath, include, swea) {
7234
7337
  import { execSync as execSync25 } from "child_process";
7235
7338
  import chalk92 from "chalk";
7236
7339
  function resolveMsbuildPath() {
7237
- const config = loadConfig();
7238
- const buildConfig = config.run?.find((r) => r.name === "build");
7340
+ const { run: run4 } = loadConfig();
7341
+ const configs = resolveRunConfigs(run4, getConfigDir());
7342
+ const buildConfig = configs.find((r) => r.name === "build");
7239
7343
  return buildConfig?.command ?? "msbuild";
7240
7344
  }
7241
7345
  function assertMsbuildInstalled() {
@@ -7453,18 +7557,18 @@ function acceptanceCriteria(issueKey) {
7453
7557
  import { execSync as execSync27 } from "child_process";
7454
7558
 
7455
7559
  // src/shared/loadJson.ts
7456
- import { existsSync as existsSync28, mkdirSync as mkdirSync6, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
7560
+ import { existsSync as existsSync29, mkdirSync as mkdirSync6, readFileSync as readFileSync25, writeFileSync as writeFileSync20 } from "fs";
7457
7561
  import { homedir as homedir6 } from "os";
7458
- import { join as join25 } from "path";
7562
+ import { join as join26 } from "path";
7459
7563
  function getStoreDir() {
7460
- return join25(homedir6(), ".assist");
7564
+ return join26(homedir6(), ".assist");
7461
7565
  }
7462
7566
  function getStorePath(filename) {
7463
- return join25(getStoreDir(), filename);
7567
+ return join26(getStoreDir(), filename);
7464
7568
  }
7465
7569
  function loadJson(filename) {
7466
7570
  const path50 = getStorePath(filename);
7467
- if (existsSync28(path50)) {
7571
+ if (existsSync29(path50)) {
7468
7572
  try {
7469
7573
  return JSON.parse(readFileSync25(path50, "utf-8"));
7470
7574
  } catch {
@@ -7475,7 +7579,7 @@ function loadJson(filename) {
7475
7579
  }
7476
7580
  function saveJson(filename, data) {
7477
7581
  const dir = getStoreDir();
7478
- if (!existsSync28(dir)) {
7582
+ if (!existsSync29(dir)) {
7479
7583
  mkdirSync6(dir, { recursive: true });
7480
7584
  }
7481
7585
  writeFileSync20(getStorePath(filename), JSON.stringify(data, null, 2));
@@ -7792,7 +7896,7 @@ function registerNews(program2) {
7792
7896
  import { spawnSync as spawnSync2 } from "child_process";
7793
7897
  import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync21 } from "fs";
7794
7898
  import { tmpdir as tmpdir3 } from "os";
7795
- import { join as join26 } from "path";
7899
+ import { join as join27 } from "path";
7796
7900
 
7797
7901
  // src/commands/prs/shared.ts
7798
7902
  import { execSync as execSync28 } from "child_process";
@@ -7864,7 +7968,7 @@ function comment2(path50, line, body) {
7864
7968
  validateLine(line);
7865
7969
  try {
7866
7970
  const prId = getCurrentPrNodeId();
7867
- const queryFile = join26(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7971
+ const queryFile = join27(tmpdir3(), `gh-query-${Date.now()}.graphql`);
7868
7972
  writeFileSync21(queryFile, MUTATION);
7869
7973
  try {
7870
7974
  const result = spawnSync2(
@@ -7909,18 +8013,18 @@ import { execSync as execSync30 } from "child_process";
7909
8013
  import { execSync as execSync29 } from "child_process";
7910
8014
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync22 } from "fs";
7911
8015
  import { tmpdir as tmpdir4 } from "os";
7912
- import { join as join28 } from "path";
8016
+ import { join as join29 } from "path";
7913
8017
 
7914
8018
  // src/commands/prs/loadCommentsCache.ts
7915
- import { existsSync as existsSync29, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
7916
- import { join as join27 } from "path";
8019
+ import { existsSync as existsSync30, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
8020
+ import { join as join28 } from "path";
7917
8021
  import { parse as parse2 } from "yaml";
7918
8022
  function getCachePath(prNumber) {
7919
- return join27(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
8023
+ return join28(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
7920
8024
  }
7921
8025
  function loadCommentsCache(prNumber) {
7922
8026
  const cachePath = getCachePath(prNumber);
7923
- if (!existsSync29(cachePath)) {
8027
+ if (!existsSync30(cachePath)) {
7924
8028
  return null;
7925
8029
  }
7926
8030
  const content = readFileSync26(cachePath, "utf-8");
@@ -7928,7 +8032,7 @@ function loadCommentsCache(prNumber) {
7928
8032
  }
7929
8033
  function deleteCommentsCache(prNumber) {
7930
8034
  const cachePath = getCachePath(prNumber);
7931
- if (existsSync29(cachePath)) {
8035
+ if (existsSync30(cachePath)) {
7932
8036
  unlinkSync7(cachePath);
7933
8037
  console.log("No more unresolved line comments. Cache dropped.");
7934
8038
  }
@@ -7943,7 +8047,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
7943
8047
  }
7944
8048
  function resolveThread(threadId) {
7945
8049
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
7946
- const queryFile = join28(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
8050
+ const queryFile = join29(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
7947
8051
  writeFileSync22(queryFile, mutation);
7948
8052
  try {
7949
8053
  execSync29(
@@ -8025,18 +8129,18 @@ function fixed(commentId, sha) {
8025
8129
  }
8026
8130
 
8027
8131
  // src/commands/prs/listComments/index.ts
8028
- import { existsSync as existsSync30, mkdirSync as mkdirSync7, writeFileSync as writeFileSync24 } from "fs";
8029
- import { join as join30 } from "path";
8132
+ import { existsSync as existsSync31, mkdirSync as mkdirSync7, writeFileSync as writeFileSync24 } from "fs";
8133
+ import { join as join31 } from "path";
8030
8134
  import { stringify } from "yaml";
8031
8135
 
8032
8136
  // src/commands/prs/fetchThreadIds.ts
8033
8137
  import { execSync as execSync31 } from "child_process";
8034
8138
  import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync23 } from "fs";
8035
8139
  import { tmpdir as tmpdir5 } from "os";
8036
- import { join as join29 } from "path";
8140
+ import { join as join30 } from "path";
8037
8141
  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 } } } } } } }`;
8038
8142
  function fetchThreadIds(org, repo, prNumber) {
8039
- const queryFile = join29(tmpdir5(), `gh-query-${Date.now()}.graphql`);
8143
+ const queryFile = join30(tmpdir5(), `gh-query-${Date.now()}.graphql`);
8040
8144
  writeFileSync23(queryFile, THREAD_QUERY);
8041
8145
  try {
8042
8146
  const result = execSync31(
@@ -8150,8 +8254,8 @@ function printComments2(result) {
8150
8254
 
8151
8255
  // src/commands/prs/listComments/index.ts
8152
8256
  function writeCommentsCache(prNumber, comments2) {
8153
- const assistDir = join30(process.cwd(), ".assist");
8154
- if (!existsSync30(assistDir)) {
8257
+ const assistDir = join31(process.cwd(), ".assist");
8258
+ if (!existsSync31(assistDir)) {
8155
8259
  mkdirSync7(assistDir, { recursive: true });
8156
8260
  }
8157
8261
  const cacheData = {
@@ -8159,7 +8263,7 @@ function writeCommentsCache(prNumber, comments2) {
8159
8263
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
8160
8264
  comments: comments2
8161
8265
  };
8162
- const cachePath = join30(assistDir, `pr-${prNumber}-comments.yaml`);
8266
+ const cachePath = join31(assistDir, `pr-${prNumber}-comments.yaml`);
8163
8267
  writeFileSync24(cachePath, stringify(cacheData));
8164
8268
  }
8165
8269
  function handleKnownErrors(error) {
@@ -8192,7 +8296,7 @@ async function listComments() {
8192
8296
  ];
8193
8297
  updateCache(prNumber, allComments);
8194
8298
  const hasLineComments = allComments.some((c) => c.type === "line");
8195
- const cachePath = hasLineComments ? join30(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
8299
+ const cachePath = hasLineComments ? join31(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
8196
8300
  return { comments: allComments, cachePath };
8197
8301
  } catch (error) {
8198
8302
  const handled = handleKnownErrors(error);
@@ -8962,7 +9066,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
8962
9066
 
8963
9067
  // src/commands/refactor/check/index.ts
8964
9068
  function runScript(script, cwd) {
8965
- return new Promise((resolve8) => {
9069
+ return new Promise((resolve13) => {
8966
9070
  const child = spawn4("npm", ["run", script], {
8967
9071
  stdio: "pipe",
8968
9072
  shell: true,
@@ -8976,7 +9080,7 @@ function runScript(script, cwd) {
8976
9080
  output += data.toString();
8977
9081
  });
8978
9082
  child.on("close", (code) => {
8979
- resolve8({ script, code: code ?? 1, output });
9083
+ resolve13({ script, code: code ?? 1, output });
8980
9084
  });
8981
9085
  });
8982
9086
  }
@@ -10586,8 +10690,8 @@ function registerSeq(program2) {
10586
10690
  }
10587
10691
 
10588
10692
  // src/commands/transcript/shared.ts
10589
- import { existsSync as existsSync31, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
10590
- import { basename as basename4, join as join31, relative } from "path";
10693
+ import { existsSync as existsSync32, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
10694
+ import { basename as basename4, join as join32, relative as relative2 } from "path";
10591
10695
  import * as readline2 from "readline";
10592
10696
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
10593
10697
  function getDatePrefix(daysOffset = 0) {
@@ -10602,10 +10706,10 @@ function isValidDatePrefix(filename) {
10602
10706
  return DATE_PREFIX_REGEX.test(filename);
10603
10707
  }
10604
10708
  function collectFiles(dir, extension) {
10605
- if (!existsSync31(dir)) return [];
10709
+ if (!existsSync32(dir)) return [];
10606
10710
  const results = [];
10607
10711
  for (const entry of readdirSync5(dir)) {
10608
- const fullPath = join31(dir, entry);
10712
+ const fullPath = join32(dir, entry);
10609
10713
  if (statSync4(fullPath).isDirectory()) {
10610
10714
  results.push(...collectFiles(fullPath, extension));
10611
10715
  } else if (entry.endsWith(extension)) {
@@ -10617,7 +10721,7 @@ function collectFiles(dir, extension) {
10617
10721
  function toFileInfo(baseDir, fullPath) {
10618
10722
  return {
10619
10723
  absolutePath: fullPath,
10620
- relativePath: relative(baseDir, fullPath),
10724
+ relativePath: relative2(baseDir, fullPath),
10621
10725
  filename: basename4(fullPath)
10622
10726
  };
10623
10727
  }
@@ -10637,9 +10741,9 @@ function createReadlineInterface() {
10637
10741
  });
10638
10742
  }
10639
10743
  function askQuestion(rl, question) {
10640
- return new Promise((resolve8) => {
10744
+ return new Promise((resolve13) => {
10641
10745
  rl.question(question, (answer) => {
10642
- resolve8(answer.trim());
10746
+ resolve13(answer.trim());
10643
10747
  });
10644
10748
  });
10645
10749
  }
@@ -10699,14 +10803,14 @@ async function configure() {
10699
10803
  }
10700
10804
 
10701
10805
  // src/commands/transcript/format/index.ts
10702
- import { existsSync as existsSync33 } from "fs";
10806
+ import { existsSync as existsSync34 } from "fs";
10703
10807
 
10704
10808
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
10705
- import { dirname as dirname18, join as join33 } from "path";
10809
+ import { dirname as dirname19, join as join34 } from "path";
10706
10810
 
10707
10811
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
10708
10812
  import { renameSync as renameSync2 } from "fs";
10709
- import { join as join32 } from "path";
10813
+ import { join as join33 } from "path";
10710
10814
  async function resolveDate(rl, choice) {
10711
10815
  if (choice === "1") return getDatePrefix(0);
10712
10816
  if (choice === "2") return getDatePrefix(-1);
@@ -10721,7 +10825,7 @@ async function resolveDate(rl, choice) {
10721
10825
  }
10722
10826
  function renameWithPrefix(vttDir, vttFile, prefix2) {
10723
10827
  const newFilename = `${prefix2}.${vttFile}`;
10724
- renameSync2(join32(vttDir, vttFile), join32(vttDir, newFilename));
10828
+ renameSync2(join33(vttDir, vttFile), join33(vttDir, newFilename));
10725
10829
  console.log(`Renamed to: ${newFilename}`);
10726
10830
  return newFilename;
10727
10831
  }
@@ -10752,15 +10856,15 @@ async function fixInvalidDatePrefixes(vttFiles) {
10752
10856
  for (let i = 0; i < vttFiles.length; i++) {
10753
10857
  const vttFile = vttFiles[i];
10754
10858
  if (!isValidDatePrefix(vttFile.filename)) {
10755
- const vttFileDir = dirname18(vttFile.absolutePath);
10859
+ const vttFileDir = dirname19(vttFile.absolutePath);
10756
10860
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
10757
10861
  if (newFilename) {
10758
- const newRelativePath = join33(
10759
- dirname18(vttFile.relativePath),
10862
+ const newRelativePath = join34(
10863
+ dirname19(vttFile.relativePath),
10760
10864
  newFilename
10761
10865
  );
10762
10866
  vttFiles[i] = {
10763
- absolutePath: join33(vttFileDir, newFilename),
10867
+ absolutePath: join34(vttFileDir, newFilename),
10764
10868
  relativePath: newRelativePath,
10765
10869
  filename: newFilename
10766
10870
  };
@@ -10773,8 +10877,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
10773
10877
  }
10774
10878
 
10775
10879
  // src/commands/transcript/format/processVttFile/index.ts
10776
- import { existsSync as existsSync32, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync25 } from "fs";
10777
- import { basename as basename5, dirname as dirname19, join as join34 } from "path";
10880
+ import { existsSync as existsSync33, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync25 } from "fs";
10881
+ import { basename as basename5, dirname as dirname20, join as join35 } from "path";
10778
10882
 
10779
10883
  // src/commands/transcript/cleanText.ts
10780
10884
  function cleanText(text) {
@@ -10984,21 +11088,21 @@ function toMdFilename(vttFilename) {
10984
11088
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
10985
11089
  }
10986
11090
  function resolveOutputDir(relativeDir, transcriptsDir) {
10987
- return relativeDir === "." ? transcriptsDir : join34(transcriptsDir, relativeDir);
11091
+ return relativeDir === "." ? transcriptsDir : join35(transcriptsDir, relativeDir);
10988
11092
  }
10989
11093
  function buildOutputPaths(vttFile, transcriptsDir) {
10990
11094
  const mdFile = toMdFilename(vttFile.filename);
10991
- const relativeDir = dirname19(vttFile.relativePath);
11095
+ const relativeDir = dirname20(vttFile.relativePath);
10992
11096
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
10993
- const outputPath = join34(outputDir, mdFile);
11097
+ const outputPath = join35(outputDir, mdFile);
10994
11098
  return { outputDir, outputPath, mdFile, relativeDir };
10995
11099
  }
10996
11100
  function logSkipped(relativeDir, mdFile) {
10997
- console.log(`Skipping (already exists): ${join34(relativeDir, mdFile)}`);
11101
+ console.log(`Skipping (already exists): ${join35(relativeDir, mdFile)}`);
10998
11102
  return "skipped";
10999
11103
  }
11000
11104
  function ensureDirectory(dir, label2) {
11001
- if (!existsSync32(dir)) {
11105
+ if (!existsSync33(dir)) {
11002
11106
  mkdirSync8(dir, { recursive: true });
11003
11107
  console.log(`Created ${label2}: ${dir}`);
11004
11108
  }
@@ -11034,7 +11138,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
11034
11138
  logReduction(cues.length, chatMessages.length);
11035
11139
  }
11036
11140
  function tryProcessVtt(vttFile, paths) {
11037
- if (existsSync32(paths.outputPath))
11141
+ if (existsSync33(paths.outputPath))
11038
11142
  return logSkipped(paths.relativeDir, paths.mdFile);
11039
11143
  convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
11040
11144
  return "processed";
@@ -11060,7 +11164,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
11060
11164
  logSummary(counts);
11061
11165
  }
11062
11166
  function requireVttDir(vttDir) {
11063
- if (!existsSync33(vttDir)) {
11167
+ if (!existsSync34(vttDir)) {
11064
11168
  console.error(`VTT directory not found: ${vttDir}`);
11065
11169
  process.exit(1);
11066
11170
  }
@@ -11092,18 +11196,18 @@ async function format() {
11092
11196
  }
11093
11197
 
11094
11198
  // src/commands/transcript/summarise/index.ts
11095
- import { existsSync as existsSync35 } from "fs";
11096
- import { basename as basename6, dirname as dirname21, join as join36, relative as relative2 } from "path";
11199
+ import { existsSync as existsSync36 } from "fs";
11200
+ import { basename as basename6, dirname as dirname22, join as join37, relative as relative3 } from "path";
11097
11201
 
11098
11202
  // src/commands/transcript/summarise/processStagedFile/index.ts
11099
11203
  import {
11100
- existsSync as existsSync34,
11204
+ existsSync as existsSync35,
11101
11205
  mkdirSync as mkdirSync9,
11102
11206
  readFileSync as readFileSync28,
11103
11207
  renameSync as renameSync3,
11104
11208
  rmSync
11105
11209
  } from "fs";
11106
- import { dirname as dirname20, join as join35 } from "path";
11210
+ import { dirname as dirname21, join as join36 } from "path";
11107
11211
 
11108
11212
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
11109
11213
  import chalk130 from "chalk";
@@ -11132,9 +11236,9 @@ function validateStagedContent(filename, content) {
11132
11236
  }
11133
11237
 
11134
11238
  // src/commands/transcript/summarise/processStagedFile/index.ts
11135
- var STAGING_DIR = join35(process.cwd(), ".assist", "transcript");
11239
+ var STAGING_DIR = join36(process.cwd(), ".assist", "transcript");
11136
11240
  function processStagedFile() {
11137
- if (!existsSync34(STAGING_DIR)) {
11241
+ if (!existsSync35(STAGING_DIR)) {
11138
11242
  return false;
11139
11243
  }
11140
11244
  const stagedFiles = findMdFilesRecursive(STAGING_DIR);
@@ -11156,9 +11260,9 @@ function processStagedFile() {
11156
11260
  );
11157
11261
  process.exit(1);
11158
11262
  }
11159
- const destPath = join35(summaryDir, matchingTranscript.relativePath);
11160
- const destDir = dirname20(destPath);
11161
- if (!existsSync34(destDir)) {
11263
+ const destPath = join36(summaryDir, matchingTranscript.relativePath);
11264
+ const destDir = dirname21(destPath);
11265
+ if (!existsSync35(destDir)) {
11162
11266
  mkdirSync9(destDir, { recursive: true });
11163
11267
  }
11164
11268
  renameSync3(stagedFile.absolutePath, destPath);
@@ -11171,8 +11275,8 @@ function processStagedFile() {
11171
11275
 
11172
11276
  // src/commands/transcript/summarise/index.ts
11173
11277
  function buildRelativeKey(relativePath, baseName) {
11174
- const relDir = dirname21(relativePath);
11175
- return relDir === "." ? baseName : join36(relDir, baseName);
11278
+ const relDir = dirname22(relativePath);
11279
+ return relDir === "." ? baseName : join37(relDir, baseName);
11176
11280
  }
11177
11281
  function buildSummaryIndex(summaryDir) {
11178
11282
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -11185,7 +11289,7 @@ function buildSummaryIndex(summaryDir) {
11185
11289
  function summarise2() {
11186
11290
  processStagedFile();
11187
11291
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
11188
- if (!existsSync35(transcriptsDir)) {
11292
+ if (!existsSync36(transcriptsDir)) {
11189
11293
  console.log("No transcripts directory found.");
11190
11294
  return;
11191
11295
  }
@@ -11206,10 +11310,10 @@ function summarise2() {
11206
11310
  }
11207
11311
  const next3 = missing[0];
11208
11312
  const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
11209
- const outputPath = join36(STAGING_DIR, outputFilename);
11210
- const summaryFileDir = join36(summaryDir, dirname21(next3.relativePath));
11313
+ const outputPath = join37(STAGING_DIR, outputFilename);
11314
+ const summaryFileDir = join37(summaryDir, dirname22(next3.relativePath));
11211
11315
  const relativeTranscriptPath = encodeURI(
11212
- relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
11316
+ relative3(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
11213
11317
  );
11214
11318
  console.log(`Missing summaries: ${missing.length}
11215
11319
  `);
@@ -11253,45 +11357,45 @@ function registerVerify(program2) {
11253
11357
 
11254
11358
  // src/commands/voice/devices.ts
11255
11359
  import { spawnSync as spawnSync3 } from "child_process";
11256
- import { join as join38 } from "path";
11360
+ import { join as join39 } from "path";
11257
11361
 
11258
11362
  // src/commands/voice/shared.ts
11259
11363
  import { homedir as homedir7 } from "os";
11260
- import { dirname as dirname22, join as join37 } from "path";
11364
+ import { dirname as dirname23, join as join38 } from "path";
11261
11365
  import { fileURLToPath as fileURLToPath6 } from "url";
11262
- var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
11263
- var VOICE_DIR = join37(homedir7(), ".assist", "voice");
11366
+ var __dirname6 = dirname23(fileURLToPath6(import.meta.url));
11367
+ var VOICE_DIR = join38(homedir7(), ".assist", "voice");
11264
11368
  var voicePaths = {
11265
11369
  dir: VOICE_DIR,
11266
- pid: join37(VOICE_DIR, "voice.pid"),
11267
- log: join37(VOICE_DIR, "voice.log"),
11268
- venv: join37(VOICE_DIR, ".venv"),
11269
- lock: join37(VOICE_DIR, "voice.lock")
11370
+ pid: join38(VOICE_DIR, "voice.pid"),
11371
+ log: join38(VOICE_DIR, "voice.log"),
11372
+ venv: join38(VOICE_DIR, ".venv"),
11373
+ lock: join38(VOICE_DIR, "voice.lock")
11270
11374
  };
11271
11375
  function getPythonDir() {
11272
- return join37(__dirname6, "commands", "voice", "python");
11376
+ return join38(__dirname6, "commands", "voice", "python");
11273
11377
  }
11274
11378
  function getVenvPython() {
11275
- return process.platform === "win32" ? join37(voicePaths.venv, "Scripts", "python.exe") : join37(voicePaths.venv, "bin", "python");
11379
+ return process.platform === "win32" ? join38(voicePaths.venv, "Scripts", "python.exe") : join38(voicePaths.venv, "bin", "python");
11276
11380
  }
11277
11381
  function getLockDir() {
11278
11382
  const config = loadConfig();
11279
11383
  return config.voice?.lockDir ?? VOICE_DIR;
11280
11384
  }
11281
11385
  function getLockFile() {
11282
- return join37(getLockDir(), "voice.lock");
11386
+ return join38(getLockDir(), "voice.lock");
11283
11387
  }
11284
11388
 
11285
11389
  // src/commands/voice/devices.ts
11286
11390
  function devices() {
11287
- const script = join38(getPythonDir(), "list_devices.py");
11391
+ const script = join39(getPythonDir(), "list_devices.py");
11288
11392
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
11289
11393
  }
11290
11394
 
11291
11395
  // src/commands/voice/logs.ts
11292
- import { existsSync as existsSync36, readFileSync as readFileSync29 } from "fs";
11396
+ import { existsSync as existsSync37, readFileSync as readFileSync29 } from "fs";
11293
11397
  function logs(options2) {
11294
- if (!existsSync36(voicePaths.log)) {
11398
+ if (!existsSync37(voicePaths.log)) {
11295
11399
  console.log("No voice log file found");
11296
11400
  return;
11297
11401
  }
@@ -11319,12 +11423,12 @@ function logs(options2) {
11319
11423
  // src/commands/voice/setup.ts
11320
11424
  import { spawnSync as spawnSync4 } from "child_process";
11321
11425
  import { mkdirSync as mkdirSync11 } from "fs";
11322
- import { join as join40 } from "path";
11426
+ import { join as join41 } from "path";
11323
11427
 
11324
11428
  // src/commands/voice/checkLockFile.ts
11325
11429
  import { execSync as execSync38 } from "child_process";
11326
- import { existsSync as existsSync37, mkdirSync as mkdirSync10, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
11327
- import { join as join39 } from "path";
11430
+ import { existsSync as existsSync38, mkdirSync as mkdirSync10, readFileSync as readFileSync30, writeFileSync as writeFileSync26 } from "fs";
11431
+ import { join as join40 } from "path";
11328
11432
  function isProcessAlive2(pid) {
11329
11433
  try {
11330
11434
  process.kill(pid, 0);
@@ -11335,7 +11439,7 @@ function isProcessAlive2(pid) {
11335
11439
  }
11336
11440
  function checkLockFile() {
11337
11441
  const lockFile = getLockFile();
11338
- if (!existsSync37(lockFile)) return;
11442
+ if (!existsSync38(lockFile)) return;
11339
11443
  try {
11340
11444
  const lock = JSON.parse(readFileSync30(lockFile, "utf-8"));
11341
11445
  if (lock.pid && isProcessAlive2(lock.pid)) {
@@ -11348,7 +11452,7 @@ function checkLockFile() {
11348
11452
  }
11349
11453
  }
11350
11454
  function bootstrapVenv() {
11351
- if (existsSync37(getVenvPython())) return;
11455
+ if (existsSync38(getVenvPython())) return;
11352
11456
  console.log("Setting up Python environment...");
11353
11457
  const pythonDir = getPythonDir();
11354
11458
  execSync38(
@@ -11361,7 +11465,7 @@ function bootstrapVenv() {
11361
11465
  }
11362
11466
  function writeLockFile(pid) {
11363
11467
  const lockFile = getLockFile();
11364
- mkdirSync10(join39(lockFile, ".."), { recursive: true });
11468
+ mkdirSync10(join40(lockFile, ".."), { recursive: true });
11365
11469
  writeFileSync26(
11366
11470
  lockFile,
11367
11471
  JSON.stringify({
@@ -11377,7 +11481,7 @@ function setup() {
11377
11481
  mkdirSync11(voicePaths.dir, { recursive: true });
11378
11482
  bootstrapVenv();
11379
11483
  console.log("\nDownloading models...\n");
11380
- const script = join40(getPythonDir(), "setup_models.py");
11484
+ const script = join41(getPythonDir(), "setup_models.py");
11381
11485
  const result = spawnSync4(getVenvPython(), [script], {
11382
11486
  stdio: "inherit",
11383
11487
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -11391,7 +11495,7 @@ function setup() {
11391
11495
  // src/commands/voice/start.ts
11392
11496
  import { spawn as spawn5 } from "child_process";
11393
11497
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync27 } from "fs";
11394
- import { join as join41 } from "path";
11498
+ import { join as join42 } from "path";
11395
11499
 
11396
11500
  // src/commands/voice/buildDaemonEnv.ts
11397
11501
  function buildDaemonEnv(options2) {
@@ -11429,7 +11533,7 @@ function start2(options2) {
11429
11533
  bootstrapVenv();
11430
11534
  const debug = options2.debug || options2.foreground || process.platform === "win32";
11431
11535
  const env = buildDaemonEnv({ debug });
11432
- const script = join41(getPythonDir(), "voice_daemon.py");
11536
+ const script = join42(getPythonDir(), "voice_daemon.py");
11433
11537
  const python = getVenvPython();
11434
11538
  if (options2.foreground) {
11435
11539
  spawnForeground(python, script, env);
@@ -11439,7 +11543,7 @@ function start2(options2) {
11439
11543
  }
11440
11544
 
11441
11545
  // src/commands/voice/status.ts
11442
- import { existsSync as existsSync38, readFileSync as readFileSync31 } from "fs";
11546
+ import { existsSync as existsSync39, readFileSync as readFileSync31 } from "fs";
11443
11547
  function isProcessAlive3(pid) {
11444
11548
  try {
11445
11549
  process.kill(pid, 0);
@@ -11449,12 +11553,12 @@ function isProcessAlive3(pid) {
11449
11553
  }
11450
11554
  }
11451
11555
  function readRecentLogs(count) {
11452
- if (!existsSync38(voicePaths.log)) return [];
11556
+ if (!existsSync39(voicePaths.log)) return [];
11453
11557
  const lines = readFileSync31(voicePaths.log, "utf-8").trim().split("\n");
11454
11558
  return lines.slice(-count);
11455
11559
  }
11456
11560
  function status() {
11457
- if (!existsSync38(voicePaths.pid)) {
11561
+ if (!existsSync39(voicePaths.pid)) {
11458
11562
  console.log("Voice daemon: not running (no PID file)");
11459
11563
  return;
11460
11564
  }
@@ -11477,9 +11581,9 @@ function status() {
11477
11581
  }
11478
11582
 
11479
11583
  // src/commands/voice/stop.ts
11480
- import { existsSync as existsSync39, readFileSync as readFileSync32, unlinkSync as unlinkSync10 } from "fs";
11584
+ import { existsSync as existsSync40, readFileSync as readFileSync32, unlinkSync as unlinkSync10 } from "fs";
11481
11585
  function stop() {
11482
- if (!existsSync39(voicePaths.pid)) {
11586
+ if (!existsSync40(voicePaths.pid)) {
11483
11587
  console.log("Voice daemon is not running (no PID file)");
11484
11588
  return;
11485
11589
  }
@@ -11496,7 +11600,7 @@ function stop() {
11496
11600
  }
11497
11601
  try {
11498
11602
  const lockFile = getLockFile();
11499
- if (existsSync39(lockFile)) unlinkSync10(lockFile);
11603
+ if (existsSync40(lockFile)) unlinkSync10(lockFile);
11500
11604
  } catch {
11501
11605
  }
11502
11606
  console.log("Voice daemon stopped");
@@ -11580,7 +11684,7 @@ function extractCode(url, expectedState) {
11580
11684
  return code;
11581
11685
  }
11582
11686
  function waitForCallback(port, expectedState) {
11583
- return new Promise((resolve8, reject) => {
11687
+ return new Promise((resolve13, reject) => {
11584
11688
  const timeout = setTimeout(() => {
11585
11689
  server.close();
11586
11690
  reject(new Error("Authorization timed out after 120 seconds"));
@@ -11597,7 +11701,7 @@ function waitForCallback(port, expectedState) {
11597
11701
  const code = extractCode(url, expectedState);
11598
11702
  respondHtml(res, 200, "Authorization successful!");
11599
11703
  server.close();
11600
- resolve8(code);
11704
+ resolve13(code);
11601
11705
  } catch (err) {
11602
11706
  respondHtml(res, 400, err.message);
11603
11707
  server.close();
@@ -11718,11 +11822,11 @@ async function auth() {
11718
11822
 
11719
11823
  // src/commands/roam/showClaudeCodeIcon.ts
11720
11824
  import { readFileSync as readFileSync33 } from "fs";
11721
- import { join as join42 } from "path";
11825
+ import { join as join43 } from "path";
11722
11826
  async function showClaudeCodeIcon() {
11723
11827
  const appData = process.env.APPDATA;
11724
11828
  if (!appData) return;
11725
- const portFile = join42(appData, "Roam", "roam-local-api.port");
11829
+ const portFile = join43(appData, "Roam", "roam-local-api.port");
11726
11830
  let port;
11727
11831
  try {
11728
11832
  port = readFileSync33(portFile, "utf-8").trim();
@@ -11748,12 +11852,13 @@ function registerRoam(program2) {
11748
11852
  }
11749
11853
 
11750
11854
  // src/commands/run/index.ts
11751
- import { resolve as resolve5 } from "path";
11855
+ import { resolve as resolve10 } from "path";
11752
11856
 
11753
11857
  // src/commands/run/formatConfiguredCommands.ts
11754
11858
  function formatConfiguredCommands() {
11755
- const { run: configs } = loadConfig();
11756
- if (!configs || configs.length === 0) return "\nNo configured commands";
11859
+ const { run: entries } = loadConfig();
11860
+ const configs = resolveRunConfigs(entries, getConfigDir());
11861
+ if (configs.length === 0) return "\nNo configured commands";
11757
11862
  const names = configs.map((r) => ` ${r.name}`).join("\n");
11758
11863
  return `
11759
11864
  Configured commands:
@@ -11798,12 +11903,24 @@ function runPreCommands(pre, cwd) {
11798
11903
  }
11799
11904
 
11800
11905
  // src/commands/run/spawnRunCommand.ts
11801
- import { spawn as spawn6 } from "child_process";
11802
- function spawnRunCommand(fullCommand, env, cwd) {
11906
+ import { execFileSync, spawn as spawn6 } from "child_process";
11907
+ import { existsSync as existsSync41 } from "fs";
11908
+ import { dirname as dirname24, join as join44, resolve as resolve9 } from "path";
11909
+ function resolveCommand2(command) {
11910
+ if (process.platform !== "win32" || command !== "bash") return command;
11911
+ try {
11912
+ const gitPath = execFileSync("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
11913
+ const gitRoot = resolve9(dirname24(gitPath), "..");
11914
+ const gitBash = join44(gitRoot, "bin", "bash.exe");
11915
+ if (existsSync41(gitBash)) return gitBash;
11916
+ } catch {
11917
+ }
11918
+ return command;
11919
+ }
11920
+ function spawnRunCommand(command, args, env, cwd) {
11803
11921
  const start3 = Date.now();
11804
- const child = spawn6(fullCommand, [], {
11922
+ const child = spawn6(resolveCommand2(command), args, {
11805
11923
  stdio: "inherit",
11806
- shell: true,
11807
11924
  env: env ? { ...process.env, ...expandEnv(env) } : void 0,
11808
11925
  cwd
11809
11926
  });
@@ -11820,10 +11937,6 @@ Done in ${elapsed}`);
11820
11937
  }
11821
11938
 
11822
11939
  // src/commands/run/index.ts
11823
- function buildCommand(command, configArgs, extraArgs) {
11824
- const parts = [command, ...configArgs];
11825
- return [...parts.map(shellQuote), ...extraArgs.map(shellQuote)].join(" ");
11826
- }
11827
11940
  function printAvailableConfigs(configs) {
11828
11941
  console.error("Available configurations:");
11829
11942
  for (const r of configs) {
@@ -11836,8 +11949,9 @@ function exitNoRunConfigs() {
11836
11949
  }
11837
11950
  function requireRunConfigs() {
11838
11951
  const { run: run4 } = loadConfig();
11839
- if (!run4 || run4.length === 0) return exitNoRunConfigs();
11840
- return run4;
11952
+ const configs = resolveRunConfigs(run4, getConfigDir());
11953
+ if (configs.length === 0) return exitNoRunConfigs();
11954
+ return configs;
11841
11955
  }
11842
11956
  function exitWithConfigNotFound(name, configs) {
11843
11957
  console.error(`No run configuration found with name: ${name}`);
@@ -11846,40 +11960,48 @@ function exitWithConfigNotFound(name, configs) {
11846
11960
  }
11847
11961
  function findRunConfig(name) {
11848
11962
  const configs = requireRunConfigs();
11849
- return configs.find((r) => r.name === name) ?? exitWithConfigNotFound(name, configs);
11963
+ const exact = configs.find((r) => r.name === name);
11964
+ if (exact) return exact;
11965
+ const suffixMatches = configs.filter((r) => r.name.endsWith(`:${name}`));
11966
+ if (suffixMatches.length === 1) return suffixMatches[0];
11967
+ return exitWithConfigNotFound(name, configs);
11850
11968
  }
11851
- function listRunConfigs() {
11969
+ function listRunConfigs(verbose) {
11852
11970
  const configs = requireRunConfigs();
11853
11971
  for (const config of configs) {
11854
- const args = config.args?.length ? ` ${config.args.join(" ")}` : "";
11855
- console.log(`${config.name}: ${config.command}${args}`);
11972
+ if (verbose) {
11973
+ const args = config.args?.length ? ` ${config.args.join(" ")}` : "";
11974
+ console.log(`${config.name}: ${config.command}${args}`);
11975
+ } else {
11976
+ console.log(config.name);
11977
+ }
11856
11978
  }
11857
11979
  }
11980
+ function execRunConfig(config, args) {
11981
+ const cwd = config.cwd ? resolve10(getConfigDir(), config.cwd) : void 0;
11982
+ if (config.pre) runPreCommands(config.pre, cwd);
11983
+ const resolved = resolveParams(config.params, args);
11984
+ spawnRunCommand(
11985
+ config.command,
11986
+ [...config.args ?? [], ...resolved],
11987
+ config.env,
11988
+ cwd
11989
+ );
11990
+ }
11858
11991
  function run3(name, args) {
11859
11992
  if (!name) {
11860
11993
  console.error("error: missing required argument 'name'");
11861
11994
  console.error(formatConfiguredCommands());
11862
11995
  process.exit(1);
11863
11996
  }
11864
- const runConfig = findRunConfig(name);
11865
- const resolvedCwd = runConfig.cwd ? resolve5(getConfigDir(), runConfig.cwd) : void 0;
11866
- if (runConfig.pre) runPreCommands(runConfig.pre, resolvedCwd);
11867
- const resolved = resolveParams(runConfig.params, args);
11868
- spawnRunCommand(
11869
- buildCommand(runConfig.command, runConfig.args ?? [], resolved),
11870
- runConfig.env,
11871
- resolvedCwd
11872
- );
11997
+ execRunConfig(findRunConfig(name), args);
11873
11998
  }
11874
11999
 
11875
12000
  // src/commands/run/add.ts
11876
12001
  import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync28 } from "fs";
11877
- import { join as join43 } from "path";
11878
- function findAddIndex() {
11879
- const addIndex = process.argv.indexOf("add");
11880
- if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
11881
- return addIndex;
11882
- }
12002
+ import { join as join45 } from "path";
12003
+
12004
+ // src/commands/run/extractOption.ts
11883
12005
  function extractOption(args, flag) {
11884
12006
  const index = args.indexOf(flag);
11885
12007
  if (index === -1) return { value: void 0, remaining: args };
@@ -11888,6 +12010,13 @@ function extractOption(args, flag) {
11888
12010
  remaining: [...args.slice(0, index), ...args.slice(index + 2)]
11889
12011
  };
11890
12012
  }
12013
+
12014
+ // src/commands/run/add.ts
12015
+ function findAddIndex() {
12016
+ const addIndex = process.argv.indexOf("add");
12017
+ if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
12018
+ return addIndex;
12019
+ }
11891
12020
  function extractAddArgs(addIndex) {
11892
12021
  const rawArgs = process.argv.slice(addIndex + 3);
11893
12022
  const { value: cwd, remaining: args } = extractOption(rawArgs, "--cwd");
@@ -11931,7 +12060,7 @@ function saveNewRunConfig(name, command, args, cwd) {
11931
12060
  saveConfig(config);
11932
12061
  }
11933
12062
  function createCommandFile(name) {
11934
- const dir = join43(".claude", "commands");
12063
+ const dir = join45(".claude", "commands");
11935
12064
  mkdirSync13(dir, { recursive: true });
11936
12065
  const content = `---
11937
12066
  description: Run ${name}
@@ -11939,7 +12068,7 @@ description: Run ${name}
11939
12068
 
11940
12069
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
11941
12070
  `;
11942
- const filePath = join43(dir, `${name}.md`);
12071
+ const filePath = join45(dir, `${name}.md`);
11943
12072
  writeFileSync28(filePath, content);
11944
12073
  console.log(`Created command file: ${filePath}`);
11945
12074
  }
@@ -11952,9 +12081,49 @@ function add3() {
11952
12081
  );
11953
12082
  }
11954
12083
 
12084
+ // src/commands/run/link.ts
12085
+ function findLinkIndex() {
12086
+ const idx = process.argv.indexOf("link");
12087
+ if (idx === -1 || idx + 1 >= process.argv.length) return -1;
12088
+ return idx;
12089
+ }
12090
+ function parseLinkArgs() {
12091
+ const idx = findLinkIndex();
12092
+ if (idx === -1) return null;
12093
+ const path50 = process.argv[idx + 1];
12094
+ const rest = process.argv.slice(idx + 2);
12095
+ const { value: prefix2 } = extractOption(rest, "--prefix");
12096
+ if (!prefix2) return null;
12097
+ return { path: path50, prefix: prefix2 };
12098
+ }
12099
+ function hasDuplicateLink(runList, linkPath) {
12100
+ return runList.some(
12101
+ (r) => typeof r === "object" && r !== null && "link" in r && r.link === linkPath
12102
+ );
12103
+ }
12104
+ function link2() {
12105
+ const parsed = parseLinkArgs();
12106
+ if (!parsed) {
12107
+ console.error("Usage: assist run link <path> --prefix <prefix>");
12108
+ process.exit(1);
12109
+ }
12110
+ const config = loadProjectConfig();
12111
+ if (!config.run) config.run = [];
12112
+ const runList = config.run;
12113
+ if (hasDuplicateLink(runList, parsed.path)) {
12114
+ console.error(`Link to "${parsed.path}" already exists`);
12115
+ process.exit(1);
12116
+ }
12117
+ runList.push({ link: parsed.path, prefix: parsed.prefix });
12118
+ saveConfig(config);
12119
+ console.log(
12120
+ `Linked run configurations from: ${parsed.path} (prefix: ${parsed.prefix})`
12121
+ );
12122
+ }
12123
+
11955
12124
  // src/commands/run/remove.ts
11956
- import { existsSync as existsSync40, unlinkSync as unlinkSync11 } from "fs";
11957
- import { join as join44 } from "path";
12125
+ import { existsSync as existsSync42, unlinkSync as unlinkSync11 } from "fs";
12126
+ import { join as join46 } from "path";
11958
12127
  function findRemoveIndex() {
11959
12128
  const idx = process.argv.indexOf("remove");
11960
12129
  if (idx === -1 || idx + 1 >= process.argv.length) return -1;
@@ -11969,8 +12138,8 @@ function parseRemoveName() {
11969
12138
  return process.argv[idx + 1];
11970
12139
  }
11971
12140
  function deleteCommandFile(name) {
11972
- const filePath = join44(".claude", "commands", `${name}.md`);
11973
- if (existsSync40(filePath)) {
12141
+ const filePath = join46(".claude", "commands", `${name}.md`);
12142
+ if (existsSync42(filePath)) {
11974
12143
  unlinkSync11(filePath);
11975
12144
  console.log(`Deleted command file: ${filePath}`);
11976
12145
  }
@@ -11992,7 +12161,7 @@ function remove() {
11992
12161
  // src/commands/run/registerRun.ts
11993
12162
  function registerRun(program2) {
11994
12163
  const runCommand = program2.command("run").description("Run a configured command from assist.yml").argument("[name]", "Name of the configured command").argument("[args...]", "Arguments to pass to the command").allowUnknownOption().addHelpText("after", () => formatConfiguredCommands()).action((name, args) => run3(name, args));
11995
- runCommand.command("list").description("List configured run commands").action(listRunConfigs);
12164
+ runCommand.command("list").description("List configured run commands").option("-v, --verbose", "Show full command details").action((opts) => listRunConfigs(!!opts.verbose));
11996
12165
  runCommand.command("add").description("Add a new run configuration to assist.yml").argument("<name>", "Name for the run configuration").argument("<command>", "Command to execute").argument("[args...]", "Static args to pass to the command").option(
11997
12166
  "--cwd <dir>",
11998
12167
  "Working directory (resolved relative to the config file)"
@@ -12000,14 +12169,15 @@ function registerRun(program2) {
12000
12169
  "after",
12001
12170
  '\nPositional params can be added to the config manually:\n params:\n - name: env # assist run deploy prod \u2192 appends "prod"\n required: true\n - name: tag\n default: latest'
12002
12171
  ).allowUnknownOption().allowExcessArguments().action(() => add3());
12172
+ runCommand.command("link").description("Link run configurations from another project's assist.yml").argument("<path>", "Relative path to the linked project").requiredOption("--prefix <prefix>", "Namespace prefix for linked commands").allowUnknownOption().action(() => link2());
12003
12173
  runCommand.command("remove").description("Remove a run configuration from assist.yml").argument("<name>", "Name of the run configuration to remove").action(() => remove());
12004
12174
  }
12005
12175
 
12006
12176
  // src/commands/screenshot/index.ts
12007
12177
  import { execSync as execSync41 } from "child_process";
12008
- import { existsSync as existsSync41, mkdirSync as mkdirSync14, unlinkSync as unlinkSync12, writeFileSync as writeFileSync29 } from "fs";
12178
+ import { existsSync as existsSync43, mkdirSync as mkdirSync14, unlinkSync as unlinkSync12, writeFileSync as writeFileSync29 } from "fs";
12009
12179
  import { tmpdir as tmpdir6 } from "os";
12010
- import { join as join45, resolve as resolve6 } from "path";
12180
+ import { join as join47, resolve as resolve11 } from "path";
12011
12181
  import chalk132 from "chalk";
12012
12182
 
12013
12183
  // src/commands/screenshot/captureWindowPs1.ts
@@ -12137,14 +12307,14 @@ Write-Output $OutputPath
12137
12307
 
12138
12308
  // src/commands/screenshot/index.ts
12139
12309
  function buildOutputPath(outputDir, processName) {
12140
- if (!existsSync41(outputDir)) {
12310
+ if (!existsSync43(outputDir)) {
12141
12311
  mkdirSync14(outputDir, { recursive: true });
12142
12312
  }
12143
12313
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
12144
- return resolve6(outputDir, `${processName}-${timestamp}.png`);
12314
+ return resolve11(outputDir, `${processName}-${timestamp}.png`);
12145
12315
  }
12146
12316
  function runPowerShellScript(processName, outputPath) {
12147
- const scriptPath = join45(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
12317
+ const scriptPath = join47(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
12148
12318
  writeFileSync29(scriptPath, captureWindowPs1, "utf-8");
12149
12319
  try {
12150
12320
  execSync41(
@@ -12157,7 +12327,7 @@ function runPowerShellScript(processName, outputPath) {
12157
12327
  }
12158
12328
  function screenshot(processName) {
12159
12329
  const config = loadConfig();
12160
- const outputDir = resolve6(config.screenshot.outputDir);
12330
+ const outputDir = resolve11(config.screenshot.outputDir);
12161
12331
  const outputPath = buildOutputPath(outputDir, processName);
12162
12332
  console.log(chalk132.gray(`Capturing window for process "${processName}" ...`));
12163
12333
  try {