@staff0rd/assist 0.106.0 → 0.107.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.106.0",
9
+ version: "0.107.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -143,6 +143,9 @@ var assistConfigSchema = z.strictObject({
143
143
  restructure: z.strictObject({
144
144
  ignore: z.array(z.string()).default([])
145
145
  }).optional(),
146
+ jira: z.strictObject({
147
+ acField: z.string().default("customfield_11937")
148
+ }).optional(),
146
149
  roam: z.strictObject({
147
150
  clientId: z.string(),
148
151
  clientSecret: z.string(),
@@ -2225,7 +2228,7 @@ async function add() {
2225
2228
  const type = await promptType();
2226
2229
  const name = await promptName();
2227
2230
  const description = await promptDescription();
2228
- const acceptanceCriteria = await promptAcceptanceCriteria();
2231
+ const acceptanceCriteria2 = await promptAcceptanceCriteria();
2229
2232
  const items = loadBacklog();
2230
2233
  const id = getNextId(items);
2231
2234
  items.push({
@@ -2233,7 +2236,7 @@ async function add() {
2233
2236
  type,
2234
2237
  name,
2235
2238
  description,
2236
- acceptanceCriteria,
2239
+ acceptanceCriteria: acceptanceCriteria2,
2237
2240
  status: "todo"
2238
2241
  });
2239
2242
  saveBacklog(items);
@@ -4210,12 +4213,200 @@ function registerDevlog(program2) {
4210
4213
  ).option("--all", "Show all non-archived repos regardless of push date").action(repos);
4211
4214
  }
4212
4215
 
4216
+ // src/commands/jira/acceptanceCriteria.ts
4217
+ import { execSync as execSync20 } from "child_process";
4218
+ import chalk45 from "chalk";
4219
+
4220
+ // src/commands/jira/adfToText.ts
4221
+ function renderInline(node) {
4222
+ const text = node.text ?? "";
4223
+ if (node.marks?.some((m) => m.type === "code")) return `\`${text}\``;
4224
+ return text;
4225
+ }
4226
+ function renderChildren(node, indent) {
4227
+ return renderNodes(node.content ?? [], indent);
4228
+ }
4229
+ function renderOrderedList(node, indent) {
4230
+ let counter = 0;
4231
+ return (node.content ?? []).map((item) => {
4232
+ counter++;
4233
+ return renderListItem(item, indent, `${counter}.`);
4234
+ }).join("\n");
4235
+ }
4236
+ function renderBulletList(node, indent) {
4237
+ return (node.content ?? []).map((item) => renderListItem(item, indent, "-")).join("\n");
4238
+ }
4239
+ function renderHeading(node, indent) {
4240
+ const level = node.attrs?.level ?? 1;
4241
+ return `${"#".repeat(level)} ${renderChildren(node, indent)}`;
4242
+ }
4243
+ var renderers = {
4244
+ text: (node) => renderInline(node),
4245
+ paragraph: renderChildren,
4246
+ orderedList: renderOrderedList,
4247
+ bulletList: renderBulletList,
4248
+ listItem: (node, indent) => renderListItem(node, indent, "-"),
4249
+ heading: renderHeading,
4250
+ doc: renderChildren
4251
+ };
4252
+ function renderNode(node, indent) {
4253
+ const renderer = renderers[node.type];
4254
+ if (renderer) return renderer(node, indent);
4255
+ return node.content ? renderChildren(node, indent) : "";
4256
+ }
4257
+ function renderNodes(nodes, indent) {
4258
+ return nodes.map((node) => renderNode(node, indent)).join("");
4259
+ }
4260
+ function isListNode(node) {
4261
+ return node.type === "orderedList" || node.type === "bulletList";
4262
+ }
4263
+ function renderListChild(child, indent, pad, marker, isFirst) {
4264
+ if (isListNode(child)) return renderNodes([child], indent + 1);
4265
+ if (child.type !== "paragraph") return renderNode(child, indent);
4266
+ const text = renderChildren(child, indent);
4267
+ return isFirst ? `${pad}${marker} ${text}` : `${pad} ${text}`;
4268
+ }
4269
+ function renderListItem(node, indent, marker) {
4270
+ const pad = " ".repeat(indent);
4271
+ return (node.content ?? []).map((child, i) => renderListChild(child, indent, pad, marker, i === 0)).join("\n");
4272
+ }
4273
+ function adfToText(doc) {
4274
+ return renderNodes([doc], 0);
4275
+ }
4276
+
4277
+ // src/commands/jira/acceptanceCriteria.ts
4278
+ var DEFAULT_AC_FIELD = "customfield_11937";
4279
+ function acceptanceCriteria(issueKey) {
4280
+ const config = loadConfig();
4281
+ const field = config.jira?.acField ?? DEFAULT_AC_FIELD;
4282
+ let result;
4283
+ try {
4284
+ result = execSync20(
4285
+ `acli jira workitem view ${issueKey} -f ${field} --json`,
4286
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
4287
+ );
4288
+ } catch (error) {
4289
+ if (error instanceof Error && "stderr" in error) {
4290
+ const stderr = error.stderr;
4291
+ if (stderr.includes("unauthorized")) {
4292
+ console.error(
4293
+ chalk45.red("Jira authentication expired."),
4294
+ "Run",
4295
+ chalk45.cyan("assist jira auth"),
4296
+ "to re-authenticate."
4297
+ );
4298
+ process.exit(1);
4299
+ }
4300
+ }
4301
+ console.error(chalk45.red(`Failed to fetch ${issueKey}.`));
4302
+ process.exit(1);
4303
+ }
4304
+ const parsed = JSON.parse(result);
4305
+ const acValue = parsed?.fields?.[field];
4306
+ if (!acValue) {
4307
+ console.log(chalk45.yellow(`No acceptance criteria found on ${issueKey}.`));
4308
+ return;
4309
+ }
4310
+ if (typeof acValue === "string") {
4311
+ console.log(acValue);
4312
+ return;
4313
+ }
4314
+ if (acValue.type === "doc") {
4315
+ console.log(adfToText(acValue));
4316
+ return;
4317
+ }
4318
+ console.log(JSON.stringify(acValue, null, 2));
4319
+ }
4320
+
4321
+ // src/commands/jira/jiraAuth.ts
4322
+ import { execSync as execSync21 } from "child_process";
4323
+ import Enquirer from "enquirer";
4324
+
4325
+ // src/shared/loadJson.ts
4326
+ import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
4327
+ import { homedir as homedir6 } from "os";
4328
+ import { join as join16 } from "path";
4329
+ function getStoreDir() {
4330
+ return join16(homedir6(), ".assist");
4331
+ }
4332
+ function getStorePath(filename) {
4333
+ return join16(getStoreDir(), filename);
4334
+ }
4335
+ function loadJson(filename) {
4336
+ const path35 = getStorePath(filename);
4337
+ if (existsSync20(path35)) {
4338
+ try {
4339
+ return JSON.parse(readFileSync18(path35, "utf-8"));
4340
+ } catch {
4341
+ return {};
4342
+ }
4343
+ }
4344
+ return {};
4345
+ }
4346
+ function saveJson(filename, data) {
4347
+ const dir = getStoreDir();
4348
+ if (!existsSync20(dir)) {
4349
+ mkdirSync5(dir, { recursive: true });
4350
+ }
4351
+ writeFileSync16(getStorePath(filename), JSON.stringify(data, null, 2));
4352
+ }
4353
+
4354
+ // src/commands/jira/jiraAuth.ts
4355
+ var CONFIG_FILE = "jira.json";
4356
+ async function promptCredentials(config) {
4357
+ const { Input, Password } = Enquirer;
4358
+ const site = await new Input({
4359
+ name: "site",
4360
+ message: "Jira site (e.g., mycompany.atlassian.net):",
4361
+ initial: config.site
4362
+ }).run();
4363
+ const email = await new Input({
4364
+ name: "email",
4365
+ message: "Email:",
4366
+ initial: config.email
4367
+ }).run();
4368
+ const token = await new Password({
4369
+ name: "token",
4370
+ message: "API token (https://id.atlassian.com/manage-profile/security/api-tokens):"
4371
+ }).run();
4372
+ return { site, email, token };
4373
+ }
4374
+ async function jiraAuth() {
4375
+ const config = loadJson(CONFIG_FILE);
4376
+ try {
4377
+ const { site, email, token } = await promptCredentials(config);
4378
+ if (!site || !email || !token) {
4379
+ console.error("All fields are required.");
4380
+ process.exit(1);
4381
+ }
4382
+ execSync21(`acli jira auth login --site ${site} --email "${email}" --token`, {
4383
+ encoding: "utf-8",
4384
+ input: token,
4385
+ stdio: ["pipe", "inherit", "inherit"]
4386
+ });
4387
+ saveJson(CONFIG_FILE, { site, email });
4388
+ console.log("Successfully authenticated with Jira.");
4389
+ } catch (error) {
4390
+ if (error instanceof Error) {
4391
+ console.error("Error authenticating with Jira:", error.message);
4392
+ }
4393
+ process.exit(1);
4394
+ }
4395
+ }
4396
+
4397
+ // src/commands/registerJira.ts
4398
+ function registerJira(program2) {
4399
+ const jiraCommand = program2.command("jira").description("Jira utilities");
4400
+ jiraCommand.command("auth").description("Authenticate with Jira via API token").action(() => jiraAuth());
4401
+ jiraCommand.command("ac <issue-key>").description("Print acceptance criteria for a Jira issue").action((issueKey) => acceptanceCriteria(issueKey));
4402
+ }
4403
+
4213
4404
  // src/commands/netframework/buildTree.ts
4214
- import { readFileSync as readFileSync18 } from "fs";
4405
+ import { readFileSync as readFileSync19 } from "fs";
4215
4406
  import path17 from "path";
4216
4407
  var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
4217
4408
  function getProjectRefs(csprojPath) {
4218
- const content = readFileSync18(csprojPath, "utf-8");
4409
+ const content = readFileSync19(csprojPath, "utf-8");
4219
4410
  const refs = [];
4220
4411
  for (const match of content.matchAll(PROJECT_REF_RE)) {
4221
4412
  refs.push(match[1].replace(/\\/g, "/"));
@@ -4232,7 +4423,7 @@ function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
4232
4423
  for (const ref of getProjectRefs(abs)) {
4233
4424
  const childAbs = path17.resolve(dir, ref);
4234
4425
  try {
4235
- readFileSync18(childAbs);
4426
+ readFileSync19(childAbs);
4236
4427
  node.children.push(buildTree(childAbs, repoRoot, visited));
4237
4428
  } catch {
4238
4429
  node.children.push({
@@ -4257,7 +4448,7 @@ function collectAllDeps(node) {
4257
4448
  }
4258
4449
 
4259
4450
  // src/commands/netframework/findContainingSolutions.ts
4260
- import { readdirSync as readdirSync2, readFileSync as readFileSync19, statSync } from "fs";
4451
+ import { readdirSync as readdirSync2, readFileSync as readFileSync20, statSync } from "fs";
4261
4452
  import path18 from "path";
4262
4453
  function findSlnFiles(dir, maxDepth, depth = 0) {
4263
4454
  if (depth > maxDepth) return [];
@@ -4292,7 +4483,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
4292
4483
  const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
4293
4484
  for (const sln of slnFiles) {
4294
4485
  try {
4295
- const content = readFileSync19(sln, "utf-8");
4486
+ const content = readFileSync20(sln, "utf-8");
4296
4487
  if (pattern2.test(content)) {
4297
4488
  matches.push(path18.relative(repoRoot, sln));
4298
4489
  }
@@ -4306,30 +4497,30 @@ function escapeRegex(s) {
4306
4497
  }
4307
4498
 
4308
4499
  // src/commands/netframework/printTree.ts
4309
- import chalk45 from "chalk";
4500
+ import chalk46 from "chalk";
4310
4501
  function printNodes(nodes, prefix2) {
4311
4502
  for (let i = 0; i < nodes.length; i++) {
4312
4503
  const isLast = i === nodes.length - 1;
4313
4504
  const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
4314
4505
  const childPrefix = isLast ? " " : "\u2502 ";
4315
4506
  const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
4316
- const label2 = isMissing ? chalk45.red(nodes[i].relativePath) : nodes[i].relativePath;
4507
+ const label2 = isMissing ? chalk46.red(nodes[i].relativePath) : nodes[i].relativePath;
4317
4508
  console.log(`${prefix2}${connector}${label2}`);
4318
4509
  printNodes(nodes[i].children, prefix2 + childPrefix);
4319
4510
  }
4320
4511
  }
4321
4512
  function printTree(tree, totalCount, solutions) {
4322
- console.log(chalk45.bold("\nProject Dependency Tree"));
4323
- console.log(chalk45.cyan(tree.relativePath));
4513
+ console.log(chalk46.bold("\nProject Dependency Tree"));
4514
+ console.log(chalk46.cyan(tree.relativePath));
4324
4515
  printNodes(tree.children, "");
4325
- console.log(chalk45.dim(`
4516
+ console.log(chalk46.dim(`
4326
4517
  ${totalCount} projects total (including root)`));
4327
- console.log(chalk45.bold("\nSolution Membership"));
4518
+ console.log(chalk46.bold("\nSolution Membership"));
4328
4519
  if (solutions.length === 0) {
4329
- console.log(chalk45.yellow(" Not found in any .sln"));
4520
+ console.log(chalk46.yellow(" Not found in any .sln"));
4330
4521
  } else {
4331
4522
  for (const sln of solutions) {
4332
- console.log(` ${chalk45.green(sln)}`);
4523
+ console.log(` ${chalk46.green(sln)}`);
4333
4524
  }
4334
4525
  }
4335
4526
  console.log();
@@ -4356,17 +4547,17 @@ function printJson(tree, totalCount, solutions) {
4356
4547
  }
4357
4548
 
4358
4549
  // src/commands/netframework/resolveCsproj.ts
4359
- import { existsSync as existsSync21 } from "fs";
4550
+ import { existsSync as existsSync22 } from "fs";
4360
4551
  import path20 from "path";
4361
- import chalk46 from "chalk";
4552
+ import chalk47 from "chalk";
4362
4553
 
4363
4554
  // src/commands/netframework/findRepoRoot.ts
4364
- import { existsSync as existsSync20 } from "fs";
4555
+ import { existsSync as existsSync21 } from "fs";
4365
4556
  import path19 from "path";
4366
4557
  function findRepoRoot(dir) {
4367
4558
  let current = dir;
4368
4559
  while (current !== path19.dirname(current)) {
4369
- if (existsSync20(path19.join(current, ".git"))) {
4560
+ if (existsSync21(path19.join(current, ".git"))) {
4370
4561
  return current;
4371
4562
  }
4372
4563
  current = path19.dirname(current);
@@ -4377,13 +4568,13 @@ function findRepoRoot(dir) {
4377
4568
  // src/commands/netframework/resolveCsproj.ts
4378
4569
  function resolveCsproj(csprojPath) {
4379
4570
  const resolved = path20.resolve(csprojPath);
4380
- if (!existsSync21(resolved)) {
4381
- console.error(chalk46.red(`File not found: ${resolved}`));
4571
+ if (!existsSync22(resolved)) {
4572
+ console.error(chalk47.red(`File not found: ${resolved}`));
4382
4573
  process.exit(1);
4383
4574
  }
4384
4575
  const repoRoot = findRepoRoot(path20.dirname(resolved));
4385
4576
  if (!repoRoot) {
4386
- console.error(chalk46.red("Could not find git repository root"));
4577
+ console.error(chalk47.red("Could not find git repository root"));
4387
4578
  process.exit(1);
4388
4579
  }
4389
4580
  return { resolved, repoRoot };
@@ -4403,12 +4594,12 @@ async function deps(csprojPath, options2) {
4403
4594
  }
4404
4595
 
4405
4596
  // src/commands/netframework/inSln.ts
4406
- import chalk47 from "chalk";
4597
+ import chalk48 from "chalk";
4407
4598
  async function inSln(csprojPath) {
4408
4599
  const { resolved, repoRoot } = resolveCsproj(csprojPath);
4409
4600
  const solutions = findContainingSolutions(resolved, repoRoot);
4410
4601
  if (solutions.length === 0) {
4411
- console.log(chalk47.yellow("Not found in any .sln file"));
4602
+ console.log(chalk48.yellow("Not found in any .sln file"));
4412
4603
  process.exit(1);
4413
4604
  }
4414
4605
  for (const sln of solutions) {
@@ -4425,12 +4616,12 @@ function registerNetframework(program2) {
4425
4616
 
4426
4617
  // src/commands/prs/comment.ts
4427
4618
  import { spawnSync as spawnSync2 } from "child_process";
4428
- import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync16 } from "fs";
4619
+ import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync17 } from "fs";
4429
4620
  import { tmpdir as tmpdir2 } from "os";
4430
- import { join as join16 } from "path";
4621
+ import { join as join17 } from "path";
4431
4622
 
4432
4623
  // src/commands/prs/shared.ts
4433
- import { execSync as execSync20 } from "child_process";
4624
+ import { execSync as execSync22 } from "child_process";
4434
4625
  function isGhNotInstalled(error) {
4435
4626
  if (error instanceof Error) {
4436
4627
  const msg = error.message.toLowerCase();
@@ -4446,14 +4637,14 @@ function isNotFound(error) {
4446
4637
  }
4447
4638
  function getRepoInfo() {
4448
4639
  const repoInfo = JSON.parse(
4449
- execSync20("gh repo view --json owner,name", { encoding: "utf-8" })
4640
+ execSync22("gh repo view --json owner,name", { encoding: "utf-8" })
4450
4641
  );
4451
4642
  return { org: repoInfo.owner.login, repo: repoInfo.name };
4452
4643
  }
4453
4644
  function getCurrentPrNumber() {
4454
4645
  try {
4455
4646
  const prInfo = JSON.parse(
4456
- execSync20("gh pr view --json number", { encoding: "utf-8" })
4647
+ execSync22("gh pr view --json number", { encoding: "utf-8" })
4457
4648
  );
4458
4649
  return prInfo.number;
4459
4650
  } catch (error) {
@@ -4467,7 +4658,7 @@ function getCurrentPrNumber() {
4467
4658
  function getCurrentPrNodeId() {
4468
4659
  try {
4469
4660
  const prInfo = JSON.parse(
4470
- execSync20("gh pr view --json id", { encoding: "utf-8" })
4661
+ execSync22("gh pr view --json id", { encoding: "utf-8" })
4471
4662
  );
4472
4663
  return prInfo.id;
4473
4664
  } catch (error) {
@@ -4499,8 +4690,8 @@ function comment(path35, line, body) {
4499
4690
  validateLine(line);
4500
4691
  try {
4501
4692
  const prId = getCurrentPrNodeId();
4502
- const queryFile = join16(tmpdir2(), `gh-query-${Date.now()}.graphql`);
4503
- writeFileSync16(queryFile, MUTATION);
4693
+ const queryFile = join17(tmpdir2(), `gh-query-${Date.now()}.graphql`);
4694
+ writeFileSync17(queryFile, MUTATION);
4504
4695
  try {
4505
4696
  const result = spawnSync2(
4506
4697
  "gh",
@@ -4538,32 +4729,32 @@ function comment(path35, line, body) {
4538
4729
  }
4539
4730
 
4540
4731
  // src/commands/prs/fixed.ts
4541
- import { execSync as execSync22 } from "child_process";
4732
+ import { execSync as execSync24 } from "child_process";
4542
4733
 
4543
4734
  // src/commands/prs/resolveCommentWithReply.ts
4544
- import { execSync as execSync21 } from "child_process";
4545
- import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync17 } from "fs";
4735
+ import { execSync as execSync23 } from "child_process";
4736
+ import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "fs";
4546
4737
  import { tmpdir as tmpdir3 } from "os";
4547
- import { join as join18 } from "path";
4738
+ import { join as join19 } from "path";
4548
4739
 
4549
4740
  // src/commands/prs/loadCommentsCache.ts
4550
- import { existsSync as existsSync22, readFileSync as readFileSync20, unlinkSync as unlinkSync4 } from "fs";
4551
- import { join as join17 } from "path";
4741
+ import { existsSync as existsSync23, readFileSync as readFileSync21, unlinkSync as unlinkSync4 } from "fs";
4742
+ import { join as join18 } from "path";
4552
4743
  import { parse as parse2 } from "yaml";
4553
4744
  function getCachePath(prNumber) {
4554
- return join17(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
4745
+ return join18(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
4555
4746
  }
4556
4747
  function loadCommentsCache(prNumber) {
4557
4748
  const cachePath = getCachePath(prNumber);
4558
- if (!existsSync22(cachePath)) {
4749
+ if (!existsSync23(cachePath)) {
4559
4750
  return null;
4560
4751
  }
4561
- const content = readFileSync20(cachePath, "utf-8");
4752
+ const content = readFileSync21(cachePath, "utf-8");
4562
4753
  return parse2(content);
4563
4754
  }
4564
4755
  function deleteCommentsCache(prNumber) {
4565
4756
  const cachePath = getCachePath(prNumber);
4566
- if (existsSync22(cachePath)) {
4757
+ if (existsSync23(cachePath)) {
4567
4758
  unlinkSync4(cachePath);
4568
4759
  console.log("No more unresolved line comments. Cache dropped.");
4569
4760
  }
@@ -4571,19 +4762,19 @@ function deleteCommentsCache(prNumber) {
4571
4762
 
4572
4763
  // src/commands/prs/resolveCommentWithReply.ts
4573
4764
  function replyToComment(org, repo, prNumber, commentId, message) {
4574
- execSync21(
4765
+ execSync23(
4575
4766
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
4576
- { stdio: "inherit" }
4767
+ { stdio: ["inherit", "pipe", "inherit"] }
4577
4768
  );
4578
4769
  }
4579
4770
  function resolveThread(threadId) {
4580
4771
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
4581
- const queryFile = join18(tmpdir3(), `gh-mutation-${Date.now()}.graphql`);
4582
- writeFileSync17(queryFile, mutation);
4772
+ const queryFile = join19(tmpdir3(), `gh-mutation-${Date.now()}.graphql`);
4773
+ writeFileSync18(queryFile, mutation);
4583
4774
  try {
4584
- execSync21(
4775
+ execSync23(
4585
4776
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
4586
- { stdio: "inherit" }
4777
+ { stdio: ["inherit", "pipe", "inherit"] }
4587
4778
  );
4588
4779
  } finally {
4589
4780
  unlinkSync5(queryFile);
@@ -4633,7 +4824,7 @@ function resolveCommentWithReply(commentId, message) {
4633
4824
  // src/commands/prs/fixed.ts
4634
4825
  function verifySha(sha) {
4635
4826
  try {
4636
- return execSync22(`git rev-parse --verify ${sha}`, {
4827
+ return execSync24(`git rev-parse --verify ${sha}`, {
4637
4828
  encoding: "utf-8"
4638
4829
  }).trim();
4639
4830
  } catch {
@@ -4659,21 +4850,21 @@ function fixed(commentId, sha) {
4659
4850
  }
4660
4851
 
4661
4852
  // src/commands/prs/listComments/index.ts
4662
- import { existsSync as existsSync23, mkdirSync as mkdirSync5, writeFileSync as writeFileSync19 } from "fs";
4663
- import { join as join20 } from "path";
4853
+ import { existsSync as existsSync24, mkdirSync as mkdirSync6, writeFileSync as writeFileSync20 } from "fs";
4854
+ import { join as join21 } from "path";
4664
4855
  import { stringify } from "yaml";
4665
4856
 
4666
4857
  // src/commands/prs/fetchThreadIds.ts
4667
- import { execSync as execSync23 } from "child_process";
4668
- import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync18 } from "fs";
4858
+ import { execSync as execSync25 } from "child_process";
4859
+ import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync19 } from "fs";
4669
4860
  import { tmpdir as tmpdir4 } from "os";
4670
- import { join as join19 } from "path";
4861
+ import { join as join20 } from "path";
4671
4862
  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 } } } } } } }`;
4672
4863
  function fetchThreadIds(org, repo, prNumber) {
4673
- const queryFile = join19(tmpdir4(), `gh-query-${Date.now()}.graphql`);
4674
- writeFileSync18(queryFile, THREAD_QUERY);
4864
+ const queryFile = join20(tmpdir4(), `gh-query-${Date.now()}.graphql`);
4865
+ writeFileSync19(queryFile, THREAD_QUERY);
4675
4866
  try {
4676
- const result = execSync23(
4867
+ const result = execSync25(
4677
4868
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
4678
4869
  { encoding: "utf-8" }
4679
4870
  );
@@ -4695,9 +4886,9 @@ function fetchThreadIds(org, repo, prNumber) {
4695
4886
  }
4696
4887
 
4697
4888
  // src/commands/prs/listComments/fetchReviewComments.ts
4698
- import { execSync as execSync24 } from "child_process";
4889
+ import { execSync as execSync26 } from "child_process";
4699
4890
  function fetchJson(endpoint) {
4700
- const result = execSync24(`gh api --paginate ${endpoint}`, {
4891
+ const result = execSync26(`gh api --paginate ${endpoint}`, {
4701
4892
  encoding: "utf-8"
4702
4893
  });
4703
4894
  if (!result.trim()) return [];
@@ -4739,20 +4930,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
4739
4930
  }
4740
4931
 
4741
4932
  // src/commands/prs/listComments/printComments.ts
4742
- import chalk48 from "chalk";
4933
+ import chalk49 from "chalk";
4743
4934
  function formatForHuman(comment2) {
4744
4935
  if (comment2.type === "review") {
4745
- const stateColor = comment2.state === "APPROVED" ? chalk48.green : comment2.state === "CHANGES_REQUESTED" ? chalk48.red : chalk48.yellow;
4936
+ const stateColor = comment2.state === "APPROVED" ? chalk49.green : comment2.state === "CHANGES_REQUESTED" ? chalk49.red : chalk49.yellow;
4746
4937
  return [
4747
- `${chalk48.cyan("Review")} by ${chalk48.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
4938
+ `${chalk49.cyan("Review")} by ${chalk49.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
4748
4939
  comment2.body,
4749
4940
  ""
4750
4941
  ].join("\n");
4751
4942
  }
4752
4943
  const location = comment2.line ? `:${comment2.line}` : "";
4753
4944
  return [
4754
- `${chalk48.cyan("Line comment")} by ${chalk48.bold(comment2.user)} on ${chalk48.dim(`${comment2.path}${location}`)}`,
4755
- chalk48.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
4945
+ `${chalk49.cyan("Line comment")} by ${chalk49.bold(comment2.user)} on ${chalk49.dim(`${comment2.path}${location}`)}`,
4946
+ chalk49.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
4756
4947
  comment2.body,
4757
4948
  ""
4758
4949
  ].join("\n");
@@ -4784,17 +4975,17 @@ function printComments(result) {
4784
4975
 
4785
4976
  // src/commands/prs/listComments/index.ts
4786
4977
  function writeCommentsCache(prNumber, comments) {
4787
- const assistDir = join20(process.cwd(), ".assist");
4788
- if (!existsSync23(assistDir)) {
4789
- mkdirSync5(assistDir, { recursive: true });
4978
+ const assistDir = join21(process.cwd(), ".assist");
4979
+ if (!existsSync24(assistDir)) {
4980
+ mkdirSync6(assistDir, { recursive: true });
4790
4981
  }
4791
4982
  const cacheData = {
4792
4983
  prNumber,
4793
4984
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
4794
4985
  comments
4795
4986
  };
4796
- const cachePath = join20(assistDir, `pr-${prNumber}-comments.yaml`);
4797
- writeFileSync19(cachePath, stringify(cacheData));
4987
+ const cachePath = join21(assistDir, `pr-${prNumber}-comments.yaml`);
4988
+ writeFileSync20(cachePath, stringify(cacheData));
4798
4989
  }
4799
4990
  function handleKnownErrors(error) {
4800
4991
  if (isGhNotInstalled(error)) {
@@ -4826,7 +5017,7 @@ async function listComments() {
4826
5017
  ];
4827
5018
  updateCache(prNumber, allComments);
4828
5019
  const hasLineComments = allComments.some((c) => c.type === "line");
4829
- const cachePath = hasLineComments ? join20(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
5020
+ const cachePath = hasLineComments ? join21(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
4830
5021
  return { comments: allComments, cachePath };
4831
5022
  } catch (error) {
4832
5023
  const handled = handleKnownErrors(error);
@@ -4836,19 +5027,19 @@ async function listComments() {
4836
5027
  }
4837
5028
 
4838
5029
  // src/commands/prs/prs/index.ts
4839
- import { execSync as execSync25 } from "child_process";
5030
+ import { execSync as execSync27 } from "child_process";
4840
5031
 
4841
5032
  // src/commands/prs/prs/displayPaginated/index.ts
4842
5033
  import enquirer5 from "enquirer";
4843
5034
 
4844
5035
  // src/commands/prs/prs/displayPaginated/printPr.ts
4845
- import chalk49 from "chalk";
5036
+ import chalk50 from "chalk";
4846
5037
  var STATUS_MAP = {
4847
- MERGED: (pr) => pr.mergedAt ? { label: chalk49.magenta("merged"), date: pr.mergedAt } : null,
4848
- CLOSED: (pr) => pr.closedAt ? { label: chalk49.red("closed"), date: pr.closedAt } : null
5038
+ MERGED: (pr) => pr.mergedAt ? { label: chalk50.magenta("merged"), date: pr.mergedAt } : null,
5039
+ CLOSED: (pr) => pr.closedAt ? { label: chalk50.red("closed"), date: pr.closedAt } : null
4849
5040
  };
4850
5041
  function defaultStatus(pr) {
4851
- return { label: chalk49.green("opened"), date: pr.createdAt };
5042
+ return { label: chalk50.green("opened"), date: pr.createdAt };
4852
5043
  }
4853
5044
  function getStatus2(pr) {
4854
5045
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -4857,11 +5048,11 @@ function formatDate(dateStr) {
4857
5048
  return new Date(dateStr).toISOString().split("T")[0];
4858
5049
  }
4859
5050
  function formatPrHeader(pr, status2) {
4860
- return `${chalk49.cyan(`#${pr.number}`)} ${pr.title} ${chalk49.dim(`(${pr.author.login},`)} ${status2.label} ${chalk49.dim(`${formatDate(status2.date)})`)}`;
5051
+ return `${chalk50.cyan(`#${pr.number}`)} ${pr.title} ${chalk50.dim(`(${pr.author.login},`)} ${status2.label} ${chalk50.dim(`${formatDate(status2.date)})`)}`;
4861
5052
  }
4862
5053
  function logPrDetails(pr) {
4863
5054
  console.log(
4864
- chalk49.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
5055
+ chalk50.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
4865
5056
  );
4866
5057
  console.log();
4867
5058
  }
@@ -4942,7 +5133,7 @@ async function displayPaginated(pullRequests) {
4942
5133
  async function prs(options2) {
4943
5134
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
4944
5135
  try {
4945
- const result = execSync25(
5136
+ const result = execSync27(
4946
5137
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
4947
5138
  { encoding: "utf-8" }
4948
5139
  );
@@ -4965,7 +5156,7 @@ async function prs(options2) {
4965
5156
  }
4966
5157
 
4967
5158
  // src/commands/prs/wontfix.ts
4968
- import { execSync as execSync26 } from "child_process";
5159
+ import { execSync as execSync28 } from "child_process";
4969
5160
  function validateReason(reason) {
4970
5161
  const lowerReason = reason.toLowerCase();
4971
5162
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -4982,7 +5173,7 @@ function validateShaReferences(reason) {
4982
5173
  const invalidShas = [];
4983
5174
  for (const sha of shas) {
4984
5175
  try {
4985
- execSync26(`git cat-file -t ${sha}`, { stdio: "pipe" });
5176
+ execSync28(`git cat-file -t ${sha}`, { stdio: "pipe" });
4986
5177
  } catch {
4987
5178
  invalidShas.push(sha);
4988
5179
  }
@@ -5031,7 +5222,7 @@ import { spawn as spawn3 } from "child_process";
5031
5222
  import * as path21 from "path";
5032
5223
 
5033
5224
  // src/commands/refactor/logViolations.ts
5034
- import chalk50 from "chalk";
5225
+ import chalk51 from "chalk";
5035
5226
  var DEFAULT_MAX_LINES = 100;
5036
5227
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
5037
5228
  if (violations.length === 0) {
@@ -5040,43 +5231,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
5040
5231
  }
5041
5232
  return;
5042
5233
  }
5043
- console.error(chalk50.red(`
5234
+ console.error(chalk51.red(`
5044
5235
  Refactor check failed:
5045
5236
  `));
5046
- console.error(chalk50.red(` The following files exceed ${maxLines} lines:
5237
+ console.error(chalk51.red(` The following files exceed ${maxLines} lines:
5047
5238
  `));
5048
5239
  for (const violation of violations) {
5049
- console.error(chalk50.red(` ${violation.file} (${violation.lines} lines)`));
5240
+ console.error(chalk51.red(` ${violation.file} (${violation.lines} lines)`));
5050
5241
  }
5051
5242
  console.error(
5052
- chalk50.yellow(
5243
+ chalk51.yellow(
5053
5244
  `
5054
5245
  Each file needs to be sensibly refactored, or if there is no sensible
5055
5246
  way to refactor it, ignore it with:
5056
5247
  `
5057
5248
  )
5058
5249
  );
5059
- console.error(chalk50.gray(` assist refactor ignore <file>
5250
+ console.error(chalk51.gray(` assist refactor ignore <file>
5060
5251
  `));
5061
5252
  if (process.env.CLAUDECODE) {
5062
- console.error(chalk50.cyan(`
5253
+ console.error(chalk51.cyan(`
5063
5254
  ## Extracting Code to New Files
5064
5255
  `));
5065
5256
  console.error(
5066
- chalk50.cyan(
5257
+ chalk51.cyan(
5067
5258
  ` When extracting logic from one file to another, consider where the extracted code belongs:
5068
5259
  `
5069
5260
  )
5070
5261
  );
5071
5262
  console.error(
5072
- chalk50.cyan(
5263
+ chalk51.cyan(
5073
5264
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
5074
5265
  original file's domain, create a new folder containing both the original and extracted files.
5075
5266
  `
5076
5267
  )
5077
5268
  );
5078
5269
  console.error(
5079
- chalk50.cyan(
5270
+ chalk51.cyan(
5080
5271
  ` 2. Share common utilities: If the extracted code can be reused across multiple
5081
5272
  domains, move it to a common/shared folder.
5082
5273
  `
@@ -5086,7 +5277,7 @@ Refactor check failed:
5086
5277
  }
5087
5278
 
5088
5279
  // src/commands/refactor/check/getViolations/index.ts
5089
- import { execSync as execSync27 } from "child_process";
5280
+ import { execSync as execSync29 } from "child_process";
5090
5281
  import fs15 from "fs";
5091
5282
  import { minimatch as minimatch4 } from "minimatch";
5092
5283
 
@@ -5136,7 +5327,7 @@ function getGitFiles(options2) {
5136
5327
  }
5137
5328
  const files = /* @__PURE__ */ new Set();
5138
5329
  if (options2.staged || options2.modified) {
5139
- const staged = execSync27("git diff --cached --name-only", {
5330
+ const staged = execSync29("git diff --cached --name-only", {
5140
5331
  encoding: "utf-8"
5141
5332
  });
5142
5333
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -5144,7 +5335,7 @@ function getGitFiles(options2) {
5144
5335
  }
5145
5336
  }
5146
5337
  if (options2.unstaged || options2.modified) {
5147
- const unstaged = execSync27("git diff --name-only", { encoding: "utf-8" });
5338
+ const unstaged = execSync29("git diff --name-only", { encoding: "utf-8" });
5148
5339
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
5149
5340
  files.add(file);
5150
5341
  }
@@ -5232,11 +5423,11 @@ async function check(pattern2, options2) {
5232
5423
 
5233
5424
  // src/commands/refactor/ignore.ts
5234
5425
  import fs16 from "fs";
5235
- import chalk51 from "chalk";
5426
+ import chalk52 from "chalk";
5236
5427
  var REFACTOR_YML_PATH2 = "refactor.yml";
5237
5428
  function ignore(file) {
5238
5429
  if (!fs16.existsSync(file)) {
5239
- console.error(chalk51.red(`Error: File does not exist: ${file}`));
5430
+ console.error(chalk52.red(`Error: File does not exist: ${file}`));
5240
5431
  process.exit(1);
5241
5432
  }
5242
5433
  const content = fs16.readFileSync(file, "utf-8");
@@ -5252,7 +5443,7 @@ function ignore(file) {
5252
5443
  fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
5253
5444
  }
5254
5445
  console.log(
5255
- chalk51.green(
5446
+ chalk52.green(
5256
5447
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
5257
5448
  )
5258
5449
  );
@@ -5260,7 +5451,7 @@ function ignore(file) {
5260
5451
 
5261
5452
  // src/commands/refactor/restructure/index.ts
5262
5453
  import path30 from "path";
5263
- import chalk54 from "chalk";
5454
+ import chalk55 from "chalk";
5264
5455
 
5265
5456
  // src/commands/refactor/restructure/buildImportGraph/index.ts
5266
5457
  import path22 from "path";
@@ -5503,50 +5694,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
5503
5694
 
5504
5695
  // src/commands/refactor/restructure/displayPlan.ts
5505
5696
  import path26 from "path";
5506
- import chalk52 from "chalk";
5697
+ import chalk53 from "chalk";
5507
5698
  function relPath(filePath) {
5508
5699
  return path26.relative(process.cwd(), filePath);
5509
5700
  }
5510
5701
  function displayMoves(plan) {
5511
5702
  if (plan.moves.length === 0) return;
5512
- console.log(chalk52.bold("\nFile moves:"));
5703
+ console.log(chalk53.bold("\nFile moves:"));
5513
5704
  for (const move of plan.moves) {
5514
5705
  console.log(
5515
- ` ${chalk52.red(relPath(move.from))} \u2192 ${chalk52.green(relPath(move.to))}`
5706
+ ` ${chalk53.red(relPath(move.from))} \u2192 ${chalk53.green(relPath(move.to))}`
5516
5707
  );
5517
- console.log(chalk52.dim(` ${move.reason}`));
5708
+ console.log(chalk53.dim(` ${move.reason}`));
5518
5709
  }
5519
5710
  }
5520
5711
  function displayRewrites(rewrites) {
5521
5712
  if (rewrites.length === 0) return;
5522
5713
  const affectedFiles = new Set(rewrites.map((r) => r.file));
5523
- console.log(chalk52.bold(`
5714
+ console.log(chalk53.bold(`
5524
5715
  Import rewrites (${affectedFiles.size} files):`));
5525
5716
  for (const file of affectedFiles) {
5526
- console.log(` ${chalk52.cyan(relPath(file))}:`);
5717
+ console.log(` ${chalk53.cyan(relPath(file))}:`);
5527
5718
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
5528
5719
  (r) => r.file === file
5529
5720
  )) {
5530
5721
  console.log(
5531
- ` ${chalk52.red(`"${oldSpecifier}"`)} \u2192 ${chalk52.green(`"${newSpecifier}"`)}`
5722
+ ` ${chalk53.red(`"${oldSpecifier}"`)} \u2192 ${chalk53.green(`"${newSpecifier}"`)}`
5532
5723
  );
5533
5724
  }
5534
5725
  }
5535
5726
  }
5536
5727
  function displayPlan(plan) {
5537
5728
  if (plan.warnings.length > 0) {
5538
- console.log(chalk52.yellow("\nWarnings:"));
5539
- for (const w of plan.warnings) console.log(chalk52.yellow(` ${w}`));
5729
+ console.log(chalk53.yellow("\nWarnings:"));
5730
+ for (const w of plan.warnings) console.log(chalk53.yellow(` ${w}`));
5540
5731
  }
5541
5732
  if (plan.newDirectories.length > 0) {
5542
- console.log(chalk52.bold("\nNew directories:"));
5733
+ console.log(chalk53.bold("\nNew directories:"));
5543
5734
  for (const dir of plan.newDirectories)
5544
- console.log(chalk52.green(` ${dir}/`));
5735
+ console.log(chalk53.green(` ${dir}/`));
5545
5736
  }
5546
5737
  displayMoves(plan);
5547
5738
  displayRewrites(plan.rewrites);
5548
5739
  console.log(
5549
- chalk52.dim(
5740
+ chalk53.dim(
5550
5741
  `
5551
5742
  Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
5552
5743
  )
@@ -5556,18 +5747,18 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
5556
5747
  // src/commands/refactor/restructure/executePlan.ts
5557
5748
  import fs18 from "fs";
5558
5749
  import path27 from "path";
5559
- import chalk53 from "chalk";
5750
+ import chalk54 from "chalk";
5560
5751
  function executePlan(plan) {
5561
5752
  const updatedContents = applyRewrites(plan.rewrites);
5562
5753
  for (const [file, content] of updatedContents) {
5563
5754
  fs18.writeFileSync(file, content, "utf-8");
5564
5755
  console.log(
5565
- chalk53.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
5756
+ chalk54.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
5566
5757
  );
5567
5758
  }
5568
5759
  for (const dir of plan.newDirectories) {
5569
5760
  fs18.mkdirSync(dir, { recursive: true });
5570
- console.log(chalk53.green(` Created ${path27.relative(process.cwd(), dir)}/`));
5761
+ console.log(chalk54.green(` Created ${path27.relative(process.cwd(), dir)}/`));
5571
5762
  }
5572
5763
  for (const move of plan.moves) {
5573
5764
  const targetDir = path27.dirname(move.to);
@@ -5576,7 +5767,7 @@ function executePlan(plan) {
5576
5767
  }
5577
5768
  fs18.renameSync(move.from, move.to);
5578
5769
  console.log(
5579
- chalk53.white(
5770
+ chalk54.white(
5580
5771
  ` Moved ${path27.relative(process.cwd(), move.from)} \u2192 ${path27.relative(process.cwd(), move.to)}`
5581
5772
  )
5582
5773
  );
@@ -5591,7 +5782,7 @@ function removeEmptyDirectories(dirs) {
5591
5782
  if (entries.length === 0) {
5592
5783
  fs18.rmdirSync(dir);
5593
5784
  console.log(
5594
- chalk53.dim(
5785
+ chalk54.dim(
5595
5786
  ` Removed empty directory ${path27.relative(process.cwd(), dir)}`
5596
5787
  )
5597
5788
  );
@@ -5722,22 +5913,22 @@ async function restructure(pattern2, options2 = {}) {
5722
5913
  const targetPattern = pattern2 ?? "src";
5723
5914
  const files = findSourceFiles2(targetPattern);
5724
5915
  if (files.length === 0) {
5725
- console.log(chalk54.yellow("No files found matching pattern"));
5916
+ console.log(chalk55.yellow("No files found matching pattern"));
5726
5917
  return;
5727
5918
  }
5728
5919
  const tsConfigPath = path30.resolve("tsconfig.json");
5729
5920
  const plan = buildPlan(files, tsConfigPath);
5730
5921
  if (plan.moves.length === 0) {
5731
- console.log(chalk54.green("No restructuring needed"));
5922
+ console.log(chalk55.green("No restructuring needed"));
5732
5923
  return;
5733
5924
  }
5734
5925
  displayPlan(plan);
5735
5926
  if (options2.apply) {
5736
- console.log(chalk54.bold("\nApplying changes..."));
5927
+ console.log(chalk55.bold("\nApplying changes..."));
5737
5928
  executePlan(plan);
5738
- console.log(chalk54.green("\nRestructuring complete"));
5929
+ console.log(chalk55.green("\nRestructuring complete"));
5739
5930
  } else {
5740
- console.log(chalk54.dim("\nDry run. Use --apply to execute."));
5931
+ console.log(chalk55.dim("\nDry run. Use --apply to execute."));
5741
5932
  }
5742
5933
  }
5743
5934
 
@@ -5760,8 +5951,8 @@ function registerRefactor(program2) {
5760
5951
  }
5761
5952
 
5762
5953
  // src/commands/transcript/shared.ts
5763
- import { existsSync as existsSync24, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
5764
- import { basename as basename4, join as join21, relative } from "path";
5954
+ import { existsSync as existsSync25, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
5955
+ import { basename as basename4, join as join22, relative } from "path";
5765
5956
  import * as readline2 from "readline";
5766
5957
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
5767
5958
  function getDatePrefix(daysOffset = 0) {
@@ -5776,10 +5967,10 @@ function isValidDatePrefix(filename) {
5776
5967
  return DATE_PREFIX_REGEX.test(filename);
5777
5968
  }
5778
5969
  function collectFiles(dir, extension) {
5779
- if (!existsSync24(dir)) return [];
5970
+ if (!existsSync25(dir)) return [];
5780
5971
  const results = [];
5781
5972
  for (const entry of readdirSync3(dir)) {
5782
- const fullPath = join21(dir, entry);
5973
+ const fullPath = join22(dir, entry);
5783
5974
  if (statSync2(fullPath).isDirectory()) {
5784
5975
  results.push(...collectFiles(fullPath, extension));
5785
5976
  } else if (entry.endsWith(extension)) {
@@ -5873,14 +6064,14 @@ async function configure() {
5873
6064
  }
5874
6065
 
5875
6066
  // src/commands/transcript/format/index.ts
5876
- import { existsSync as existsSync26 } from "fs";
6067
+ import { existsSync as existsSync27 } from "fs";
5877
6068
 
5878
6069
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
5879
- import { dirname as dirname15, join as join23 } from "path";
6070
+ import { dirname as dirname15, join as join24 } from "path";
5880
6071
 
5881
6072
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
5882
6073
  import { renameSync } from "fs";
5883
- import { join as join22 } from "path";
6074
+ import { join as join23 } from "path";
5884
6075
  async function resolveDate(rl, choice) {
5885
6076
  if (choice === "1") return getDatePrefix(0);
5886
6077
  if (choice === "2") return getDatePrefix(-1);
@@ -5895,7 +6086,7 @@ async function resolveDate(rl, choice) {
5895
6086
  }
5896
6087
  function renameWithPrefix(vttDir, vttFile, prefix2) {
5897
6088
  const newFilename = `${prefix2}.${vttFile}`;
5898
- renameSync(join22(vttDir, vttFile), join22(vttDir, newFilename));
6089
+ renameSync(join23(vttDir, vttFile), join23(vttDir, newFilename));
5899
6090
  console.log(`Renamed to: ${newFilename}`);
5900
6091
  return newFilename;
5901
6092
  }
@@ -5929,12 +6120,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
5929
6120
  const vttFileDir = dirname15(vttFile.absolutePath);
5930
6121
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
5931
6122
  if (newFilename) {
5932
- const newRelativePath = join23(
6123
+ const newRelativePath = join24(
5933
6124
  dirname15(vttFile.relativePath),
5934
6125
  newFilename
5935
6126
  );
5936
6127
  vttFiles[i] = {
5937
- absolutePath: join23(vttFileDir, newFilename),
6128
+ absolutePath: join24(vttFileDir, newFilename),
5938
6129
  relativePath: newRelativePath,
5939
6130
  filename: newFilename
5940
6131
  };
@@ -5947,8 +6138,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
5947
6138
  }
5948
6139
 
5949
6140
  // src/commands/transcript/format/processVttFile/index.ts
5950
- import { existsSync as existsSync25, mkdirSync as mkdirSync6, readFileSync as readFileSync21, writeFileSync as writeFileSync20 } from "fs";
5951
- import { basename as basename5, dirname as dirname16, join as join24 } from "path";
6141
+ import { existsSync as existsSync26, mkdirSync as mkdirSync7, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "fs";
6142
+ import { basename as basename5, dirname as dirname16, join as join25 } from "path";
5952
6143
 
5953
6144
  // src/commands/transcript/cleanText.ts
5954
6145
  function cleanText(text) {
@@ -6158,22 +6349,22 @@ function toMdFilename(vttFilename) {
6158
6349
  return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
6159
6350
  }
6160
6351
  function resolveOutputDir(relativeDir, transcriptsDir) {
6161
- return relativeDir === "." ? transcriptsDir : join24(transcriptsDir, relativeDir);
6352
+ return relativeDir === "." ? transcriptsDir : join25(transcriptsDir, relativeDir);
6162
6353
  }
6163
6354
  function buildOutputPaths(vttFile, transcriptsDir) {
6164
6355
  const mdFile = toMdFilename(vttFile.filename);
6165
6356
  const relativeDir = dirname16(vttFile.relativePath);
6166
6357
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
6167
- const outputPath = join24(outputDir, mdFile);
6358
+ const outputPath = join25(outputDir, mdFile);
6168
6359
  return { outputDir, outputPath, mdFile, relativeDir };
6169
6360
  }
6170
6361
  function logSkipped(relativeDir, mdFile) {
6171
- console.log(`Skipping (already exists): ${join24(relativeDir, mdFile)}`);
6362
+ console.log(`Skipping (already exists): ${join25(relativeDir, mdFile)}`);
6172
6363
  return "skipped";
6173
6364
  }
6174
6365
  function ensureDirectory(dir, label2) {
6175
- if (!existsSync25(dir)) {
6176
- mkdirSync6(dir, { recursive: true });
6366
+ if (!existsSync26(dir)) {
6367
+ mkdirSync7(dir, { recursive: true });
6177
6368
  console.log(`Created ${label2}: ${dir}`);
6178
6369
  }
6179
6370
  }
@@ -6195,10 +6386,10 @@ function logReduction(cueCount, messageCount) {
6195
6386
  }
6196
6387
  function readAndParseCues(inputPath) {
6197
6388
  console.log(`Reading: ${inputPath}`);
6198
- return processCues(readFileSync21(inputPath, "utf-8"));
6389
+ return processCues(readFileSync22(inputPath, "utf-8"));
6199
6390
  }
6200
6391
  function writeFormatted(outputPath, content) {
6201
- writeFileSync20(outputPath, content, "utf-8");
6392
+ writeFileSync21(outputPath, content, "utf-8");
6202
6393
  console.log(`Written: ${outputPath}`);
6203
6394
  }
6204
6395
  function convertVttToMarkdown(inputPath, outputPath) {
@@ -6208,7 +6399,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
6208
6399
  logReduction(cues.length, chatMessages.length);
6209
6400
  }
6210
6401
  function tryProcessVtt(vttFile, paths) {
6211
- if (existsSync25(paths.outputPath))
6402
+ if (existsSync26(paths.outputPath))
6212
6403
  return logSkipped(paths.relativeDir, paths.mdFile);
6213
6404
  convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
6214
6405
  return "processed";
@@ -6234,7 +6425,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
6234
6425
  logSummary(counts);
6235
6426
  }
6236
6427
  function requireVttDir(vttDir) {
6237
- if (!existsSync26(vttDir)) {
6428
+ if (!existsSync27(vttDir)) {
6238
6429
  console.error(`VTT directory not found: ${vttDir}`);
6239
6430
  process.exit(1);
6240
6431
  }
@@ -6266,28 +6457,28 @@ async function format() {
6266
6457
  }
6267
6458
 
6268
6459
  // src/commands/transcript/summarise/index.ts
6269
- import { existsSync as existsSync28 } from "fs";
6270
- import { basename as basename6, dirname as dirname18, join as join26, relative as relative2 } from "path";
6460
+ import { existsSync as existsSync29 } from "fs";
6461
+ import { basename as basename6, dirname as dirname18, join as join27, relative as relative2 } from "path";
6271
6462
 
6272
6463
  // src/commands/transcript/summarise/processStagedFile/index.ts
6273
6464
  import {
6274
- existsSync as existsSync27,
6275
- mkdirSync as mkdirSync7,
6276
- readFileSync as readFileSync22,
6465
+ existsSync as existsSync28,
6466
+ mkdirSync as mkdirSync8,
6467
+ readFileSync as readFileSync23,
6277
6468
  renameSync as renameSync2,
6278
6469
  rmSync
6279
6470
  } from "fs";
6280
- import { dirname as dirname17, join as join25 } from "path";
6471
+ import { dirname as dirname17, join as join26 } from "path";
6281
6472
 
6282
6473
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
6283
- import chalk55 from "chalk";
6474
+ import chalk56 from "chalk";
6284
6475
  var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
6285
6476
  function validateStagedContent(filename, content) {
6286
6477
  const firstLine = content.split("\n")[0];
6287
6478
  const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
6288
6479
  if (!match) {
6289
6480
  console.error(
6290
- chalk55.red(
6481
+ chalk56.red(
6291
6482
  `Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
6292
6483
  )
6293
6484
  );
@@ -6296,7 +6487,7 @@ function validateStagedContent(filename, content) {
6296
6487
  const contentAfterLink = content.slice(firstLine.length).trim();
6297
6488
  if (!contentAfterLink) {
6298
6489
  console.error(
6299
- chalk55.red(
6490
+ chalk56.red(
6300
6491
  `Staged file ${filename} has no summary content after the transcript link.`
6301
6492
  )
6302
6493
  );
@@ -6306,9 +6497,9 @@ function validateStagedContent(filename, content) {
6306
6497
  }
6307
6498
 
6308
6499
  // src/commands/transcript/summarise/processStagedFile/index.ts
6309
- var STAGING_DIR = join25(process.cwd(), ".assist", "transcript");
6500
+ var STAGING_DIR = join26(process.cwd(), ".assist", "transcript");
6310
6501
  function processStagedFile() {
6311
- if (!existsSync27(STAGING_DIR)) {
6502
+ if (!existsSync28(STAGING_DIR)) {
6312
6503
  return false;
6313
6504
  }
6314
6505
  const stagedFiles = findMdFilesRecursive(STAGING_DIR);
@@ -6317,7 +6508,7 @@ function processStagedFile() {
6317
6508
  }
6318
6509
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
6319
6510
  const stagedFile = stagedFiles[0];
6320
- const content = readFileSync22(stagedFile.absolutePath, "utf-8");
6511
+ const content = readFileSync23(stagedFile.absolutePath, "utf-8");
6321
6512
  validateStagedContent(stagedFile.filename, content);
6322
6513
  const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
6323
6514
  const transcriptFiles = findMdFilesRecursive(transcriptsDir);
@@ -6330,10 +6521,10 @@ function processStagedFile() {
6330
6521
  );
6331
6522
  process.exit(1);
6332
6523
  }
6333
- const destPath = join25(summaryDir, matchingTranscript.relativePath);
6524
+ const destPath = join26(summaryDir, matchingTranscript.relativePath);
6334
6525
  const destDir = dirname17(destPath);
6335
- if (!existsSync27(destDir)) {
6336
- mkdirSync7(destDir, { recursive: true });
6526
+ if (!existsSync28(destDir)) {
6527
+ mkdirSync8(destDir, { recursive: true });
6337
6528
  }
6338
6529
  renameSync2(stagedFile.absolutePath, destPath);
6339
6530
  const remaining = findMdFilesRecursive(STAGING_DIR);
@@ -6346,7 +6537,7 @@ function processStagedFile() {
6346
6537
  // src/commands/transcript/summarise/index.ts
6347
6538
  function buildRelativeKey(relativePath, baseName) {
6348
6539
  const relDir = dirname18(relativePath);
6349
- return relDir === "." ? baseName : join26(relDir, baseName);
6540
+ return relDir === "." ? baseName : join27(relDir, baseName);
6350
6541
  }
6351
6542
  function buildSummaryIndex(summaryDir) {
6352
6543
  const summaryFiles = findMdFilesRecursive(summaryDir);
@@ -6359,7 +6550,7 @@ function buildSummaryIndex(summaryDir) {
6359
6550
  function summarise2() {
6360
6551
  processStagedFile();
6361
6552
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
6362
- if (!existsSync28(transcriptsDir)) {
6553
+ if (!existsSync29(transcriptsDir)) {
6363
6554
  console.log("No transcripts directory found.");
6364
6555
  return;
6365
6556
  }
@@ -6380,8 +6571,8 @@ function summarise2() {
6380
6571
  }
6381
6572
  const next2 = missing[0];
6382
6573
  const outputFilename = `${getTranscriptBaseName(next2.filename)}.md`;
6383
- const outputPath = join26(STAGING_DIR, outputFilename);
6384
- const summaryFileDir = join26(summaryDir, dirname18(next2.relativePath));
6574
+ const outputPath = join27(STAGING_DIR, outputFilename);
6575
+ const summaryFileDir = join27(summaryDir, dirname18(next2.relativePath));
6385
6576
  const relativeTranscriptPath = encodeURI(
6386
6577
  relative2(summaryFileDir, next2.absolutePath).replace(/\\/g, "/")
6387
6578
  );
@@ -6427,50 +6618,50 @@ function registerVerify(program2) {
6427
6618
 
6428
6619
  // src/commands/voice/devices.ts
6429
6620
  import { spawnSync as spawnSync3 } from "child_process";
6430
- import { join as join28 } from "path";
6621
+ import { join as join29 } from "path";
6431
6622
 
6432
6623
  // src/commands/voice/shared.ts
6433
- import { homedir as homedir6 } from "os";
6434
- import { dirname as dirname19, join as join27 } from "path";
6624
+ import { homedir as homedir7 } from "os";
6625
+ import { dirname as dirname19, join as join28 } from "path";
6435
6626
  import { fileURLToPath as fileURLToPath6 } from "url";
6436
6627
  var __dirname7 = dirname19(fileURLToPath6(import.meta.url));
6437
- var VOICE_DIR = join27(homedir6(), ".assist", "voice");
6628
+ var VOICE_DIR = join28(homedir7(), ".assist", "voice");
6438
6629
  var voicePaths = {
6439
6630
  dir: VOICE_DIR,
6440
- pid: join27(VOICE_DIR, "voice.pid"),
6441
- log: join27(VOICE_DIR, "voice.log"),
6442
- venv: join27(VOICE_DIR, ".venv"),
6443
- lock: join27(VOICE_DIR, "voice.lock")
6631
+ pid: join28(VOICE_DIR, "voice.pid"),
6632
+ log: join28(VOICE_DIR, "voice.log"),
6633
+ venv: join28(VOICE_DIR, ".venv"),
6634
+ lock: join28(VOICE_DIR, "voice.lock")
6444
6635
  };
6445
6636
  function getPythonDir() {
6446
- return join27(__dirname7, "commands", "voice", "python");
6637
+ return join28(__dirname7, "commands", "voice", "python");
6447
6638
  }
6448
6639
  function getVenvPython() {
6449
- return process.platform === "win32" ? join27(voicePaths.venv, "Scripts", "python.exe") : join27(voicePaths.venv, "bin", "python");
6640
+ return process.platform === "win32" ? join28(voicePaths.venv, "Scripts", "python.exe") : join28(voicePaths.venv, "bin", "python");
6450
6641
  }
6451
6642
  function getLockDir() {
6452
6643
  const config = loadConfig();
6453
6644
  return config.voice?.lockDir ?? VOICE_DIR;
6454
6645
  }
6455
6646
  function getLockFile() {
6456
- return join27(getLockDir(), "voice.lock");
6647
+ return join28(getLockDir(), "voice.lock");
6457
6648
  }
6458
6649
 
6459
6650
  // src/commands/voice/devices.ts
6460
6651
  function devices() {
6461
- const script = join28(getPythonDir(), "list_devices.py");
6652
+ const script = join29(getPythonDir(), "list_devices.py");
6462
6653
  spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
6463
6654
  }
6464
6655
 
6465
6656
  // src/commands/voice/logs.ts
6466
- import { existsSync as existsSync29, readFileSync as readFileSync23 } from "fs";
6657
+ import { existsSync as existsSync30, readFileSync as readFileSync24 } from "fs";
6467
6658
  function logs(options2) {
6468
- if (!existsSync29(voicePaths.log)) {
6659
+ if (!existsSync30(voicePaths.log)) {
6469
6660
  console.log("No voice log file found");
6470
6661
  return;
6471
6662
  }
6472
6663
  const count = Number.parseInt(options2.lines ?? "150", 10);
6473
- const content = readFileSync23(voicePaths.log, "utf-8").trim();
6664
+ const content = readFileSync24(voicePaths.log, "utf-8").trim();
6474
6665
  if (!content) {
6475
6666
  console.log("Voice log is empty");
6476
6667
  return;
@@ -6492,13 +6683,13 @@ function logs(options2) {
6492
6683
 
6493
6684
  // src/commands/voice/setup.ts
6494
6685
  import { spawnSync as spawnSync4 } from "child_process";
6495
- import { mkdirSync as mkdirSync9 } from "fs";
6496
- import { join as join30 } from "path";
6686
+ import { mkdirSync as mkdirSync10 } from "fs";
6687
+ import { join as join31 } from "path";
6497
6688
 
6498
6689
  // src/commands/voice/checkLockFile.ts
6499
- import { execSync as execSync28 } from "child_process";
6500
- import { existsSync as existsSync30, mkdirSync as mkdirSync8, readFileSync as readFileSync24, writeFileSync as writeFileSync21 } from "fs";
6501
- import { join as join29 } from "path";
6690
+ import { execSync as execSync30 } from "child_process";
6691
+ import { existsSync as existsSync31, mkdirSync as mkdirSync9, readFileSync as readFileSync25, writeFileSync as writeFileSync22 } from "fs";
6692
+ import { join as join30 } from "path";
6502
6693
  function isProcessAlive(pid) {
6503
6694
  try {
6504
6695
  process.kill(pid, 0);
@@ -6509,9 +6700,9 @@ function isProcessAlive(pid) {
6509
6700
  }
6510
6701
  function checkLockFile() {
6511
6702
  const lockFile = getLockFile();
6512
- if (!existsSync30(lockFile)) return;
6703
+ if (!existsSync31(lockFile)) return;
6513
6704
  try {
6514
- const lock = JSON.parse(readFileSync24(lockFile, "utf-8"));
6705
+ const lock = JSON.parse(readFileSync25(lockFile, "utf-8"));
6515
6706
  if (lock.pid && isProcessAlive(lock.pid)) {
6516
6707
  console.error(
6517
6708
  `Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
@@ -6522,10 +6713,10 @@ function checkLockFile() {
6522
6713
  }
6523
6714
  }
6524
6715
  function bootstrapVenv() {
6525
- if (existsSync30(getVenvPython())) return;
6716
+ if (existsSync31(getVenvPython())) return;
6526
6717
  console.log("Setting up Python environment...");
6527
6718
  const pythonDir = getPythonDir();
6528
- execSync28(
6719
+ execSync30(
6529
6720
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
6530
6721
  {
6531
6722
  stdio: "inherit",
@@ -6535,8 +6726,8 @@ function bootstrapVenv() {
6535
6726
  }
6536
6727
  function writeLockFile(pid) {
6537
6728
  const lockFile = getLockFile();
6538
- mkdirSync8(join29(lockFile, ".."), { recursive: true });
6539
- writeFileSync21(
6729
+ mkdirSync9(join30(lockFile, ".."), { recursive: true });
6730
+ writeFileSync22(
6540
6731
  lockFile,
6541
6732
  JSON.stringify({
6542
6733
  pid,
@@ -6548,10 +6739,10 @@ function writeLockFile(pid) {
6548
6739
 
6549
6740
  // src/commands/voice/setup.ts
6550
6741
  function setup() {
6551
- mkdirSync9(voicePaths.dir, { recursive: true });
6742
+ mkdirSync10(voicePaths.dir, { recursive: true });
6552
6743
  bootstrapVenv();
6553
6744
  console.log("\nDownloading models...\n");
6554
- const script = join30(getPythonDir(), "setup_models.py");
6745
+ const script = join31(getPythonDir(), "setup_models.py");
6555
6746
  const result = spawnSync4(getVenvPython(), [script], {
6556
6747
  stdio: "inherit",
6557
6748
  env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
@@ -6564,8 +6755,8 @@ function setup() {
6564
6755
 
6565
6756
  // src/commands/voice/start.ts
6566
6757
  import { spawn as spawn4 } from "child_process";
6567
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync22 } from "fs";
6568
- import { join as join31 } from "path";
6758
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync23 } from "fs";
6759
+ import { join as join32 } from "path";
6569
6760
 
6570
6761
  // src/commands/voice/buildDaemonEnv.ts
6571
6762
  function buildDaemonEnv(options2) {
@@ -6593,17 +6784,17 @@ function spawnBackground(python, script, env) {
6593
6784
  console.error("Failed to start voice daemon");
6594
6785
  process.exit(1);
6595
6786
  }
6596
- writeFileSync22(voicePaths.pid, String(pid));
6787
+ writeFileSync23(voicePaths.pid, String(pid));
6597
6788
  writeLockFile(pid);
6598
6789
  console.log(`Voice daemon started (PID ${pid})`);
6599
6790
  }
6600
6791
  function start2(options2) {
6601
- mkdirSync10(voicePaths.dir, { recursive: true });
6792
+ mkdirSync11(voicePaths.dir, { recursive: true });
6602
6793
  checkLockFile();
6603
6794
  bootstrapVenv();
6604
6795
  const debug = options2.debug || options2.foreground || process.platform === "win32";
6605
6796
  const env = buildDaemonEnv({ debug });
6606
- const script = join31(getPythonDir(), "voice_daemon.py");
6797
+ const script = join32(getPythonDir(), "voice_daemon.py");
6607
6798
  const python = getVenvPython();
6608
6799
  if (options2.foreground) {
6609
6800
  spawnForeground(python, script, env);
@@ -6613,7 +6804,7 @@ function start2(options2) {
6613
6804
  }
6614
6805
 
6615
6806
  // src/commands/voice/status.ts
6616
- import { existsSync as existsSync31, readFileSync as readFileSync25 } from "fs";
6807
+ import { existsSync as existsSync32, readFileSync as readFileSync26 } from "fs";
6617
6808
  function isProcessAlive2(pid) {
6618
6809
  try {
6619
6810
  process.kill(pid, 0);
@@ -6623,16 +6814,16 @@ function isProcessAlive2(pid) {
6623
6814
  }
6624
6815
  }
6625
6816
  function readRecentLogs(count) {
6626
- if (!existsSync31(voicePaths.log)) return [];
6627
- const lines = readFileSync25(voicePaths.log, "utf-8").trim().split("\n");
6817
+ if (!existsSync32(voicePaths.log)) return [];
6818
+ const lines = readFileSync26(voicePaths.log, "utf-8").trim().split("\n");
6628
6819
  return lines.slice(-count);
6629
6820
  }
6630
6821
  function status() {
6631
- if (!existsSync31(voicePaths.pid)) {
6822
+ if (!existsSync32(voicePaths.pid)) {
6632
6823
  console.log("Voice daemon: not running (no PID file)");
6633
6824
  return;
6634
6825
  }
6635
- const pid = Number.parseInt(readFileSync25(voicePaths.pid, "utf-8").trim(), 10);
6826
+ const pid = Number.parseInt(readFileSync26(voicePaths.pid, "utf-8").trim(), 10);
6636
6827
  const alive = isProcessAlive2(pid);
6637
6828
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
6638
6829
  const recent = readRecentLogs(5);
@@ -6651,13 +6842,13 @@ function status() {
6651
6842
  }
6652
6843
 
6653
6844
  // src/commands/voice/stop.ts
6654
- import { existsSync as existsSync32, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
6845
+ import { existsSync as existsSync33, readFileSync as readFileSync27, unlinkSync as unlinkSync7 } from "fs";
6655
6846
  function stop() {
6656
- if (!existsSync32(voicePaths.pid)) {
6847
+ if (!existsSync33(voicePaths.pid)) {
6657
6848
  console.log("Voice daemon is not running (no PID file)");
6658
6849
  return;
6659
6850
  }
6660
- const pid = Number.parseInt(readFileSync26(voicePaths.pid, "utf-8").trim(), 10);
6851
+ const pid = Number.parseInt(readFileSync27(voicePaths.pid, "utf-8").trim(), 10);
6661
6852
  try {
6662
6853
  process.kill(pid, "SIGTERM");
6663
6854
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -6670,7 +6861,7 @@ function stop() {
6670
6861
  }
6671
6862
  try {
6672
6863
  const lockFile = getLockFile();
6673
- if (existsSync32(lockFile)) unlinkSync7(lockFile);
6864
+ if (existsSync33(lockFile)) unlinkSync7(lockFile);
6674
6865
  } catch {
6675
6866
  }
6676
6867
  console.log("Voice daemon stopped");
@@ -6689,14 +6880,14 @@ function registerVoice(program2) {
6689
6880
 
6690
6881
  // src/commands/roam/auth.ts
6691
6882
  import { randomBytes } from "crypto";
6692
- import chalk56 from "chalk";
6883
+ import chalk57 from "chalk";
6693
6884
 
6694
6885
  // src/lib/openBrowser.ts
6695
- import { execSync as execSync29 } from "child_process";
6886
+ import { execSync as execSync31 } from "child_process";
6696
6887
  function tryExec(commands) {
6697
6888
  for (const cmd of commands) {
6698
6889
  try {
6699
- execSync29(cmd);
6890
+ execSync31(cmd);
6700
6891
  return true;
6701
6892
  } catch {
6702
6893
  }
@@ -6841,7 +7032,7 @@ async function promptField(name, existing) {
6841
7032
  });
6842
7033
  return value.trim() || existing || "";
6843
7034
  }
6844
- async function promptCredentials(existing) {
7035
+ async function promptCredentials2(existing) {
6845
7036
  const clientId = await promptField("Client ID", existing?.clientId);
6846
7037
  const clientSecret = await promptField(
6847
7038
  "Client Secret",
@@ -6856,7 +7047,7 @@ async function promptCredentials(existing) {
6856
7047
  // src/commands/roam/auth.ts
6857
7048
  async function auth() {
6858
7049
  const config = loadGlobalConfigRaw();
6859
- const { clientId, clientSecret } = await promptCredentials(
7050
+ const { clientId, clientSecret } = await promptCredentials2(
6860
7051
  config.roam
6861
7052
  );
6862
7053
  const existingRoam = config.roam ?? {};
@@ -6864,13 +7055,13 @@ async function auth() {
6864
7055
  saveGlobalConfig(config);
6865
7056
  const state = randomBytes(16).toString("hex");
6866
7057
  console.log(
6867
- chalk56.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
7058
+ chalk57.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
6868
7059
  );
6869
- console.log(chalk56.white("http://localhost:14523/callback\n"));
6870
- console.log(chalk56.blue("Opening browser for authorization..."));
6871
- console.log(chalk56.dim("Waiting for authorization callback..."));
7060
+ console.log(chalk57.white("http://localhost:14523/callback\n"));
7061
+ console.log(chalk57.blue("Opening browser for authorization..."));
7062
+ console.log(chalk57.dim("Waiting for authorization callback..."));
6872
7063
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
6873
- console.log(chalk56.dim("Exchanging code for tokens..."));
7064
+ console.log(chalk57.dim("Exchanging code for tokens..."));
6874
7065
  const tokens = await exchangeToken({
6875
7066
  code,
6876
7067
  clientId,
@@ -6886,7 +7077,7 @@ async function auth() {
6886
7077
  };
6887
7078
  saveGlobalConfig(config);
6888
7079
  console.log(
6889
- chalk56.green("Roam credentials and tokens saved to ~/.assist.yml")
7080
+ chalk57.green("Roam credentials and tokens saved to ~/.assist.yml")
6890
7081
  );
6891
7082
  }
6892
7083
 
@@ -6933,8 +7124,8 @@ function resolveParams(params, cliArgs) {
6933
7124
  }
6934
7125
 
6935
7126
  // src/commands/run/add.ts
6936
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync23 } from "fs";
6937
- import { join as join32 } from "path";
7127
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync24 } from "fs";
7128
+ import { join as join33 } from "path";
6938
7129
  function findAddIndex() {
6939
7130
  const addIndex = process.argv.indexOf("add");
6940
7131
  if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
@@ -6988,16 +7179,16 @@ function saveNewRunConfig(name, command, args) {
6988
7179
  saveConfig(config);
6989
7180
  }
6990
7181
  function createCommandFile(name) {
6991
- const dir = join32(".claude", "commands");
6992
- mkdirSync11(dir, { recursive: true });
7182
+ const dir = join33(".claude", "commands");
7183
+ mkdirSync12(dir, { recursive: true });
6993
7184
  const content = `---
6994
7185
  description: Run ${name}
6995
7186
  ---
6996
7187
 
6997
7188
  Run \`assist run ${name} $ARGUMENTS 2>&1\`.
6998
7189
  `;
6999
- const filePath = join32(dir, `${name}.md`);
7000
- writeFileSync23(filePath, content);
7190
+ const filePath = join33(dir, `${name}.md`);
7191
+ writeFileSync24(filePath, content);
7001
7192
  console.log(`Created command file: ${filePath}`);
7002
7193
  }
7003
7194
  function add2() {
@@ -7074,14 +7265,14 @@ function run2(name, args) {
7074
7265
  }
7075
7266
 
7076
7267
  // src/commands/statusLine.ts
7077
- import chalk57 from "chalk";
7268
+ import chalk58 from "chalk";
7078
7269
  function formatNumber(num) {
7079
7270
  return num.toLocaleString("en-US");
7080
7271
  }
7081
7272
  function colorizePercent(pct) {
7082
7273
  const label2 = `${pct}%`;
7083
- if (pct > 80) return chalk57.red(label2);
7084
- if (pct > 40) return chalk57.yellow(label2);
7274
+ if (pct > 80) return chalk58.red(label2);
7275
+ if (pct > 40) return chalk58.yellow(label2);
7085
7276
  return label2;
7086
7277
  }
7087
7278
  async function statusLine() {
@@ -7107,7 +7298,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
7107
7298
  // src/commands/sync/syncClaudeMd.ts
7108
7299
  import * as fs21 from "fs";
7109
7300
  import * as path31 from "path";
7110
- import chalk58 from "chalk";
7301
+ import chalk59 from "chalk";
7111
7302
  async function syncClaudeMd(claudeDir, targetBase) {
7112
7303
  const source = path31.join(claudeDir, "CLAUDE.md");
7113
7304
  const target = path31.join(targetBase, "CLAUDE.md");
@@ -7116,12 +7307,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
7116
7307
  const targetContent = fs21.readFileSync(target, "utf-8");
7117
7308
  if (sourceContent !== targetContent) {
7118
7309
  console.log(
7119
- chalk58.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
7310
+ chalk59.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
7120
7311
  );
7121
7312
  console.log();
7122
7313
  printDiff(targetContent, sourceContent);
7123
7314
  const confirm = await promptConfirm(
7124
- chalk58.red("Overwrite existing CLAUDE.md?"),
7315
+ chalk59.red("Overwrite existing CLAUDE.md?"),
7125
7316
  false
7126
7317
  );
7127
7318
  if (!confirm) {
@@ -7137,7 +7328,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
7137
7328
  // src/commands/sync/syncSettings.ts
7138
7329
  import * as fs22 from "fs";
7139
7330
  import * as path32 from "path";
7140
- import chalk59 from "chalk";
7331
+ import chalk60 from "chalk";
7141
7332
  async function syncSettings(claudeDir, targetBase, options2) {
7142
7333
  const source = path32.join(claudeDir, "settings.json");
7143
7334
  const target = path32.join(targetBase, "settings.json");
@@ -7153,14 +7344,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
7153
7344
  if (mergedContent !== normalizedTarget) {
7154
7345
  if (!options2?.yes) {
7155
7346
  console.log(
7156
- chalk59.yellow(
7347
+ chalk60.yellow(
7157
7348
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
7158
7349
  )
7159
7350
  );
7160
7351
  console.log();
7161
7352
  printDiff(targetContent, mergedContent);
7162
7353
  const confirm = await promptConfirm(
7163
- chalk59.red("Overwrite existing settings.json?"),
7354
+ chalk60.red("Overwrite existing settings.json?"),
7164
7355
  false
7165
7356
  );
7166
7357
  if (!confirm) {
@@ -7197,7 +7388,7 @@ function syncCommands(claudeDir, targetBase) {
7197
7388
  }
7198
7389
 
7199
7390
  // src/commands/update.ts
7200
- import { execSync as execSync30 } from "child_process";
7391
+ import { execSync as execSync32 } from "child_process";
7201
7392
  import * as path34 from "path";
7202
7393
  function isGlobalNpmInstall(dir) {
7203
7394
  try {
@@ -7205,7 +7396,7 @@ function isGlobalNpmInstall(dir) {
7205
7396
  if (resolved.split(path34.sep).includes("node_modules")) {
7206
7397
  return true;
7207
7398
  }
7208
- const globalPrefix = execSync30("npm prefix -g", { stdio: "pipe" }).toString().trim();
7399
+ const globalPrefix = execSync32("npm prefix -g", { stdio: "pipe" }).toString().trim();
7209
7400
  return resolved.toLowerCase().startsWith(path34.resolve(globalPrefix).toLowerCase());
7210
7401
  } catch {
7211
7402
  return false;
@@ -7216,18 +7407,18 @@ async function update() {
7216
7407
  console.log(`Assist is installed at: ${installDir}`);
7217
7408
  if (isGitRepo(installDir)) {
7218
7409
  console.log("Detected git repo installation, pulling latest...");
7219
- execSync30("git pull", { cwd: installDir, stdio: "inherit" });
7410
+ execSync32("git pull", { cwd: installDir, stdio: "inherit" });
7220
7411
  console.log("Installing dependencies...");
7221
- execSync30("npm i", { cwd: installDir, stdio: "inherit" });
7412
+ execSync32("npm i", { cwd: installDir, stdio: "inherit" });
7222
7413
  console.log("Building...");
7223
- execSync30("npm run build", { cwd: installDir, stdio: "inherit" });
7414
+ execSync32("npm run build", { cwd: installDir, stdio: "inherit" });
7224
7415
  console.log("Syncing commands...");
7225
- execSync30("assist sync", { stdio: "inherit" });
7416
+ execSync32("assist sync", { stdio: "inherit" });
7226
7417
  } else if (isGlobalNpmInstall(installDir)) {
7227
7418
  console.log("Detected global npm installation, updating...");
7228
- execSync30("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
7419
+ execSync32("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
7229
7420
  console.log("Syncing commands...");
7230
- execSync30("assist sync", { stdio: "inherit" });
7421
+ execSync32("assist sync", { stdio: "inherit" });
7231
7422
  } else {
7232
7423
  console.error(
7233
7424
  "Could not determine installation method. Expected a git repo or global npm install."
@@ -7265,6 +7456,7 @@ program.command("notify").description(
7265
7456
  ).action(notify);
7266
7457
  program.command("update").description("Update assist to the latest version and sync commands").action(update);
7267
7458
  registerCliHook(program);
7459
+ registerJira(program);
7268
7460
  registerPrs(program);
7269
7461
  registerRoam(program);
7270
7462
  registerBacklog(program);