@staff0rd/assist 0.107.0 → 0.108.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.107.0",
9
+ version: "0.108.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -40,6 +40,7 @@ var package_default = {
40
40
  commander: "^14.0.2",
41
41
  diff: "^8.0.2",
42
42
  enquirer: "^2.4.1",
43
+ entities: "^7.0.1",
43
44
  "is-wsl": "^3.1.0",
44
45
  minimatch: "^10.1.1",
45
46
  "node-notifier": "^10.0.1",
@@ -156,6 +157,9 @@ var assistConfigSchema = z.strictObject({
156
157
  run: z.array(runConfigSchema).optional(),
157
158
  transcript: transcriptConfigSchema.optional(),
158
159
  cliReadVerbs: z.record(z.string(), z.array(z.string())).optional(),
160
+ news: z.strictObject({
161
+ feeds: z.array(z.string()).default([])
162
+ }).default({ feeds: [] }),
159
163
  voice: z.strictObject({
160
164
  wakeWords: z.array(z.string()).default(DEFAULT_WAKE_WORDS),
161
165
  mic: z.string().optional(),
@@ -2346,15 +2350,63 @@ async function start(id) {
2346
2350
  }
2347
2351
  }
2348
2352
 
2349
- // src/commands/backlog/web/index.ts
2353
+ // src/shared/web.ts
2350
2354
  import { exec } from "child_process";
2351
- import { createServer } from "http";
2352
- import chalk29 from "chalk";
2353
-
2354
- // src/commands/backlog/web/handleRequest.ts
2355
2355
  import { readFileSync as readFileSync12 } from "fs";
2356
+ import {
2357
+ createServer
2358
+ } from "http";
2356
2359
  import { dirname as dirname11, join as join10 } from "path";
2357
2360
  import { fileURLToPath as fileURLToPath3 } from "url";
2361
+ import chalk29 from "chalk";
2362
+ function respondJson(res, status2, data) {
2363
+ res.writeHead(status2, { "Content-Type": "application/json" });
2364
+ res.end(JSON.stringify(data));
2365
+ }
2366
+ function createBundleHandler(importMetaUrl, bundlePath) {
2367
+ const dir = dirname11(fileURLToPath3(importMetaUrl));
2368
+ let cache;
2369
+ return (_req, res) => {
2370
+ if (!cache) {
2371
+ cache = readFileSync12(join10(dir, bundlePath), "utf-8");
2372
+ }
2373
+ res.writeHead(200, { "Content-Type": "application/javascript" });
2374
+ res.end(cache);
2375
+ };
2376
+ }
2377
+ function createHtmlHandler(getHtml3) {
2378
+ return (_req, res) => {
2379
+ res.writeHead(200, { "Content-Type": "text/html" });
2380
+ res.end(getHtml3());
2381
+ };
2382
+ }
2383
+ function parseRoute(req, port) {
2384
+ const url = new URL(req.url ?? "/", `http://localhost:${port}`);
2385
+ return { method: req.method ?? "GET", pathname: url.pathname };
2386
+ }
2387
+ function createRouteHandler(routes3) {
2388
+ return async (req, res, port) => {
2389
+ const { method, pathname } = parseRoute(req, port);
2390
+ const handler = routes3[`${method} ${pathname}`];
2391
+ if (handler) {
2392
+ await handler(req, res);
2393
+ return;
2394
+ }
2395
+ res.writeHead(404);
2396
+ res.end();
2397
+ };
2398
+ }
2399
+ function startWebServer(label2, port, handler) {
2400
+ const url = `http://localhost:${port}`;
2401
+ const server = createServer((req, res) => {
2402
+ handler(req, res, port);
2403
+ });
2404
+ server.listen(port, () => {
2405
+ console.log(chalk29.green(`${label2}: ${url}`));
2406
+ console.log(chalk29.dim("Press Ctrl+C to stop"));
2407
+ exec(`open ${url}`);
2408
+ });
2409
+ }
2358
2410
 
2359
2411
  // src/commands/backlog/web/getHtml.ts
2360
2412
  function getHtml() {
@@ -2379,11 +2431,7 @@ function getHtml() {
2379
2431
  </html>`;
2380
2432
  }
2381
2433
 
2382
- // src/commands/backlog/web/respondJson.ts
2383
- function respondJson(res, status2, data) {
2384
- res.writeHead(status2, { "Content-Type": "application/json" });
2385
- res.end(JSON.stringify(data));
2386
- }
2434
+ // src/commands/backlog/web/parseItemBody.ts
2387
2435
  function readBody(req) {
2388
2436
  return new Promise((resolve6, reject) => {
2389
2437
  let body = "";
@@ -2451,25 +2499,12 @@ async function updateItem(req, res, id) {
2451
2499
  }
2452
2500
 
2453
2501
  // src/commands/backlog/web/handleRequest.ts
2454
- var __dirname4 = dirname11(fileURLToPath3(import.meta.url));
2455
- var bundleCache;
2456
- function serveBundle(_req, res) {
2457
- if (!bundleCache) {
2458
- bundleCache = readFileSync12(
2459
- join10(__dirname4, "commands/backlog/web/bundle.js"),
2460
- "utf-8"
2461
- );
2462
- }
2463
- res.writeHead(200, { "Content-Type": "application/javascript" });
2464
- res.end(bundleCache);
2465
- }
2466
- function serveHtml(_req, res) {
2467
- res.writeHead(200, { "Content-Type": "text/html" });
2468
- res.end(getHtml());
2469
- }
2470
2502
  var routes = {
2471
- "GET /": serveHtml,
2472
- "GET /bundle.js": serveBundle,
2503
+ "GET /": createHtmlHandler(getHtml),
2504
+ "GET /bundle.js": createBundleHandler(
2505
+ import.meta.url,
2506
+ "commands/backlog/web/bundle.js"
2507
+ ),
2473
2508
  "GET /api/items": listItems,
2474
2509
  "POST /api/items": createItem
2475
2510
  };
@@ -2478,17 +2513,11 @@ var itemRoutes = {
2478
2513
  PUT: (req, res, id) => updateItem(req, res, id),
2479
2514
  DELETE: (_req, res, id) => deleteItem(res, id)
2480
2515
  };
2481
- function parseRoute(req, port) {
2482
- const url = new URL(req.url ?? "/", `http://localhost:${port}`);
2483
- return { method: req.method ?? "GET", pathname: url.pathname };
2484
- }
2516
+ var baseHandler = createRouteHandler(routes);
2485
2517
  async function handleRequest(req, res, port) {
2486
- const { method, pathname } = parseRoute(req, port);
2487
- const handler = routes[`${method} ${pathname}`];
2488
- if (handler) {
2489
- await handler(req, res);
2490
- return;
2491
- }
2518
+ const url = new URL(req.url ?? "/", `http://localhost:${port}`);
2519
+ const method = req.method ?? "GET";
2520
+ const pathname = url.pathname;
2492
2521
  const itemMatch = pathname.match(/^\/api\/items\/(\d+)$/);
2493
2522
  if (itemMatch) {
2494
2523
  const itemHandler = itemRoutes[method];
@@ -2497,22 +2526,16 @@ async function handleRequest(req, res, port) {
2497
2526
  return;
2498
2527
  }
2499
2528
  }
2500
- res.writeHead(404);
2501
- res.end();
2529
+ await baseHandler(req, res, port);
2502
2530
  }
2503
2531
 
2504
2532
  // src/commands/backlog/web/index.ts
2505
2533
  async function web(options2) {
2506
- const port = Number.parseInt(options2.port, 10);
2507
- const url = `http://localhost:${port}`;
2508
- const server = createServer((req, res) => {
2509
- handleRequest(req, res, port);
2510
- });
2511
- server.listen(port, () => {
2512
- console.log(chalk29.green(`Backlog web view: ${url}`));
2513
- console.log(chalk29.dim("Press Ctrl+C to stop"));
2514
- exec(`open ${url}`);
2515
- });
2534
+ startWebServer(
2535
+ "Backlog web view",
2536
+ Number.parseInt(options2.port, 10),
2537
+ handleRequest
2538
+ );
2516
2539
  }
2517
2540
 
2518
2541
  // src/commands/registerBacklog.ts
@@ -2613,9 +2636,9 @@ import { existsSync as existsSync16, readFileSync as readFileSync13, writeFileSy
2613
2636
  import { dirname as dirname12, resolve as resolve2 } from "path";
2614
2637
  import { fileURLToPath as fileURLToPath4 } from "url";
2615
2638
  var __filename2 = fileURLToPath4(import.meta.url);
2616
- var __dirname5 = dirname12(__filename2);
2639
+ var __dirname4 = dirname12(__filename2);
2617
2640
  function getCliReadsPath() {
2618
- return resolve2(__dirname5, "..", "assist.cli-reads");
2641
+ return resolve2(__dirname4, "..", "assist.cli-reads");
2619
2642
  }
2620
2643
  var cachedLines;
2621
2644
  function getCliReadsLines() {
@@ -2834,9 +2857,9 @@ import { execSync as execSync13 } from "child_process";
2834
2857
  import { dirname as dirname13, resolve as resolve4 } from "path";
2835
2858
  import { fileURLToPath as fileURLToPath5 } from "url";
2836
2859
  var __filename3 = fileURLToPath5(import.meta.url);
2837
- var __dirname6 = dirname13(__filename3);
2860
+ var __dirname5 = dirname13(__filename3);
2838
2861
  function getInstallDir() {
2839
- return resolve4(__dirname6, "..");
2862
+ return resolve4(__dirname5, "..");
2840
2863
  }
2841
2864
  function isGitRepo(dir) {
2842
2865
  try {
@@ -4614,6 +4637,230 @@ function registerNetframework(program2) {
4614
4637
  cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
4615
4638
  }
4616
4639
 
4640
+ // src/commands/news/add/index.ts
4641
+ import chalk49 from "chalk";
4642
+ import enquirer5 from "enquirer";
4643
+ async function add2(url) {
4644
+ if (!url) {
4645
+ const response = await enquirer5.prompt({
4646
+ type: "input",
4647
+ name: "url",
4648
+ message: "RSS feed URL:",
4649
+ validate: (value) => {
4650
+ try {
4651
+ new URL(value);
4652
+ return true;
4653
+ } catch {
4654
+ return "Please enter a valid URL";
4655
+ }
4656
+ }
4657
+ });
4658
+ url = response.url;
4659
+ }
4660
+ const config = loadGlobalConfigRaw();
4661
+ const news = config.news ?? {};
4662
+ const feeds = news.feeds ?? [];
4663
+ if (feeds.includes(url)) {
4664
+ console.log(chalk49.yellow("Feed already exists in config"));
4665
+ return;
4666
+ }
4667
+ feeds.push(url);
4668
+ config.news = { ...news, feeds };
4669
+ saveGlobalConfig(config);
4670
+ console.log(chalk49.green(`Added feed: ${url}`));
4671
+ }
4672
+
4673
+ // src/commands/news/web/handleRequest.ts
4674
+ import chalk50 from "chalk";
4675
+
4676
+ // src/commands/news/web/shared.ts
4677
+ import { decodeHTML } from "entities";
4678
+ function extractText(xml, tag) {
4679
+ const cdataMatch = xml.match(
4680
+ new RegExp(`<${tag}>\\s*<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>\\s*</${tag}>`)
4681
+ );
4682
+ if (cdataMatch) return cdataMatch[1].trim();
4683
+ const match = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`));
4684
+ return match ? match[1].trim() : "";
4685
+ }
4686
+ function extractLink(itemXml) {
4687
+ const atomLink = itemXml.match(
4688
+ /<link[^>]*rel=["']alternate["'][^>]*href=["']([^"']+)["']/
4689
+ );
4690
+ if (atomLink) return atomLink[1];
4691
+ const atomLink2 = itemXml.match(/<link[^>]*href=["']([^"']+)["']/);
4692
+ if (atomLink2) return atomLink2[1];
4693
+ return extractText(itemXml, "link");
4694
+ }
4695
+ function parseDate(dateStr) {
4696
+ if (!dateStr) return (/* @__PURE__ */ new Date(0)).toISOString();
4697
+ try {
4698
+ return new Date(dateStr).toISOString();
4699
+ } catch {
4700
+ return (/* @__PURE__ */ new Date(0)).toISOString();
4701
+ }
4702
+ }
4703
+ function stripHtml(html) {
4704
+ const decoded = decodeHTML(html);
4705
+ const stripped = decoded.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
4706
+ return decodeHTML(stripped);
4707
+ }
4708
+ function matchAll(xml, regex) {
4709
+ const results = [];
4710
+ for (const m of xml.matchAll(regex)) {
4711
+ results.push(m[1]);
4712
+ }
4713
+ return results;
4714
+ }
4715
+ var MAX_EXCERPT = 500;
4716
+ function excerpt(xml, ...tags) {
4717
+ for (const tag of tags) {
4718
+ const raw = extractText(xml, tag);
4719
+ if (!raw) continue;
4720
+ const text = stripHtml(raw);
4721
+ if (text.length <= MAX_EXCERPT) return text;
4722
+ return `${text.slice(0, MAX_EXCERPT)}\u2026`;
4723
+ }
4724
+ return "";
4725
+ }
4726
+
4727
+ // src/commands/news/web/parseFeed.ts
4728
+ function parseRss(xml, feedOrigin) {
4729
+ const feedTitle = extractText(xml, "title");
4730
+ return matchAll(xml, /<item[\s>]([\s\S]*?)<\/item>/g).map((itemXml) => ({
4731
+ title: extractText(itemXml, "title"),
4732
+ link: extractLink(itemXml),
4733
+ pubDate: parseDate(
4734
+ extractText(itemXml, "pubDate") || extractText(itemXml, "dc:date")
4735
+ ),
4736
+ feedTitle,
4737
+ feedOrigin,
4738
+ excerpt: excerpt(itemXml, "description", "content:encoded")
4739
+ }));
4740
+ }
4741
+ function parseAtom(xml, feedOrigin) {
4742
+ const feedTitle = extractText(xml, "title");
4743
+ return matchAll(xml, /<entry[\s>]([\s\S]*?)<\/entry>/g).map((entryXml) => ({
4744
+ title: extractText(entryXml, "title"),
4745
+ link: extractLink(entryXml),
4746
+ pubDate: parseDate(
4747
+ extractText(entryXml, "published") || extractText(entryXml, "updated")
4748
+ ),
4749
+ feedTitle,
4750
+ feedOrigin,
4751
+ excerpt: excerpt(entryXml, "summary", "content")
4752
+ }));
4753
+ }
4754
+ function parseFeed(xml, feedOrigin) {
4755
+ if (xml.includes("<feed")) return parseAtom(xml, feedOrigin);
4756
+ return parseRss(xml, feedOrigin);
4757
+ }
4758
+
4759
+ // src/commands/news/web/fetchFeeds.ts
4760
+ async function fetchFeeds(urls, onProgress) {
4761
+ let done2 = 0;
4762
+ const results = await Promise.allSettled(
4763
+ urls.map(async (url) => {
4764
+ const origin = new URL(url).origin;
4765
+ const res = await fetch(url);
4766
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
4767
+ const items2 = parseFeed(await res.text(), origin);
4768
+ done2++;
4769
+ onProgress?.(done2, urls.length);
4770
+ return items2;
4771
+ })
4772
+ );
4773
+ const items = [];
4774
+ for (const result of results) {
4775
+ if (result.status === "fulfilled") {
4776
+ items.push(...result.value);
4777
+ }
4778
+ }
4779
+ items.sort(
4780
+ (a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()
4781
+ );
4782
+ return items;
4783
+ }
4784
+
4785
+ // src/commands/news/web/getHtml.ts
4786
+ function getHtml2() {
4787
+ return `<!DOCTYPE html>
4788
+ <html lang="en" class="dark">
4789
+ <head>
4790
+ <meta charset="UTF-8">
4791
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4792
+ <title>News</title>
4793
+ <script src="https://cdn.tailwindcss.com"></script>
4794
+ <script>tailwind.config={darkMode:'class'}</script>
4795
+ </head>
4796
+ <body class="font-[-apple-system,BlinkMacSystemFont,'Segoe_UI',Roboto,sans-serif] bg-gray-950 text-gray-200 leading-normal">
4797
+ <div class="max-w-3xl mx-auto px-4 py-6" id="app"></div>
4798
+ <script src="/bundle.js"></script>
4799
+ </body>
4800
+ </html>`;
4801
+ }
4802
+
4803
+ // src/commands/news/web/handleRequest.ts
4804
+ var cachedItems;
4805
+ var prefetchPromise;
4806
+ function prefetch() {
4807
+ const config = loadConfig();
4808
+ const total = config.news.feeds.length;
4809
+ if (total === 0) return;
4810
+ process.stdout.write(chalk50.dim(`Fetching ${total} feed(s)\u2026 `));
4811
+ prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
4812
+ const width = 20;
4813
+ const filled = Math.round(done2 / t * width);
4814
+ const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
4815
+ process.stdout.write(
4816
+ `\r${chalk50.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
4817
+ );
4818
+ }).then((items) => {
4819
+ process.stdout.write(
4820
+ `\r${chalk50.green(`Fetched ${items.length} items from ${total} feed(s)`)}
4821
+ `
4822
+ );
4823
+ cachedItems = items;
4824
+ return items;
4825
+ });
4826
+ }
4827
+ async function listItems2(_req, res) {
4828
+ if (!cachedItems && prefetchPromise) {
4829
+ await prefetchPromise;
4830
+ }
4831
+ if (!cachedItems) {
4832
+ const config = loadConfig();
4833
+ cachedItems = await fetchFeeds(config.news.feeds);
4834
+ }
4835
+ respondJson(res, 200, cachedItems);
4836
+ }
4837
+ var routes2 = {
4838
+ "GET /": createHtmlHandler(getHtml2),
4839
+ "GET /bundle.js": createBundleHandler(
4840
+ import.meta.url,
4841
+ "commands/news/web/bundle.js"
4842
+ ),
4843
+ "GET /api/items": listItems2
4844
+ };
4845
+ var handleRequest2 = createRouteHandler(routes2);
4846
+
4847
+ // src/commands/news/web/index.ts
4848
+ async function web2(options2) {
4849
+ prefetch();
4850
+ startWebServer(
4851
+ "News web view",
4852
+ Number.parseInt(options2.port, 10),
4853
+ handleRequest2
4854
+ );
4855
+ }
4856
+
4857
+ // src/commands/registerNews.ts
4858
+ function registerNews(program2) {
4859
+ const newsCommand = program2.command("news").description("View latest news from configured RSS feeds").action(() => web2({ port: "3001" }));
4860
+ newsCommand.command("add").description("Add an RSS feed URL to the config").argument("<url>", "RSS feed URL").action(add2);
4861
+ newsCommand.command("web").description("Start a web view of the news feeds").option("-p, --port <number>", "Port to listen on", "3001").action(web2);
4862
+ }
4863
+
4617
4864
  // src/commands/prs/comment.ts
4618
4865
  import { spawnSync as spawnSync2 } from "child_process";
4619
4866
  import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync17 } from "fs";
@@ -4930,20 +5177,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
4930
5177
  }
4931
5178
 
4932
5179
  // src/commands/prs/listComments/printComments.ts
4933
- import chalk49 from "chalk";
5180
+ import chalk51 from "chalk";
4934
5181
  function formatForHuman(comment2) {
4935
5182
  if (comment2.type === "review") {
4936
- const stateColor = comment2.state === "APPROVED" ? chalk49.green : comment2.state === "CHANGES_REQUESTED" ? chalk49.red : chalk49.yellow;
5183
+ const stateColor = comment2.state === "APPROVED" ? chalk51.green : comment2.state === "CHANGES_REQUESTED" ? chalk51.red : chalk51.yellow;
4937
5184
  return [
4938
- `${chalk49.cyan("Review")} by ${chalk49.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
5185
+ `${chalk51.cyan("Review")} by ${chalk51.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
4939
5186
  comment2.body,
4940
5187
  ""
4941
5188
  ].join("\n");
4942
5189
  }
4943
5190
  const location = comment2.line ? `:${comment2.line}` : "";
4944
5191
  return [
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")),
5192
+ `${chalk51.cyan("Line comment")} by ${chalk51.bold(comment2.user)} on ${chalk51.dim(`${comment2.path}${location}`)}`,
5193
+ chalk51.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
4947
5194
  comment2.body,
4948
5195
  ""
4949
5196
  ].join("\n");
@@ -5030,16 +5277,16 @@ async function listComments() {
5030
5277
  import { execSync as execSync27 } from "child_process";
5031
5278
 
5032
5279
  // src/commands/prs/prs/displayPaginated/index.ts
5033
- import enquirer5 from "enquirer";
5280
+ import enquirer6 from "enquirer";
5034
5281
 
5035
5282
  // src/commands/prs/prs/displayPaginated/printPr.ts
5036
- import chalk50 from "chalk";
5283
+ import chalk52 from "chalk";
5037
5284
  var STATUS_MAP = {
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
5285
+ MERGED: (pr) => pr.mergedAt ? { label: chalk52.magenta("merged"), date: pr.mergedAt } : null,
5286
+ CLOSED: (pr) => pr.closedAt ? { label: chalk52.red("closed"), date: pr.closedAt } : null
5040
5287
  };
5041
5288
  function defaultStatus(pr) {
5042
- return { label: chalk50.green("opened"), date: pr.createdAt };
5289
+ return { label: chalk52.green("opened"), date: pr.createdAt };
5043
5290
  }
5044
5291
  function getStatus2(pr) {
5045
5292
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -5048,11 +5295,11 @@ function formatDate(dateStr) {
5048
5295
  return new Date(dateStr).toISOString().split("T")[0];
5049
5296
  }
5050
5297
  function formatPrHeader(pr, status2) {
5051
- return `${chalk50.cyan(`#${pr.number}`)} ${pr.title} ${chalk50.dim(`(${pr.author.login},`)} ${status2.label} ${chalk50.dim(`${formatDate(status2.date)})`)}`;
5298
+ return `${chalk52.cyan(`#${pr.number}`)} ${pr.title} ${chalk52.dim(`(${pr.author.login},`)} ${status2.label} ${chalk52.dim(`${formatDate(status2.date)})`)}`;
5052
5299
  }
5053
5300
  function logPrDetails(pr) {
5054
5301
  console.log(
5055
- chalk50.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
5302
+ chalk52.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
5056
5303
  );
5057
5304
  console.log();
5058
5305
  }
@@ -5100,7 +5347,7 @@ function parseAction(action) {
5100
5347
  }
5101
5348
  async function promptNavigation(currentPage, totalPages) {
5102
5349
  const choices = buildNavChoices(currentPage, totalPages);
5103
- const { action } = await enquirer5.prompt({
5350
+ const { action } = await enquirer6.prompt({
5104
5351
  type: "select",
5105
5352
  name: "action",
5106
5353
  message: "Navigate",
@@ -5222,7 +5469,7 @@ import { spawn as spawn3 } from "child_process";
5222
5469
  import * as path21 from "path";
5223
5470
 
5224
5471
  // src/commands/refactor/logViolations.ts
5225
- import chalk51 from "chalk";
5472
+ import chalk53 from "chalk";
5226
5473
  var DEFAULT_MAX_LINES = 100;
5227
5474
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
5228
5475
  if (violations.length === 0) {
@@ -5231,43 +5478,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
5231
5478
  }
5232
5479
  return;
5233
5480
  }
5234
- console.error(chalk51.red(`
5481
+ console.error(chalk53.red(`
5235
5482
  Refactor check failed:
5236
5483
  `));
5237
- console.error(chalk51.red(` The following files exceed ${maxLines} lines:
5484
+ console.error(chalk53.red(` The following files exceed ${maxLines} lines:
5238
5485
  `));
5239
5486
  for (const violation of violations) {
5240
- console.error(chalk51.red(` ${violation.file} (${violation.lines} lines)`));
5487
+ console.error(chalk53.red(` ${violation.file} (${violation.lines} lines)`));
5241
5488
  }
5242
5489
  console.error(
5243
- chalk51.yellow(
5490
+ chalk53.yellow(
5244
5491
  `
5245
5492
  Each file needs to be sensibly refactored, or if there is no sensible
5246
5493
  way to refactor it, ignore it with:
5247
5494
  `
5248
5495
  )
5249
5496
  );
5250
- console.error(chalk51.gray(` assist refactor ignore <file>
5497
+ console.error(chalk53.gray(` assist refactor ignore <file>
5251
5498
  `));
5252
5499
  if (process.env.CLAUDECODE) {
5253
- console.error(chalk51.cyan(`
5500
+ console.error(chalk53.cyan(`
5254
5501
  ## Extracting Code to New Files
5255
5502
  `));
5256
5503
  console.error(
5257
- chalk51.cyan(
5504
+ chalk53.cyan(
5258
5505
  ` When extracting logic from one file to another, consider where the extracted code belongs:
5259
5506
  `
5260
5507
  )
5261
5508
  );
5262
5509
  console.error(
5263
- chalk51.cyan(
5510
+ chalk53.cyan(
5264
5511
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
5265
5512
  original file's domain, create a new folder containing both the original and extracted files.
5266
5513
  `
5267
5514
  )
5268
5515
  );
5269
5516
  console.error(
5270
- chalk51.cyan(
5517
+ chalk53.cyan(
5271
5518
  ` 2. Share common utilities: If the extracted code can be reused across multiple
5272
5519
  domains, move it to a common/shared folder.
5273
5520
  `
@@ -5423,11 +5670,11 @@ async function check(pattern2, options2) {
5423
5670
 
5424
5671
  // src/commands/refactor/ignore.ts
5425
5672
  import fs16 from "fs";
5426
- import chalk52 from "chalk";
5673
+ import chalk54 from "chalk";
5427
5674
  var REFACTOR_YML_PATH2 = "refactor.yml";
5428
5675
  function ignore(file) {
5429
5676
  if (!fs16.existsSync(file)) {
5430
- console.error(chalk52.red(`Error: File does not exist: ${file}`));
5677
+ console.error(chalk54.red(`Error: File does not exist: ${file}`));
5431
5678
  process.exit(1);
5432
5679
  }
5433
5680
  const content = fs16.readFileSync(file, "utf-8");
@@ -5443,7 +5690,7 @@ function ignore(file) {
5443
5690
  fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
5444
5691
  }
5445
5692
  console.log(
5446
- chalk52.green(
5693
+ chalk54.green(
5447
5694
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
5448
5695
  )
5449
5696
  );
@@ -5451,7 +5698,7 @@ function ignore(file) {
5451
5698
 
5452
5699
  // src/commands/refactor/restructure/index.ts
5453
5700
  import path30 from "path";
5454
- import chalk55 from "chalk";
5701
+ import chalk57 from "chalk";
5455
5702
 
5456
5703
  // src/commands/refactor/restructure/buildImportGraph/index.ts
5457
5704
  import path22 from "path";
@@ -5694,50 +5941,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
5694
5941
 
5695
5942
  // src/commands/refactor/restructure/displayPlan.ts
5696
5943
  import path26 from "path";
5697
- import chalk53 from "chalk";
5944
+ import chalk55 from "chalk";
5698
5945
  function relPath(filePath) {
5699
5946
  return path26.relative(process.cwd(), filePath);
5700
5947
  }
5701
5948
  function displayMoves(plan) {
5702
5949
  if (plan.moves.length === 0) return;
5703
- console.log(chalk53.bold("\nFile moves:"));
5950
+ console.log(chalk55.bold("\nFile moves:"));
5704
5951
  for (const move of plan.moves) {
5705
5952
  console.log(
5706
- ` ${chalk53.red(relPath(move.from))} \u2192 ${chalk53.green(relPath(move.to))}`
5953
+ ` ${chalk55.red(relPath(move.from))} \u2192 ${chalk55.green(relPath(move.to))}`
5707
5954
  );
5708
- console.log(chalk53.dim(` ${move.reason}`));
5955
+ console.log(chalk55.dim(` ${move.reason}`));
5709
5956
  }
5710
5957
  }
5711
5958
  function displayRewrites(rewrites) {
5712
5959
  if (rewrites.length === 0) return;
5713
5960
  const affectedFiles = new Set(rewrites.map((r) => r.file));
5714
- console.log(chalk53.bold(`
5961
+ console.log(chalk55.bold(`
5715
5962
  Import rewrites (${affectedFiles.size} files):`));
5716
5963
  for (const file of affectedFiles) {
5717
- console.log(` ${chalk53.cyan(relPath(file))}:`);
5964
+ console.log(` ${chalk55.cyan(relPath(file))}:`);
5718
5965
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
5719
5966
  (r) => r.file === file
5720
5967
  )) {
5721
5968
  console.log(
5722
- ` ${chalk53.red(`"${oldSpecifier}"`)} \u2192 ${chalk53.green(`"${newSpecifier}"`)}`
5969
+ ` ${chalk55.red(`"${oldSpecifier}"`)} \u2192 ${chalk55.green(`"${newSpecifier}"`)}`
5723
5970
  );
5724
5971
  }
5725
5972
  }
5726
5973
  }
5727
5974
  function displayPlan(plan) {
5728
5975
  if (plan.warnings.length > 0) {
5729
- console.log(chalk53.yellow("\nWarnings:"));
5730
- for (const w of plan.warnings) console.log(chalk53.yellow(` ${w}`));
5976
+ console.log(chalk55.yellow("\nWarnings:"));
5977
+ for (const w of plan.warnings) console.log(chalk55.yellow(` ${w}`));
5731
5978
  }
5732
5979
  if (plan.newDirectories.length > 0) {
5733
- console.log(chalk53.bold("\nNew directories:"));
5980
+ console.log(chalk55.bold("\nNew directories:"));
5734
5981
  for (const dir of plan.newDirectories)
5735
- console.log(chalk53.green(` ${dir}/`));
5982
+ console.log(chalk55.green(` ${dir}/`));
5736
5983
  }
5737
5984
  displayMoves(plan);
5738
5985
  displayRewrites(plan.rewrites);
5739
5986
  console.log(
5740
- chalk53.dim(
5987
+ chalk55.dim(
5741
5988
  `
5742
5989
  Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
5743
5990
  )
@@ -5747,18 +5994,18 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
5747
5994
  // src/commands/refactor/restructure/executePlan.ts
5748
5995
  import fs18 from "fs";
5749
5996
  import path27 from "path";
5750
- import chalk54 from "chalk";
5997
+ import chalk56 from "chalk";
5751
5998
  function executePlan(plan) {
5752
5999
  const updatedContents = applyRewrites(plan.rewrites);
5753
6000
  for (const [file, content] of updatedContents) {
5754
6001
  fs18.writeFileSync(file, content, "utf-8");
5755
6002
  console.log(
5756
- chalk54.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
6003
+ chalk56.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
5757
6004
  );
5758
6005
  }
5759
6006
  for (const dir of plan.newDirectories) {
5760
6007
  fs18.mkdirSync(dir, { recursive: true });
5761
- console.log(chalk54.green(` Created ${path27.relative(process.cwd(), dir)}/`));
6008
+ console.log(chalk56.green(` Created ${path27.relative(process.cwd(), dir)}/`));
5762
6009
  }
5763
6010
  for (const move of plan.moves) {
5764
6011
  const targetDir = path27.dirname(move.to);
@@ -5767,7 +6014,7 @@ function executePlan(plan) {
5767
6014
  }
5768
6015
  fs18.renameSync(move.from, move.to);
5769
6016
  console.log(
5770
- chalk54.white(
6017
+ chalk56.white(
5771
6018
  ` Moved ${path27.relative(process.cwd(), move.from)} \u2192 ${path27.relative(process.cwd(), move.to)}`
5772
6019
  )
5773
6020
  );
@@ -5782,7 +6029,7 @@ function removeEmptyDirectories(dirs) {
5782
6029
  if (entries.length === 0) {
5783
6030
  fs18.rmdirSync(dir);
5784
6031
  console.log(
5785
- chalk54.dim(
6032
+ chalk56.dim(
5786
6033
  ` Removed empty directory ${path27.relative(process.cwd(), dir)}`
5787
6034
  )
5788
6035
  );
@@ -5913,22 +6160,22 @@ async function restructure(pattern2, options2 = {}) {
5913
6160
  const targetPattern = pattern2 ?? "src";
5914
6161
  const files = findSourceFiles2(targetPattern);
5915
6162
  if (files.length === 0) {
5916
- console.log(chalk55.yellow("No files found matching pattern"));
6163
+ console.log(chalk57.yellow("No files found matching pattern"));
5917
6164
  return;
5918
6165
  }
5919
6166
  const tsConfigPath = path30.resolve("tsconfig.json");
5920
6167
  const plan = buildPlan(files, tsConfigPath);
5921
6168
  if (plan.moves.length === 0) {
5922
- console.log(chalk55.green("No restructuring needed"));
6169
+ console.log(chalk57.green("No restructuring needed"));
5923
6170
  return;
5924
6171
  }
5925
6172
  displayPlan(plan);
5926
6173
  if (options2.apply) {
5927
- console.log(chalk55.bold("\nApplying changes..."));
6174
+ console.log(chalk57.bold("\nApplying changes..."));
5928
6175
  executePlan(plan);
5929
- console.log(chalk55.green("\nRestructuring complete"));
6176
+ console.log(chalk57.green("\nRestructuring complete"));
5930
6177
  } else {
5931
- console.log(chalk55.dim("\nDry run. Use --apply to execute."));
6178
+ console.log(chalk57.dim("\nDry run. Use --apply to execute."));
5932
6179
  }
5933
6180
  }
5934
6181
 
@@ -6471,14 +6718,14 @@ import {
6471
6718
  import { dirname as dirname17, join as join26 } from "path";
6472
6719
 
6473
6720
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
6474
- import chalk56 from "chalk";
6721
+ import chalk58 from "chalk";
6475
6722
  var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
6476
6723
  function validateStagedContent(filename, content) {
6477
6724
  const firstLine = content.split("\n")[0];
6478
6725
  const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
6479
6726
  if (!match) {
6480
6727
  console.error(
6481
- chalk56.red(
6728
+ chalk58.red(
6482
6729
  `Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
6483
6730
  )
6484
6731
  );
@@ -6487,7 +6734,7 @@ function validateStagedContent(filename, content) {
6487
6734
  const contentAfterLink = content.slice(firstLine.length).trim();
6488
6735
  if (!contentAfterLink) {
6489
6736
  console.error(
6490
- chalk56.red(
6737
+ chalk58.red(
6491
6738
  `Staged file ${filename} has no summary content after the transcript link.`
6492
6739
  )
6493
6740
  );
@@ -6624,7 +6871,7 @@ import { join as join29 } from "path";
6624
6871
  import { homedir as homedir7 } from "os";
6625
6872
  import { dirname as dirname19, join as join28 } from "path";
6626
6873
  import { fileURLToPath as fileURLToPath6 } from "url";
6627
- var __dirname7 = dirname19(fileURLToPath6(import.meta.url));
6874
+ var __dirname6 = dirname19(fileURLToPath6(import.meta.url));
6628
6875
  var VOICE_DIR = join28(homedir7(), ".assist", "voice");
6629
6876
  var voicePaths = {
6630
6877
  dir: VOICE_DIR,
@@ -6634,7 +6881,7 @@ var voicePaths = {
6634
6881
  lock: join28(VOICE_DIR, "voice.lock")
6635
6882
  };
6636
6883
  function getPythonDir() {
6637
- return join28(__dirname7, "commands", "voice", "python");
6884
+ return join28(__dirname6, "commands", "voice", "python");
6638
6885
  }
6639
6886
  function getVenvPython() {
6640
6887
  return process.platform === "win32" ? join28(voicePaths.venv, "Scripts", "python.exe") : join28(voicePaths.venv, "bin", "python");
@@ -6880,7 +7127,7 @@ function registerVoice(program2) {
6880
7127
 
6881
7128
  // src/commands/roam/auth.ts
6882
7129
  import { randomBytes } from "crypto";
6883
- import chalk57 from "chalk";
7130
+ import chalk59 from "chalk";
6884
7131
 
6885
7132
  // src/lib/openBrowser.ts
6886
7133
  import { execSync as execSync31 } from "child_process";
@@ -7015,7 +7262,7 @@ async function exchangeToken(params) {
7015
7262
  }
7016
7263
 
7017
7264
  // src/commands/roam/promptCredentials.ts
7018
- import enquirer6 from "enquirer";
7265
+ import enquirer7 from "enquirer";
7019
7266
  function censor(value) {
7020
7267
  const visible = value.slice(-4);
7021
7268
  return `${"*".repeat(value.length - 4)}${visible}`;
@@ -7024,7 +7271,7 @@ function label(name, existing) {
7024
7271
  return existing ? `${name} (${censor(existing)})` : name;
7025
7272
  }
7026
7273
  async function promptField(name, existing) {
7027
- const { value } = await enquirer6.prompt({
7274
+ const { value } = await enquirer7.prompt({
7028
7275
  type: "input",
7029
7276
  name: "value",
7030
7277
  message: `${label(name, existing)}:`,
@@ -7055,13 +7302,13 @@ async function auth() {
7055
7302
  saveGlobalConfig(config);
7056
7303
  const state = randomBytes(16).toString("hex");
7057
7304
  console.log(
7058
- chalk57.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
7305
+ chalk59.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
7059
7306
  );
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..."));
7307
+ console.log(chalk59.white("http://localhost:14523/callback\n"));
7308
+ console.log(chalk59.blue("Opening browser for authorization..."));
7309
+ console.log(chalk59.dim("Waiting for authorization callback..."));
7063
7310
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
7064
- console.log(chalk57.dim("Exchanging code for tokens..."));
7311
+ console.log(chalk59.dim("Exchanging code for tokens..."));
7065
7312
  const tokens = await exchangeToken({
7066
7313
  code,
7067
7314
  clientId,
@@ -7077,7 +7324,7 @@ async function auth() {
7077
7324
  };
7078
7325
  saveGlobalConfig(config);
7079
7326
  console.log(
7080
- chalk57.green("Roam credentials and tokens saved to ~/.assist.yml")
7327
+ chalk59.green("Roam credentials and tokens saved to ~/.assist.yml")
7081
7328
  );
7082
7329
  }
7083
7330
 
@@ -7191,7 +7438,7 @@ Run \`assist run ${name} $ARGUMENTS 2>&1\`.
7191
7438
  writeFileSync24(filePath, content);
7192
7439
  console.log(`Created command file: ${filePath}`);
7193
7440
  }
7194
- function add2() {
7441
+ function add3() {
7195
7442
  const { name, command, args } = requireParsedArgs();
7196
7443
  saveNewRunConfig(name, command, args);
7197
7444
  createCommandFile(name);
@@ -7265,14 +7512,14 @@ function run2(name, args) {
7265
7512
  }
7266
7513
 
7267
7514
  // src/commands/statusLine.ts
7268
- import chalk58 from "chalk";
7515
+ import chalk60 from "chalk";
7269
7516
  function formatNumber(num) {
7270
7517
  return num.toLocaleString("en-US");
7271
7518
  }
7272
7519
  function colorizePercent(pct) {
7273
7520
  const label2 = `${pct}%`;
7274
- if (pct > 80) return chalk58.red(label2);
7275
- if (pct > 40) return chalk58.yellow(label2);
7521
+ if (pct > 80) return chalk60.red(label2);
7522
+ if (pct > 40) return chalk60.yellow(label2);
7276
7523
  return label2;
7277
7524
  }
7278
7525
  async function statusLine() {
@@ -7298,7 +7545,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
7298
7545
  // src/commands/sync/syncClaudeMd.ts
7299
7546
  import * as fs21 from "fs";
7300
7547
  import * as path31 from "path";
7301
- import chalk59 from "chalk";
7548
+ import chalk61 from "chalk";
7302
7549
  async function syncClaudeMd(claudeDir, targetBase) {
7303
7550
  const source = path31.join(claudeDir, "CLAUDE.md");
7304
7551
  const target = path31.join(targetBase, "CLAUDE.md");
@@ -7307,12 +7554,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
7307
7554
  const targetContent = fs21.readFileSync(target, "utf-8");
7308
7555
  if (sourceContent !== targetContent) {
7309
7556
  console.log(
7310
- chalk59.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
7557
+ chalk61.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
7311
7558
  );
7312
7559
  console.log();
7313
7560
  printDiff(targetContent, sourceContent);
7314
7561
  const confirm = await promptConfirm(
7315
- chalk59.red("Overwrite existing CLAUDE.md?"),
7562
+ chalk61.red("Overwrite existing CLAUDE.md?"),
7316
7563
  false
7317
7564
  );
7318
7565
  if (!confirm) {
@@ -7328,7 +7575,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
7328
7575
  // src/commands/sync/syncSettings.ts
7329
7576
  import * as fs22 from "fs";
7330
7577
  import * as path32 from "path";
7331
- import chalk60 from "chalk";
7578
+ import chalk62 from "chalk";
7332
7579
  async function syncSettings(claudeDir, targetBase, options2) {
7333
7580
  const source = path32.join(claudeDir, "settings.json");
7334
7581
  const target = path32.join(targetBase, "settings.json");
@@ -7344,14 +7591,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
7344
7591
  if (mergedContent !== normalizedTarget) {
7345
7592
  if (!options2?.yes) {
7346
7593
  console.log(
7347
- chalk60.yellow(
7594
+ chalk62.yellow(
7348
7595
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
7349
7596
  )
7350
7597
  );
7351
7598
  console.log();
7352
7599
  printDiff(targetContent, mergedContent);
7353
7600
  const confirm = await promptConfirm(
7354
- chalk60.red("Overwrite existing settings.json?"),
7601
+ chalk62.red("Overwrite existing settings.json?"),
7355
7602
  false
7356
7603
  );
7357
7604
  if (!confirm) {
@@ -7367,9 +7614,9 @@ async function syncSettings(claudeDir, targetBase, options2) {
7367
7614
 
7368
7615
  // src/commands/sync.ts
7369
7616
  var __filename4 = fileURLToPath7(import.meta.url);
7370
- var __dirname8 = path33.dirname(__filename4);
7617
+ var __dirname7 = path33.dirname(__filename4);
7371
7618
  async function sync(options2) {
7372
- const claudeDir = path33.join(__dirname8, "..", "claude");
7619
+ const claudeDir = path33.join(__dirname7, "..", "claude");
7373
7620
  const targetBase = path33.join(os.homedir(), ".claude");
7374
7621
  syncCommands(claudeDir, targetBase);
7375
7622
  await syncSettings(claudeDir, targetBase, { yes: options2?.yes });
@@ -7432,7 +7679,7 @@ var program = new Command();
7432
7679
  program.name("assist").description("CLI application").version(package_default.version);
7433
7680
  program.command("sync").description("Copy command files to ~/.claude/commands").option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
7434
7681
  program.command("init").description("Initialize VS Code and verify configurations").action(init4);
7435
- program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <files...> <message>").action(commit);
7682
+ program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <message> [files...]").action(commit);
7436
7683
  var configCommand = program.command("config").description("View and modify assist.yml configuration");
7437
7684
  configCommand.command("set <key> <value>").description("Set a config value (e.g. commit.push true)").action(configSet);
7438
7685
  configCommand.command("get <key>").description("Get a config value").action(configGet);
@@ -7444,7 +7691,7 @@ runCommand.command("list").description("List configured run commands").action(li
7444
7691
  runCommand.command("add").description("Add a new run configuration to assist.yml").argument("<name>", "Name for the run configuration").argument("<command>", "Command to execute").argument("[args...]", "Static args to pass to the command").addHelpText(
7445
7692
  "after",
7446
7693
  '\nPositional params can be added to the config manually:\n params:\n - name: env # assist run deploy prod \u2192 appends "prod"\n required: true\n - name: tag\n default: latest'
7447
- ).allowUnknownOption().allowExcessArguments().action(() => add2());
7694
+ ).allowUnknownOption().allowExcessArguments().action(() => add3());
7448
7695
  registerNew(program);
7449
7696
  var lintCommand = program.command("lint").description("Run lint checks for conventions not enforced by biomejs").action(lint);
7450
7697
  lintCommand.command("init").description("Initialize Biome with standard linter config").action(init);
@@ -7466,6 +7713,7 @@ registerDevlog(program);
7466
7713
  registerDeploy(program);
7467
7714
  registerComplexity(program);
7468
7715
  registerNetframework(program);
7716
+ registerNews(program);
7469
7717
  registerTranscript(program);
7470
7718
  registerVoice(program);
7471
7719
  program.parse();