@staff0rd/assist 0.120.1 → 0.121.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.120.1",
9
+ version: "0.121.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -90,10 +90,10 @@ import { stringify as stringifyYaml } from "yaml";
90
90
  // src/shared/loadRawYaml.ts
91
91
  import { existsSync, readFileSync } from "fs";
92
92
  import { parse as parseYaml } from "yaml";
93
- function loadRawYaml(path42) {
94
- if (!existsSync(path42)) return {};
93
+ function loadRawYaml(path44) {
94
+ if (!existsSync(path44)) return {};
95
95
  try {
96
- const content = readFileSync(path42, "utf-8");
96
+ const content = readFileSync(path44, "utf-8");
97
97
  return parseYaml(content) || {};
98
98
  } catch {
99
99
  return {};
@@ -114,7 +114,8 @@ var runConfigSchema = z.strictObject({
114
114
  args: z.array(z.string()).optional(),
115
115
  params: z.array(runParamSchema).optional(),
116
116
  env: z.record(z.string(), z.string()).optional(),
117
- filter: z.string().optional()
117
+ filter: z.string().optional(),
118
+ pre: z.array(z.string()).optional()
118
119
  });
119
120
  var transcriptConfigSchema = z.strictObject({
120
121
  vttDir: z.string(),
@@ -351,9 +352,9 @@ function isTraversable(value) {
351
352
  function stepInto(current, key) {
352
353
  return isTraversable(current) ? current[key] : void 0;
353
354
  }
354
- function getNestedValue(obj, path42) {
355
+ function getNestedValue(obj, path44) {
355
356
  let current = obj;
356
- for (const key of path42.split(".")) current = stepInto(current, key);
357
+ for (const key of path44.split(".")) current = stepInto(current, key);
357
358
  return current;
358
359
  }
359
360
 
@@ -394,8 +395,8 @@ function stepIntoNested(container, key, nextKey) {
394
395
  }
395
396
  return ensureObject(container, resolved);
396
397
  }
397
- function setNestedValue(obj, path42, value) {
398
- const keys = path42.split(".");
398
+ function setNestedValue(obj, path44, value) {
399
+ const keys = path44.split(".");
399
400
  const result = { ...obj };
400
401
  let current = result;
401
402
  for (let i = 0; i < keys.length - 1; i++) {
@@ -2841,12 +2842,12 @@ function getCliReadsPath() {
2841
2842
  var cachedLines;
2842
2843
  function getCliReadsLines() {
2843
2844
  if (cachedLines) return cachedLines;
2844
- const path42 = getCliReadsPath();
2845
- if (!existsSync16(path42)) {
2845
+ const path44 = getCliReadsPath();
2846
+ if (!existsSync16(path44)) {
2846
2847
  cachedLines = [];
2847
2848
  return cachedLines;
2848
2849
  }
2849
- cachedLines = readFileSync13(path42, "utf-8").split("\n").filter((line) => line.trim() !== "");
2850
+ cachedLines = readFileSync13(path44, "utf-8").split("\n").filter((line) => line.trim() !== "");
2850
2851
  return cachedLines;
2851
2852
  }
2852
2853
  function loadCliReads() {
@@ -3198,14 +3199,14 @@ function showProgress(p, label2) {
3198
3199
  const pct = Math.round(p.done / p.total * 100);
3199
3200
  process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
3200
3201
  }
3201
- async function resolveCommand(cli, path42, description, depth, p) {
3202
- showProgress(p, path42.join(" "));
3203
- const subHelp = await runHelp([cli, ...path42]);
3202
+ async function resolveCommand(cli, path44, description, depth, p) {
3203
+ showProgress(p, path44.join(" "));
3204
+ const subHelp = await runHelp([cli, ...path44]);
3204
3205
  if (!subHelp || !hasSubcommands(subHelp)) {
3205
- return [{ path: path42, description }];
3206
+ return [{ path: path44, description }];
3206
3207
  }
3207
- const children = await discoverAt(cli, path42, depth + 1, p);
3208
- return children.length > 0 ? children : [{ path: path42, description }];
3208
+ const children = await discoverAt(cli, path44, depth + 1, p);
3209
+ return children.length > 0 ? children : [{ path: path44, description }];
3209
3210
  }
3210
3211
  async function discoverAt(cli, parentPath, depth, p) {
3211
3212
  if (depth > SAFETY_DEPTH) return [];
@@ -3353,9 +3354,9 @@ function logPath(cli) {
3353
3354
  return join12(homedir4(), ".assist", `cli-discover-${safeName}.log`);
3354
3355
  }
3355
3356
  function readCache(cli) {
3356
- const path42 = logPath(cli);
3357
- if (!existsSync18(path42)) return void 0;
3358
- return readFileSync15(path42, "utf-8");
3357
+ const path44 = logPath(cli);
3358
+ if (!existsSync18(path44)) return void 0;
3359
+ return readFileSync15(path44, "utf-8");
3359
3360
  }
3360
3361
  function writeCache(cli, output) {
3361
3362
  const dir = join12(homedir4(), ".assist");
@@ -4437,234 +4438,88 @@ function registerDevlog(program2) {
4437
4438
  ).option("--all", "Show all non-archived repos regardless of push date").action(repos);
4438
4439
  }
4439
4440
 
4440
- // src/commands/jira/acceptanceCriteria.ts
4441
- import chalk49 from "chalk";
4442
-
4443
- // src/commands/jira/adfToText.ts
4444
- function renderInline(node) {
4445
- const text = node.text ?? "";
4446
- if (node.marks?.some((m) => m.type === "code")) return `\`${text}\``;
4447
- return text;
4448
- }
4449
- function renderChildren(node, indent) {
4450
- return renderNodes(node.content ?? [], indent);
4451
- }
4452
- function renderOrderedList(node, indent) {
4453
- let counter = 0;
4454
- return (node.content ?? []).map((item) => {
4455
- counter++;
4456
- return renderListItem(item, indent, `${counter}.`);
4457
- }).join("\n");
4458
- }
4459
- function renderBulletList(node, indent) {
4460
- return (node.content ?? []).map((item) => renderListItem(item, indent, "-")).join("\n");
4461
- }
4462
- function renderHeading(node, indent) {
4463
- const level = node.attrs?.level ?? 1;
4464
- return `${"#".repeat(level)} ${renderChildren(node, indent)}`;
4465
- }
4466
- var renderers = {
4467
- text: (node) => renderInline(node),
4468
- paragraph: renderChildren,
4469
- orderedList: renderOrderedList,
4470
- bulletList: renderBulletList,
4471
- listItem: (node, indent) => renderListItem(node, indent, "-"),
4472
- heading: renderHeading,
4473
- doc: renderChildren
4474
- };
4475
- function renderNode(node, indent) {
4476
- const renderer = renderers[node.type];
4477
- if (renderer) return renderer(node, indent);
4478
- return node.content ? renderChildren(node, indent) : "";
4479
- }
4480
- function renderNodes(nodes, indent) {
4481
- return nodes.map((node) => renderNode(node, indent)).join("");
4482
- }
4483
- function isListNode(node) {
4484
- return node.type === "orderedList" || node.type === "bulletList";
4485
- }
4486
- function renderListChild(child, indent, pad, marker, isFirst) {
4487
- if (isListNode(child)) return renderNodes([child], indent + 1);
4488
- if (child.type !== "paragraph") return renderNode(child, indent);
4489
- const text = renderChildren(child, indent);
4490
- return isFirst ? `${pad}${marker} ${text}` : `${pad} ${text}`;
4491
- }
4492
- function renderListItem(node, indent, marker) {
4493
- const pad = " ".repeat(indent);
4494
- return (node.content ?? []).map((child, i) => renderListChild(child, indent, pad, marker, i === 0)).join("\n");
4495
- }
4496
- function adfToText(doc) {
4497
- return renderNodes([doc], 0);
4498
- }
4499
-
4500
- // src/commands/jira/fetchIssue.ts
4501
- import { execSync as execSync20 } from "child_process";
4441
+ // src/commands/dotnet/checkBuildLocks.ts
4442
+ import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
4443
+ import { join as join16 } from "path";
4502
4444
  import chalk48 from "chalk";
4503
- function fetchIssue(issueKey, fields) {
4504
- let result;
4505
- try {
4506
- result = execSync20(
4507
- `acli jira workitem view ${issueKey} -f ${fields} --json`,
4508
- { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4509
- );
4510
- } catch (error) {
4511
- if (error instanceof Error && "stderr" in error) {
4512
- const stderr = error.stderr;
4513
- if (stderr.includes("unauthorized")) {
4514
- console.error(
4515
- chalk48.red("Jira authentication expired."),
4516
- "Run",
4517
- chalk48.cyan("assist jira auth"),
4518
- "to re-authenticate."
4519
- );
4520
- process.exit(1);
4521
- }
4445
+
4446
+ // src/shared/findRepoRoot.ts
4447
+ import { existsSync as existsSync20 } from "fs";
4448
+ import path21 from "path";
4449
+ function findRepoRoot(dir) {
4450
+ let current = dir;
4451
+ while (current !== path21.dirname(current)) {
4452
+ if (existsSync20(path21.join(current, ".git"))) {
4453
+ return current;
4522
4454
  }
4523
- console.error(chalk48.red(`Failed to fetch ${issueKey}.`));
4524
- process.exit(1);
4455
+ current = path21.dirname(current);
4525
4456
  }
4526
- return JSON.parse(result);
4457
+ return null;
4527
4458
  }
4528
4459
 
4529
- // src/commands/jira/acceptanceCriteria.ts
4530
- var DEFAULT_AC_FIELD = "customfield_11937";
4531
- function acceptanceCriteria(issueKey) {
4532
- const config = loadConfig();
4533
- const field = config.jira?.acField ?? DEFAULT_AC_FIELD;
4534
- const parsed = fetchIssue(issueKey, field);
4535
- const acValue = parsed?.fields?.[field];
4536
- if (!acValue) {
4537
- console.log(chalk49.yellow(`No acceptance criteria found on ${issueKey}.`));
4538
- return;
4539
- }
4540
- if (typeof acValue === "string") {
4541
- console.log(acValue);
4542
- return;
4543
- }
4544
- if (acValue.type === "doc") {
4545
- console.log(adfToText(acValue));
4546
- return;
4460
+ // src/commands/dotnet/checkBuildLocks.ts
4461
+ var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "packages"]);
4462
+ function isLockedDll(debugDir) {
4463
+ let files;
4464
+ try {
4465
+ files = readdirSync2(debugDir, { recursive: true });
4466
+ } catch {
4467
+ return null;
4547
4468
  }
4548
- console.log(JSON.stringify(acValue, null, 2));
4549
- }
4550
-
4551
- // src/commands/jira/jiraAuth.ts
4552
- import { execSync as execSync21 } from "child_process";
4553
- import Enquirer from "enquirer";
4554
-
4555
- // src/shared/loadJson.ts
4556
- import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "fs";
4557
- import { homedir as homedir6 } from "os";
4558
- import { join as join16 } from "path";
4559
- function getStoreDir() {
4560
- return join16(homedir6(), ".assist");
4561
- }
4562
- function getStorePath(filename) {
4563
- return join16(getStoreDir(), filename);
4564
- }
4565
- function loadJson(filename) {
4566
- const path42 = getStorePath(filename);
4567
- if (existsSync20(path42)) {
4469
+ for (const file of files) {
4470
+ if (!file.toLowerCase().endsWith(".dll")) continue;
4471
+ const dllPath = join16(debugDir, file);
4568
4472
  try {
4569
- return JSON.parse(readFileSync18(path42, "utf-8"));
4473
+ const fd = openSync(dllPath, "r+");
4474
+ closeSync(fd);
4570
4475
  } catch {
4571
- return {};
4476
+ return dllPath;
4572
4477
  }
4573
4478
  }
4574
- return {};
4575
- }
4576
- function saveJson(filename, data) {
4577
- const dir = getStoreDir();
4578
- if (!existsSync20(dir)) {
4579
- mkdirSync5(dir, { recursive: true });
4580
- }
4581
- writeFileSync17(getStorePath(filename), JSON.stringify(data, null, 2));
4582
- }
4583
-
4584
- // src/commands/jira/jiraAuth.ts
4585
- var CONFIG_FILE = "jira.json";
4586
- async function promptCredentials(config) {
4587
- const { Input: Input2, Password } = Enquirer;
4588
- const site = await new Input2({
4589
- name: "site",
4590
- message: "Jira site (e.g., mycompany.atlassian.net):",
4591
- initial: config.site
4592
- }).run();
4593
- const email = await new Input2({
4594
- name: "email",
4595
- message: "Email:",
4596
- initial: config.email
4597
- }).run();
4598
- const token = await new Password({
4599
- name: "token",
4600
- message: "API token (https://id.atlassian.com/manage-profile/security/api-tokens):"
4601
- }).run();
4602
- return { site, email, token };
4479
+ return null;
4603
4480
  }
4604
- async function jiraAuth() {
4605
- const config = loadJson(CONFIG_FILE);
4481
+ function findFirstLockedDll(dir) {
4482
+ let entries;
4606
4483
  try {
4607
- const { site, email, token } = await promptCredentials(config);
4608
- if (!site || !email || !token) {
4609
- console.error("All fields are required.");
4610
- process.exit(1);
4611
- }
4612
- execSync21(`acli jira auth login --site ${site} --email "${email}" --token`, {
4613
- encoding: "utf-8",
4614
- input: token,
4615
- stdio: ["pipe", "inherit", "inherit"]
4616
- });
4617
- saveJson(CONFIG_FILE, { site, email });
4618
- console.log("Successfully authenticated with Jira.");
4619
- } catch (error) {
4620
- if (error instanceof Error) {
4621
- console.error("Error authenticating with Jira:", error.message);
4622
- }
4623
- process.exit(1);
4484
+ entries = readdirSync2(dir);
4485
+ } catch {
4486
+ return null;
4624
4487
  }
4625
- }
4626
-
4627
- // src/commands/jira/viewIssue.ts
4628
- import chalk50 from "chalk";
4629
- function viewIssue(issueKey) {
4630
- const parsed = fetchIssue(issueKey, "summary,description");
4631
- const fields = parsed?.fields;
4632
- const summary = fields?.summary;
4633
- const description = fields?.description;
4634
- if (summary) {
4635
- console.log(chalk50.bold(summary));
4488
+ if (entries.includes("bin")) {
4489
+ const locked = isLockedDll(join16(dir, "bin", "Debug"));
4490
+ if (locked) return locked;
4636
4491
  }
4637
- if (description) {
4638
- if (summary) console.log();
4639
- if (typeof description === "string") {
4640
- console.log(description);
4641
- } else if (description.type === "doc") {
4642
- console.log(adfToText(description));
4643
- } else {
4644
- console.log(JSON.stringify(description, null, 2));
4645
- }
4492
+ for (const entry of entries) {
4493
+ if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
4494
+ continue;
4495
+ const found = findFirstLockedDll(join16(dir, entry));
4496
+ if (found) return found;
4646
4497
  }
4647
- if (!summary && !description) {
4648
- console.log(
4649
- chalk50.yellow(`No summary or description found on ${issueKey}.`)
4498
+ return null;
4499
+ }
4500
+ function getSearchRoot() {
4501
+ return findRepoRoot(process.cwd()) ?? process.cwd();
4502
+ }
4503
+ function checkBuildLocks(startDir) {
4504
+ const locked = findFirstLockedDll(startDir ?? getSearchRoot());
4505
+ if (locked) {
4506
+ console.error(
4507
+ chalk48.red("Build output locked (is VS debugging?): ") + locked
4650
4508
  );
4509
+ process.exit(1);
4651
4510
  }
4652
4511
  }
4653
-
4654
- // src/commands/registerJira.ts
4655
- function registerJira(program2) {
4656
- const jiraCommand = program2.command("jira").description("Jira utilities");
4657
- jiraCommand.command("auth").description("Authenticate with Jira via API token").action(() => jiraAuth());
4658
- jiraCommand.command("ac <issue-key>").description("Print acceptance criteria for a Jira issue").action((issueKey) => acceptanceCriteria(issueKey));
4659
- jiraCommand.command("view <issue-key>").description("Print the title and description of a Jira issue").action((issueKey) => viewIssue(issueKey));
4512
+ async function checkBuildLocksCommand() {
4513
+ checkBuildLocks();
4514
+ console.log(chalk48.green("No build locks detected"));
4660
4515
  }
4661
4516
 
4662
- // src/commands/netframework/buildTree.ts
4663
- import { readFileSync as readFileSync19 } from "fs";
4664
- import path21 from "path";
4517
+ // src/commands/dotnet/buildTree.ts
4518
+ import { readFileSync as readFileSync18 } from "fs";
4519
+ import path22 from "path";
4665
4520
  var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
4666
4521
  function getProjectRefs(csprojPath) {
4667
- const content = readFileSync19(csprojPath, "utf-8");
4522
+ const content = readFileSync18(csprojPath, "utf-8");
4668
4523
  const refs = [];
4669
4524
  for (const match of content.matchAll(PROJECT_REF_RE)) {
4670
4525
  refs.push(match[1].replace(/\\/g, "/"));
@@ -4672,16 +4527,16 @@ function getProjectRefs(csprojPath) {
4672
4527
  return refs;
4673
4528
  }
4674
4529
  function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
4675
- const abs = path21.resolve(csprojPath);
4676
- const rel = path21.relative(repoRoot, abs);
4530
+ const abs = path22.resolve(csprojPath);
4531
+ const rel = path22.relative(repoRoot, abs);
4677
4532
  const node = { path: abs, relativePath: rel, children: [] };
4678
4533
  if (visited.has(abs)) return node;
4679
4534
  visited.add(abs);
4680
- const dir = path21.dirname(abs);
4535
+ const dir = path22.dirname(abs);
4681
4536
  for (const ref of getProjectRefs(abs)) {
4682
- const childAbs = path21.resolve(dir, ref);
4537
+ const childAbs = path22.resolve(dir, ref);
4683
4538
  try {
4684
- readFileSync19(childAbs);
4539
+ readFileSync18(childAbs);
4685
4540
  node.children.push(buildTree(childAbs, repoRoot, visited));
4686
4541
  } catch {
4687
4542
  node.children.push({
@@ -4705,22 +4560,22 @@ function collectAllDeps(node) {
4705
4560
  return result;
4706
4561
  }
4707
4562
 
4708
- // src/commands/netframework/findContainingSolutions.ts
4709
- import { readdirSync as readdirSync2, readFileSync as readFileSync20, statSync } from "fs";
4710
- import path22 from "path";
4563
+ // src/commands/dotnet/findContainingSolutions.ts
4564
+ import { readdirSync as readdirSync3, readFileSync as readFileSync19, statSync } from "fs";
4565
+ import path23 from "path";
4711
4566
  function findSlnFiles(dir, maxDepth, depth = 0) {
4712
4567
  if (depth > maxDepth) return [];
4713
4568
  const results = [];
4714
4569
  let entries;
4715
4570
  try {
4716
- entries = readdirSync2(dir);
4571
+ entries = readdirSync3(dir);
4717
4572
  } catch {
4718
4573
  return results;
4719
4574
  }
4720
4575
  for (const entry of entries) {
4721
4576
  if (entry.startsWith(".") || entry === "node_modules" || entry === "packages")
4722
4577
  continue;
4723
- const full = path22.join(dir, entry);
4578
+ const full = path23.join(dir, entry);
4724
4579
  try {
4725
4580
  const stat = statSync(full);
4726
4581
  if (stat.isFile() && entry.endsWith(".sln")) {
@@ -4734,16 +4589,16 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
4734
4589
  return results;
4735
4590
  }
4736
4591
  function findContainingSolutions(csprojPath, repoRoot) {
4737
- const csprojAbs = path22.resolve(csprojPath);
4738
- const csprojBasename = path22.basename(csprojAbs);
4592
+ const csprojAbs = path23.resolve(csprojPath);
4593
+ const csprojBasename = path23.basename(csprojAbs);
4739
4594
  const slnFiles = findSlnFiles(repoRoot, 3);
4740
4595
  const matches = [];
4741
4596
  const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
4742
4597
  for (const sln of slnFiles) {
4743
4598
  try {
4744
- const content = readFileSync20(sln, "utf-8");
4599
+ const content = readFileSync19(sln, "utf-8");
4745
4600
  if (pattern2.test(content)) {
4746
- matches.push(path22.relative(repoRoot, sln));
4601
+ matches.push(path23.relative(repoRoot, sln));
4747
4602
  }
4748
4603
  } catch {
4749
4604
  }
@@ -4754,31 +4609,31 @@ function escapeRegex(s) {
4754
4609
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4755
4610
  }
4756
4611
 
4757
- // src/commands/netframework/printTree.ts
4758
- import chalk51 from "chalk";
4612
+ // src/commands/dotnet/printTree.ts
4613
+ import chalk49 from "chalk";
4759
4614
  function printNodes(nodes, prefix2) {
4760
4615
  for (let i = 0; i < nodes.length; i++) {
4761
4616
  const isLast = i === nodes.length - 1;
4762
4617
  const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
4763
4618
  const childPrefix = isLast ? " " : "\u2502 ";
4764
4619
  const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
4765
- const label2 = isMissing ? chalk51.red(nodes[i].relativePath) : nodes[i].relativePath;
4620
+ const label2 = isMissing ? chalk49.red(nodes[i].relativePath) : nodes[i].relativePath;
4766
4621
  console.log(`${prefix2}${connector}${label2}`);
4767
4622
  printNodes(nodes[i].children, prefix2 + childPrefix);
4768
4623
  }
4769
4624
  }
4770
4625
  function printTree(tree, totalCount, solutions) {
4771
- console.log(chalk51.bold("\nProject Dependency Tree"));
4772
- console.log(chalk51.cyan(tree.relativePath));
4626
+ console.log(chalk49.bold("\nProject Dependency Tree"));
4627
+ console.log(chalk49.cyan(tree.relativePath));
4773
4628
  printNodes(tree.children, "");
4774
- console.log(chalk51.dim(`
4629
+ console.log(chalk49.dim(`
4775
4630
  ${totalCount} projects total (including root)`));
4776
- console.log(chalk51.bold("\nSolution Membership"));
4631
+ console.log(chalk49.bold("\nSolution Membership"));
4777
4632
  if (solutions.length === 0) {
4778
- console.log(chalk51.yellow(" Not found in any .sln"));
4633
+ console.log(chalk49.yellow(" Not found in any .sln"));
4779
4634
  } else {
4780
4635
  for (const sln of solutions) {
4781
- console.log(` ${chalk51.green(sln)}`);
4636
+ console.log(` ${chalk49.green(sln)}`);
4782
4637
  }
4783
4638
  }
4784
4639
  console.log();
@@ -4804,76 +4659,504 @@ function printJson(tree, totalCount, solutions) {
4804
4659
  );
4805
4660
  }
4806
4661
 
4807
- // src/commands/netframework/resolveCsproj.ts
4808
- import { existsSync as existsSync22 } from "fs";
4662
+ // src/commands/dotnet/resolveCsproj.ts
4663
+ import { existsSync as existsSync21 } from "fs";
4809
4664
  import path24 from "path";
4665
+ import chalk50 from "chalk";
4666
+ function resolveCsproj(csprojPath) {
4667
+ const resolved = path24.resolve(csprojPath);
4668
+ if (!existsSync21(resolved)) {
4669
+ console.error(chalk50.red(`File not found: ${resolved}`));
4670
+ process.exit(1);
4671
+ }
4672
+ const repoRoot = findRepoRoot(path24.dirname(resolved));
4673
+ if (!repoRoot) {
4674
+ console.error(chalk50.red("Could not find git repository root"));
4675
+ process.exit(1);
4676
+ }
4677
+ return { resolved, repoRoot };
4678
+ }
4679
+
4680
+ // src/commands/dotnet/deps.ts
4681
+ async function deps(csprojPath, options2) {
4682
+ const { resolved, repoRoot } = resolveCsproj(csprojPath);
4683
+ const tree = buildTree(resolved, repoRoot);
4684
+ const totalCount = collectAllDeps(tree).size + 1;
4685
+ const solutions = findContainingSolutions(resolved, repoRoot);
4686
+ if (options2.json) {
4687
+ printJson(tree, totalCount, solutions);
4688
+ } else {
4689
+ printTree(tree, totalCount, solutions);
4690
+ }
4691
+ }
4692
+
4693
+ // src/commands/dotnet/inSln.ts
4694
+ import chalk51 from "chalk";
4695
+ async function inSln(csprojPath) {
4696
+ const { resolved, repoRoot } = resolveCsproj(csprojPath);
4697
+ const solutions = findContainingSolutions(resolved, repoRoot);
4698
+ if (solutions.length === 0) {
4699
+ console.log(chalk51.yellow("Not found in any .sln file"));
4700
+ process.exit(1);
4701
+ }
4702
+ for (const sln of solutions) {
4703
+ console.log(sln);
4704
+ }
4705
+ }
4706
+
4707
+ // src/commands/dotnet/inspect.ts
4708
+ import { existsSync as existsSync23 } from "fs";
4709
+ import path26 from "path";
4710
+ import chalk55 from "chalk";
4711
+
4712
+ // src/shared/formatElapsed.ts
4713
+ function formatElapsed(ms) {
4714
+ const secs = ms / 1e3;
4715
+ if (secs < 60) return `${secs.toFixed(1)}s`;
4716
+ const mins = Math.floor(secs / 60);
4717
+ const remainSecs = secs - mins * 60;
4718
+ return `${mins}m ${remainSecs.toFixed(1)}s`;
4719
+ }
4720
+
4721
+ // src/commands/dotnet/deadCodeRules.ts
4722
+ var deadCodeRules = /* @__PURE__ */ new Set([
4723
+ "UnusedMember.Global",
4724
+ "UnusedMember.Local",
4725
+ "UnusedType.Global",
4726
+ "UnusedType.Local",
4727
+ "UnusedParameter.Global",
4728
+ "UnusedParameter.Local",
4729
+ "NotAccessedField.Global",
4730
+ "NotAccessedField.Local",
4731
+ "NotAccessedVariable.Local",
4732
+ "UnusedAutoPropertyAccessor.Global",
4733
+ "UnusedAutoPropertyAccessor.Local",
4734
+ "ClassNeverInstantiated.Global",
4735
+ "ClassNeverInstantiated.Local",
4736
+ "UnusedMethodReturnValue.Global",
4737
+ "UnusedMethodReturnValue.Local",
4738
+ "UnusedVariable.Compiler",
4739
+ "RedundantUsingDirective"
4740
+ ]);
4741
+
4742
+ // src/commands/dotnet/displayIssues.ts
4810
4743
  import chalk52 from "chalk";
4744
+ var SEVERITY_COLOR = {
4745
+ ERROR: chalk52.red,
4746
+ WARNING: chalk52.yellow,
4747
+ SUGGESTION: chalk52.cyan,
4748
+ HINT: chalk52.dim
4749
+ };
4750
+ function groupByFile(issues) {
4751
+ const byFile = /* @__PURE__ */ new Map();
4752
+ for (const issue of issues) {
4753
+ const existing = byFile.get(issue.file);
4754
+ if (existing) {
4755
+ existing.push(issue);
4756
+ } else {
4757
+ byFile.set(issue.file, [issue]);
4758
+ }
4759
+ }
4760
+ return byFile;
4761
+ }
4762
+ function displayIssues(issues) {
4763
+ for (const [file, fileIssues] of groupByFile(issues)) {
4764
+ console.log(chalk52.bold(file));
4765
+ for (const issue of fileIssues.sort((a, b) => a.line - b.line)) {
4766
+ const color = SEVERITY_COLOR[issue.severity] ?? chalk52.white;
4767
+ console.log(
4768
+ ` ${chalk52.dim(`${issue.line}:`)} ${color(issue.severity)} [${issue.typeId}] ${issue.message}`
4769
+ );
4770
+ }
4771
+ }
4772
+ console.log(chalk52.dim(`
4773
+ ${issues.length} issue(s) found`));
4774
+ }
4811
4775
 
4812
- // src/shared/findRepoRoot.ts
4813
- import { existsSync as existsSync21 } from "fs";
4814
- import path23 from "path";
4815
- function findRepoRoot(dir) {
4816
- let current = dir;
4817
- while (current !== path23.dirname(current)) {
4818
- if (existsSync21(path23.join(current, ".git"))) {
4819
- return current;
4776
+ // src/commands/dotnet/findSolution.ts
4777
+ import { readdirSync as readdirSync4 } from "fs";
4778
+ import { dirname as dirname16, join as join17 } from "path";
4779
+ import chalk53 from "chalk";
4780
+ function findSlnInDir(dir) {
4781
+ try {
4782
+ return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join17(dir, f));
4783
+ } catch {
4784
+ return [];
4785
+ }
4786
+ }
4787
+ function findSolution() {
4788
+ const repoRoot = findRepoRoot(process.cwd());
4789
+ const ceiling = repoRoot ?? process.cwd();
4790
+ let current = process.cwd();
4791
+ while (true) {
4792
+ const slnFiles = findSlnInDir(current);
4793
+ if (slnFiles.length === 1) return slnFiles[0];
4794
+ if (slnFiles.length > 1) {
4795
+ console.error(chalk53.red(`Multiple .sln files found in ${current}:`));
4796
+ for (const f of slnFiles) console.error(` ${f}`);
4797
+ console.error(
4798
+ chalk53.yellow("Specify which one: assist dotnet inspect <sln>")
4799
+ );
4800
+ process.exit(1);
4820
4801
  }
4821
- current = path23.dirname(current);
4802
+ if (current === ceiling) break;
4803
+ current = dirname16(current);
4822
4804
  }
4823
- return null;
4805
+ console.error(chalk53.red("No .sln file found between cwd and repo root"));
4806
+ process.exit(1);
4807
+ }
4808
+
4809
+ // src/commands/dotnet/getChangedCsFiles.ts
4810
+ import { execSync as execSync20 } from "child_process";
4811
+ function getChangedCsFiles(ref) {
4812
+ const cmd = ref ? `git diff --name-only ${ref}~1 ${ref}` : "git diff --name-only HEAD";
4813
+ const output = execSync20(cmd, { encoding: "utf-8" }).trim();
4814
+ if (output === "") return [];
4815
+ return output.split("\n").filter((f) => f.toLowerCase().endsWith(".cs"));
4816
+ }
4817
+
4818
+ // src/commands/dotnet/parseInspectReport.ts
4819
+ var LEVEL_TO_SEVERITY = {
4820
+ error: "ERROR",
4821
+ warning: "WARNING",
4822
+ note: "SUGGESTION"
4823
+ };
4824
+ function parseInspectReport(json) {
4825
+ const sarif = JSON.parse(json);
4826
+ const results = sarif.runs?.[0]?.results;
4827
+ if (!Array.isArray(results)) return [];
4828
+ return results.map((r) => ({
4829
+ typeId: r.ruleId,
4830
+ file: r.locations?.[0]?.physicalLocation?.artifactLocation?.uri ?? "",
4831
+ line: r.locations?.[0]?.physicalLocation?.region?.startLine ?? 0,
4832
+ message: r.message?.text ?? "",
4833
+ severity: LEVEL_TO_SEVERITY[r.level] ?? "WARNING"
4834
+ }));
4835
+ }
4836
+
4837
+ // src/commands/dotnet/runInspectCode.ts
4838
+ import { execSync as execSync21 } from "child_process";
4839
+ import { existsSync as existsSync22, readFileSync as readFileSync20, unlinkSync as unlinkSync3 } from "fs";
4840
+ import { tmpdir as tmpdir2 } from "os";
4841
+ import path25 from "path";
4842
+ import chalk54 from "chalk";
4843
+ function assertJbInstalled() {
4844
+ try {
4845
+ execSync21("jb inspectcode --version", { stdio: "pipe" });
4846
+ } catch {
4847
+ console.error(chalk54.red("jb is not installed. Install with:"));
4848
+ console.error(
4849
+ chalk54.yellow(" dotnet tool install -g JetBrains.ReSharper.GlobalTools")
4850
+ );
4851
+ process.exit(1);
4852
+ }
4853
+ }
4854
+ function runInspectCode(slnPath, include, swea) {
4855
+ const reportPath = path25.join(tmpdir2(), `inspect-${Date.now()}.xml`);
4856
+ const sweaFlag = swea ? " --swea" : "";
4857
+ try {
4858
+ execSync21(
4859
+ `jb inspectcode "${slnPath}" -o="${reportPath}" --include="${include}"${sweaFlag} --verbosity=OFF`,
4860
+ { stdio: "pipe" }
4861
+ );
4862
+ } catch (err) {
4863
+ if (err && typeof err === "object" && "stderr" in err) {
4864
+ process.stderr.write(err.stderr);
4865
+ }
4866
+ console.error(chalk54.red("jb inspectcode failed"));
4867
+ process.exit(1);
4868
+ }
4869
+ if (!existsSync22(reportPath)) {
4870
+ console.error(chalk54.red("Report file not generated"));
4871
+ process.exit(1);
4872
+ }
4873
+ const xml = readFileSync20(reportPath, "utf-8");
4874
+ unlinkSync3(reportPath);
4875
+ return xml;
4876
+ }
4877
+
4878
+ // src/commands/dotnet/inspect.ts
4879
+ function resolveSolution(sln) {
4880
+ if (sln) {
4881
+ const resolved = path26.resolve(sln);
4882
+ if (!existsSync23(resolved)) {
4883
+ console.error(chalk55.red(`Solution file not found: ${resolved}`));
4884
+ process.exit(1);
4885
+ }
4886
+ return resolved;
4887
+ }
4888
+ return findSolution();
4889
+ }
4890
+ function runAndParse(resolved, changedFiles, all, swea) {
4891
+ const start3 = Date.now();
4892
+ const report = runInspectCode(resolved, changedFiles.join(";"), swea);
4893
+ const elapsed = Date.now() - start3;
4894
+ const allIssues = parseInspectReport(report);
4895
+ const issues = all ? allIssues : allIssues.filter((i) => deadCodeRules.has(i.typeId));
4896
+ return { issues, elapsed };
4897
+ }
4898
+ function reportResults(issues, elapsed) {
4899
+ if (issues.length > 0) displayIssues(issues);
4900
+ else console.log(chalk55.green("No issues found"));
4901
+ console.log(chalk55.dim(`Completed in ${formatElapsed(elapsed)}`));
4902
+ if (issues.length > 0) process.exit(1);
4903
+ }
4904
+ async function inspect(sln, options2) {
4905
+ const resolved = resolveSolution(sln);
4906
+ checkBuildLocks();
4907
+ assertJbInstalled();
4908
+ const changedFiles = getChangedCsFiles(options2.ref);
4909
+ if (changedFiles.length === 0) {
4910
+ console.log(chalk55.green("No changed .cs files found"));
4911
+ return;
4912
+ }
4913
+ console.log(
4914
+ chalk55.dim(`Inspecting ${changedFiles.length} changed file(s)...`)
4915
+ );
4916
+ const result = runAndParse(
4917
+ resolved,
4918
+ changedFiles,
4919
+ !!options2.all,
4920
+ !!options2.swea
4921
+ );
4922
+ reportResults(result.issues, result.elapsed);
4923
+ }
4924
+
4925
+ // src/commands/registerDotnet.ts
4926
+ function registerDotnet(program2) {
4927
+ const cmd = program2.command("dotnet").description(".NET project utilities");
4928
+ cmd.command("inspect").description(
4929
+ "Run JetBrains inspections on changed .cs files to find dead code"
4930
+ ).argument("[sln]", "Path to a .sln file (auto-detected if omitted)").option("--ref <ref>", "Git commit to inspect (default: working copy)").option("--all", "Show all issues, not just dead code").option("--swea", "Enable solution-wide error analysis").action(inspect);
4931
+ cmd.command("check-locks").description("Check if build output files are locked by a debugger").action(checkBuildLocksCommand);
4932
+ cmd.command("deps").description("Show .csproj project dependency tree and solution membership").argument("<csproj>", "Path to a .csproj file").option("--json", "Output as JSON").action(deps);
4933
+ cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
4934
+ }
4935
+
4936
+ // src/commands/jira/acceptanceCriteria.ts
4937
+ import chalk57 from "chalk";
4938
+
4939
+ // src/commands/jira/adfToText.ts
4940
+ function renderInline(node) {
4941
+ const text = node.text ?? "";
4942
+ if (node.marks?.some((m) => m.type === "code")) return `\`${text}\``;
4943
+ return text;
4944
+ }
4945
+ function renderChildren(node, indent) {
4946
+ return renderNodes(node.content ?? [], indent);
4947
+ }
4948
+ function renderOrderedList(node, indent) {
4949
+ let counter = 0;
4950
+ return (node.content ?? []).map((item) => {
4951
+ counter++;
4952
+ return renderListItem(item, indent, `${counter}.`);
4953
+ }).join("\n");
4954
+ }
4955
+ function renderBulletList(node, indent) {
4956
+ return (node.content ?? []).map((item) => renderListItem(item, indent, "-")).join("\n");
4957
+ }
4958
+ function renderHeading(node, indent) {
4959
+ const level = node.attrs?.level ?? 1;
4960
+ return `${"#".repeat(level)} ${renderChildren(node, indent)}`;
4961
+ }
4962
+ var renderers = {
4963
+ text: (node) => renderInline(node),
4964
+ paragraph: renderChildren,
4965
+ orderedList: renderOrderedList,
4966
+ bulletList: renderBulletList,
4967
+ listItem: (node, indent) => renderListItem(node, indent, "-"),
4968
+ heading: renderHeading,
4969
+ doc: renderChildren
4970
+ };
4971
+ function renderNode(node, indent) {
4972
+ const renderer = renderers[node.type];
4973
+ if (renderer) return renderer(node, indent);
4974
+ return node.content ? renderChildren(node, indent) : "";
4975
+ }
4976
+ function renderNodes(nodes, indent) {
4977
+ return nodes.map((node) => renderNode(node, indent)).join("");
4978
+ }
4979
+ function isListNode(node) {
4980
+ return node.type === "orderedList" || node.type === "bulletList";
4981
+ }
4982
+ function renderListChild(child, indent, pad, marker, isFirst) {
4983
+ if (isListNode(child)) return renderNodes([child], indent + 1);
4984
+ if (child.type !== "paragraph") return renderNode(child, indent);
4985
+ const text = renderChildren(child, indent);
4986
+ return isFirst ? `${pad}${marker} ${text}` : `${pad} ${text}`;
4987
+ }
4988
+ function renderListItem(node, indent, marker) {
4989
+ const pad = " ".repeat(indent);
4990
+ return (node.content ?? []).map((child, i) => renderListChild(child, indent, pad, marker, i === 0)).join("\n");
4991
+ }
4992
+ function adfToText(doc) {
4993
+ return renderNodes([doc], 0);
4994
+ }
4995
+
4996
+ // src/commands/jira/fetchIssue.ts
4997
+ import { execSync as execSync22 } from "child_process";
4998
+ import chalk56 from "chalk";
4999
+ function fetchIssue(issueKey, fields) {
5000
+ let result;
5001
+ try {
5002
+ result = execSync22(
5003
+ `acli jira workitem view ${issueKey} -f ${fields} --json`,
5004
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
5005
+ );
5006
+ } catch (error) {
5007
+ if (error instanceof Error && "stderr" in error) {
5008
+ const stderr = error.stderr;
5009
+ if (stderr.includes("unauthorized")) {
5010
+ console.error(
5011
+ chalk56.red("Jira authentication expired."),
5012
+ "Run",
5013
+ chalk56.cyan("assist jira auth"),
5014
+ "to re-authenticate."
5015
+ );
5016
+ process.exit(1);
5017
+ }
5018
+ }
5019
+ console.error(chalk56.red(`Failed to fetch ${issueKey}.`));
5020
+ process.exit(1);
5021
+ }
5022
+ return JSON.parse(result);
5023
+ }
5024
+
5025
+ // src/commands/jira/acceptanceCriteria.ts
5026
+ var DEFAULT_AC_FIELD = "customfield_11937";
5027
+ function acceptanceCriteria(issueKey) {
5028
+ const config = loadConfig();
5029
+ const field = config.jira?.acField ?? DEFAULT_AC_FIELD;
5030
+ const parsed = fetchIssue(issueKey, field);
5031
+ const acValue = parsed?.fields?.[field];
5032
+ if (!acValue) {
5033
+ console.log(chalk57.yellow(`No acceptance criteria found on ${issueKey}.`));
5034
+ return;
5035
+ }
5036
+ if (typeof acValue === "string") {
5037
+ console.log(acValue);
5038
+ return;
5039
+ }
5040
+ if (acValue.type === "doc") {
5041
+ console.log(adfToText(acValue));
5042
+ return;
5043
+ }
5044
+ console.log(JSON.stringify(acValue, null, 2));
5045
+ }
5046
+
5047
+ // src/commands/jira/jiraAuth.ts
5048
+ import { execSync as execSync23 } from "child_process";
5049
+ import Enquirer from "enquirer";
5050
+
5051
+ // src/shared/loadJson.ts
5052
+ import { existsSync as existsSync24, mkdirSync as mkdirSync5, readFileSync as readFileSync21, writeFileSync as writeFileSync17 } from "fs";
5053
+ import { homedir as homedir6 } from "os";
5054
+ import { join as join18 } from "path";
5055
+ function getStoreDir() {
5056
+ return join18(homedir6(), ".assist");
5057
+ }
5058
+ function getStorePath(filename) {
5059
+ return join18(getStoreDir(), filename);
5060
+ }
5061
+ function loadJson(filename) {
5062
+ const path44 = getStorePath(filename);
5063
+ if (existsSync24(path44)) {
5064
+ try {
5065
+ return JSON.parse(readFileSync21(path44, "utf-8"));
5066
+ } catch {
5067
+ return {};
5068
+ }
5069
+ }
5070
+ return {};
5071
+ }
5072
+ function saveJson(filename, data) {
5073
+ const dir = getStoreDir();
5074
+ if (!existsSync24(dir)) {
5075
+ mkdirSync5(dir, { recursive: true });
5076
+ }
5077
+ writeFileSync17(getStorePath(filename), JSON.stringify(data, null, 2));
5078
+ }
5079
+
5080
+ // src/commands/jira/jiraAuth.ts
5081
+ var CONFIG_FILE = "jira.json";
5082
+ async function promptCredentials(config) {
5083
+ const { Input: Input2, Password } = Enquirer;
5084
+ const site = await new Input2({
5085
+ name: "site",
5086
+ message: "Jira site (e.g., mycompany.atlassian.net):",
5087
+ initial: config.site
5088
+ }).run();
5089
+ const email = await new Input2({
5090
+ name: "email",
5091
+ message: "Email:",
5092
+ initial: config.email
5093
+ }).run();
5094
+ const token = await new Password({
5095
+ name: "token",
5096
+ message: "API token (https://id.atlassian.com/manage-profile/security/api-tokens):"
5097
+ }).run();
5098
+ return { site, email, token };
4824
5099
  }
4825
-
4826
- // src/commands/netframework/resolveCsproj.ts
4827
- function resolveCsproj(csprojPath) {
4828
- const resolved = path24.resolve(csprojPath);
4829
- if (!existsSync22(resolved)) {
4830
- console.error(chalk52.red(`File not found: ${resolved}`));
4831
- process.exit(1);
4832
- }
4833
- const repoRoot = findRepoRoot(path24.dirname(resolved));
4834
- if (!repoRoot) {
4835
- console.error(chalk52.red("Could not find git repository root"));
5100
+ async function jiraAuth() {
5101
+ const config = loadJson(CONFIG_FILE);
5102
+ try {
5103
+ const { site, email, token } = await promptCredentials(config);
5104
+ if (!site || !email || !token) {
5105
+ console.error("All fields are required.");
5106
+ process.exit(1);
5107
+ }
5108
+ execSync23(`acli jira auth login --site ${site} --email "${email}" --token`, {
5109
+ encoding: "utf-8",
5110
+ input: token,
5111
+ stdio: ["pipe", "inherit", "inherit"]
5112
+ });
5113
+ saveJson(CONFIG_FILE, { site, email });
5114
+ console.log("Successfully authenticated with Jira.");
5115
+ } catch (error) {
5116
+ if (error instanceof Error) {
5117
+ console.error("Error authenticating with Jira:", error.message);
5118
+ }
4836
5119
  process.exit(1);
4837
5120
  }
4838
- return { resolved, repoRoot };
4839
5121
  }
4840
5122
 
4841
- // src/commands/netframework/deps.ts
4842
- async function deps(csprojPath, options2) {
4843
- const { resolved, repoRoot } = resolveCsproj(csprojPath);
4844
- const tree = buildTree(resolved, repoRoot);
4845
- const totalCount = collectAllDeps(tree).size + 1;
4846
- const solutions = findContainingSolutions(resolved, repoRoot);
4847
- if (options2.json) {
4848
- printJson(tree, totalCount, solutions);
4849
- } else {
4850
- printTree(tree, totalCount, solutions);
5123
+ // src/commands/jira/viewIssue.ts
5124
+ import chalk58 from "chalk";
5125
+ function viewIssue(issueKey) {
5126
+ const parsed = fetchIssue(issueKey, "summary,description");
5127
+ const fields = parsed?.fields;
5128
+ const summary = fields?.summary;
5129
+ const description = fields?.description;
5130
+ if (summary) {
5131
+ console.log(chalk58.bold(summary));
4851
5132
  }
4852
- }
4853
-
4854
- // src/commands/netframework/inSln.ts
4855
- import chalk53 from "chalk";
4856
- async function inSln(csprojPath) {
4857
- const { resolved, repoRoot } = resolveCsproj(csprojPath);
4858
- const solutions = findContainingSolutions(resolved, repoRoot);
4859
- if (solutions.length === 0) {
4860
- console.log(chalk53.yellow("Not found in any .sln file"));
4861
- process.exit(1);
5133
+ if (description) {
5134
+ if (summary) console.log();
5135
+ if (typeof description === "string") {
5136
+ console.log(description);
5137
+ } else if (description.type === "doc") {
5138
+ console.log(adfToText(description));
5139
+ } else {
5140
+ console.log(JSON.stringify(description, null, 2));
5141
+ }
4862
5142
  }
4863
- for (const sln of solutions) {
4864
- console.log(sln);
5143
+ if (!summary && !description) {
5144
+ console.log(
5145
+ chalk58.yellow(`No summary or description found on ${issueKey}.`)
5146
+ );
4865
5147
  }
4866
5148
  }
4867
5149
 
4868
- // src/commands/registerNetframework.ts
4869
- function registerNetframework(program2) {
4870
- const cmd = program2.command("netframework").description(".NET Framework project utilities");
4871
- cmd.command("deps").description("Show .csproj project dependency tree and solution membership").argument("<csproj>", "Path to a .csproj file").option("--json", "Output as JSON").action(deps);
4872
- cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
5150
+ // src/commands/registerJira.ts
5151
+ function registerJira(program2) {
5152
+ const jiraCommand = program2.command("jira").description("Jira utilities");
5153
+ jiraCommand.command("auth").description("Authenticate with Jira via API token").action(() => jiraAuth());
5154
+ jiraCommand.command("ac <issue-key>").description("Print acceptance criteria for a Jira issue").action((issueKey) => acceptanceCriteria(issueKey));
5155
+ jiraCommand.command("view <issue-key>").description("Print the title and description of a Jira issue").action((issueKey) => viewIssue(issueKey));
4873
5156
  }
4874
5157
 
4875
5158
  // src/commands/news/add/index.ts
4876
- import chalk54 from "chalk";
5159
+ import chalk59 from "chalk";
4877
5160
  import enquirer5 from "enquirer";
4878
5161
  async function add2(url) {
4879
5162
  if (!url) {
@@ -4896,17 +5179,17 @@ async function add2(url) {
4896
5179
  const news = config.news ?? {};
4897
5180
  const feeds = news.feeds ?? [];
4898
5181
  if (feeds.includes(url)) {
4899
- console.log(chalk54.yellow("Feed already exists in config"));
5182
+ console.log(chalk59.yellow("Feed already exists in config"));
4900
5183
  return;
4901
5184
  }
4902
5185
  feeds.push(url);
4903
5186
  config.news = { ...news, feeds };
4904
5187
  saveGlobalConfig(config);
4905
- console.log(chalk54.green(`Added feed: ${url}`));
5188
+ console.log(chalk59.green(`Added feed: ${url}`));
4906
5189
  }
4907
5190
 
4908
5191
  // src/commands/news/web/handleRequest.ts
4909
- import chalk55 from "chalk";
5192
+ import chalk60 from "chalk";
4910
5193
 
4911
5194
  // src/commands/news/web/shared.ts
4912
5195
  import { decodeHTML } from "entities";
@@ -5042,17 +5325,17 @@ function prefetch() {
5042
5325
  const config = loadConfig();
5043
5326
  const total = config.news.feeds.length;
5044
5327
  if (total === 0) return;
5045
- process.stdout.write(chalk55.dim(`Fetching ${total} feed(s)\u2026 `));
5328
+ process.stdout.write(chalk60.dim(`Fetching ${total} feed(s)\u2026 `));
5046
5329
  prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
5047
5330
  const width = 20;
5048
5331
  const filled = Math.round(done2 / t * width);
5049
5332
  const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
5050
5333
  process.stdout.write(
5051
- `\r${chalk55.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
5334
+ `\r${chalk60.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
5052
5335
  );
5053
5336
  }).then((items) => {
5054
5337
  process.stdout.write(
5055
- `\r${chalk55.green(`Fetched ${items.length} items from ${total} feed(s)`)}
5338
+ `\r${chalk60.green(`Fetched ${items.length} items from ${total} feed(s)`)}
5056
5339
  `
5057
5340
  );
5058
5341
  cachedItems = items;
@@ -5098,12 +5381,12 @@ function registerNews(program2) {
5098
5381
 
5099
5382
  // src/commands/prs/comment.ts
5100
5383
  import { spawnSync as spawnSync2 } from "child_process";
5101
- import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync18 } from "fs";
5102
- import { tmpdir as tmpdir2 } from "os";
5103
- import { join as join17 } from "path";
5384
+ import { unlinkSync as unlinkSync4, writeFileSync as writeFileSync18 } from "fs";
5385
+ import { tmpdir as tmpdir3 } from "os";
5386
+ import { join as join19 } from "path";
5104
5387
 
5105
5388
  // src/commands/prs/shared.ts
5106
- import { execSync as execSync22 } from "child_process";
5389
+ import { execSync as execSync24 } from "child_process";
5107
5390
  function isGhNotInstalled(error) {
5108
5391
  if (error instanceof Error) {
5109
5392
  const msg = error.message.toLowerCase();
@@ -5119,14 +5402,14 @@ function isNotFound(error) {
5119
5402
  }
5120
5403
  function getRepoInfo() {
5121
5404
  const repoInfo = JSON.parse(
5122
- execSync22("gh repo view --json owner,name", { encoding: "utf-8" })
5405
+ execSync24("gh repo view --json owner,name", { encoding: "utf-8" })
5123
5406
  );
5124
5407
  return { org: repoInfo.owner.login, repo: repoInfo.name };
5125
5408
  }
5126
5409
  function getCurrentPrNumber() {
5127
5410
  try {
5128
5411
  const prInfo = JSON.parse(
5129
- execSync22("gh pr view --json number", { encoding: "utf-8" })
5412
+ execSync24("gh pr view --json number", { encoding: "utf-8" })
5130
5413
  );
5131
5414
  return prInfo.number;
5132
5415
  } catch (error) {
@@ -5140,7 +5423,7 @@ function getCurrentPrNumber() {
5140
5423
  function getCurrentPrNodeId() {
5141
5424
  try {
5142
5425
  const prInfo = JSON.parse(
5143
- execSync22("gh pr view --json id", { encoding: "utf-8" })
5426
+ execSync24("gh pr view --json id", { encoding: "utf-8" })
5144
5427
  );
5145
5428
  return prInfo.id;
5146
5429
  } catch (error) {
@@ -5167,12 +5450,12 @@ function validateLine(line) {
5167
5450
  process.exit(1);
5168
5451
  }
5169
5452
  }
5170
- function comment(path42, line, body) {
5453
+ function comment(path44, line, body) {
5171
5454
  validateBody(body);
5172
5455
  validateLine(line);
5173
5456
  try {
5174
5457
  const prId = getCurrentPrNodeId();
5175
- const queryFile = join17(tmpdir2(), `gh-query-${Date.now()}.graphql`);
5458
+ const queryFile = join19(tmpdir3(), `gh-query-${Date.now()}.graphql`);
5176
5459
  writeFileSync18(queryFile, MUTATION);
5177
5460
  try {
5178
5461
  const result = spawnSync2(
@@ -5187,7 +5470,7 @@ function comment(path42, line, body) {
5187
5470
  "-f",
5188
5471
  `body=${body}`,
5189
5472
  "-f",
5190
- `path=${path42}`,
5473
+ `path=${path44}`,
5191
5474
  "-F",
5192
5475
  `line=${line}`
5193
5476
  ],
@@ -5196,9 +5479,9 @@ function comment(path42, line, body) {
5196
5479
  if (result.status !== 0) {
5197
5480
  throw new Error(result.stderr || result.stdout);
5198
5481
  }
5199
- console.log(`Added review comment on ${path42}:${line}`);
5482
+ console.log(`Added review comment on ${path44}:${line}`);
5200
5483
  } finally {
5201
- unlinkSync3(queryFile);
5484
+ unlinkSync4(queryFile);
5202
5485
  }
5203
5486
  } catch (error) {
5204
5487
  if (isGhNotInstalled(error)) {
@@ -5211,55 +5494,55 @@ function comment(path42, line, body) {
5211
5494
  }
5212
5495
 
5213
5496
  // src/commands/prs/fixed.ts
5214
- import { execSync as execSync24 } from "child_process";
5497
+ import { execSync as execSync26 } from "child_process";
5215
5498
 
5216
5499
  // src/commands/prs/resolveCommentWithReply.ts
5217
- import { execSync as execSync23 } from "child_process";
5218
- import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "fs";
5219
- import { tmpdir as tmpdir3 } from "os";
5220
- import { join as join19 } from "path";
5500
+ import { execSync as execSync25 } from "child_process";
5501
+ import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync19 } from "fs";
5502
+ import { tmpdir as tmpdir4 } from "os";
5503
+ import { join as join21 } from "path";
5221
5504
 
5222
5505
  // src/commands/prs/loadCommentsCache.ts
5223
- import { existsSync as existsSync23, readFileSync as readFileSync21, unlinkSync as unlinkSync4 } from "fs";
5224
- import { join as join18 } from "path";
5506
+ import { existsSync as existsSync25, readFileSync as readFileSync22, unlinkSync as unlinkSync5 } from "fs";
5507
+ import { join as join20 } from "path";
5225
5508
  import { parse as parse2 } from "yaml";
5226
5509
  function getCachePath(prNumber) {
5227
- return join18(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
5510
+ return join20(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
5228
5511
  }
5229
5512
  function loadCommentsCache(prNumber) {
5230
5513
  const cachePath = getCachePath(prNumber);
5231
- if (!existsSync23(cachePath)) {
5514
+ if (!existsSync25(cachePath)) {
5232
5515
  return null;
5233
5516
  }
5234
- const content = readFileSync21(cachePath, "utf-8");
5517
+ const content = readFileSync22(cachePath, "utf-8");
5235
5518
  return parse2(content);
5236
5519
  }
5237
5520
  function deleteCommentsCache(prNumber) {
5238
5521
  const cachePath = getCachePath(prNumber);
5239
- if (existsSync23(cachePath)) {
5240
- unlinkSync4(cachePath);
5522
+ if (existsSync25(cachePath)) {
5523
+ unlinkSync5(cachePath);
5241
5524
  console.log("No more unresolved line comments. Cache dropped.");
5242
5525
  }
5243
5526
  }
5244
5527
 
5245
5528
  // src/commands/prs/resolveCommentWithReply.ts
5246
5529
  function replyToComment(org, repo, prNumber, commentId, message) {
5247
- execSync23(
5530
+ execSync25(
5248
5531
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
5249
5532
  { stdio: ["inherit", "pipe", "inherit"] }
5250
5533
  );
5251
5534
  }
5252
5535
  function resolveThread(threadId) {
5253
5536
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
5254
- const queryFile = join19(tmpdir3(), `gh-mutation-${Date.now()}.graphql`);
5537
+ const queryFile = join21(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
5255
5538
  writeFileSync19(queryFile, mutation);
5256
5539
  try {
5257
- execSync23(
5540
+ execSync25(
5258
5541
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
5259
5542
  { stdio: ["inherit", "pipe", "inherit"] }
5260
5543
  );
5261
5544
  } finally {
5262
- unlinkSync5(queryFile);
5545
+ unlinkSync6(queryFile);
5263
5546
  }
5264
5547
  }
5265
5548
  function requireCache(prNumber) {
@@ -5306,7 +5589,7 @@ function resolveCommentWithReply(commentId, message) {
5306
5589
  // src/commands/prs/fixed.ts
5307
5590
  function verifySha(sha) {
5308
5591
  try {
5309
- return execSync24(`git rev-parse --verify ${sha}`, {
5592
+ return execSync26(`git rev-parse --verify ${sha}`, {
5310
5593
  encoding: "utf-8"
5311
5594
  }).trim();
5312
5595
  } catch {
@@ -5320,7 +5603,7 @@ function fixed(commentId, sha) {
5320
5603
  const { org, repo } = getRepoInfo();
5321
5604
  const repoUrl = `https://github.com/${org}/${repo}`;
5322
5605
  const message = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
5323
- execSync24("git push", { stdio: "inherit" });
5606
+ execSync26("git push", { stdio: "inherit" });
5324
5607
  resolveCommentWithReply(commentId, message);
5325
5608
  } catch (error) {
5326
5609
  if (isGhNotInstalled(error)) {
@@ -5333,21 +5616,21 @@ function fixed(commentId, sha) {
5333
5616
  }
5334
5617
 
5335
5618
  // src/commands/prs/listComments/index.ts
5336
- import { existsSync as existsSync24, mkdirSync as mkdirSync6, writeFileSync as writeFileSync21 } from "fs";
5337
- import { join as join21 } from "path";
5619
+ import { existsSync as existsSync26, mkdirSync as mkdirSync6, writeFileSync as writeFileSync21 } from "fs";
5620
+ import { join as join23 } from "path";
5338
5621
  import { stringify } from "yaml";
5339
5622
 
5340
5623
  // src/commands/prs/fetchThreadIds.ts
5341
- import { execSync as execSync25 } from "child_process";
5342
- import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync20 } from "fs";
5343
- import { tmpdir as tmpdir4 } from "os";
5344
- import { join as join20 } from "path";
5624
+ import { execSync as execSync27 } from "child_process";
5625
+ import { unlinkSync as unlinkSync7, writeFileSync as writeFileSync20 } from "fs";
5626
+ import { tmpdir as tmpdir5 } from "os";
5627
+ import { join as join22 } from "path";
5345
5628
  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 } } } } } } }`;
5346
5629
  function fetchThreadIds(org, repo, prNumber) {
5347
- const queryFile = join20(tmpdir4(), `gh-query-${Date.now()}.graphql`);
5630
+ const queryFile = join22(tmpdir5(), `gh-query-${Date.now()}.graphql`);
5348
5631
  writeFileSync20(queryFile, THREAD_QUERY);
5349
5632
  try {
5350
- const result = execSync25(
5633
+ const result = execSync27(
5351
5634
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
5352
5635
  { encoding: "utf-8" }
5353
5636
  );
@@ -5364,14 +5647,14 @@ function fetchThreadIds(org, repo, prNumber) {
5364
5647
  }
5365
5648
  return { threadMap, resolvedThreadIds };
5366
5649
  } finally {
5367
- unlinkSync6(queryFile);
5650
+ unlinkSync7(queryFile);
5368
5651
  }
5369
5652
  }
5370
5653
 
5371
5654
  // src/commands/prs/listComments/fetchReviewComments.ts
5372
- import { execSync as execSync26 } from "child_process";
5655
+ import { execSync as execSync28 } from "child_process";
5373
5656
  function fetchJson(endpoint) {
5374
- const result = execSync26(`gh api --paginate ${endpoint}`, {
5657
+ const result = execSync28(`gh api --paginate ${endpoint}`, {
5375
5658
  encoding: "utf-8"
5376
5659
  });
5377
5660
  if (!result.trim()) return [];
@@ -5413,20 +5696,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
5413
5696
  }
5414
5697
 
5415
5698
  // src/commands/prs/listComments/printComments.ts
5416
- import chalk56 from "chalk";
5699
+ import chalk61 from "chalk";
5417
5700
  function formatForHuman(comment2) {
5418
5701
  if (comment2.type === "review") {
5419
- const stateColor = comment2.state === "APPROVED" ? chalk56.green : comment2.state === "CHANGES_REQUESTED" ? chalk56.red : chalk56.yellow;
5702
+ const stateColor = comment2.state === "APPROVED" ? chalk61.green : comment2.state === "CHANGES_REQUESTED" ? chalk61.red : chalk61.yellow;
5420
5703
  return [
5421
- `${chalk56.cyan("Review")} by ${chalk56.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
5704
+ `${chalk61.cyan("Review")} by ${chalk61.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
5422
5705
  comment2.body,
5423
5706
  ""
5424
5707
  ].join("\n");
5425
5708
  }
5426
5709
  const location = comment2.line ? `:${comment2.line}` : "";
5427
5710
  return [
5428
- `${chalk56.cyan("Line comment")} by ${chalk56.bold(comment2.user)} on ${chalk56.dim(`${comment2.path}${location}`)}`,
5429
- chalk56.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
5711
+ `${chalk61.cyan("Line comment")} by ${chalk61.bold(comment2.user)} on ${chalk61.dim(`${comment2.path}${location}`)}`,
5712
+ chalk61.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
5430
5713
  comment2.body,
5431
5714
  ""
5432
5715
  ].join("\n");
@@ -5458,8 +5741,8 @@ function printComments(result) {
5458
5741
 
5459
5742
  // src/commands/prs/listComments/index.ts
5460
5743
  function writeCommentsCache(prNumber, comments) {
5461
- const assistDir = join21(process.cwd(), ".assist");
5462
- if (!existsSync24(assistDir)) {
5744
+ const assistDir = join23(process.cwd(), ".assist");
5745
+ if (!existsSync26(assistDir)) {
5463
5746
  mkdirSync6(assistDir, { recursive: true });
5464
5747
  }
5465
5748
  const cacheData = {
@@ -5467,7 +5750,7 @@ function writeCommentsCache(prNumber, comments) {
5467
5750
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
5468
5751
  comments
5469
5752
  };
5470
- const cachePath = join21(assistDir, `pr-${prNumber}-comments.yaml`);
5753
+ const cachePath = join23(assistDir, `pr-${prNumber}-comments.yaml`);
5471
5754
  writeFileSync21(cachePath, stringify(cacheData));
5472
5755
  }
5473
5756
  function handleKnownErrors(error) {
@@ -5500,7 +5783,7 @@ async function listComments() {
5500
5783
  ];
5501
5784
  updateCache(prNumber, allComments);
5502
5785
  const hasLineComments = allComments.some((c) => c.type === "line");
5503
- const cachePath = hasLineComments ? join21(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
5786
+ const cachePath = hasLineComments ? join23(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
5504
5787
  return { comments: allComments, cachePath };
5505
5788
  } catch (error) {
5506
5789
  const handled = handleKnownErrors(error);
@@ -5510,19 +5793,19 @@ async function listComments() {
5510
5793
  }
5511
5794
 
5512
5795
  // src/commands/prs/prs/index.ts
5513
- import { execSync as execSync27 } from "child_process";
5796
+ import { execSync as execSync29 } from "child_process";
5514
5797
 
5515
5798
  // src/commands/prs/prs/displayPaginated/index.ts
5516
5799
  import enquirer6 from "enquirer";
5517
5800
 
5518
5801
  // src/commands/prs/prs/displayPaginated/printPr.ts
5519
- import chalk57 from "chalk";
5802
+ import chalk62 from "chalk";
5520
5803
  var STATUS_MAP = {
5521
- MERGED: (pr) => pr.mergedAt ? { label: chalk57.magenta("merged"), date: pr.mergedAt } : null,
5522
- CLOSED: (pr) => pr.closedAt ? { label: chalk57.red("closed"), date: pr.closedAt } : null
5804
+ MERGED: (pr) => pr.mergedAt ? { label: chalk62.magenta("merged"), date: pr.mergedAt } : null,
5805
+ CLOSED: (pr) => pr.closedAt ? { label: chalk62.red("closed"), date: pr.closedAt } : null
5523
5806
  };
5524
5807
  function defaultStatus(pr) {
5525
- return { label: chalk57.green("opened"), date: pr.createdAt };
5808
+ return { label: chalk62.green("opened"), date: pr.createdAt };
5526
5809
  }
5527
5810
  function getStatus2(pr) {
5528
5811
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -5531,11 +5814,11 @@ function formatDate(dateStr) {
5531
5814
  return new Date(dateStr).toISOString().split("T")[0];
5532
5815
  }
5533
5816
  function formatPrHeader(pr, status2) {
5534
- return `${chalk57.cyan(`#${pr.number}`)} ${pr.title} ${chalk57.dim(`(${pr.author.login},`)} ${status2.label} ${chalk57.dim(`${formatDate(status2.date)})`)}`;
5817
+ return `${chalk62.cyan(`#${pr.number}`)} ${pr.title} ${chalk62.dim(`(${pr.author.login},`)} ${status2.label} ${chalk62.dim(`${formatDate(status2.date)})`)}`;
5535
5818
  }
5536
5819
  function logPrDetails(pr) {
5537
5820
  console.log(
5538
- chalk57.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
5821
+ chalk62.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
5539
5822
  );
5540
5823
  console.log();
5541
5824
  }
@@ -5616,7 +5899,7 @@ async function displayPaginated(pullRequests) {
5616
5899
  async function prs(options2) {
5617
5900
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
5618
5901
  try {
5619
- const result = execSync27(
5902
+ const result = execSync29(
5620
5903
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
5621
5904
  { encoding: "utf-8" }
5622
5905
  );
@@ -5639,7 +5922,7 @@ async function prs(options2) {
5639
5922
  }
5640
5923
 
5641
5924
  // src/commands/prs/wontfix.ts
5642
- import { execSync as execSync28 } from "child_process";
5925
+ import { execSync as execSync30 } from "child_process";
5643
5926
  function validateReason(reason) {
5644
5927
  const lowerReason = reason.toLowerCase();
5645
5928
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -5656,7 +5939,7 @@ function validateShaReferences(reason) {
5656
5939
  const invalidShas = [];
5657
5940
  for (const sha of shas) {
5658
5941
  try {
5659
- execSync28(`git cat-file -t ${sha}`, { stdio: "pipe" });
5942
+ execSync30(`git cat-file -t ${sha}`, { stdio: "pipe" });
5660
5943
  } catch {
5661
5944
  invalidShas.push(sha);
5662
5945
  }
@@ -5695,13 +5978,13 @@ function registerPrs(program2) {
5695
5978
  prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason) => {
5696
5979
  wontfix(Number.parseInt(commentId, 10), reason);
5697
5980
  });
5698
- prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path42, line, body) => {
5699
- comment(path42, Number.parseInt(line, 10), body);
5981
+ prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path44, line, body) => {
5982
+ comment(path44, Number.parseInt(line, 10), body);
5700
5983
  });
5701
5984
  }
5702
5985
 
5703
5986
  // src/commands/ravendb/ravendbAuth.ts
5704
- import chalk62 from "chalk";
5987
+ import chalk67 from "chalk";
5705
5988
 
5706
5989
  // src/commands/ravendb/loadConnections.ts
5707
5990
  function loadConnections() {
@@ -5718,18 +6001,18 @@ function saveConnections(connections) {
5718
6001
  }
5719
6002
 
5720
6003
  // src/commands/ravendb/promptConnection.ts
5721
- import chalk60 from "chalk";
6004
+ import chalk65 from "chalk";
5722
6005
  import Enquirer3 from "enquirer";
5723
6006
 
5724
6007
  // src/commands/ravendb/selectOpSecret.ts
5725
- import chalk59 from "chalk";
6008
+ import chalk64 from "chalk";
5726
6009
  import Enquirer2 from "enquirer";
5727
6010
 
5728
6011
  // src/commands/ravendb/searchItems.ts
5729
- import { execSync as execSync29 } from "child_process";
5730
- import chalk58 from "chalk";
6012
+ import { execSync as execSync31 } from "child_process";
6013
+ import chalk63 from "chalk";
5731
6014
  function opExec(args) {
5732
- return execSync29(`op ${args}`, {
6015
+ return execSync31(`op ${args}`, {
5733
6016
  encoding: "utf-8",
5734
6017
  stdio: ["pipe", "pipe", "pipe"]
5735
6018
  }).trim();
@@ -5740,7 +6023,7 @@ function searchItems(search) {
5740
6023
  items = JSON.parse(opExec("item list --format=json"));
5741
6024
  } catch {
5742
6025
  console.error(
5743
- chalk58.red(
6026
+ chalk63.red(
5744
6027
  "Failed to search 1Password. Ensure the CLI is installed and you are signed in."
5745
6028
  )
5746
6029
  );
@@ -5754,7 +6037,7 @@ function getItemFields(itemId) {
5754
6037
  const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
5755
6038
  return item.fields.filter((f) => f.reference && f.label);
5756
6039
  } catch {
5757
- console.error(chalk58.red("Failed to get item details from 1Password."));
6040
+ console.error(chalk63.red("Failed to get item details from 1Password."));
5758
6041
  process.exit(1);
5759
6042
  }
5760
6043
  }
@@ -5773,7 +6056,7 @@ async function selectOpSecret(searchTerm) {
5773
6056
  }).run();
5774
6057
  const items = searchItems(search);
5775
6058
  if (items.length === 0) {
5776
- console.error(chalk59.red(`No items found matching "${search}".`));
6059
+ console.error(chalk64.red(`No items found matching "${search}".`));
5777
6060
  process.exit(1);
5778
6061
  }
5779
6062
  const itemId = await selectOne(
@@ -5782,7 +6065,7 @@ async function selectOpSecret(searchTerm) {
5782
6065
  );
5783
6066
  const fields = getItemFields(itemId);
5784
6067
  if (fields.length === 0) {
5785
- console.error(chalk59.red("No fields with references found on this item."));
6068
+ console.error(chalk64.red("No fields with references found on this item."));
5786
6069
  process.exit(1);
5787
6070
  }
5788
6071
  const ref = await selectOne(
@@ -5800,7 +6083,7 @@ async function promptConnection(existingNames) {
5800
6083
  message: "Connection name:"
5801
6084
  }).run();
5802
6085
  if (existingNames.includes(name)) {
5803
- console.error(chalk60.red(`Connection "${name}" already exists.`));
6086
+ console.error(chalk65.red(`Connection "${name}" already exists.`));
5804
6087
  process.exit(1);
5805
6088
  }
5806
6089
  const url = await new Input2({
@@ -5812,22 +6095,22 @@ async function promptConnection(existingNames) {
5812
6095
  message: "Database name:"
5813
6096
  }).run();
5814
6097
  if (!name || !url || !database) {
5815
- console.error(chalk60.red("All fields are required."));
6098
+ console.error(chalk65.red("All fields are required."));
5816
6099
  process.exit(1);
5817
6100
  }
5818
6101
  const apiKeyRef = await selectOpSecret();
5819
- console.log(chalk60.dim(`Using: ${apiKeyRef}`));
6102
+ console.log(chalk65.dim(`Using: ${apiKeyRef}`));
5820
6103
  return { name, url, database, apiKeyRef };
5821
6104
  }
5822
6105
 
5823
6106
  // src/commands/ravendb/ravendbSetConnection.ts
5824
- import chalk61 from "chalk";
6107
+ import chalk66 from "chalk";
5825
6108
  function ravendbSetConnection(name) {
5826
6109
  const raw = loadGlobalConfigRaw();
5827
6110
  const ravendb = raw.ravendb ?? {};
5828
6111
  const connections = ravendb.connections ?? [];
5829
6112
  if (!connections.some((c) => c.name === name)) {
5830
- console.error(chalk61.red(`Connection "${name}" not found.`));
6113
+ console.error(chalk66.red(`Connection "${name}" not found.`));
5831
6114
  console.error(
5832
6115
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
5833
6116
  );
@@ -5849,7 +6132,7 @@ async function ravendbAuth(options2) {
5849
6132
  }
5850
6133
  for (const c of connections) {
5851
6134
  console.log(
5852
- `${chalk62.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`
6135
+ `${chalk67.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`
5853
6136
  );
5854
6137
  }
5855
6138
  return;
@@ -5857,7 +6140,7 @@ async function ravendbAuth(options2) {
5857
6140
  if (options2.remove) {
5858
6141
  const filtered = connections.filter((c) => c.name !== options2.remove);
5859
6142
  if (filtered.length === connections.length) {
5860
- console.error(chalk62.red(`Connection "${options2.remove}" not found.`));
6143
+ console.error(chalk67.red(`Connection "${options2.remove}" not found.`));
5861
6144
  process.exit(1);
5862
6145
  }
5863
6146
  saveConnections(filtered);
@@ -5875,10 +6158,10 @@ async function ravendbAuth(options2) {
5875
6158
  }
5876
6159
 
5877
6160
  // src/commands/ravendb/ravendbCollections.ts
5878
- import chalk66 from "chalk";
6161
+ import chalk71 from "chalk";
5879
6162
 
5880
6163
  // src/commands/ravendb/ravenFetch.ts
5881
- import chalk64 from "chalk";
6164
+ import chalk69 from "chalk";
5882
6165
 
5883
6166
  // src/commands/ravendb/getAccessToken.ts
5884
6167
  var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
@@ -5914,21 +6197,21 @@ ${errorText}`
5914
6197
  }
5915
6198
 
5916
6199
  // src/commands/ravendb/resolveOpSecret.ts
5917
- import { execSync as execSync30 } from "child_process";
5918
- import chalk63 from "chalk";
6200
+ import { execSync as execSync32 } from "child_process";
6201
+ import chalk68 from "chalk";
5919
6202
  function resolveOpSecret(reference) {
5920
6203
  if (!reference.startsWith("op://")) {
5921
- console.error(chalk63.red(`Invalid secret reference: must start with op://`));
6204
+ console.error(chalk68.red(`Invalid secret reference: must start with op://`));
5922
6205
  process.exit(1);
5923
6206
  }
5924
6207
  try {
5925
- return execSync30(`op read "${reference}"`, {
6208
+ return execSync32(`op read "${reference}"`, {
5926
6209
  encoding: "utf-8",
5927
6210
  stdio: ["pipe", "pipe", "pipe"]
5928
6211
  }).trim();
5929
6212
  } catch {
5930
6213
  console.error(
5931
- chalk63.red(
6214
+ chalk68.red(
5932
6215
  "Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
5933
6216
  )
5934
6217
  );
@@ -5937,10 +6220,10 @@ function resolveOpSecret(reference) {
5937
6220
  }
5938
6221
 
5939
6222
  // src/commands/ravendb/ravenFetch.ts
5940
- async function ravenFetch(connection, path42) {
6223
+ async function ravenFetch(connection, path44) {
5941
6224
  const apiKey = resolveOpSecret(connection.apiKeyRef);
5942
6225
  let accessToken = await getAccessToken(apiKey);
5943
- const url = `${connection.url}${path42}`;
6226
+ const url = `${connection.url}${path44}`;
5944
6227
  const headers = {
5945
6228
  Authorization: `Bearer ${accessToken}`,
5946
6229
  "Content-Type": "application/json"
@@ -5955,7 +6238,7 @@ async function ravenFetch(connection, path42) {
5955
6238
  if (!response.ok) {
5956
6239
  const body = await response.text();
5957
6240
  console.error(
5958
- chalk64.red(`RavenDB error: ${response.status} ${response.statusText}`)
6241
+ chalk69.red(`RavenDB error: ${response.status} ${response.statusText}`)
5959
6242
  );
5960
6243
  console.error(body.substring(0, 500));
5961
6244
  process.exit(1);
@@ -5964,7 +6247,7 @@ async function ravenFetch(connection, path42) {
5964
6247
  }
5965
6248
 
5966
6249
  // src/commands/ravendb/resolveConnection.ts
5967
- import chalk65 from "chalk";
6250
+ import chalk70 from "chalk";
5968
6251
  function loadRavendb() {
5969
6252
  const raw = loadGlobalConfigRaw();
5970
6253
  const ravendb = raw.ravendb;
@@ -5978,7 +6261,7 @@ function resolveConnection(name) {
5978
6261
  const connectionName = name ?? defaultConnection;
5979
6262
  if (!connectionName) {
5980
6263
  console.error(
5981
- chalk65.red(
6264
+ chalk70.red(
5982
6265
  "No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
5983
6266
  )
5984
6267
  );
@@ -5986,7 +6269,7 @@ function resolveConnection(name) {
5986
6269
  }
5987
6270
  const connection = connections.find((c) => c.name === connectionName);
5988
6271
  if (!connection) {
5989
- console.error(chalk65.red(`Connection "${connectionName}" not found.`));
6272
+ console.error(chalk70.red(`Connection "${connectionName}" not found.`));
5990
6273
  console.error(
5991
6274
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
5992
6275
  );
@@ -6017,29 +6300,29 @@ async function ravendbCollections(connectionName) {
6017
6300
  return;
6018
6301
  }
6019
6302
  for (const c of collections) {
6020
- console.log(`${chalk66.bold(c.Name)} ${c.CountOfDocuments} docs`);
6303
+ console.log(`${chalk71.bold(c.Name)} ${c.CountOfDocuments} docs`);
6021
6304
  }
6022
6305
  }
6023
6306
 
6024
6307
  // src/commands/ravendb/ravendbQuery.ts
6025
- import chalk68 from "chalk";
6308
+ import chalk73 from "chalk";
6026
6309
 
6027
6310
  // src/commands/ravendb/fetchAllPages.ts
6028
- import chalk67 from "chalk";
6311
+ import chalk72 from "chalk";
6029
6312
 
6030
6313
  // src/commands/ravendb/buildQueryPath.ts
6031
6314
  function buildQueryPath(opts) {
6032
6315
  const db = encodeURIComponent(opts.db);
6033
- let path42;
6316
+ let path44;
6034
6317
  if (opts.collection) {
6035
- path42 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
6318
+ path44 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
6036
6319
  } else {
6037
- path42 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
6320
+ path44 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
6038
6321
  }
6039
6322
  if (opts.query) {
6040
- path42 += `&query=${encodeURIComponent(opts.query)}`;
6323
+ path44 += `&query=${encodeURIComponent(opts.query)}`;
6041
6324
  }
6042
- return path42;
6325
+ return path44;
6043
6326
  }
6044
6327
 
6045
6328
  // src/commands/ravendb/fetchAllPages.ts
@@ -6048,7 +6331,7 @@ async function fetchAllPages(connection, opts) {
6048
6331
  let start3 = 0;
6049
6332
  while (true) {
6050
6333
  const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
6051
- const path42 = buildQueryPath({
6334
+ const path44 = buildQueryPath({
6052
6335
  db: connection.database,
6053
6336
  collection: opts.collection,
6054
6337
  start: start3,
@@ -6056,14 +6339,14 @@ async function fetchAllPages(connection, opts) {
6056
6339
  sort: opts.sort,
6057
6340
  query: opts.query
6058
6341
  });
6059
- const data = await ravenFetch(connection, path42);
6342
+ const data = await ravenFetch(connection, path44);
6060
6343
  const results = data.Results ?? [];
6061
6344
  const totalResults = data.TotalResults ?? 0;
6062
6345
  if (results.length === 0) break;
6063
6346
  allResults.push(...results);
6064
6347
  start3 += results.length;
6065
6348
  process.stderr.write(
6066
- `\r${chalk67.dim(`Fetched ${allResults.length}/${totalResults}`)}`
6349
+ `\r${chalk72.dim(`Fetched ${allResults.length}/${totalResults}`)}`
6067
6350
  );
6068
6351
  if (start3 >= totalResults) break;
6069
6352
  if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
@@ -6078,7 +6361,7 @@ async function fetchAllPages(connection, opts) {
6078
6361
  async function ravendbQuery(connectionName, collection, options2) {
6079
6362
  const resolved = resolveArgs(connectionName, collection);
6080
6363
  if (!resolved.collection && !options2.query) {
6081
- console.error(chalk68.red("Provide a collection name or --query filter."));
6364
+ console.error(chalk73.red("Provide a collection name or --query filter."));
6082
6365
  process.exit(1);
6083
6366
  }
6084
6367
  const { collection: col } = resolved;
@@ -6110,10 +6393,10 @@ function registerRavendb(program2) {
6110
6393
 
6111
6394
  // src/commands/refactor/check/index.ts
6112
6395
  import { spawn as spawn3 } from "child_process";
6113
- import * as path25 from "path";
6396
+ import * as path27 from "path";
6114
6397
 
6115
6398
  // src/commands/refactor/logViolations.ts
6116
- import chalk69 from "chalk";
6399
+ import chalk74 from "chalk";
6117
6400
  var DEFAULT_MAX_LINES = 100;
6118
6401
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
6119
6402
  if (violations.length === 0) {
@@ -6122,43 +6405,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
6122
6405
  }
6123
6406
  return;
6124
6407
  }
6125
- console.error(chalk69.red(`
6408
+ console.error(chalk74.red(`
6126
6409
  Refactor check failed:
6127
6410
  `));
6128
- console.error(chalk69.red(` The following files exceed ${maxLines} lines:
6411
+ console.error(chalk74.red(` The following files exceed ${maxLines} lines:
6129
6412
  `));
6130
6413
  for (const violation of violations) {
6131
- console.error(chalk69.red(` ${violation.file} (${violation.lines} lines)`));
6414
+ console.error(chalk74.red(` ${violation.file} (${violation.lines} lines)`));
6132
6415
  }
6133
6416
  console.error(
6134
- chalk69.yellow(
6417
+ chalk74.yellow(
6135
6418
  `
6136
6419
  Each file needs to be sensibly refactored, or if there is no sensible
6137
6420
  way to refactor it, ignore it with:
6138
6421
  `
6139
6422
  )
6140
6423
  );
6141
- console.error(chalk69.gray(` assist refactor ignore <file>
6424
+ console.error(chalk74.gray(` assist refactor ignore <file>
6142
6425
  `));
6143
6426
  if (process.env.CLAUDECODE) {
6144
- console.error(chalk69.cyan(`
6427
+ console.error(chalk74.cyan(`
6145
6428
  ## Extracting Code to New Files
6146
6429
  `));
6147
6430
  console.error(
6148
- chalk69.cyan(
6431
+ chalk74.cyan(
6149
6432
  ` When extracting logic from one file to another, consider where the extracted code belongs:
6150
6433
  `
6151
6434
  )
6152
6435
  );
6153
6436
  console.error(
6154
- chalk69.cyan(
6437
+ chalk74.cyan(
6155
6438
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
6156
6439
  original file's domain, create a new folder containing both the original and extracted files.
6157
6440
  `
6158
6441
  )
6159
6442
  );
6160
6443
  console.error(
6161
- chalk69.cyan(
6444
+ chalk74.cyan(
6162
6445
  ` 2. Share common utilities: If the extracted code can be reused across multiple
6163
6446
  domains, move it to a common/shared folder.
6164
6447
  `
@@ -6168,7 +6451,7 @@ Refactor check failed:
6168
6451
  }
6169
6452
 
6170
6453
  // src/commands/refactor/check/getViolations/index.ts
6171
- import { execSync as execSync31 } from "child_process";
6454
+ import { execSync as execSync33 } from "child_process";
6172
6455
  import fs16 from "fs";
6173
6456
  import { minimatch as minimatch4 } from "minimatch";
6174
6457
 
@@ -6218,7 +6501,7 @@ function getGitFiles(options2) {
6218
6501
  }
6219
6502
  const files = /* @__PURE__ */ new Set();
6220
6503
  if (options2.staged || options2.modified) {
6221
- const staged = execSync31("git diff --cached --name-only", {
6504
+ const staged = execSync33("git diff --cached --name-only", {
6222
6505
  encoding: "utf-8"
6223
6506
  });
6224
6507
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -6226,7 +6509,7 @@ function getGitFiles(options2) {
6226
6509
  }
6227
6510
  }
6228
6511
  if (options2.unstaged || options2.modified) {
6229
- const unstaged = execSync31("git diff --name-only", { encoding: "utf-8" });
6512
+ const unstaged = execSync33("git diff --name-only", { encoding: "utf-8" });
6230
6513
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
6231
6514
  files.add(file);
6232
6515
  }
@@ -6287,7 +6570,7 @@ ${failed.length} verify script(s) failed:`);
6287
6570
  async function runVerifyQuietly() {
6288
6571
  const result = findPackageJsonWithVerifyScripts(process.cwd());
6289
6572
  if (!result) return true;
6290
- const packageDir = path25.dirname(result.packageJsonPath);
6573
+ const packageDir = path27.dirname(result.packageJsonPath);
6291
6574
  const results = await Promise.all(
6292
6575
  result.verifyScripts.map((script) => runScript(script, packageDir))
6293
6576
  );
@@ -6314,11 +6597,11 @@ async function check(pattern2, options2) {
6314
6597
 
6315
6598
  // src/commands/refactor/ignore.ts
6316
6599
  import fs17 from "fs";
6317
- import chalk70 from "chalk";
6600
+ import chalk75 from "chalk";
6318
6601
  var REFACTOR_YML_PATH2 = "refactor.yml";
6319
6602
  function ignore(file) {
6320
6603
  if (!fs17.existsSync(file)) {
6321
- console.error(chalk70.red(`Error: File does not exist: ${file}`));
6604
+ console.error(chalk75.red(`Error: File does not exist: ${file}`));
6322
6605
  process.exit(1);
6323
6606
  }
6324
6607
  const content = fs17.readFileSync(file, "utf-8");
@@ -6334,43 +6617,43 @@ function ignore(file) {
6334
6617
  fs17.writeFileSync(REFACTOR_YML_PATH2, entry);
6335
6618
  }
6336
6619
  console.log(
6337
- chalk70.green(
6620
+ chalk75.green(
6338
6621
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
6339
6622
  )
6340
6623
  );
6341
6624
  }
6342
6625
 
6343
6626
  // src/commands/refactor/rename/index.ts
6344
- import path26 from "path";
6345
- import chalk71 from "chalk";
6627
+ import path28 from "path";
6628
+ import chalk76 from "chalk";
6346
6629
  import { Project as Project2 } from "ts-morph";
6347
6630
  async function rename(source, destination, options2 = {}) {
6348
- const sourcePath = path26.resolve(source);
6349
- const destPath = path26.resolve(destination);
6631
+ const sourcePath = path28.resolve(source);
6632
+ const destPath = path28.resolve(destination);
6350
6633
  const cwd = process.cwd();
6351
- const relSource = path26.relative(cwd, sourcePath);
6352
- const relDest = path26.relative(cwd, destPath);
6634
+ const relSource = path28.relative(cwd, sourcePath);
6635
+ const relDest = path28.relative(cwd, destPath);
6353
6636
  const project = new Project2({
6354
- tsConfigFilePath: path26.resolve("tsconfig.json")
6637
+ tsConfigFilePath: path28.resolve("tsconfig.json")
6355
6638
  });
6356
6639
  const sourceFile = project.getSourceFile(sourcePath);
6357
6640
  if (!sourceFile) {
6358
- console.log(chalk71.red(`File not found in project: ${source}`));
6641
+ console.log(chalk76.red(`File not found in project: ${source}`));
6359
6642
  process.exit(1);
6360
6643
  }
6361
- console.log(chalk71.bold(`Rename: ${relSource} \u2192 ${relDest}`));
6644
+ console.log(chalk76.bold(`Rename: ${relSource} \u2192 ${relDest}`));
6362
6645
  if (options2.apply) {
6363
6646
  sourceFile.move(destPath);
6364
6647
  await project.save();
6365
- console.log(chalk71.green("Done"));
6648
+ console.log(chalk76.green("Done"));
6366
6649
  } else {
6367
- console.log(chalk71.dim("Dry run. Use --apply to execute."));
6650
+ console.log(chalk76.dim("Dry run. Use --apply to execute."));
6368
6651
  }
6369
6652
  }
6370
6653
 
6371
6654
  // src/commands/refactor/renameSymbol/index.ts
6372
- import path28 from "path";
6373
- import chalk72 from "chalk";
6655
+ import path30 from "path";
6656
+ import chalk77 from "chalk";
6374
6657
  import { Project as Project3 } from "ts-morph";
6375
6658
 
6376
6659
  // src/commands/refactor/renameSymbol/findSymbol.ts
@@ -6398,12 +6681,12 @@ function findSymbol(sourceFile, symbolName) {
6398
6681
  }
6399
6682
 
6400
6683
  // src/commands/refactor/renameSymbol/groupReferences.ts
6401
- import path27 from "path";
6684
+ import path29 from "path";
6402
6685
  function groupReferences(symbol, cwd) {
6403
6686
  const refs = symbol.findReferencesAsNodes();
6404
6687
  const grouped = /* @__PURE__ */ new Map();
6405
6688
  for (const ref of refs) {
6406
- const refFile = path27.relative(cwd, ref.getSourceFile().getFilePath());
6689
+ const refFile = path29.relative(cwd, ref.getSourceFile().getFilePath());
6407
6690
  const lines = grouped.get(refFile) ?? [];
6408
6691
  if (!grouped.has(refFile)) grouped.set(refFile, lines);
6409
6692
  lines.push(ref.getStartLineNumber());
@@ -6413,47 +6696,47 @@ function groupReferences(symbol, cwd) {
6413
6696
 
6414
6697
  // src/commands/refactor/renameSymbol/index.ts
6415
6698
  async function renameSymbol(file, oldName, newName, options2 = {}) {
6416
- const filePath = path28.resolve(file);
6417
- const tsConfigPath = path28.resolve("tsconfig.json");
6699
+ const filePath = path30.resolve(file);
6700
+ const tsConfigPath = path30.resolve("tsconfig.json");
6418
6701
  const cwd = process.cwd();
6419
6702
  const project = new Project3({ tsConfigFilePath: tsConfigPath });
6420
6703
  const sourceFile = project.getSourceFile(filePath);
6421
6704
  if (!sourceFile) {
6422
- console.log(chalk72.red(`File not found in project: ${file}`));
6705
+ console.log(chalk77.red(`File not found in project: ${file}`));
6423
6706
  process.exit(1);
6424
6707
  }
6425
6708
  const symbol = findSymbol(sourceFile, oldName);
6426
6709
  if (!symbol) {
6427
- console.log(chalk72.red(`Symbol "${oldName}" not found in ${file}`));
6710
+ console.log(chalk77.red(`Symbol "${oldName}" not found in ${file}`));
6428
6711
  process.exit(1);
6429
6712
  }
6430
6713
  const grouped = groupReferences(symbol, cwd);
6431
6714
  const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
6432
6715
  console.log(
6433
- chalk72.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
6716
+ chalk77.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
6434
6717
  `)
6435
6718
  );
6436
6719
  for (const [refFile, lines] of grouped) {
6437
6720
  console.log(
6438
- ` ${chalk72.dim(refFile)}: lines ${chalk72.cyan(lines.join(", "))}`
6721
+ ` ${chalk77.dim(refFile)}: lines ${chalk77.cyan(lines.join(", "))}`
6439
6722
  );
6440
6723
  }
6441
6724
  if (options2.apply) {
6442
6725
  symbol.rename(newName);
6443
6726
  await project.save();
6444
- console.log(chalk72.green(`
6727
+ console.log(chalk77.green(`
6445
6728
  Renamed ${oldName} \u2192 ${newName}`));
6446
6729
  } else {
6447
- console.log(chalk72.dim("\nDry run. Use --apply to execute."));
6730
+ console.log(chalk77.dim("\nDry run. Use --apply to execute."));
6448
6731
  }
6449
6732
  }
6450
6733
 
6451
6734
  // src/commands/refactor/restructure/index.ts
6452
- import path37 from "path";
6453
- import chalk75 from "chalk";
6735
+ import path39 from "path";
6736
+ import chalk80 from "chalk";
6454
6737
 
6455
6738
  // src/commands/refactor/restructure/buildImportGraph/index.ts
6456
- import path29 from "path";
6739
+ import path31 from "path";
6457
6740
  import ts7 from "typescript";
6458
6741
 
6459
6742
  // src/commands/refactor/restructure/buildImportGraph/getImportSpecifiers.ts
@@ -6480,7 +6763,7 @@ function loadParsedConfig(tsConfigPath) {
6480
6763
  return ts7.parseJsonConfigFileContent(
6481
6764
  configFile.config,
6482
6765
  ts7.sys,
6483
- path29.dirname(tsConfigPath)
6766
+ path31.dirname(tsConfigPath)
6484
6767
  );
6485
6768
  }
6486
6769
  function addToSetMap(map, key, value) {
@@ -6496,7 +6779,7 @@ function resolveImport(specifier, filePath, options2) {
6496
6779
  const resolved = ts7.resolveModuleName(specifier, filePath, options2, ts7.sys);
6497
6780
  const resolvedPath = resolved.resolvedModule?.resolvedFileName;
6498
6781
  if (!resolvedPath || resolvedPath.includes("node_modules")) return null;
6499
- return path29.resolve(resolvedPath);
6782
+ return path31.resolve(resolvedPath);
6500
6783
  }
6501
6784
  function buildImportGraph(candidateFiles, tsConfigPath) {
6502
6785
  const parsed = loadParsedConfig(tsConfigPath);
@@ -6505,7 +6788,7 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
6505
6788
  const importedBy = /* @__PURE__ */ new Map();
6506
6789
  const imports = /* @__PURE__ */ new Map();
6507
6790
  for (const sourceFile of program2.getSourceFiles()) {
6508
- const filePath = path29.resolve(sourceFile.fileName);
6791
+ const filePath = path31.resolve(sourceFile.fileName);
6509
6792
  if (filePath.includes("node_modules")) continue;
6510
6793
  for (const specifier of getImportSpecifiers(sourceFile)) {
6511
6794
  const absTarget = resolveImport(specifier, filePath, parsed.options);
@@ -6519,12 +6802,12 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
6519
6802
  }
6520
6803
 
6521
6804
  // src/commands/refactor/restructure/clusterDirectories.ts
6522
- import path30 from "path";
6805
+ import path32 from "path";
6523
6806
  function clusterDirectories(graph) {
6524
6807
  const dirImportedBy = /* @__PURE__ */ new Map();
6525
6808
  for (const edge of graph.edges) {
6526
- const sourceDir = path30.dirname(edge.source);
6527
- const targetDir = path30.dirname(edge.target);
6809
+ const sourceDir = path32.dirname(edge.source);
6810
+ const targetDir = path32.dirname(edge.target);
6528
6811
  if (sourceDir === targetDir) continue;
6529
6812
  if (!graph.files.has(edge.target)) continue;
6530
6813
  const existing = dirImportedBy.get(targetDir) ?? /* @__PURE__ */ new Set();
@@ -6552,20 +6835,20 @@ function clusterDirectories(graph) {
6552
6835
  return clusters;
6553
6836
  }
6554
6837
  function isAncestor(ancestor, descendant) {
6555
- const rel = path30.relative(ancestor, descendant);
6838
+ const rel = path32.relative(ancestor, descendant);
6556
6839
  return !rel.startsWith("..") && rel !== "";
6557
6840
  }
6558
6841
 
6559
6842
  // src/commands/refactor/restructure/clusterFiles.ts
6560
- import path31 from "path";
6843
+ import path33 from "path";
6561
6844
  function findRootParent(file, importedBy, visited) {
6562
6845
  const importers = importedBy.get(file);
6563
6846
  if (!importers || importers.size !== 1) return file;
6564
6847
  const parent = [...importers][0];
6565
- const parentDir = path31.dirname(parent);
6566
- const fileDir = path31.dirname(file);
6848
+ const parentDir = path33.dirname(parent);
6849
+ const fileDir = path33.dirname(file);
6567
6850
  if (parentDir !== fileDir) return file;
6568
- if (path31.basename(parent, path31.extname(parent)) === "index") return file;
6851
+ if (path33.basename(parent, path33.extname(parent)) === "index") return file;
6569
6852
  if (visited.has(parent)) return file;
6570
6853
  visited.add(parent);
6571
6854
  return findRootParent(parent, importedBy, visited);
@@ -6573,16 +6856,16 @@ function findRootParent(file, importedBy, visited) {
6573
6856
  function clusterFiles(graph) {
6574
6857
  const clusters = /* @__PURE__ */ new Map();
6575
6858
  for (const file of graph.files) {
6576
- const basename7 = path31.basename(file, path31.extname(file));
6859
+ const basename7 = path33.basename(file, path33.extname(file));
6577
6860
  if (basename7 === "index") continue;
6578
6861
  const importers = graph.importedBy.get(file);
6579
6862
  if (!importers || importers.size !== 1) continue;
6580
6863
  const parent = [...importers][0];
6581
6864
  if (!graph.files.has(parent)) continue;
6582
- const parentDir = path31.dirname(parent);
6583
- const fileDir = path31.dirname(file);
6865
+ const parentDir = path33.dirname(parent);
6866
+ const fileDir = path33.dirname(file);
6584
6867
  if (parentDir !== fileDir) continue;
6585
- const parentBasename = path31.basename(parent, path31.extname(parent));
6868
+ const parentBasename = path33.basename(parent, path33.extname(parent));
6586
6869
  if (parentBasename === "index") continue;
6587
6870
  const root = findRootParent(parent, graph.importedBy, /* @__PURE__ */ new Set([file]));
6588
6871
  if (!root || root === file) continue;
@@ -6594,7 +6877,7 @@ function clusterFiles(graph) {
6594
6877
  }
6595
6878
 
6596
6879
  // src/commands/refactor/restructure/computeRewrites/index.ts
6597
- import path32 from "path";
6880
+ import path34 from "path";
6598
6881
 
6599
6882
  // src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
6600
6883
  import fs18 from "fs";
@@ -6603,7 +6886,7 @@ function getOrCreateList(map, key) {
6603
6886
  if (!map.has(key)) map.set(key, list4);
6604
6887
  return list4;
6605
6888
  }
6606
- function groupByFile(rewrites) {
6889
+ function groupByFile2(rewrites) {
6607
6890
  const grouped = /* @__PURE__ */ new Map();
6608
6891
  for (const rewrite of rewrites) {
6609
6892
  getOrCreateList(grouped, rewrite.file).push(rewrite);
@@ -6624,7 +6907,7 @@ function applyFileRewrites(file, fileRewrites) {
6624
6907
  }
6625
6908
  function applyRewrites(rewrites) {
6626
6909
  const updatedContents = /* @__PURE__ */ new Map();
6627
- for (const [file, fileRewrites] of groupByFile(rewrites)) {
6910
+ for (const [file, fileRewrites] of groupByFile2(rewrites)) {
6628
6911
  updatedContents.set(file, applyFileRewrites(file, fileRewrites));
6629
6912
  }
6630
6913
  return updatedContents;
@@ -6648,7 +6931,7 @@ function normalizeSpecifier(rel) {
6648
6931
  );
6649
6932
  }
6650
6933
  function computeSpecifier(fromFile, toFile) {
6651
- return normalizeSpecifier(path32.relative(path32.dirname(fromFile), toFile));
6934
+ return normalizeSpecifier(path34.relative(path34.dirname(fromFile), toFile));
6652
6935
  }
6653
6936
  function isAffected(edge, moveMap) {
6654
6937
  return moveMap.has(edge.target) || moveMap.has(edge.source);
@@ -6692,51 +6975,51 @@ function computeRewrites(moves, edges, allProjectFiles) {
6692
6975
  }
6693
6976
 
6694
6977
  // src/commands/refactor/restructure/displayPlan.ts
6695
- import path33 from "path";
6696
- import chalk73 from "chalk";
6978
+ import path35 from "path";
6979
+ import chalk78 from "chalk";
6697
6980
  function relPath(filePath) {
6698
- return path33.relative(process.cwd(), filePath);
6981
+ return path35.relative(process.cwd(), filePath);
6699
6982
  }
6700
6983
  function displayMoves(plan) {
6701
6984
  if (plan.moves.length === 0) return;
6702
- console.log(chalk73.bold("\nFile moves:"));
6985
+ console.log(chalk78.bold("\nFile moves:"));
6703
6986
  for (const move of plan.moves) {
6704
6987
  console.log(
6705
- ` ${chalk73.red(relPath(move.from))} \u2192 ${chalk73.green(relPath(move.to))}`
6988
+ ` ${chalk78.red(relPath(move.from))} \u2192 ${chalk78.green(relPath(move.to))}`
6706
6989
  );
6707
- console.log(chalk73.dim(` ${move.reason}`));
6990
+ console.log(chalk78.dim(` ${move.reason}`));
6708
6991
  }
6709
6992
  }
6710
6993
  function displayRewrites(rewrites) {
6711
6994
  if (rewrites.length === 0) return;
6712
6995
  const affectedFiles = new Set(rewrites.map((r) => r.file));
6713
- console.log(chalk73.bold(`
6996
+ console.log(chalk78.bold(`
6714
6997
  Import rewrites (${affectedFiles.size} files):`));
6715
6998
  for (const file of affectedFiles) {
6716
- console.log(` ${chalk73.cyan(relPath(file))}:`);
6999
+ console.log(` ${chalk78.cyan(relPath(file))}:`);
6717
7000
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
6718
7001
  (r) => r.file === file
6719
7002
  )) {
6720
7003
  console.log(
6721
- ` ${chalk73.red(`"${oldSpecifier}"`)} \u2192 ${chalk73.green(`"${newSpecifier}"`)}`
7004
+ ` ${chalk78.red(`"${oldSpecifier}"`)} \u2192 ${chalk78.green(`"${newSpecifier}"`)}`
6722
7005
  );
6723
7006
  }
6724
7007
  }
6725
7008
  }
6726
7009
  function displayPlan(plan) {
6727
7010
  if (plan.warnings.length > 0) {
6728
- console.log(chalk73.yellow("\nWarnings:"));
6729
- for (const w of plan.warnings) console.log(chalk73.yellow(` ${w}`));
7011
+ console.log(chalk78.yellow("\nWarnings:"));
7012
+ for (const w of plan.warnings) console.log(chalk78.yellow(` ${w}`));
6730
7013
  }
6731
7014
  if (plan.newDirectories.length > 0) {
6732
- console.log(chalk73.bold("\nNew directories:"));
7015
+ console.log(chalk78.bold("\nNew directories:"));
6733
7016
  for (const dir of plan.newDirectories)
6734
- console.log(chalk73.green(` ${dir}/`));
7017
+ console.log(chalk78.green(` ${dir}/`));
6735
7018
  }
6736
7019
  displayMoves(plan);
6737
7020
  displayRewrites(plan.rewrites);
6738
7021
  console.log(
6739
- chalk73.dim(
7022
+ chalk78.dim(
6740
7023
  `
6741
7024
  Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
6742
7025
  )
@@ -6745,33 +7028,33 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
6745
7028
 
6746
7029
  // src/commands/refactor/restructure/executePlan.ts
6747
7030
  import fs19 from "fs";
6748
- import path34 from "path";
6749
- import chalk74 from "chalk";
7031
+ import path36 from "path";
7032
+ import chalk79 from "chalk";
6750
7033
  function executePlan(plan) {
6751
7034
  const updatedContents = applyRewrites(plan.rewrites);
6752
7035
  for (const [file, content] of updatedContents) {
6753
7036
  fs19.writeFileSync(file, content, "utf-8");
6754
7037
  console.log(
6755
- chalk74.cyan(` Rewrote imports in ${path34.relative(process.cwd(), file)}`)
7038
+ chalk79.cyan(` Rewrote imports in ${path36.relative(process.cwd(), file)}`)
6756
7039
  );
6757
7040
  }
6758
7041
  for (const dir of plan.newDirectories) {
6759
7042
  fs19.mkdirSync(dir, { recursive: true });
6760
- console.log(chalk74.green(` Created ${path34.relative(process.cwd(), dir)}/`));
7043
+ console.log(chalk79.green(` Created ${path36.relative(process.cwd(), dir)}/`));
6761
7044
  }
6762
7045
  for (const move of plan.moves) {
6763
- const targetDir = path34.dirname(move.to);
7046
+ const targetDir = path36.dirname(move.to);
6764
7047
  if (!fs19.existsSync(targetDir)) {
6765
7048
  fs19.mkdirSync(targetDir, { recursive: true });
6766
7049
  }
6767
7050
  fs19.renameSync(move.from, move.to);
6768
7051
  console.log(
6769
- chalk74.white(
6770
- ` Moved ${path34.relative(process.cwd(), move.from)} \u2192 ${path34.relative(process.cwd(), move.to)}`
7052
+ chalk79.white(
7053
+ ` Moved ${path36.relative(process.cwd(), move.from)} \u2192 ${path36.relative(process.cwd(), move.to)}`
6771
7054
  )
6772
7055
  );
6773
7056
  }
6774
- removeEmptyDirectories(plan.moves.map((m) => path34.dirname(m.from)));
7057
+ removeEmptyDirectories(plan.moves.map((m) => path36.dirname(m.from)));
6775
7058
  }
6776
7059
  function removeEmptyDirectories(dirs) {
6777
7060
  const unique = [...new Set(dirs)];
@@ -6781,8 +7064,8 @@ function removeEmptyDirectories(dirs) {
6781
7064
  if (entries.length === 0) {
6782
7065
  fs19.rmdirSync(dir);
6783
7066
  console.log(
6784
- chalk74.dim(
6785
- ` Removed empty directory ${path34.relative(process.cwd(), dir)}`
7067
+ chalk79.dim(
7068
+ ` Removed empty directory ${path36.relative(process.cwd(), dir)}`
6786
7069
  )
6787
7070
  );
6788
7071
  }
@@ -6790,7 +7073,7 @@ function removeEmptyDirectories(dirs) {
6790
7073
  }
6791
7074
 
6792
7075
  // src/commands/refactor/restructure/planFileMoves/index.ts
6793
- import path36 from "path";
7076
+ import path38 from "path";
6794
7077
 
6795
7078
  // src/commands/refactor/restructure/planFileMoves/shared.ts
6796
7079
  import fs20 from "fs";
@@ -6805,9 +7088,9 @@ function checkDirConflict(result, label2, dir) {
6805
7088
 
6806
7089
  // src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
6807
7090
  import fs21 from "fs";
6808
- import path35 from "path";
7091
+ import path37 from "path";
6809
7092
  function collectEntry(results, dir, entry) {
6810
- const full = path35.join(dir, entry.name);
7093
+ const full = path37.join(dir, entry.name);
6811
7094
  const items = entry.isDirectory() ? listFilesRecursive(full) : [full];
6812
7095
  results.push(...items);
6813
7096
  }
@@ -6821,15 +7104,15 @@ function listFilesRecursive(dir) {
6821
7104
  }
6822
7105
  function addDirectoryFileMoves(moves, childDir, newLocation, reason) {
6823
7106
  for (const file of listFilesRecursive(childDir)) {
6824
- const rel = path35.relative(childDir, file);
6825
- moves.push({ from: file, to: path35.join(newLocation, rel), reason });
7107
+ const rel = path37.relative(childDir, file);
7108
+ moves.push({ from: file, to: path37.join(newLocation, rel), reason });
6826
7109
  }
6827
7110
  }
6828
7111
  function resolveChildDest(parentDir, childDir) {
6829
- return path35.join(parentDir, path35.basename(childDir));
7112
+ return path37.join(parentDir, path37.basename(childDir));
6830
7113
  }
6831
7114
  function childMoveReason(parentDir) {
6832
- return `Directory only imported from ${path35.basename(parentDir)}/`;
7115
+ return `Directory only imported from ${path37.basename(parentDir)}/`;
6833
7116
  }
6834
7117
  function registerDirectoryMove(result, childDir, dest, parentDir) {
6835
7118
  result.directories.push(dest);
@@ -6854,7 +7137,7 @@ function planDirectoryMoves(clusters) {
6854
7137
 
6855
7138
  // src/commands/refactor/restructure/planFileMoves/index.ts
6856
7139
  function childMoveData(child, newDir, parentBase) {
6857
- const to = path36.join(newDir, path36.basename(child));
7140
+ const to = path38.join(newDir, path38.basename(child));
6858
7141
  return { from: child, to, reason: `Only imported by ${parentBase}` };
6859
7142
  }
6860
7143
  function addChildMoves(moves, children, newDir, parentBase) {
@@ -6862,15 +7145,15 @@ function addChildMoves(moves, children, newDir, parentBase) {
6862
7145
  moves.push(childMoveData(child, newDir, parentBase));
6863
7146
  }
6864
7147
  function getBaseName(filePath) {
6865
- return path36.basename(filePath, path36.extname(filePath));
7148
+ return path38.basename(filePath, path38.extname(filePath));
6866
7149
  }
6867
7150
  function resolveClusterDir(parent) {
6868
- return path36.join(path36.dirname(parent), getBaseName(parent));
7151
+ return path38.join(path38.dirname(parent), getBaseName(parent));
6869
7152
  }
6870
7153
  function createParentMove(parent, newDir) {
6871
7154
  return {
6872
7155
  from: parent,
6873
- to: path36.join(newDir, `index${path36.extname(parent)}`),
7156
+ to: path38.join(newDir, `index${path38.extname(parent)}`),
6874
7157
  reason: `Main module of new ${getBaseName(parent)}/ directory`
6875
7158
  };
6876
7159
  }
@@ -6894,7 +7177,7 @@ function planFileMoves(clusters) {
6894
7177
 
6895
7178
  // src/commands/refactor/restructure/index.ts
6896
7179
  function buildPlan(candidateFiles, tsConfigPath) {
6897
- const candidates = new Set(candidateFiles.map((f) => path37.resolve(f)));
7180
+ const candidates = new Set(candidateFiles.map((f) => path39.resolve(f)));
6898
7181
  const graph = buildImportGraph(candidates, tsConfigPath);
6899
7182
  const allProjectFiles = /* @__PURE__ */ new Set([
6900
7183
  ...graph.importedBy.keys(),
@@ -6914,22 +7197,22 @@ async function restructure(pattern2, options2 = {}) {
6914
7197
  const targetPattern = pattern2 ?? "src";
6915
7198
  const files = findSourceFiles2(targetPattern);
6916
7199
  if (files.length === 0) {
6917
- console.log(chalk75.yellow("No files found matching pattern"));
7200
+ console.log(chalk80.yellow("No files found matching pattern"));
6918
7201
  return;
6919
7202
  }
6920
- const tsConfigPath = path37.resolve("tsconfig.json");
7203
+ const tsConfigPath = path39.resolve("tsconfig.json");
6921
7204
  const plan = buildPlan(files, tsConfigPath);
6922
7205
  if (plan.moves.length === 0) {
6923
- console.log(chalk75.green("No restructuring needed"));
7206
+ console.log(chalk80.green("No restructuring needed"));
6924
7207
  return;
6925
7208
  }
6926
7209
  displayPlan(plan);
6927
7210
  if (options2.apply) {
6928
- console.log(chalk75.bold("\nApplying changes..."));
7211
+ console.log(chalk80.bold("\nApplying changes..."));
6929
7212
  executePlan(plan);
6930
- console.log(chalk75.green("\nRestructuring complete"));
7213
+ console.log(chalk80.green("\nRestructuring complete"));
6931
7214
  } else {
6932
- console.log(chalk75.dim("\nDry run. Use --apply to execute."));
7215
+ console.log(chalk80.dim("\nDry run. Use --apply to execute."));
6933
7216
  }
6934
7217
  }
6935
7218
 
@@ -6957,8 +7240,8 @@ function registerRefactor(program2) {
6957
7240
  }
6958
7241
 
6959
7242
  // src/commands/transcript/shared.ts
6960
- import { existsSync as existsSync25, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
6961
- import { basename as basename4, join as join22, relative } from "path";
7243
+ import { existsSync as existsSync27, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
7244
+ import { basename as basename4, join as join24, relative } from "path";
6962
7245
  import * as readline2 from "readline";
6963
7246
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
6964
7247
  function getDatePrefix(daysOffset = 0) {
@@ -6973,10 +7256,10 @@ function isValidDatePrefix(filename) {
6973
7256
  return DATE_PREFIX_REGEX.test(filename);
6974
7257
  }
6975
7258
  function collectFiles(dir, extension) {
6976
- if (!existsSync25(dir)) return [];
7259
+ if (!existsSync27(dir)) return [];
6977
7260
  const results = [];
6978
- for (const entry of readdirSync3(dir)) {
6979
- const fullPath = join22(dir, entry);
7261
+ for (const entry of readdirSync5(dir)) {
7262
+ const fullPath = join24(dir, entry);
6980
7263
  if (statSync2(fullPath).isDirectory()) {
6981
7264
  results.push(...collectFiles(fullPath, extension));
6982
7265
  } else if (entry.endsWith(extension)) {
@@ -7070,14 +7353,14 @@ async function configure() {
7070
7353
  }
7071
7354
 
7072
7355
  // src/commands/transcript/format/index.ts
7073
- import { existsSync as existsSync27 } from "fs";
7356
+ import { existsSync as existsSync29 } from "fs";
7074
7357
 
7075
7358
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
7076
- import { dirname as dirname17, join as join24 } from "path";
7359
+ import { dirname as dirname18, join as join26 } from "path";
7077
7360
 
7078
7361
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
7079
7362
  import { renameSync } from "fs";
7080
- import { join as join23 } from "path";
7363
+ import { join as join25 } from "path";
7081
7364
  async function resolveDate(rl, choice) {
7082
7365
  if (choice === "1") return getDatePrefix(0);
7083
7366
  if (choice === "2") return getDatePrefix(-1);
@@ -7092,7 +7375,7 @@ async function resolveDate(rl, choice) {
7092
7375
  }
7093
7376
  function renameWithPrefix(vttDir, vttFile, prefix2) {
7094
7377
  const newFilename = `${prefix2}.${vttFile}`;
7095
- renameSync(join23(vttDir, vttFile), join23(vttDir, newFilename));
7378
+ renameSync(join25(vttDir, vttFile), join25(vttDir, newFilename));
7096
7379
  console.log(`Renamed to: ${newFilename}`);
7097
7380
  return newFilename;
7098
7381
  }
@@ -7123,15 +7406,15 @@ async function fixInvalidDatePrefixes(vttFiles) {
7123
7406
  for (let i = 0; i < vttFiles.length; i++) {
7124
7407
  const vttFile = vttFiles[i];
7125
7408
  if (!isValidDatePrefix(vttFile.filename)) {
7126
- const vttFileDir = dirname17(vttFile.absolutePath);
7409
+ const vttFileDir = dirname18(vttFile.absolutePath);
7127
7410
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
7128
7411
  if (newFilename) {
7129
- const newRelativePath = join24(
7130
- dirname17(vttFile.relativePath),
7412
+ const newRelativePath = join26(
7413
+ dirname18(vttFile.relativePath),
7131
7414
  newFilename
7132
7415
  );
7133
7416
  vttFiles[i] = {
7134
- absolutePath: join24(vttFileDir, newFilename),
7417
+ absolutePath: join26(vttFileDir, newFilename),
7135
7418
  relativePath: newRelativePath,
7136
7419
  filename: newFilename
7137
7420
  };
@@ -7144,8 +7427,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
7144
7427
  }
7145
7428
 
7146
7429
  // src/commands/transcript/format/processVttFile/index.ts
7147
- import { existsSync as existsSync26, mkdirSync as mkdirSync7, readFileSync as readFileSync22, writeFileSync as writeFileSync22 } from "fs";
7148
- import { basename as basename5, dirname as dirname18, join as join25 } from "path";
7430
+ import { existsSync as existsSync28, mkdirSync as mkdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync22 } from "fs";
7431
+ import { basename as basename5, dirname as dirname19, join as join27 } from "path";
7149
7432
 
7150
7433
  // src/commands/transcript/cleanText.ts
7151
7434
  function cleanText(text) {
@@ -7355,21 +7638,21 @@ function toMdFilename(vttFilename) {
7355
7638
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
7356
7639
  }
7357
7640
  function resolveOutputDir(relativeDir, transcriptsDir) {
7358
- return relativeDir === "." ? transcriptsDir : join25(transcriptsDir, relativeDir);
7641
+ return relativeDir === "." ? transcriptsDir : join27(transcriptsDir, relativeDir);
7359
7642
  }
7360
7643
  function buildOutputPaths(vttFile, transcriptsDir) {
7361
7644
  const mdFile = toMdFilename(vttFile.filename);
7362
- const relativeDir = dirname18(vttFile.relativePath);
7645
+ const relativeDir = dirname19(vttFile.relativePath);
7363
7646
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
7364
- const outputPath = join25(outputDir, mdFile);
7647
+ const outputPath = join27(outputDir, mdFile);
7365
7648
  return { outputDir, outputPath, mdFile, relativeDir };
7366
7649
  }
7367
7650
  function logSkipped(relativeDir, mdFile) {
7368
- console.log(`Skipping (already exists): ${join25(relativeDir, mdFile)}`);
7651
+ console.log(`Skipping (already exists): ${join27(relativeDir, mdFile)}`);
7369
7652
  return "skipped";
7370
7653
  }
7371
7654
  function ensureDirectory(dir, label2) {
7372
- if (!existsSync26(dir)) {
7655
+ if (!existsSync28(dir)) {
7373
7656
  mkdirSync7(dir, { recursive: true });
7374
7657
  console.log(`Created ${label2}: ${dir}`);
7375
7658
  }
@@ -7392,7 +7675,7 @@ function logReduction(cueCount, messageCount) {
7392
7675
  }
7393
7676
  function readAndParseCues(inputPath) {
7394
7677
  console.log(`Reading: ${inputPath}`);
7395
- return processCues(readFileSync22(inputPath, "utf-8"));
7678
+ return processCues(readFileSync23(inputPath, "utf-8"));
7396
7679
  }
7397
7680
  function writeFormatted(outputPath, content) {
7398
7681
  writeFileSync22(outputPath, content, "utf-8");
@@ -7405,7 +7688,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
7405
7688
  logReduction(cues.length, chatMessages.length);
7406
7689
  }
7407
7690
  function tryProcessVtt(vttFile, paths) {
7408
- if (existsSync26(paths.outputPath))
7691
+ if (existsSync28(paths.outputPath))
7409
7692
  return logSkipped(paths.relativeDir, paths.mdFile);
7410
7693
  convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
7411
7694
  return "processed";
@@ -7431,7 +7714,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
7431
7714
  logSummary(counts);
7432
7715
  }
7433
7716
  function requireVttDir(vttDir) {
7434
- if (!existsSync27(vttDir)) {
7717
+ if (!existsSync29(vttDir)) {
7435
7718
  console.error(`VTT directory not found: ${vttDir}`);
7436
7719
  process.exit(1);
7437
7720
  }
@@ -7463,28 +7746,28 @@ async function format() {
7463
7746
  }
7464
7747
 
7465
7748
  // src/commands/transcript/summarise/index.ts
7466
- import { existsSync as existsSync29 } from "fs";
7467
- import { basename as basename6, dirname as dirname20, join as join27, relative as relative2 } from "path";
7749
+ import { existsSync as existsSync31 } from "fs";
7750
+ import { basename as basename6, dirname as dirname21, join as join29, relative as relative2 } from "path";
7468
7751
 
7469
7752
  // src/commands/transcript/summarise/processStagedFile/index.ts
7470
7753
  import {
7471
- existsSync as existsSync28,
7754
+ existsSync as existsSync30,
7472
7755
  mkdirSync as mkdirSync8,
7473
- readFileSync as readFileSync23,
7756
+ readFileSync as readFileSync24,
7474
7757
  renameSync as renameSync2,
7475
7758
  rmSync
7476
7759
  } from "fs";
7477
- import { dirname as dirname19, join as join26 } from "path";
7760
+ import { dirname as dirname20, join as join28 } from "path";
7478
7761
 
7479
7762
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
7480
- import chalk76 from "chalk";
7763
+ import chalk81 from "chalk";
7481
7764
  var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
7482
7765
  function validateStagedContent(filename, content) {
7483
7766
  const firstLine = content.split("\n")[0];
7484
7767
  const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
7485
7768
  if (!match) {
7486
7769
  console.error(
7487
- chalk76.red(
7770
+ chalk81.red(
7488
7771
  `Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
7489
7772
  )
7490
7773
  );
@@ -7493,7 +7776,7 @@ function validateStagedContent(filename, content) {
7493
7776
  const contentAfterLink = content.slice(firstLine.length).trim();
7494
7777
  if (!contentAfterLink) {
7495
7778
  console.error(
7496
- chalk76.red(
7779
+ chalk81.red(
7497
7780
  `Staged file ${filename} has no summary content after the transcript link.`
7498
7781
  )
7499
7782
  );
@@ -7503,9 +7786,9 @@ function validateStagedContent(filename, content) {
7503
7786
  }
7504
7787
 
7505
7788
  // src/commands/transcript/summarise/processStagedFile/index.ts
7506
- var STAGING_DIR = join26(process.cwd(), ".assist", "transcript");
7789
+ var STAGING_DIR = join28(process.cwd(), ".assist", "transcript");
7507
7790
  function processStagedFile() {
7508
- if (!existsSync28(STAGING_DIR)) {
7791
+ if (!existsSync30(STAGING_DIR)) {
7509
7792
  return false;
7510
7793
  }
7511
7794
  const stagedFiles = findMdFilesRecursive(STAGING_DIR);
@@ -7514,7 +7797,7 @@ function processStagedFile() {
7514
7797
  }
7515
7798
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
7516
7799
  const stagedFile = stagedFiles[0];
7517
- const content = readFileSync23(stagedFile.absolutePath, "utf-8");
7800
+ const content = readFileSync24(stagedFile.absolutePath, "utf-8");
7518
7801
  validateStagedContent(stagedFile.filename, content);
7519
7802
  const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
7520
7803
  const transcriptFiles = findMdFilesRecursive(transcriptsDir);
@@ -7527,9 +7810,9 @@ function processStagedFile() {
7527
7810
  );
7528
7811
  process.exit(1);
7529
7812
  }
7530
- const destPath = join26(summaryDir, matchingTranscript.relativePath);
7531
- const destDir = dirname19(destPath);
7532
- if (!existsSync28(destDir)) {
7813
+ const destPath = join28(summaryDir, matchingTranscript.relativePath);
7814
+ const destDir = dirname20(destPath);
7815
+ if (!existsSync30(destDir)) {
7533
7816
  mkdirSync8(destDir, { recursive: true });
7534
7817
  }
7535
7818
  renameSync2(stagedFile.absolutePath, destPath);
@@ -7542,8 +7825,8 @@ function processStagedFile() {
7542
7825
 
7543
7826
  // src/commands/transcript/summarise/index.ts
7544
7827
  function buildRelativeKey(relativePath, baseName) {
7545
- const relDir = dirname20(relativePath);
7546
- return relDir === "." ? baseName : join27(relDir, baseName);
7828
+ const relDir = dirname21(relativePath);
7829
+ return relDir === "." ? baseName : join29(relDir, baseName);
7547
7830
  }
7548
7831
  function buildSummaryIndex(summaryDir) {
7549
7832
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -7556,7 +7839,7 @@ function buildSummaryIndex(summaryDir) {
7556
7839
  function summarise2() {
7557
7840
  processStagedFile();
7558
7841
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
7559
- if (!existsSync29(transcriptsDir)) {
7842
+ if (!existsSync31(transcriptsDir)) {
7560
7843
  console.log("No transcripts directory found.");
7561
7844
  return;
7562
7845
  }
@@ -7577,8 +7860,8 @@ function summarise2() {
7577
7860
  }
7578
7861
  const next2 = missing[0];
7579
7862
  const outputFilename = `${getTranscriptBaseName(next2.filename)}.md`;
7580
- const outputPath = join27(STAGING_DIR, outputFilename);
7581
- const summaryFileDir = join27(summaryDir, dirname20(next2.relativePath));
7863
+ const outputPath = join29(STAGING_DIR, outputFilename);
7864
+ const summaryFileDir = join29(summaryDir, dirname21(next2.relativePath));
7582
7865
  const relativeTranscriptPath = encodeURI(
7583
7866
  relative2(summaryFileDir, next2.absolutePath).replace(/\\/g, "/")
7584
7867
  );
@@ -7624,50 +7907,50 @@ function registerVerify(program2) {
7624
7907
 
7625
7908
  // src/commands/voice/devices.ts
7626
7909
  import { spawnSync as spawnSync3 } from "child_process";
7627
- import { join as join29 } from "path";
7910
+ import { join as join31 } from "path";
7628
7911
 
7629
7912
  // src/commands/voice/shared.ts
7630
7913
  import { homedir as homedir7 } from "os";
7631
- import { dirname as dirname21, join as join28 } from "path";
7914
+ import { dirname as dirname22, join as join30 } from "path";
7632
7915
  import { fileURLToPath as fileURLToPath6 } from "url";
7633
- var __dirname6 = dirname21(fileURLToPath6(import.meta.url));
7634
- var VOICE_DIR = join28(homedir7(), ".assist", "voice");
7916
+ var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
7917
+ var VOICE_DIR = join30(homedir7(), ".assist", "voice");
7635
7918
  var voicePaths = {
7636
7919
  dir: VOICE_DIR,
7637
- pid: join28(VOICE_DIR, "voice.pid"),
7638
- log: join28(VOICE_DIR, "voice.log"),
7639
- venv: join28(VOICE_DIR, ".venv"),
7640
- lock: join28(VOICE_DIR, "voice.lock")
7920
+ pid: join30(VOICE_DIR, "voice.pid"),
7921
+ log: join30(VOICE_DIR, "voice.log"),
7922
+ venv: join30(VOICE_DIR, ".venv"),
7923
+ lock: join30(VOICE_DIR, "voice.lock")
7641
7924
  };
7642
7925
  function getPythonDir() {
7643
- return join28(__dirname6, "commands", "voice", "python");
7926
+ return join30(__dirname6, "commands", "voice", "python");
7644
7927
  }
7645
7928
  function getVenvPython() {
7646
- return process.platform === "win32" ? join28(voicePaths.venv, "Scripts", "python.exe") : join28(voicePaths.venv, "bin", "python");
7929
+ return process.platform === "win32" ? join30(voicePaths.venv, "Scripts", "python.exe") : join30(voicePaths.venv, "bin", "python");
7647
7930
  }
7648
7931
  function getLockDir() {
7649
7932
  const config = loadConfig();
7650
7933
  return config.voice?.lockDir ?? VOICE_DIR;
7651
7934
  }
7652
7935
  function getLockFile() {
7653
- return join28(getLockDir(), "voice.lock");
7936
+ return join30(getLockDir(), "voice.lock");
7654
7937
  }
7655
7938
 
7656
7939
  // src/commands/voice/devices.ts
7657
7940
  function devices() {
7658
- const script = join29(getPythonDir(), "list_devices.py");
7941
+ const script = join31(getPythonDir(), "list_devices.py");
7659
7942
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
7660
7943
  }
7661
7944
 
7662
7945
  // src/commands/voice/logs.ts
7663
- import { existsSync as existsSync30, readFileSync as readFileSync24 } from "fs";
7946
+ import { existsSync as existsSync32, readFileSync as readFileSync25 } from "fs";
7664
7947
  function logs(options2) {
7665
- if (!existsSync30(voicePaths.log)) {
7948
+ if (!existsSync32(voicePaths.log)) {
7666
7949
  console.log("No voice log file found");
7667
7950
  return;
7668
7951
  }
7669
7952
  const count = Number.parseInt(options2.lines ?? "150", 10);
7670
- const content = readFileSync24(voicePaths.log, "utf-8").trim();
7953
+ const content = readFileSync25(voicePaths.log, "utf-8").trim();
7671
7954
  if (!content) {
7672
7955
  console.log("Voice log is empty");
7673
7956
  return;
@@ -7690,12 +7973,12 @@ function logs(options2) {
7690
7973
  // src/commands/voice/setup.ts
7691
7974
  import { spawnSync as spawnSync4 } from "child_process";
7692
7975
  import { mkdirSync as mkdirSync10 } from "fs";
7693
- import { join as join31 } from "path";
7976
+ import { join as join33 } from "path";
7694
7977
 
7695
7978
  // src/commands/voice/checkLockFile.ts
7696
- import { execSync as execSync32 } from "child_process";
7697
- import { existsSync as existsSync31, mkdirSync as mkdirSync9, readFileSync as readFileSync25, writeFileSync as writeFileSync23 } from "fs";
7698
- import { join as join30 } from "path";
7979
+ import { execSync as execSync34 } from "child_process";
7980
+ import { existsSync as existsSync33, mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync23 } from "fs";
7981
+ import { join as join32 } from "path";
7699
7982
  function isProcessAlive(pid) {
7700
7983
  try {
7701
7984
  process.kill(pid, 0);
@@ -7706,9 +7989,9 @@ function isProcessAlive(pid) {
7706
7989
  }
7707
7990
  function checkLockFile() {
7708
7991
  const lockFile = getLockFile();
7709
- if (!existsSync31(lockFile)) return;
7992
+ if (!existsSync33(lockFile)) return;
7710
7993
  try {
7711
- const lock = JSON.parse(readFileSync25(lockFile, "utf-8"));
7994
+ const lock = JSON.parse(readFileSync26(lockFile, "utf-8"));
7712
7995
  if (lock.pid && isProcessAlive(lock.pid)) {
7713
7996
  console.error(
7714
7997
  `Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
@@ -7719,10 +8002,10 @@ function checkLockFile() {
7719
8002
  }
7720
8003
  }
7721
8004
  function bootstrapVenv() {
7722
- if (existsSync31(getVenvPython())) return;
8005
+ if (existsSync33(getVenvPython())) return;
7723
8006
  console.log("Setting up Python environment...");
7724
8007
  const pythonDir = getPythonDir();
7725
- execSync32(
8008
+ execSync34(
7726
8009
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
7727
8010
  {
7728
8011
  stdio: "inherit",
@@ -7732,7 +8015,7 @@ function bootstrapVenv() {
7732
8015
  }
7733
8016
  function writeLockFile(pid) {
7734
8017
  const lockFile = getLockFile();
7735
- mkdirSync9(join30(lockFile, ".."), { recursive: true });
8018
+ mkdirSync9(join32(lockFile, ".."), { recursive: true });
7736
8019
  writeFileSync23(
7737
8020
  lockFile,
7738
8021
  JSON.stringify({
@@ -7748,7 +8031,7 @@ function setup() {
7748
8031
  mkdirSync10(voicePaths.dir, { recursive: true });
7749
8032
  bootstrapVenv();
7750
8033
  console.log("\nDownloading models...\n");
7751
- const script = join31(getPythonDir(), "setup_models.py");
8034
+ const script = join33(getPythonDir(), "setup_models.py");
7752
8035
  const result = spawnSync4(getVenvPython(), [script], {
7753
8036
  stdio: "inherit",
7754
8037
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -7762,7 +8045,7 @@ function setup() {
7762
8045
  // src/commands/voice/start.ts
7763
8046
  import { spawn as spawn4 } from "child_process";
7764
8047
  import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync24 } from "fs";
7765
- import { join as join32 } from "path";
8048
+ import { join as join34 } from "path";
7766
8049
 
7767
8050
  // src/commands/voice/buildDaemonEnv.ts
7768
8051
  function buildDaemonEnv(options2) {
@@ -7800,7 +8083,7 @@ function start2(options2) {
7800
8083
  bootstrapVenv();
7801
8084
  const debug = options2.debug || options2.foreground || process.platform === "win32";
7802
8085
  const env = buildDaemonEnv({ debug });
7803
- const script = join32(getPythonDir(), "voice_daemon.py");
8086
+ const script = join34(getPythonDir(), "voice_daemon.py");
7804
8087
  const python = getVenvPython();
7805
8088
  if (options2.foreground) {
7806
8089
  spawnForeground(python, script, env);
@@ -7810,7 +8093,7 @@ function start2(options2) {
7810
8093
  }
7811
8094
 
7812
8095
  // src/commands/voice/status.ts
7813
- import { existsSync as existsSync32, readFileSync as readFileSync26 } from "fs";
8096
+ import { existsSync as existsSync34, readFileSync as readFileSync27 } from "fs";
7814
8097
  function isProcessAlive2(pid) {
7815
8098
  try {
7816
8099
  process.kill(pid, 0);
@@ -7820,16 +8103,16 @@ function isProcessAlive2(pid) {
7820
8103
  }
7821
8104
  }
7822
8105
  function readRecentLogs(count) {
7823
- if (!existsSync32(voicePaths.log)) return [];
7824
- const lines = readFileSync26(voicePaths.log, "utf-8").trim().split("\n");
8106
+ if (!existsSync34(voicePaths.log)) return [];
8107
+ const lines = readFileSync27(voicePaths.log, "utf-8").trim().split("\n");
7825
8108
  return lines.slice(-count);
7826
8109
  }
7827
8110
  function status() {
7828
- if (!existsSync32(voicePaths.pid)) {
8111
+ if (!existsSync34(voicePaths.pid)) {
7829
8112
  console.log("Voice daemon: not running (no PID file)");
7830
8113
  return;
7831
8114
  }
7832
- const pid = Number.parseInt(readFileSync26(voicePaths.pid, "utf-8").trim(), 10);
8115
+ const pid = Number.parseInt(readFileSync27(voicePaths.pid, "utf-8").trim(), 10);
7833
8116
  const alive = isProcessAlive2(pid);
7834
8117
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
7835
8118
  const recent = readRecentLogs(5);
@@ -7848,13 +8131,13 @@ function status() {
7848
8131
  }
7849
8132
 
7850
8133
  // src/commands/voice/stop.ts
7851
- import { existsSync as existsSync33, readFileSync as readFileSync27, unlinkSync as unlinkSync7 } from "fs";
8134
+ import { existsSync as existsSync35, readFileSync as readFileSync28, unlinkSync as unlinkSync8 } from "fs";
7852
8135
  function stop() {
7853
- if (!existsSync33(voicePaths.pid)) {
8136
+ if (!existsSync35(voicePaths.pid)) {
7854
8137
  console.log("Voice daemon is not running (no PID file)");
7855
8138
  return;
7856
8139
  }
7857
- const pid = Number.parseInt(readFileSync27(voicePaths.pid, "utf-8").trim(), 10);
8140
+ const pid = Number.parseInt(readFileSync28(voicePaths.pid, "utf-8").trim(), 10);
7858
8141
  try {
7859
8142
  process.kill(pid, "SIGTERM");
7860
8143
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -7862,12 +8145,12 @@ function stop() {
7862
8145
  console.log(`Voice daemon (PID ${pid}) is not running`);
7863
8146
  }
7864
8147
  try {
7865
- unlinkSync7(voicePaths.pid);
8148
+ unlinkSync8(voicePaths.pid);
7866
8149
  } catch {
7867
8150
  }
7868
8151
  try {
7869
8152
  const lockFile = getLockFile();
7870
- if (existsSync33(lockFile)) unlinkSync7(lockFile);
8153
+ if (existsSync35(lockFile)) unlinkSync8(lockFile);
7871
8154
  } catch {
7872
8155
  }
7873
8156
  console.log("Voice daemon stopped");
@@ -7886,14 +8169,14 @@ function registerVoice(program2) {
7886
8169
 
7887
8170
  // src/commands/roam/auth.ts
7888
8171
  import { randomBytes } from "crypto";
7889
- import chalk77 from "chalk";
8172
+ import chalk82 from "chalk";
7890
8173
 
7891
8174
  // src/lib/openBrowser.ts
7892
- import { execSync as execSync33 } from "child_process";
8175
+ import { execSync as execSync35 } from "child_process";
7893
8176
  function tryExec(commands) {
7894
8177
  for (const cmd of commands) {
7895
8178
  try {
7896
- execSync33(cmd);
8179
+ execSync35(cmd);
7897
8180
  return true;
7898
8181
  } catch {
7899
8182
  }
@@ -8061,13 +8344,13 @@ async function auth() {
8061
8344
  saveGlobalConfig(config);
8062
8345
  const state = randomBytes(16).toString("hex");
8063
8346
  console.log(
8064
- chalk77.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
8347
+ chalk82.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
8065
8348
  );
8066
- console.log(chalk77.white("http://localhost:14523/callback\n"));
8067
- console.log(chalk77.blue("Opening browser for authorization..."));
8068
- console.log(chalk77.dim("Waiting for authorization callback..."));
8349
+ console.log(chalk82.white("http://localhost:14523/callback\n"));
8350
+ console.log(chalk82.blue("Opening browser for authorization..."));
8351
+ console.log(chalk82.dim("Waiting for authorization callback..."));
8069
8352
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
8070
- console.log(chalk77.dim("Exchanging code for tokens..."));
8353
+ console.log(chalk82.dim("Exchanging code for tokens..."));
8071
8354
  const tokens = await exchangeToken({
8072
8355
  code,
8073
8356
  clientId,
@@ -8083,7 +8366,7 @@ async function auth() {
8083
8366
  };
8084
8367
  saveGlobalConfig(config);
8085
8368
  console.log(
8086
- chalk77.green("Roam credentials and tokens saved to ~/.assist.yml")
8369
+ chalk82.green("Roam credentials and tokens saved to ~/.assist.yml")
8087
8370
  );
8088
8371
  }
8089
8372
 
@@ -8094,16 +8377,7 @@ function registerRoam(program2) {
8094
8377
  }
8095
8378
 
8096
8379
  // src/commands/run/index.ts
8097
- import { spawn as spawn5 } from "child_process";
8098
-
8099
- // src/shared/formatElapsed.ts
8100
- function formatElapsed(ms) {
8101
- const secs = ms / 1e3;
8102
- if (secs < 60) return `${secs.toFixed(1)}s`;
8103
- const mins = Math.floor(secs / 60);
8104
- const remainSecs = secs - mins * 60;
8105
- return `${mins}m ${remainSecs.toFixed(1)}s`;
8106
- }
8380
+ import { execSync as execSync36 } from "child_process";
8107
8381
 
8108
8382
  // src/commands/run/resolveParams.ts
8109
8383
  function resolveParams(params, cliArgs) {
@@ -8129,9 +8403,30 @@ function resolveParams(params, cliArgs) {
8129
8403
  return resolved;
8130
8404
  }
8131
8405
 
8406
+ // src/commands/run/spawnRunCommand.ts
8407
+ import { spawn as spawn5 } from "child_process";
8408
+ function spawnRunCommand(fullCommand, env) {
8409
+ const start3 = Date.now();
8410
+ const child = spawn5(fullCommand, [], {
8411
+ stdio: "inherit",
8412
+ shell: true,
8413
+ env: env ? { ...process.env, ...expandEnv(env) } : void 0
8414
+ });
8415
+ child.on("close", (code) => {
8416
+ const elapsed = formatElapsed(Date.now() - start3);
8417
+ console.log(`
8418
+ Done in ${elapsed}`);
8419
+ process.exit(code ?? 0);
8420
+ });
8421
+ child.on("error", (err) => {
8422
+ console.error(`Failed to execute command: ${err.message}`);
8423
+ process.exit(1);
8424
+ });
8425
+ }
8426
+
8132
8427
  // src/commands/run/add.ts
8133
8428
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync25 } from "fs";
8134
- import { join as join33 } from "path";
8429
+ import { join as join35 } from "path";
8135
8430
  function findAddIndex() {
8136
8431
  const addIndex = process.argv.indexOf("add");
8137
8432
  if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
@@ -8185,7 +8480,7 @@ function saveNewRunConfig(name, command, args) {
8185
8480
  saveConfig(config);
8186
8481
  }
8187
8482
  function createCommandFile(name) {
8188
- const dir = join33(".claude", "commands");
8483
+ const dir = join35(".claude", "commands");
8189
8484
  mkdirSync12(dir, { recursive: true });
8190
8485
  const content = `---
8191
8486
  description: Run ${name}
@@ -8193,7 +8488,7 @@ description: Run ${name}
8193
8488
 
8194
8489
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
8195
8490
  `;
8196
- const filePath = join33(dir, `${name}.md`);
8491
+ const filePath = join35(dir, `${name}.md`);
8197
8492
  writeFileSync25(filePath, content);
8198
8493
  console.log(`Created command file: ${filePath}`);
8199
8494
  }
@@ -8235,25 +8530,6 @@ function findRunConfig(name) {
8235
8530
  const configs = requireRunConfigs();
8236
8531
  return configs.find((r) => r.name === name) ?? exitWithConfigNotFound(name, configs);
8237
8532
  }
8238
- function onSpawnError(err) {
8239
- console.error(`Failed to execute command: ${err.message}`);
8240
- process.exit(1);
8241
- }
8242
- function spawnCommand2(fullCommand, env) {
8243
- const start3 = Date.now();
8244
- const child = spawn5(fullCommand, [], {
8245
- stdio: "inherit",
8246
- shell: true,
8247
- env: env ? { ...process.env, ...expandEnv(env) } : void 0
8248
- });
8249
- child.on("close", (code) => {
8250
- const elapsed = formatElapsed(Date.now() - start3);
8251
- console.log(`
8252
- Done in ${elapsed}`);
8253
- process.exit(code ?? 0);
8254
- });
8255
- child.on("error", onSpawnError);
8256
- }
8257
8533
  function listRunConfigs() {
8258
8534
  const configs = requireRunConfigs();
8259
8535
  for (const config of configs) {
@@ -8261,17 +8537,28 @@ function listRunConfigs() {
8261
8537
  console.log(`${config.name}: ${config.command}${args}`);
8262
8538
  }
8263
8539
  }
8540
+ function runPreCommands(pre) {
8541
+ for (const cmd of pre) {
8542
+ try {
8543
+ execSync36(cmd, { stdio: "inherit" });
8544
+ } catch (err) {
8545
+ const code = err && typeof err === "object" && "status" in err ? err.status : 1;
8546
+ process.exit(code);
8547
+ }
8548
+ }
8549
+ }
8264
8550
  function run2(name, args) {
8265
8551
  const runConfig = findRunConfig(name);
8552
+ if (runConfig.pre) runPreCommands(runConfig.pre);
8266
8553
  const resolved = resolveParams(runConfig.params, args);
8267
- spawnCommand2(
8554
+ spawnRunCommand(
8268
8555
  buildCommand(runConfig.command, runConfig.args ?? [], resolved),
8269
8556
  runConfig.env
8270
8557
  );
8271
8558
  }
8272
8559
 
8273
8560
  // src/commands/statusLine.ts
8274
- import chalk78 from "chalk";
8561
+ import chalk83 from "chalk";
8275
8562
  function formatNumber(num) {
8276
8563
  return num.toLocaleString("en-US");
8277
8564
  }
@@ -8286,8 +8573,8 @@ function formatTimeLeft(resetsAt) {
8286
8573
  }
8287
8574
  function colorizePercent(pct) {
8288
8575
  const label2 = `${Math.round(pct)}%`;
8289
- if (pct > 80) return chalk78.red(label2);
8290
- if (pct > 40) return chalk78.yellow(label2);
8576
+ if (pct > 80) return chalk83.red(label2);
8577
+ if (pct > 40) return chalk83.yellow(label2);
8291
8578
  return label2;
8292
8579
  }
8293
8580
  function formatLimit(limit, fallbackLabel) {
@@ -8322,27 +8609,27 @@ async function statusLine() {
8322
8609
  // src/commands/sync.ts
8323
8610
  import * as fs24 from "fs";
8324
8611
  import * as os from "os";
8325
- import * as path40 from "path";
8612
+ import * as path42 from "path";
8326
8613
  import { fileURLToPath as fileURLToPath7 } from "url";
8327
8614
 
8328
8615
  // src/commands/sync/syncClaudeMd.ts
8329
8616
  import * as fs22 from "fs";
8330
- import * as path38 from "path";
8331
- import chalk79 from "chalk";
8617
+ import * as path40 from "path";
8618
+ import chalk84 from "chalk";
8332
8619
  async function syncClaudeMd(claudeDir, targetBase) {
8333
- const source = path38.join(claudeDir, "CLAUDE.md");
8334
- const target = path38.join(targetBase, "CLAUDE.md");
8620
+ const source = path40.join(claudeDir, "CLAUDE.md");
8621
+ const target = path40.join(targetBase, "CLAUDE.md");
8335
8622
  const sourceContent = fs22.readFileSync(source, "utf-8");
8336
8623
  if (fs22.existsSync(target)) {
8337
8624
  const targetContent = fs22.readFileSync(target, "utf-8");
8338
8625
  if (sourceContent !== targetContent) {
8339
8626
  console.log(
8340
- chalk79.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
8627
+ chalk84.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
8341
8628
  );
8342
8629
  console.log();
8343
8630
  printDiff(targetContent, sourceContent);
8344
8631
  const confirm = await promptConfirm(
8345
- chalk79.red("Overwrite existing CLAUDE.md?"),
8632
+ chalk84.red("Overwrite existing CLAUDE.md?"),
8346
8633
  false
8347
8634
  );
8348
8635
  if (!confirm) {
@@ -8357,11 +8644,11 @@ async function syncClaudeMd(claudeDir, targetBase) {
8357
8644
 
8358
8645
  // src/commands/sync/syncSettings.ts
8359
8646
  import * as fs23 from "fs";
8360
- import * as path39 from "path";
8361
- import chalk80 from "chalk";
8647
+ import * as path41 from "path";
8648
+ import chalk85 from "chalk";
8362
8649
  async function syncSettings(claudeDir, targetBase, options2) {
8363
- const source = path39.join(claudeDir, "settings.json");
8364
- const target = path39.join(targetBase, "settings.json");
8650
+ const source = path41.join(claudeDir, "settings.json");
8651
+ const target = path41.join(targetBase, "settings.json");
8365
8652
  const sourceContent = fs23.readFileSync(source, "utf-8");
8366
8653
  const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
8367
8654
  if (fs23.existsSync(target)) {
@@ -8374,14 +8661,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
8374
8661
  if (mergedContent !== normalizedTarget) {
8375
8662
  if (!options2?.yes) {
8376
8663
  console.log(
8377
- chalk80.yellow(
8664
+ chalk85.yellow(
8378
8665
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
8379
8666
  )
8380
8667
  );
8381
8668
  console.log();
8382
8669
  printDiff(targetContent, mergedContent);
8383
8670
  const confirm = await promptConfirm(
8384
- chalk80.red("Overwrite existing settings.json?"),
8671
+ chalk85.red("Overwrite existing settings.json?"),
8385
8672
  false
8386
8673
  );
8387
8674
  if (!confirm) {
@@ -8397,37 +8684,37 @@ async function syncSettings(claudeDir, targetBase, options2) {
8397
8684
 
8398
8685
  // src/commands/sync.ts
8399
8686
  var __filename4 = fileURLToPath7(import.meta.url);
8400
- var __dirname7 = path40.dirname(__filename4);
8687
+ var __dirname7 = path42.dirname(__filename4);
8401
8688
  async function sync(options2) {
8402
- const claudeDir = path40.join(__dirname7, "..", "claude");
8403
- const targetBase = path40.join(os.homedir(), ".claude");
8689
+ const claudeDir = path42.join(__dirname7, "..", "claude");
8690
+ const targetBase = path42.join(os.homedir(), ".claude");
8404
8691
  syncCommands(claudeDir, targetBase);
8405
8692
  await syncSettings(claudeDir, targetBase, { yes: options2?.yes });
8406
8693
  await syncClaudeMd(claudeDir, targetBase);
8407
8694
  }
8408
8695
  function syncCommands(claudeDir, targetBase) {
8409
- const sourceDir = path40.join(claudeDir, "commands");
8410
- const targetDir = path40.join(targetBase, "commands");
8696
+ const sourceDir = path42.join(claudeDir, "commands");
8697
+ const targetDir = path42.join(targetBase, "commands");
8411
8698
  fs24.mkdirSync(targetDir, { recursive: true });
8412
8699
  const files = fs24.readdirSync(sourceDir);
8413
8700
  for (const file of files) {
8414
- fs24.copyFileSync(path40.join(sourceDir, file), path40.join(targetDir, file));
8701
+ fs24.copyFileSync(path42.join(sourceDir, file), path42.join(targetDir, file));
8415
8702
  console.log(`Copied ${file} to ${targetDir}`);
8416
8703
  }
8417
8704
  console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
8418
8705
  }
8419
8706
 
8420
8707
  // src/commands/update.ts
8421
- import { execSync as execSync34 } from "child_process";
8422
- import * as path41 from "path";
8708
+ import { execSync as execSync37 } from "child_process";
8709
+ import * as path43 from "path";
8423
8710
  function isGlobalNpmInstall(dir) {
8424
8711
  try {
8425
- const resolved = path41.resolve(dir);
8426
- if (resolved.split(path41.sep).includes("node_modules")) {
8712
+ const resolved = path43.resolve(dir);
8713
+ if (resolved.split(path43.sep).includes("node_modules")) {
8427
8714
  return true;
8428
8715
  }
8429
- const globalPrefix = execSync34("npm prefix -g", { stdio: "pipe" }).toString().trim();
8430
- return resolved.toLowerCase().startsWith(path41.resolve(globalPrefix).toLowerCase());
8716
+ const globalPrefix = execSync37("npm prefix -g", { stdio: "pipe" }).toString().trim();
8717
+ return resolved.toLowerCase().startsWith(path43.resolve(globalPrefix).toLowerCase());
8431
8718
  } catch {
8432
8719
  return false;
8433
8720
  }
@@ -8437,18 +8724,18 @@ async function update() {
8437
8724
  console.log(`Assist is installed at: ${installDir}`);
8438
8725
  if (isGitRepo(installDir)) {
8439
8726
  console.log("Detected git repo installation, pulling latest...");
8440
- execSync34("git pull", { cwd: installDir, stdio: "inherit" });
8727
+ execSync37("git pull", { cwd: installDir, stdio: "inherit" });
8441
8728
  console.log("Installing dependencies...");
8442
- execSync34("npm i", { cwd: installDir, stdio: "inherit" });
8729
+ execSync37("npm i", { cwd: installDir, stdio: "inherit" });
8443
8730
  console.log("Building...");
8444
- execSync34("npm run build", { cwd: installDir, stdio: "inherit" });
8731
+ execSync37("npm run build", { cwd: installDir, stdio: "inherit" });
8445
8732
  console.log("Syncing commands...");
8446
- execSync34("assist sync", { stdio: "inherit" });
8733
+ execSync37("assist sync", { stdio: "inherit" });
8447
8734
  } else if (isGlobalNpmInstall(installDir)) {
8448
8735
  console.log("Detected global npm installation, updating...");
8449
- execSync34("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
8736
+ execSync37("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
8450
8737
  console.log("Syncing commands...");
8451
- execSync34("assist sync", { stdio: "inherit" });
8738
+ execSync37("assist sync", { stdio: "inherit" });
8452
8739
  } else {
8453
8740
  console.error(
8454
8741
  "Could not determine installation method. Expected a git repo or global npm install."
@@ -8495,7 +8782,7 @@ registerRefactor(program);
8495
8782
  registerDevlog(program);
8496
8783
  registerDeploy(program);
8497
8784
  registerComplexity(program);
8498
- registerNetframework(program);
8785
+ registerDotnet(program);
8499
8786
  registerNews(program);
8500
8787
  registerRavendb(program);
8501
8788
  registerTranscript(program);