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