@staff0rd/assist 0.281.2 → 0.282.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.281.2",
9
+ version: "0.282.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -230,9 +230,6 @@ var assistConfigSchema = z2.strictObject({
230
230
  run: z2.array(z2.union([runConfigSchema, runLinkSchema])).optional(),
231
231
  transcript: transcriptConfigSchema.optional(),
232
232
  cliReadVerbs: z2.record(z2.string(), z2.array(z2.string())).optional(),
233
- news: z2.strictObject({
234
- feeds: z2.array(z2.string()).default([])
235
- }).default({ feeds: [] }),
236
233
  dotnet: z2.strictObject({
237
234
  inspect: z2.strictObject({
238
235
  suppress: z2.array(z2.string()).default([])
@@ -340,6 +337,7 @@ function loadConfig() {
340
337
  const globalRaw = loadRawYaml(getGlobalConfigPath());
341
338
  const projectRaw = loadRawYaml(getConfigPath());
342
339
  const merged = mergeRawConfigs(globalRaw, projectRaw);
340
+ delete merged.news;
343
341
  return assistConfigSchema.parse(merged);
344
342
  }
345
343
  function loadProjectConfig() {
@@ -444,13 +442,18 @@ var metadata = pgTable("metadata", {
444
442
  key: text().primaryKey(),
445
443
  value: text().notNull()
446
444
  });
445
+ var feeds = pgTable("feeds", {
446
+ id: integer().generatedByDefaultAsIdentity().primaryKey(),
447
+ url: text().notNull().unique()
448
+ });
447
449
  var backlogSchema = {
448
450
  items,
449
451
  comments,
450
452
  links,
451
453
  planPhases,
452
454
  planTasks,
453
- metadata
455
+ metadata,
456
+ feeds
454
457
  };
455
458
 
456
459
  // src/commands/backlog/BacklogOrm.ts
@@ -512,9 +515,43 @@ var SCHEMA = `
512
515
  key TEXT PRIMARY KEY,
513
516
  value TEXT NOT NULL
514
517
  );
518
+
519
+ CREATE TABLE IF NOT EXISTS feeds (
520
+ id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
521
+ url TEXT NOT NULL UNIQUE
522
+ );
515
523
  `;
516
- async function ensureSchema(exec4) {
517
- await exec4(SCHEMA);
524
+ async function ensureSchema(exec3) {
525
+ await exec3(SCHEMA);
526
+ }
527
+
528
+ // src/commands/backlog/addFeed.ts
529
+ async function addFeed(db, url) {
530
+ const inserted = await db.insert(feeds).values({ url }).onConflictDoNothing({ target: feeds.url }).returning({ id: feeds.id });
531
+ return inserted.length > 0;
532
+ }
533
+
534
+ // src/commands/backlog/listFeeds.ts
535
+ import { asc } from "drizzle-orm";
536
+ async function listFeeds(db) {
537
+ const rows = await db.select({ url: feeds.url }).from(feeds).orderBy(asc(feeds.id));
538
+ return rows.map((r) => r.url);
539
+ }
540
+
541
+ // src/commands/backlog/seedNewsFeeds.ts
542
+ function legacyFeeds(raw) {
543
+ const news = raw.news;
544
+ const feeds2 = news?.feeds;
545
+ return Array.isArray(feeds2) ? feeds2.filter((f) => typeof f === "string") : [];
546
+ }
547
+ async function seedNewsFeeds(db) {
548
+ const existing = await listFeeds(db);
549
+ if (existing.length > 0) return;
550
+ const projectFeeds = legacyFeeds(loadProjectConfig());
551
+ const configFeeds = projectFeeds.length > 0 ? projectFeeds : legacyFeeds(loadGlobalConfigRaw());
552
+ for (const url of configFeeds) {
553
+ await addFeed(db, url);
554
+ }
518
555
  }
519
556
 
520
557
  // src/commands/backlog/getBacklogOrm.ts
@@ -549,6 +586,7 @@ function getBacklogOrm() {
549
586
  _pool = pool;
550
587
  await ensureSchema((sql4) => pool.query(sql4));
551
588
  _orm = makeOrmFromPool(pool);
589
+ await seedNewsFeeds(_orm);
552
590
  return _orm;
553
591
  })();
554
592
  return _connecting;
@@ -1835,7 +1873,7 @@ import { Project as Project2 } from "ts-morph";
1835
1873
  function collectComments(sourceFile) {
1836
1874
  const seen = /* @__PURE__ */ new Set();
1837
1875
  const comments3 = [];
1838
- const collect3 = (node) => {
1876
+ const collect4 = (node) => {
1839
1877
  for (const range of [
1840
1878
  ...node.getLeadingCommentRanges(),
1841
1879
  ...node.getTrailingCommentRanges()
@@ -1846,8 +1884,8 @@ function collectComments(sourceFile) {
1846
1884
  comments3.push({ pos, text: range.getText() });
1847
1885
  }
1848
1886
  };
1849
- collect3(sourceFile);
1850
- sourceFile.forEachDescendant(collect3);
1887
+ collect4(sourceFile);
1888
+ sourceFile.forEachDescendant(collect4);
1851
1889
  return comments3;
1852
1890
  }
1853
1891
 
@@ -3190,10 +3228,10 @@ async function importItemsRemapped(orm, items2, origin) {
3190
3228
  }
3191
3229
 
3192
3230
  // src/commands/backlog/loadAllItems.ts
3193
- import { asc as asc2, eq as eq2 } from "drizzle-orm";
3231
+ import { asc as asc3, eq as eq2 } from "drizzle-orm";
3194
3232
 
3195
3233
  // src/commands/backlog/loadRelations.ts
3196
- import { asc, inArray } from "drizzle-orm";
3234
+ import { asc as asc2, inArray } from "drizzle-orm";
3197
3235
  function groupByItem(rows) {
3198
3236
  const map = /* @__PURE__ */ new Map();
3199
3237
  for (const row of rows) {
@@ -3203,13 +3241,13 @@ function groupByItem(rows) {
3203
3241
  }
3204
3242
  return map;
3205
3243
  }
3206
- var selectComments = (orm, ids) => orm.select().from(comments).where(inArray(comments.itemId, ids)).orderBy(asc(comments.itemId), asc(comments.idx));
3207
- var selectLinks = (orm, ids) => orm.select().from(links).where(inArray(links.itemId, ids)).orderBy(asc(links.itemId));
3208
- var selectPhases = (orm, ids) => orm.select().from(planPhases).where(inArray(planPhases.itemId, ids)).orderBy(asc(planPhases.itemId), asc(planPhases.idx));
3244
+ var selectComments = (orm, ids) => orm.select().from(comments).where(inArray(comments.itemId, ids)).orderBy(asc2(comments.itemId), asc2(comments.idx));
3245
+ var selectLinks = (orm, ids) => orm.select().from(links).where(inArray(links.itemId, ids)).orderBy(asc2(links.itemId));
3246
+ var selectPhases = (orm, ids) => orm.select().from(planPhases).where(inArray(planPhases.itemId, ids)).orderBy(asc2(planPhases.itemId), asc2(planPhases.idx));
3209
3247
  var selectTasks = (orm, ids) => orm.select().from(planTasks).where(inArray(planTasks.itemId, ids)).orderBy(
3210
- asc(planTasks.itemId),
3211
- asc(planTasks.phaseIdx),
3212
- asc(planTasks.idx)
3248
+ asc2(planTasks.itemId),
3249
+ asc2(planTasks.phaseIdx),
3250
+ asc2(planTasks.idx)
3213
3251
  );
3214
3252
  async function loadRelations(orm, ids, { includeComments = true, includeTasks = true } = {}) {
3215
3253
  const [commentRows, linkRows, phaseRows, taskRows] = await Promise.all([
@@ -3299,7 +3337,7 @@ function rowToItem(row, rel) {
3299
3337
 
3300
3338
  // src/commands/backlog/loadAllItems.ts
3301
3339
  async function loadAllItems(orm, origin) {
3302
- const rows = await orm.select().from(items).where(origin === void 0 ? void 0 : eq2(items.origin, origin)).orderBy(asc2(items.id));
3340
+ const rows = await orm.select().from(items).where(origin === void 0 ? void 0 : eq2(items.origin, origin)).orderBy(asc3(items.id));
3303
3341
  if (rows.length === 0) return [];
3304
3342
  const rel = await loadRelations(
3305
3343
  orm,
@@ -3492,7 +3530,7 @@ import { eq as eq5, sql } from "drizzle-orm";
3492
3530
  import { eq as eq4 } from "drizzle-orm";
3493
3531
 
3494
3532
  // src/commands/backlog/searchItemIds.ts
3495
- import { and, asc as asc3, eq as eq6, ilike, or } from "drizzle-orm";
3533
+ import { and, asc as asc4, eq as eq6, ilike, or } from "drizzle-orm";
3496
3534
  async function searchItemIds(orm, query, origin) {
3497
3535
  const pattern2 = `%${query}%`;
3498
3536
  const rows = await orm.selectDistinct({ id: items.id }).from(items).leftJoin(comments, eq6(comments.itemId, items.id)).leftJoin(planPhases, eq6(planPhases.itemId, items.id)).where(
@@ -3506,7 +3544,7 @@ async function searchItemIds(orm, query, origin) {
3506
3544
  ilike(planPhases.name, pattern2)
3507
3545
  )
3508
3546
  )
3509
- ).orderBy(asc3(items.id));
3547
+ ).orderBy(asc4(items.id));
3510
3548
  return rows.map((r) => r.id);
3511
3549
  }
3512
3550
 
@@ -4346,11 +4384,48 @@ import {
4346
4384
  } from "http";
4347
4385
  import chalk43 from "chalk";
4348
4386
 
4349
- // src/shared/openBrowser.ts
4350
- import { exec } from "child_process";
4387
+ // src/lib/openBrowser.ts
4388
+ import { execSync as execSync20 } from "child_process";
4389
+ function tryExec(commands) {
4390
+ for (const cmd of commands) {
4391
+ try {
4392
+ execSync20(cmd, { stdio: "ignore" });
4393
+ return true;
4394
+ } catch {
4395
+ }
4396
+ }
4397
+ return false;
4398
+ }
4351
4399
  function openBrowser(url) {
4352
- const cmd = process.platform === "win32" ? `start ${url}` : process.platform === "darwin" ? `open ${url}` : `xdg-open ${url}`;
4353
- exec(cmd);
4400
+ const platform = detectPlatform();
4401
+ const quoted = JSON.stringify(url);
4402
+ const commands = [];
4403
+ switch (platform) {
4404
+ case "macos":
4405
+ commands.push(
4406
+ `open -a "Google Chrome" ${quoted}`,
4407
+ `open -a "Microsoft Edge" ${quoted}`,
4408
+ `open -a "Safari" ${quoted}`
4409
+ );
4410
+ break;
4411
+ case "linux":
4412
+ commands.push(
4413
+ `google-chrome ${quoted}`,
4414
+ `chromium-browser ${quoted}`,
4415
+ `microsoft-edge ${quoted}`
4416
+ );
4417
+ break;
4418
+ case "windows":
4419
+ commands.push(`start chrome ${quoted}`, `start msedge ${quoted}`);
4420
+ break;
4421
+ case "wsl":
4422
+ commands.push(`xdg-open ${quoted}`);
4423
+ break;
4424
+ }
4425
+ if (!tryExec(commands)) {
4426
+ console.log(`Open this URL in Chrome, Edge, or Safari:
4427
+ ${url}`);
4428
+ }
4354
4429
  }
4355
4430
 
4356
4431
  // src/shared/web.ts
@@ -4358,20 +4433,20 @@ function respondJson(res, status2, data) {
4358
4433
  res.writeHead(status2, { "Content-Type": "application/json" });
4359
4434
  res.end(JSON.stringify(data));
4360
4435
  }
4361
- function createHtmlHandler(getHtml3) {
4436
+ function createHtmlHandler(getHtml2) {
4362
4437
  return (_req, res) => {
4363
4438
  res.writeHead(200, { "Content-Type": "text/html" });
4364
- res.end(getHtml3());
4439
+ res.end(getHtml2());
4365
4440
  };
4366
4441
  }
4367
4442
  function parseRoute(req, port) {
4368
4443
  const url = new URL(req.url ?? "/", `http://localhost:${port}`);
4369
4444
  return { method: req.method ?? "GET", pathname: url.pathname };
4370
4445
  }
4371
- function createRouteHandler(routes3) {
4446
+ function createRouteHandler(routes2) {
4372
4447
  return async (req, res, port) => {
4373
4448
  const { method, pathname } = parseRoute(req, port);
4374
- const handler = routes3[`${method} ${pathname}`];
4449
+ const handler = routes2[`${method} ${pathname}`];
4375
4450
  if (handler) {
4376
4451
  await handler(req, res);
4377
4452
  return;
@@ -4384,7 +4459,7 @@ function buildUrl(port, initialPath) {
4384
4459
  const base = `http://localhost:${port}`;
4385
4460
  return initialPath ? `${base}${initialPath}` : base;
4386
4461
  }
4387
- function startWebServer(label2, port, handler, initialPath) {
4462
+ function startWebServer(label2, port, handler, initialPath, open = true) {
4388
4463
  const url = buildUrl(port, initialPath);
4389
4464
  const server = createServer((req, res) => {
4390
4465
  handler(req, res, port);
@@ -4392,7 +4467,9 @@ function startWebServer(label2, port, handler, initialPath) {
4392
4467
  server.listen(port, () => {
4393
4468
  console.log(chalk43.green(`${label2}: ${url}`));
4394
4469
  console.log(chalk43.dim("Press Ctrl+C to stop"));
4395
- openBrowser(url);
4470
+ if (open) {
4471
+ openBrowser(url);
4472
+ }
4396
4473
  });
4397
4474
  return server;
4398
4475
  }
@@ -4531,12 +4608,12 @@ function createBundleHandler(importMetaUrl, bundlePath) {
4531
4608
  }
4532
4609
 
4533
4610
  // src/shared/createFallbackHandler.ts
4534
- function createFallbackHandler(routes3, htmlHandler2, extra) {
4535
- const baseHandler = createRouteHandler(routes3);
4611
+ function createFallbackHandler(routes2, htmlHandler2, extra) {
4612
+ const baseHandler = createRouteHandler(routes2);
4536
4613
  return async (req, res, port) => {
4537
4614
  const { method, pathname } = parseRoute(req, port);
4538
4615
  if (extra && await extra(req, res, pathname)) return;
4539
- if (routes3[`${method} ${pathname}`]) {
4616
+ if (routes2[`${method} ${pathname}`]) {
4540
4617
  await baseHandler(req, res, port);
4541
4618
  return;
4542
4619
  }
@@ -4595,7 +4672,7 @@ async function createItem(req, res) {
4595
4672
  import { eq as eq11 } from "drizzle-orm";
4596
4673
 
4597
4674
  // src/commands/backlog/loadItemSummaries.ts
4598
- import { asc as asc4, eq as eq10 } from "drizzle-orm";
4675
+ import { asc as asc5, eq as eq10 } from "drizzle-orm";
4599
4676
  async function loadItemSummaries(orm, origin) {
4600
4677
  const rows = await orm.select({
4601
4678
  id: items.id,
@@ -4603,7 +4680,7 @@ async function loadItemSummaries(orm, origin) {
4603
4680
  type: items.type,
4604
4681
  name: items.name,
4605
4682
  status: items.status
4606
- }).from(items).where(origin === void 0 ? void 0 : eq10(items.origin, origin)).orderBy(asc4(items.id));
4683
+ }).from(items).where(origin === void 0 ? void 0 : eq10(items.origin, origin)).orderBy(asc5(items.id));
4607
4684
  return rows.map((row) => ({
4608
4685
  id: row.id,
4609
4686
  origin: row.origin,
@@ -4844,7 +4921,7 @@ function getHtml() {
4844
4921
  }
4845
4922
 
4846
4923
  // src/commands/prs/getPreferredRemoteRepo.ts
4847
- import { execSync as execSync20 } from "child_process";
4924
+ import { execSync as execSync21 } from "child_process";
4848
4925
  var GITHUB_URL_PATTERN = /(?:git@github\.com:|https:\/\/github\.com\/)([^/]+)\/([^/]+?)(?:\.git)?\/?$/;
4849
4926
  function parseGitHubUrl(url) {
4850
4927
  const match = url.match(GITHUB_URL_PATTERN);
@@ -4853,7 +4930,7 @@ function parseGitHubUrl(url) {
4853
4930
  }
4854
4931
  function tryGetRemoteUrl(remote, cwd) {
4855
4932
  try {
4856
- return execSync20(`git remote get-url ${remote}`, {
4933
+ return execSync21(`git remote get-url ${remote}`, {
4857
4934
  encoding: "utf-8",
4858
4935
  stdio: ["pipe", "pipe", "pipe"],
4859
4936
  cwd
@@ -4864,7 +4941,7 @@ function tryGetRemoteUrl(remote, cwd) {
4864
4941
  }
4865
4942
  function getCurrentBranchRemote(cwd) {
4866
4943
  try {
4867
- const ref = execSync20(
4944
+ const ref = execSync21(
4868
4945
  "git rev-parse --abbrev-ref --symbolic-full-name @{u}",
4869
4946
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], cwd }
4870
4947
  ).trim();
@@ -4876,7 +4953,7 @@ function getCurrentBranchRemote(cwd) {
4876
4953
  }
4877
4954
  function listRemotes(cwd) {
4878
4955
  try {
4879
- return execSync20("git remote", {
4956
+ return execSync21("git remote", {
4880
4957
  encoding: "utf-8",
4881
4958
  stdio: ["pipe", "pipe", "pipe"],
4882
4959
  cwd
@@ -4926,7 +5003,7 @@ function githubUrl(req, res) {
4926
5003
  }
4927
5004
 
4928
5005
  // src/commands/sessions/web/gitStatus.ts
4929
- import { execSync as execSync21 } from "child_process";
5006
+ import { execSync as execSync22 } from "child_process";
4930
5007
 
4931
5008
  // src/commands/sessions/web/parseGitStatus.ts
4932
5009
  function extractPath(rest) {
@@ -4958,7 +5035,7 @@ function gitStatus(req, res) {
4958
5035
  const cwd = getCwdParam(req, res);
4959
5036
  if (!cwd) return;
4960
5037
  try {
4961
- const output = execSync21("git status --porcelain", {
5038
+ const output = execSync22("git status --porcelain", {
4962
5039
  encoding: "utf-8",
4963
5040
  stdio: ["pipe", "pipe", "pipe"],
4964
5041
  cwd
@@ -4969,10 +5046,133 @@ function gitStatus(req, res) {
4969
5046
  }
4970
5047
  }
4971
5048
 
5049
+ // src/commands/news/shared.ts
5050
+ import { decodeHTML } from "entities";
5051
+ function extractText(xml, tag) {
5052
+ const cdataMatch = xml.match(
5053
+ new RegExp(`<${tag}>\\s*<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>\\s*</${tag}>`)
5054
+ );
5055
+ if (cdataMatch) return cdataMatch[1].trim();
5056
+ const match = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`));
5057
+ return match ? match[1].trim() : "";
5058
+ }
5059
+ function extractLink(itemXml) {
5060
+ const atomLink = itemXml.match(
5061
+ /<link[^>]*rel=["']alternate["'][^>]*href=["']([^"']+)["']/
5062
+ );
5063
+ if (atomLink) return atomLink[1];
5064
+ const atomLink2 = itemXml.match(/<link[^>]*href=["']([^"']+)["']/);
5065
+ if (atomLink2) return atomLink2[1];
5066
+ return extractText(itemXml, "link");
5067
+ }
5068
+ function parseDate(dateStr) {
5069
+ if (!dateStr) return (/* @__PURE__ */ new Date(0)).toISOString();
5070
+ try {
5071
+ return new Date(dateStr).toISOString();
5072
+ } catch {
5073
+ return (/* @__PURE__ */ new Date(0)).toISOString();
5074
+ }
5075
+ }
5076
+ function stripHtml(html) {
5077
+ const decoded = decodeHTML(html);
5078
+ const stripped = decoded.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
5079
+ return decodeHTML(stripped);
5080
+ }
5081
+ function matchAll(xml, regex) {
5082
+ const results = [];
5083
+ for (const m of xml.matchAll(regex)) {
5084
+ results.push(m[1]);
5085
+ }
5086
+ return results;
5087
+ }
5088
+ var MAX_EXCERPT = 500;
5089
+ function excerpt(xml, ...tags) {
5090
+ for (const tag of tags) {
5091
+ const raw = extractText(xml, tag);
5092
+ if (!raw) continue;
5093
+ const text3 = stripHtml(raw);
5094
+ if (text3.length <= MAX_EXCERPT) return text3;
5095
+ return `${text3.slice(0, MAX_EXCERPT)}\u2026`;
5096
+ }
5097
+ return "";
5098
+ }
5099
+
5100
+ // src/commands/news/parseFeed.ts
5101
+ function parseRss(xml, feedOrigin) {
5102
+ const feedTitle = extractText(xml, "title");
5103
+ return matchAll(xml, /<item[\s>]([\s\S]*?)<\/item>/g).map((itemXml) => ({
5104
+ title: extractText(itemXml, "title"),
5105
+ link: extractLink(itemXml),
5106
+ pubDate: parseDate(
5107
+ extractText(itemXml, "pubDate") || extractText(itemXml, "dc:date")
5108
+ ),
5109
+ feedTitle,
5110
+ feedOrigin,
5111
+ excerpt: excerpt(itemXml, "description", "content:encoded")
5112
+ }));
5113
+ }
5114
+ function parseAtom(xml, feedOrigin) {
5115
+ const feedTitle = extractText(xml, "title");
5116
+ return matchAll(xml, /<entry[\s>]([\s\S]*?)<\/entry>/g).map((entryXml) => ({
5117
+ title: extractText(entryXml, "title"),
5118
+ link: extractLink(entryXml),
5119
+ pubDate: parseDate(
5120
+ extractText(entryXml, "published") || extractText(entryXml, "updated")
5121
+ ),
5122
+ feedTitle,
5123
+ feedOrigin,
5124
+ excerpt: excerpt(entryXml, "summary", "content")
5125
+ }));
5126
+ }
5127
+ function parseFeed(xml, feedOrigin) {
5128
+ if (xml.includes("<feed")) return parseAtom(xml, feedOrigin);
5129
+ return parseRss(xml, feedOrigin);
5130
+ }
5131
+
5132
+ // src/commands/news/fetchFeeds.ts
5133
+ async function fetchFeeds(urls, onProgress) {
5134
+ let done2 = 0;
5135
+ const results = await Promise.allSettled(
5136
+ urls.map(async (url) => {
5137
+ const origin = new URL(url).origin;
5138
+ const res = await fetch(url);
5139
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
5140
+ const items3 = parseFeed(await res.text(), origin);
5141
+ done2++;
5142
+ onProgress?.(done2, urls.length);
5143
+ return items3;
5144
+ })
5145
+ );
5146
+ const items2 = [];
5147
+ for (const result of results) {
5148
+ if (result.status === "fulfilled") {
5149
+ items2.push(...result.value);
5150
+ }
5151
+ }
5152
+ items2.sort(
5153
+ (a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()
5154
+ );
5155
+ return items2;
5156
+ }
5157
+
5158
+ // src/commands/sessions/web/listNewsItems.ts
5159
+ var cachedItems;
5160
+ var inflight;
5161
+ async function listNewsItems(_req, res) {
5162
+ if (!cachedItems) {
5163
+ if (!inflight)
5164
+ inflight = getReady().then(
5165
+ ({ orm }) => listFeeds(orm).then((urls) => fetchFeeds(urls))
5166
+ );
5167
+ cachedItems = await inflight;
5168
+ }
5169
+ respondJson(res, 200, cachedItems);
5170
+ }
5171
+
4972
5172
  // src/commands/sessions/web/openInCode.ts
4973
- import { exec as exec2 } from "child_process";
5173
+ import { exec } from "child_process";
4974
5174
  import { promisify } from "util";
4975
- var execAsync = promisify(exec2);
5175
+ var execAsync = promisify(exec);
4976
5176
  async function openInCode(req, res) {
4977
5177
  const cwd = getCwdParam(req, res);
4978
5178
  if (!cwd) return;
@@ -5013,7 +5213,8 @@ var routes = {
5013
5213
  "POST /api/backlog/init": initBacklog,
5014
5214
  "POST /api/open-in-code": openInCode,
5015
5215
  "GET /api/github-url": githubUrl,
5016
- "GET /api/git-status": gitStatus
5216
+ "GET /api/git-status": gitStatus,
5217
+ "GET /api/news/items": listNewsItems
5017
5218
  };
5018
5219
  var handleRequest = createFallbackHandler(
5019
5220
  routes,
@@ -5313,6 +5514,9 @@ import { spawnSync } from "child_process";
5313
5514
  function resolveExecve() {
5314
5515
  return typeof process.execve === "function" ? process.execve.bind(process) : null;
5315
5516
  }
5517
+ function withNoOpen(args) {
5518
+ return args.includes("--no-open") ? args : [...args, "--no-open"];
5519
+ }
5316
5520
  function reExecWebServer(deps2 = {}) {
5317
5521
  const {
5318
5522
  beforeExec,
@@ -5322,11 +5526,13 @@ function reExecWebServer(deps2 = {}) {
5322
5526
  } = deps2;
5323
5527
  beforeExec?.();
5324
5528
  if (execveFn) {
5325
- execveFn(process.execPath, process.argv, process.env);
5529
+ execveFn(process.execPath, withNoOpen(process.argv), process.env);
5326
5530
  return;
5327
5531
  }
5328
5532
  const [, ...args] = process.argv;
5329
- const result = spawnSyncFn(process.execPath, args, { stdio: "inherit" });
5533
+ const result = spawnSyncFn(process.execPath, withNoOpen(args), {
5534
+ stdio: "inherit"
5535
+ });
5330
5536
  exit(result.status ?? 0);
5331
5537
  }
5332
5538
 
@@ -5388,7 +5594,8 @@ async function web(options2) {
5388
5594
  "Assist",
5389
5595
  port,
5390
5596
  handleRequest,
5391
- options2.initialPath
5597
+ options2.initialPath,
5598
+ options2.open !== false
5392
5599
  );
5393
5600
  const serverCwd = process.cwd();
5394
5601
  const ctx = {
@@ -5410,7 +5617,11 @@ async function web(options2) {
5410
5617
 
5411
5618
  // src/commands/backlog/web/index.ts
5412
5619
  async function web2(options2) {
5413
- await web({ port: options2.port, initialPath: "/backlog" });
5620
+ await web({
5621
+ port: options2.port,
5622
+ initialPath: "/backlog",
5623
+ open: options2.open
5624
+ });
5414
5625
  }
5415
5626
 
5416
5627
  // src/commands/backlog/comment/index.ts
@@ -6572,9 +6783,9 @@ async function findPhase(id, phase) {
6572
6783
  }
6573
6784
 
6574
6785
  // src/commands/backlog/reindexPhases.ts
6575
- import { and as and7, asc as asc5, count as count5, eq as eq24 } from "drizzle-orm";
6786
+ import { and as and7, asc as asc6, count as count5, eq as eq24 } from "drizzle-orm";
6576
6787
  async function reindexPhases(db, itemId) {
6577
- const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq24(planPhases.itemId, itemId)).orderBy(asc5(planPhases.idx));
6788
+ const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq24(planPhases.itemId, itemId)).orderBy(asc6(planPhases.idx));
6578
6789
  for (let i = 0; i < remaining.length; i++) {
6579
6790
  const oldIdx = remaining[i].idx;
6580
6791
  if (oldIdx === i) continue;
@@ -6908,7 +7119,7 @@ function registerShowCommands(cmd) {
6908
7119
  cmd.command("show <id>").alias("view").description("Show full detail for a backlog item").action(show);
6909
7120
  }
6910
7121
  function registerWebCommand(cmd) {
6911
- cmd.command("web").description("Open the backlog tab in the web dashboard").option("-p, --port <number>", "Port to listen on", "3100").action(web2);
7122
+ cmd.command("web").description("Open the backlog tab in the web dashboard").option("-p, --port <number>", "Port to listen on", "3100").option("--no-open", "Do not open a browser on startup").action(web2);
6912
7123
  }
6913
7124
  var registrars = [
6914
7125
  registerItemCommands,
@@ -6929,9 +7140,9 @@ var registrars = [
6929
7140
  registerMoveRepoCommand
6930
7141
  ];
6931
7142
  function registerBacklog(program2) {
6932
- const cmd = program2.command("backlog").description("Manage a backlog of work items").option("--dir <path>", "Override directory for backlog file discovery").hook("preAction", (thisCommand) => {
7143
+ const cmd = program2.command("backlog").description("Manage a backlog of work items").option("--dir <path>", "Override directory for backlog file discovery").option("--no-open", "Do not open a browser on startup").hook("preAction", (thisCommand) => {
6933
7144
  setBacklogDir(thisCommand.opts().dir);
6934
- }).action(() => web2({ port: "3100" }));
7145
+ }).action((options2) => web2({ port: "3100", open: options2.open }));
6935
7146
  for (const register of registrars) {
6936
7147
  register(cmd);
6937
7148
  }
@@ -7384,7 +7595,7 @@ function matchesConfigDeny(command) {
7384
7595
  var BUILTIN_DENIES = [
7385
7596
  {
7386
7597
  pattern: "gh pr create",
7387
- message: "Do not run 'gh pr create' directly. Use 'assist prs create --title <title> --body <body>' instead \u2014 it validates the title and body before delegating to gh pr create. Before running it, get explicit approval via the AskUserQuestion tool, regardless of permission mode, with the full proposed title and body in the approve option's preview field so the user actually sees them."
7598
+ message: "Do not run 'gh pr create' directly. Use 'assist prs raise --title <title> --what <what> --why <why>' instead \u2014 it assembles and validates the body before delegating to gh. Before running it, get explicit approval via the AskUserQuestion tool, regardless of permission mode, with the full proposed title and body in the approve option's preview field so the user actually sees them."
7388
7599
  },
7389
7600
  {
7390
7601
  pattern: "git commit",
@@ -7553,7 +7764,7 @@ import { homedir as homedir9 } from "os";
7553
7764
  import { join as join22 } from "path";
7554
7765
 
7555
7766
  // src/shared/checkCliAvailable.ts
7556
- import { execSync as execSync22 } from "child_process";
7767
+ import { execSync as execSync23 } from "child_process";
7557
7768
  function checkCliAvailable(cli) {
7558
7769
  const binary = cli.split(/\s+/)[0];
7559
7770
  const opts = {
@@ -7561,11 +7772,11 @@ function checkCliAvailable(cli) {
7561
7772
  stdio: ["ignore", "pipe", "pipe"]
7562
7773
  };
7563
7774
  try {
7564
- execSync22(`command -v ${binary}`, opts);
7775
+ execSync23(`command -v ${binary}`, opts);
7565
7776
  return true;
7566
7777
  } catch {
7567
7778
  try {
7568
- execSync22(`where ${binary}`, opts);
7779
+ execSync23(`where ${binary}`, opts);
7569
7780
  return true;
7570
7781
  } catch {
7571
7782
  return false;
@@ -7665,10 +7876,10 @@ function hasSubcommands(helpText) {
7665
7876
  }
7666
7877
 
7667
7878
  // src/commands/permitCliReads/runHelp.ts
7668
- import { exec as exec3 } from "child_process";
7879
+ import { exec as exec2 } from "child_process";
7669
7880
  function runHelp(args) {
7670
7881
  return new Promise((resolve16) => {
7671
- exec3(
7882
+ exec2(
7672
7883
  `${args.join(" ")} --help`,
7673
7884
  { encoding: "utf-8", timeout: 3e4 },
7674
7885
  (_err, stdout, stderr) => {
@@ -8701,7 +8912,7 @@ function loadBlogSkipDays(repoName) {
8701
8912
  }
8702
8913
 
8703
8914
  // src/commands/devlog/shared.ts
8704
- import { execSync as execSync23 } from "child_process";
8915
+ import { execSync as execSync24 } from "child_process";
8705
8916
  import chalk92 from "chalk";
8706
8917
 
8707
8918
  // src/shared/getRepoName.ts
@@ -8793,7 +9004,7 @@ function loadAllDevlogLatestDates() {
8793
9004
  // src/commands/devlog/shared.ts
8794
9005
  function getCommitFiles(hash) {
8795
9006
  try {
8796
- const output = execSync23(`git show --name-only --format="" ${hash}`, {
9007
+ const output = execSync24(`git show --name-only --format="" ${hash}`, {
8797
9008
  encoding: "utf-8"
8798
9009
  });
8799
9010
  return output.trim().split("\n").filter(Boolean);
@@ -8889,11 +9100,11 @@ function list3(options2) {
8889
9100
  }
8890
9101
 
8891
9102
  // src/commands/devlog/getLastVersionInfo.ts
8892
- import { execFileSync as execFileSync2, execSync as execSync24 } from "child_process";
9103
+ import { execFileSync as execFileSync2, execSync as execSync25 } from "child_process";
8893
9104
  import semver from "semver";
8894
9105
  function getVersionAtCommit(hash) {
8895
9106
  try {
8896
- const content = execSync24(`git show ${hash}:package.json`, {
9107
+ const content = execSync25(`git show ${hash}:package.json`, {
8897
9108
  encoding: "utf-8"
8898
9109
  });
8899
9110
  const pkg = JSON.parse(content);
@@ -9066,7 +9277,7 @@ function next2(options2) {
9066
9277
  }
9067
9278
 
9068
9279
  // src/commands/devlog/repos/index.ts
9069
- import { execSync as execSync25 } from "child_process";
9280
+ import { execSync as execSync26 } from "child_process";
9070
9281
 
9071
9282
  // src/commands/devlog/repos/printReposTable.ts
9072
9283
  import chalk96 from "chalk";
@@ -9101,7 +9312,7 @@ function getStatus(lastPush, lastDevlog) {
9101
9312
  return lastDevlog < lastPush ? "outdated" : "ok";
9102
9313
  }
9103
9314
  function fetchRepos(days, all) {
9104
- const json = execSync25(
9315
+ const json = execSync26(
9105
9316
  "gh repo list staff0rd --json name,pushedAt,isArchived --limit 200",
9106
9317
  { encoding: "utf-8" }
9107
9318
  );
@@ -9461,7 +9672,7 @@ async function deps(csprojPath, options2) {
9461
9672
  }
9462
9673
 
9463
9674
  // src/commands/dotnet/getChangedCsFiles.ts
9464
- import { execSync as execSync26 } from "child_process";
9675
+ import { execSync as execSync27 } from "child_process";
9465
9676
  var SCOPE_ALL = "all";
9466
9677
  var SCOPE_BASE = "base:";
9467
9678
  var SCOPE_COMMIT = "commit:";
@@ -9485,7 +9696,7 @@ function getChangedCsFiles(scope) {
9485
9696
  } else {
9486
9697
  cmd = "git diff --name-only HEAD";
9487
9698
  }
9488
- const output = execSync26(cmd, { encoding: "utf-8" }).trim();
9699
+ const output = execSync27(cmd, { encoding: "utf-8" }).trim();
9489
9700
  if (output === "") return [];
9490
9701
  return output.split("\n").filter((f) => f.toLowerCase().endsWith(".cs"));
9491
9702
  }
@@ -9683,14 +9894,14 @@ function parseInspectReport(json) {
9683
9894
  }
9684
9895
 
9685
9896
  // src/commands/dotnet/runInspectCode.ts
9686
- import { execSync as execSync27 } from "child_process";
9897
+ import { execSync as execSync28 } from "child_process";
9687
9898
  import { existsSync as existsSync30, readFileSync as readFileSync24, unlinkSync as unlinkSync7 } from "fs";
9688
9899
  import { tmpdir as tmpdir3 } from "os";
9689
9900
  import path25 from "path";
9690
9901
  import chalk106 from "chalk";
9691
9902
  function assertJbInstalled() {
9692
9903
  try {
9693
- execSync27("jb inspectcode --version", { stdio: "pipe" });
9904
+ execSync28("jb inspectcode --version", { stdio: "pipe" });
9694
9905
  } catch {
9695
9906
  console.error(chalk106.red("jb is not installed. Install with:"));
9696
9907
  console.error(
@@ -9704,7 +9915,7 @@ function runInspectCode(slnPath, include, swea) {
9704
9915
  const includeFlag = include ? ` --include="${include}"` : "";
9705
9916
  const sweaFlag = swea ? " --swea" : "";
9706
9917
  try {
9707
- execSync27(
9918
+ execSync28(
9708
9919
  `jb inspectcode "${slnPath}" -o="${reportPath}"${includeFlag}${sweaFlag} --verbosity=OFF`,
9709
9920
  { stdio: "pipe" }
9710
9921
  );
@@ -9725,7 +9936,7 @@ function runInspectCode(slnPath, include, swea) {
9725
9936
  }
9726
9937
 
9727
9938
  // src/commands/dotnet/runRoslynInspect.ts
9728
- import { execSync as execSync28 } from "child_process";
9939
+ import { execSync as execSync29 } from "child_process";
9729
9940
  import chalk107 from "chalk";
9730
9941
  function resolveMsbuildPath() {
9731
9942
  const { run: run4 } = loadConfig();
@@ -9736,7 +9947,7 @@ function resolveMsbuildPath() {
9736
9947
  function assertMsbuildInstalled() {
9737
9948
  const msbuild = resolveMsbuildPath();
9738
9949
  try {
9739
- execSync28(`"${msbuild}" -version`, { stdio: "pipe" });
9950
+ execSync29(`"${msbuild}" -version`, { stdio: "pipe" });
9740
9951
  } catch {
9741
9952
  console.error(chalk107.red(`msbuild not found at: ${msbuild}`));
9742
9953
  console.error(
@@ -9762,7 +9973,7 @@ function runRoslynInspect(slnPath) {
9762
9973
  const msbuild = resolveMsbuildPath();
9763
9974
  let output;
9764
9975
  try {
9765
- output = execSync28(
9976
+ output = execSync29(
9766
9977
  `"${msbuild}" "${slnPath}" -t:Build -v:minimal -maxcpucount -p:EnforceCodeStyleInBuild=true -p:RunAnalyzersDuringBuild=true 2>&1`,
9767
9978
  { encoding: "utf-8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
9768
9979
  );
@@ -10340,12 +10551,12 @@ function adfToText(doc) {
10340
10551
  }
10341
10552
 
10342
10553
  // src/commands/jira/fetchIssue.ts
10343
- import { execSync as execSync29 } from "child_process";
10554
+ import { execSync as execSync30 } from "child_process";
10344
10555
  import chalk111 from "chalk";
10345
10556
  function fetchIssue(issueKey, fields) {
10346
10557
  let result;
10347
10558
  try {
10348
- result = execSync29(
10559
+ result = execSync30(
10349
10560
  `acli jira workitem view ${issueKey} -f ${fields} --json`,
10350
10561
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
10351
10562
  );
@@ -10391,7 +10602,7 @@ function acceptanceCriteria(issueKey) {
10391
10602
  }
10392
10603
 
10393
10604
  // src/commands/jira/jiraAuth.ts
10394
- import { execSync as execSync30 } from "child_process";
10605
+ import { execSync as execSync31 } from "child_process";
10395
10606
 
10396
10607
  // src/shared/loadJson.ts
10397
10608
  import { existsSync as existsSync33, mkdirSync as mkdirSync11, readFileSync as readFileSync27, writeFileSync as writeFileSync21 } from "fs";
@@ -10455,7 +10666,7 @@ async function jiraAuth() {
10455
10666
  console.error("All fields are required.");
10456
10667
  process.exit(1);
10457
10668
  }
10458
- execSync30(`acli jira auth login --site ${site} --email "${email}" --token`, {
10669
+ execSync31(`acli jira auth login --site ${site} --email "${email}" --token`, {
10459
10670
  encoding: "utf-8",
10460
10671
  input: token,
10461
10672
  stdio: ["pipe", "inherit", "inherit"]
@@ -10680,238 +10891,49 @@ async function add2(url) {
10680
10891
  });
10681
10892
  url = response.url;
10682
10893
  }
10683
- const config = loadGlobalConfigRaw();
10684
- const news = config.news ?? {};
10685
- const feeds = news.feeds ?? [];
10686
- if (feeds.includes(url)) {
10687
- console.log(chalk118.yellow("Feed already exists in config"));
10894
+ const { orm } = await getReady();
10895
+ const added = await addFeed(orm, url);
10896
+ if (!added) {
10897
+ console.log(chalk118.yellow("Feed already exists"));
10688
10898
  return;
10689
10899
  }
10690
- feeds.push(url);
10691
- config.news = { ...news, feeds };
10692
- saveGlobalConfig(config);
10693
10900
  console.log(chalk118.green(`Added feed: ${url}`));
10694
10901
  }
10695
10902
 
10696
- // src/commands/news/web/handleRequest.ts
10697
- import chalk119 from "chalk";
10903
+ // src/commands/registerNews.ts
10904
+ function registerNews(program2) {
10905
+ const newsCommand = program2.command("news").description("Manage RSS news feeds");
10906
+ newsCommand.command("add").description("Add an RSS feed URL").argument("<url>", "RSS feed URL").action(add2);
10907
+ }
10698
10908
 
10699
- // src/commands/news/web/shared.ts
10700
- import { decodeHTML } from "entities";
10701
- function extractText(xml, tag) {
10702
- const cdataMatch = xml.match(
10703
- new RegExp(`<${tag}>\\s*<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>\\s*</${tag}>`)
10704
- );
10705
- if (cdataMatch) return cdataMatch[1].trim();
10706
- const match = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`));
10707
- return match ? match[1].trim() : "";
10909
+ // src/commands/prompts/printPromptsTable.ts
10910
+ import chalk119 from "chalk";
10911
+ function truncate(str, max) {
10912
+ if (str.length <= max) return str;
10913
+ return `${str.slice(0, max - 1)}\u2026`;
10708
10914
  }
10709
- function extractLink(itemXml) {
10710
- const atomLink = itemXml.match(
10711
- /<link[^>]*rel=["']alternate["'][^>]*href=["']([^"']+)["']/
10915
+ function printPromptsTable(rows) {
10916
+ const countWidth = 5;
10917
+ const toolWidth = Math.max(4, ...rows.map((r) => r.tool.length));
10918
+ const commandWidth = Math.max(
10919
+ 7,
10920
+ ...rows.map((r) => truncate(r.command, 60).length)
10712
10921
  );
10713
- if (atomLink) return atomLink[1];
10714
- const atomLink2 = itemXml.match(/<link[^>]*href=["']([^"']+)["']/);
10715
- if (atomLink2) return atomLink2[1];
10716
- return extractText(itemXml, "link");
10717
- }
10718
- function parseDate(dateStr) {
10719
- if (!dateStr) return (/* @__PURE__ */ new Date(0)).toISOString();
10720
- try {
10721
- return new Date(dateStr).toISOString();
10722
- } catch {
10723
- return (/* @__PURE__ */ new Date(0)).toISOString();
10724
- }
10725
- }
10726
- function stripHtml(html) {
10727
- const decoded = decodeHTML(html);
10728
- const stripped = decoded.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
10729
- return decodeHTML(stripped);
10730
- }
10731
- function matchAll(xml, regex) {
10732
- const results = [];
10733
- for (const m of xml.matchAll(regex)) {
10734
- results.push(m[1]);
10735
- }
10736
- return results;
10737
- }
10738
- var MAX_EXCERPT = 500;
10739
- function excerpt(xml, ...tags) {
10740
- for (const tag of tags) {
10741
- const raw = extractText(xml, tag);
10742
- if (!raw) continue;
10743
- const text3 = stripHtml(raw);
10744
- if (text3.length <= MAX_EXCERPT) return text3;
10745
- return `${text3.slice(0, MAX_EXCERPT)}\u2026`;
10746
- }
10747
- return "";
10748
- }
10749
-
10750
- // src/commands/news/web/parseFeed.ts
10751
- function parseRss(xml, feedOrigin) {
10752
- const feedTitle = extractText(xml, "title");
10753
- return matchAll(xml, /<item[\s>]([\s\S]*?)<\/item>/g).map((itemXml) => ({
10754
- title: extractText(itemXml, "title"),
10755
- link: extractLink(itemXml),
10756
- pubDate: parseDate(
10757
- extractText(itemXml, "pubDate") || extractText(itemXml, "dc:date")
10758
- ),
10759
- feedTitle,
10760
- feedOrigin,
10761
- excerpt: excerpt(itemXml, "description", "content:encoded")
10762
- }));
10763
- }
10764
- function parseAtom(xml, feedOrigin) {
10765
- const feedTitle = extractText(xml, "title");
10766
- return matchAll(xml, /<entry[\s>]([\s\S]*?)<\/entry>/g).map((entryXml) => ({
10767
- title: extractText(entryXml, "title"),
10768
- link: extractLink(entryXml),
10769
- pubDate: parseDate(
10770
- extractText(entryXml, "published") || extractText(entryXml, "updated")
10771
- ),
10772
- feedTitle,
10773
- feedOrigin,
10774
- excerpt: excerpt(entryXml, "summary", "content")
10775
- }));
10776
- }
10777
- function parseFeed(xml, feedOrigin) {
10778
- if (xml.includes("<feed")) return parseAtom(xml, feedOrigin);
10779
- return parseRss(xml, feedOrigin);
10780
- }
10781
-
10782
- // src/commands/news/web/fetchFeeds.ts
10783
- async function fetchFeeds(urls, onProgress) {
10784
- let done2 = 0;
10785
- const results = await Promise.allSettled(
10786
- urls.map(async (url) => {
10787
- const origin = new URL(url).origin;
10788
- const res = await fetch(url);
10789
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
10790
- const items3 = parseFeed(await res.text(), origin);
10791
- done2++;
10792
- onProgress?.(done2, urls.length);
10793
- return items3;
10794
- })
10795
- );
10796
- const items2 = [];
10797
- for (const result of results) {
10798
- if (result.status === "fulfilled") {
10799
- items2.push(...result.value);
10800
- }
10801
- }
10802
- items2.sort(
10803
- (a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()
10804
- );
10805
- return items2;
10806
- }
10807
-
10808
- // src/commands/news/web/getHtml.ts
10809
- function getHtml2() {
10810
- return `<!DOCTYPE html>
10811
- <html lang="en" class="dark">
10812
- <head>
10813
- <meta charset="UTF-8">
10814
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
10815
- <title>News</title>
10816
- <script src="https://cdn.tailwindcss.com"></script>
10817
- <script>tailwind.config={darkMode:'class'}</script>
10818
- </head>
10819
- <body class="font-[-apple-system,BlinkMacSystemFont,'Segoe_UI',Roboto,sans-serif] bg-gray-950 text-gray-200 leading-normal">
10820
- <div class="max-w-3xl mx-auto px-4 py-6" id="app"></div>
10821
- <script src="/bundle.js"></script>
10822
- </body>
10823
- </html>`;
10824
- }
10825
-
10826
- // src/commands/news/web/handleRequest.ts
10827
- var cachedItems;
10828
- var prefetchPromise;
10829
- function prefetch() {
10830
- const config = loadConfig();
10831
- const total = config.news.feeds.length;
10832
- if (total === 0) return;
10833
- process.stdout.write(chalk119.dim(`Fetching ${total} feed(s)\u2026 `));
10834
- prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
10835
- const width = 20;
10836
- const filled = Math.round(done2 / t * width);
10837
- const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
10838
- process.stdout.write(
10839
- `\r${chalk119.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
10840
- );
10841
- }).then((items2) => {
10842
- process.stdout.write(
10843
- `\r${chalk119.green(`Fetched ${items2.length} items from ${total} feed(s)`)}
10844
- `
10845
- );
10846
- cachedItems = items2;
10847
- return items2;
10848
- });
10849
- }
10850
- async function listItems2(_req, res) {
10851
- if (!cachedItems && prefetchPromise) {
10852
- await prefetchPromise;
10853
- }
10854
- if (!cachedItems) {
10855
- const config = loadConfig();
10856
- cachedItems = await fetchFeeds(config.news.feeds);
10857
- }
10858
- respondJson(res, 200, cachedItems);
10859
- }
10860
- var routes2 = {
10861
- "GET /": createHtmlHandler(getHtml2),
10862
- "GET /bundle.js": createBundleHandler(
10863
- import.meta.url,
10864
- "commands/news/web/bundle.js"
10865
- ),
10866
- "GET /api/items": listItems2
10867
- };
10868
- var handleRequest2 = createRouteHandler(routes2);
10869
-
10870
- // src/commands/news/web/index.ts
10871
- async function web3(options2) {
10872
- prefetch();
10873
- startWebServer(
10874
- "News web view",
10875
- Number.parseInt(options2.port, 10),
10876
- handleRequest2
10877
- );
10878
- }
10879
-
10880
- // src/commands/registerNews.ts
10881
- function registerNews(program2) {
10882
- const newsCommand = program2.command("news").description("View latest news from configured RSS feeds").action(() => web3({ port: "3001" }));
10883
- newsCommand.command("add").description("Add an RSS feed URL to the config").argument("<url>", "RSS feed URL").action(add2);
10884
- newsCommand.command("web").description("Start a web view of the news feeds").option("-p, --port <number>", "Port to listen on", "3001").action(web3);
10885
- }
10886
-
10887
- // src/commands/prompts/printPromptsTable.ts
10888
- import chalk120 from "chalk";
10889
- function truncate(str, max) {
10890
- if (str.length <= max) return str;
10891
- return `${str.slice(0, max - 1)}\u2026`;
10892
- }
10893
- function printPromptsTable(rows) {
10894
- const countWidth = 5;
10895
- const toolWidth = Math.max(4, ...rows.map((r) => r.tool.length));
10896
- const commandWidth = Math.max(
10897
- 7,
10898
- ...rows.map((r) => truncate(r.command, 60).length)
10899
- );
10900
- const header = [
10901
- "#".padStart(countWidth),
10902
- "Tool".padEnd(toolWidth),
10903
- "Command".padEnd(commandWidth),
10904
- "Repos"
10905
- ].join(" ");
10906
- console.log(chalk120.dim(header));
10907
- console.log(chalk120.dim("-".repeat(header.length)));
10908
- for (const row of rows) {
10909
- const count6 = String(row.count).padStart(countWidth);
10910
- const tool = row.tool.padEnd(toolWidth);
10911
- const command = truncate(row.command, 60).padEnd(commandWidth);
10912
- console.log(
10913
- `${chalk120.yellow(count6)} ${tool} ${command} ${chalk120.dim(row.repos)}`
10914
- );
10922
+ const header = [
10923
+ "#".padStart(countWidth),
10924
+ "Tool".padEnd(toolWidth),
10925
+ "Command".padEnd(commandWidth),
10926
+ "Repos"
10927
+ ].join(" ");
10928
+ console.log(chalk119.dim(header));
10929
+ console.log(chalk119.dim("-".repeat(header.length)));
10930
+ for (const row of rows) {
10931
+ const count6 = String(row.count).padStart(countWidth);
10932
+ const tool = row.tool.padEnd(toolWidth);
10933
+ const command = truncate(row.command, 60).padEnd(commandWidth);
10934
+ console.log(
10935
+ `${chalk119.yellow(count6)} ${tool} ${command} ${chalk119.dim(row.repos)}`
10936
+ );
10915
10937
  }
10916
10938
  }
10917
10939
 
@@ -10939,7 +10961,7 @@ function registerPrompts(program2) {
10939
10961
  }
10940
10962
 
10941
10963
  // src/commands/prs/shared.ts
10942
- import { execSync as execSync31 } from "child_process";
10964
+ import { execSync as execSync32 } from "child_process";
10943
10965
  function isGhNotInstalled(error) {
10944
10966
  if (error instanceof Error) {
10945
10967
  const msg = error.message.toLowerCase();
@@ -10957,12 +10979,12 @@ function getRepoInfo() {
10957
10979
  const preferred = getPreferredRemoteRepo();
10958
10980
  if (preferred) return preferred;
10959
10981
  const repoInfo = JSON.parse(
10960
- execSync31("gh repo view --json owner,name", { encoding: "utf-8" })
10982
+ execSync32("gh repo view --json owner,name", { encoding: "utf-8" })
10961
10983
  );
10962
10984
  return { org: repoInfo.owner.login, repo: repoInfo.name };
10963
10985
  }
10964
10986
  function getCurrentBranch() {
10965
- return execSync31("git rev-parse --abbrev-ref HEAD", {
10987
+ return execSync32("git rev-parse --abbrev-ref HEAD", {
10966
10988
  encoding: "utf-8"
10967
10989
  }).trim();
10968
10990
  }
@@ -10970,7 +10992,7 @@ function viewCurrentPr(fields) {
10970
10992
  const { org, repo } = getRepoInfo();
10971
10993
  const branch = getCurrentBranch();
10972
10994
  return JSON.parse(
10973
- execSync31(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
10995
+ execSync32(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
10974
10996
  encoding: "utf-8"
10975
10997
  })
10976
10998
  );
@@ -10986,6 +11008,17 @@ function getCurrentPrNumber() {
10986
11008
  throw error;
10987
11009
  }
10988
11010
  }
11011
+ function getCurrentPr() {
11012
+ try {
11013
+ return viewCurrentPr("number,body");
11014
+ } catch (error) {
11015
+ if (error instanceof Error && error.message.includes("no pull requests")) {
11016
+ console.error("Error: No pull request found for the current branch.");
11017
+ process.exit(1);
11018
+ }
11019
+ throw error;
11020
+ }
11021
+ }
10989
11022
  function getCurrentPrNodeId() {
10990
11023
  try {
10991
11024
  return viewCurrentPr("id").id;
@@ -11062,37 +11095,102 @@ function comment2(path54, line, body, startLine) {
11062
11095
  }
11063
11096
  }
11064
11097
 
11065
- // src/commands/prs/create.ts
11066
- import { execSync as execSync32 } from "child_process";
11098
+ // src/commands/prs/edit.ts
11099
+ import { execSync as execSync33 } from "child_process";
11067
11100
 
11068
- // src/commands/prs/buildCreateArgs.ts
11069
- function buildCreateArgs(title, body, options2) {
11070
- const args = [
11071
- "gh pr create",
11072
- `--title ${shellQuote(title)}`,
11073
- `--body ${shellQuote(body)}`
11074
- ];
11075
- const valueFlags = [
11076
- ["--base", options2.base],
11077
- ["--head", options2.head],
11078
- ["--milestone", options2.milestone]
11079
- ];
11080
- for (const [flag, value] of valueFlags) {
11081
- if (value) args.push(`${flag} ${shellQuote(value)}`);
11101
+ // src/commands/prs/buildPrBody.ts
11102
+ function jiraBrowseUrl(key) {
11103
+ const { site } = loadJson("jira.json");
11104
+ return site ? `https://${site}/browse/${key}` : key;
11105
+ }
11106
+ function renderWhy(why, resolves) {
11107
+ if (resolves && resolves.length > 0) {
11108
+ const urls = resolves.map(jiraBrowseUrl).join(", ");
11109
+ return `${why}
11110
+
11111
+ Resolves ${urls}`;
11082
11112
  }
11083
- if (options2.draft) args.push("--draft");
11084
- if (options2.web) args.push("--web");
11085
- const repeatableFlags = [
11086
- ["--label", options2.label],
11087
- ["--assignee", options2.assignee],
11088
- ["--reviewer", options2.reviewer]
11113
+ return why;
11114
+ }
11115
+ function buildPrBody(sections) {
11116
+ const parts = [
11117
+ `## What
11118
+
11119
+ ${sections.what}`,
11120
+ `## Why
11121
+
11122
+ ${renderWhy(sections.why, sections.resolves)}`
11089
11123
  ];
11090
- for (const [flag, values] of repeatableFlags) {
11091
- for (const value of values ?? []) {
11092
- args.push(`${flag} ${shellQuote(value)}`);
11124
+ if (sections.how) {
11125
+ parts.push(`## How
11126
+
11127
+ ${sections.how}`);
11128
+ }
11129
+ return parts.join("\n\n");
11130
+ }
11131
+
11132
+ // src/commands/prs/parsePrBody.ts
11133
+ function parsePrBody(body) {
11134
+ const sections = [];
11135
+ let current = null;
11136
+ const flush = () => {
11137
+ if (current) {
11138
+ sections.push({
11139
+ heading: current.heading,
11140
+ content: current.lines.join("\n").trim()
11141
+ });
11142
+ }
11143
+ };
11144
+ for (const line of body.split("\n")) {
11145
+ const match = /^##\s+(.+?)\s*$/.exec(line);
11146
+ if (match) {
11147
+ flush();
11148
+ current = { heading: match[1], lines: [] };
11149
+ } else if (current) {
11150
+ current.lines.push(line);
11093
11151
  }
11094
11152
  }
11095
- return args;
11153
+ flush();
11154
+ return sections;
11155
+ }
11156
+ function serializePrBody(sections) {
11157
+ return sections.map((section2) => `## ${section2.heading}
11158
+
11159
+ ${section2.content}`).join("\n\n");
11160
+ }
11161
+
11162
+ // src/commands/prs/editPrBody.ts
11163
+ function stripResolves(content) {
11164
+ return content.replace(/\n+Resolves [^\n]*$/, "").trimEnd();
11165
+ }
11166
+ function extractResolves(content) {
11167
+ const match = /\n+(Resolves [^\n]*)$/.exec(content);
11168
+ return match ? match[1] : "";
11169
+ }
11170
+ function editPrBody(body, sections) {
11171
+ const parsed = parsePrBody(body);
11172
+ const find = (heading) => parsed.find((s) => s.heading.toLowerCase() === heading.toLowerCase());
11173
+ const upsert = (heading, content) => {
11174
+ const existing = find(heading);
11175
+ if (existing) existing.content = content;
11176
+ else parsed.push({ heading, content });
11177
+ };
11178
+ if (sections.what !== void 0) upsert("What", sections.what);
11179
+ const hasResolves = (sections.resolves?.length ?? 0) > 0;
11180
+ if (sections.why !== void 0 || hasResolves) {
11181
+ const existingWhy = find("Why")?.content ?? "";
11182
+ const baseWhy = sections.why !== void 0 ? sections.why : stripResolves(existingWhy);
11183
+ if (hasResolves) {
11184
+ upsert("Why", renderWhy(baseWhy, sections.resolves));
11185
+ } else {
11186
+ const resolves = extractResolves(existingWhy);
11187
+ upsert("Why", resolves ? `${baseWhy}
11188
+
11189
+ ${resolves}` : baseWhy);
11190
+ }
11191
+ }
11192
+ if (sections.how !== void 0) upsert("How", sections.how);
11193
+ return serializePrBody(parsed);
11096
11194
  }
11097
11195
 
11098
11196
  // src/commands/prs/validatePrContent.ts
@@ -11107,28 +11205,34 @@ function validatePrContent(title, body) {
11107
11205
  }
11108
11206
  }
11109
11207
 
11110
- // src/commands/prs/create.ts
11111
- function create(options2) {
11112
- if (!options2.title || !options2.body) {
11208
+ // src/commands/prs/edit.ts
11209
+ function edit(options2) {
11210
+ const hasResolves = (options2.resolves?.length ?? 0) > 0;
11211
+ const hasSection = options2.what !== void 0 || options2.why !== void 0 || options2.how !== void 0 || hasResolves;
11212
+ if (!options2.title && !hasSection) {
11113
11213
  console.error(
11114
- "Usage: assist prs create --title <title> --body <body> [--base <branch>] [--head <branch>] [--draft] [--web] [--label <label>] [--assignee <login>] [--reviewer <handle>] [--milestone <name>]"
11214
+ "Usage: assist prs edit [--title <title>] [--what <what>] [--why <why>] [--how <how>] [--resolves <key>]"
11115
11215
  );
11116
11216
  process.exit(1);
11117
11217
  }
11118
- validatePrContent(options2.title, options2.body);
11119
- const args = buildCreateArgs(options2.title, options2.body, options2);
11218
+ const { number, body } = getCurrentPr();
11219
+ const newBody = editPrBody(body, options2);
11220
+ validatePrContent(options2.title ?? "", newBody);
11221
+ const args = [`gh pr edit ${number}`];
11222
+ if (options2.title) args.push(`--title ${shellQuote(options2.title)}`);
11223
+ args.push(`--body ${shellQuote(newBody)}`);
11120
11224
  try {
11121
- execSync32(args.join(" "), { stdio: "inherit" });
11225
+ execSync33(args.join(" "), { stdio: "inherit" });
11122
11226
  } catch (_error) {
11123
11227
  process.exit(1);
11124
11228
  }
11125
11229
  }
11126
11230
 
11127
11231
  // src/commands/prs/fixed.ts
11128
- import { execSync as execSync34 } from "child_process";
11232
+ import { execSync as execSync35 } from "child_process";
11129
11233
 
11130
11234
  // src/commands/prs/resolveCommentWithReply.ts
11131
- import { execSync as execSync33 } from "child_process";
11235
+ import { execSync as execSync34 } from "child_process";
11132
11236
  import { unlinkSync as unlinkSync10, writeFileSync as writeFileSync23 } from "fs";
11133
11237
  import { tmpdir as tmpdir5 } from "os";
11134
11238
  import { join as join34 } from "path";
@@ -11158,7 +11262,7 @@ function deleteCommentsCache(prNumber) {
11158
11262
 
11159
11263
  // src/commands/prs/resolveCommentWithReply.ts
11160
11264
  function replyToComment(org, repo, prNumber, commentId, message) {
11161
- execSync33(
11265
+ execSync34(
11162
11266
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
11163
11267
  { stdio: ["inherit", "pipe", "inherit"] }
11164
11268
  );
@@ -11168,7 +11272,7 @@ function resolveThread(threadId) {
11168
11272
  const queryFile = join34(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
11169
11273
  writeFileSync23(queryFile, mutation);
11170
11274
  try {
11171
- execSync33(
11275
+ execSync34(
11172
11276
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
11173
11277
  { stdio: ["inherit", "pipe", "inherit"] }
11174
11278
  );
@@ -11220,7 +11324,7 @@ function resolveCommentWithReply(commentId, message) {
11220
11324
  // src/commands/prs/fixed.ts
11221
11325
  function verifySha(sha) {
11222
11326
  try {
11223
- return execSync34(`git rev-parse --verify ${sha}`, {
11327
+ return execSync35(`git rev-parse --verify ${sha}`, {
11224
11328
  encoding: "utf-8"
11225
11329
  }).trim();
11226
11330
  } catch {
@@ -11234,7 +11338,7 @@ function fixed(commentId, sha) {
11234
11338
  const { org, repo } = getRepoInfo();
11235
11339
  const repoUrl = `https://github.com/${org}/${repo}`;
11236
11340
  const message = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
11237
- execSync34("git push", { stdio: "inherit" });
11341
+ execSync35("git push", { stdio: "inherit" });
11238
11342
  resolveCommentWithReply(commentId, message);
11239
11343
  } catch (error) {
11240
11344
  if (isGhNotInstalled(error)) {
@@ -11252,7 +11356,7 @@ import { join as join36 } from "path";
11252
11356
  import { stringify } from "yaml";
11253
11357
 
11254
11358
  // src/commands/prs/fetchThreadIds.ts
11255
- import { execSync as execSync35 } from "child_process";
11359
+ import { execSync as execSync36 } from "child_process";
11256
11360
  import { unlinkSync as unlinkSync11, writeFileSync as writeFileSync24 } from "fs";
11257
11361
  import { tmpdir as tmpdir6 } from "os";
11258
11362
  import { join as join35 } from "path";
@@ -11261,7 +11365,7 @@ function fetchThreadIds(org, repo, prNumber) {
11261
11365
  const queryFile = join35(tmpdir6(), `gh-query-${Date.now()}.graphql`);
11262
11366
  writeFileSync24(queryFile, THREAD_QUERY);
11263
11367
  try {
11264
- const result = execSync35(
11368
+ const result = execSync36(
11265
11369
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
11266
11370
  { encoding: "utf-8" }
11267
11371
  );
@@ -11283,9 +11387,9 @@ function fetchThreadIds(org, repo, prNumber) {
11283
11387
  }
11284
11388
 
11285
11389
  // src/commands/prs/listComments/fetchReviewComments.ts
11286
- import { execSync as execSync36 } from "child_process";
11390
+ import { execSync as execSync37 } from "child_process";
11287
11391
  function fetchJson(endpoint) {
11288
- const result = execSync36(`gh api --paginate ${endpoint}`, {
11392
+ const result = execSync37(`gh api --paginate ${endpoint}`, {
11289
11393
  encoding: "utf-8"
11290
11394
  });
11291
11395
  if (!result.trim()) return [];
@@ -11327,20 +11431,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
11327
11431
  }
11328
11432
 
11329
11433
  // src/commands/prs/listComments/printComments.ts
11330
- import chalk121 from "chalk";
11434
+ import chalk120 from "chalk";
11331
11435
  function formatForHuman(comment3) {
11332
11436
  if (comment3.type === "review") {
11333
- const stateColor = comment3.state === "APPROVED" ? chalk121.green : comment3.state === "CHANGES_REQUESTED" ? chalk121.red : chalk121.yellow;
11437
+ const stateColor = comment3.state === "APPROVED" ? chalk120.green : comment3.state === "CHANGES_REQUESTED" ? chalk120.red : chalk120.yellow;
11334
11438
  return [
11335
- `${chalk121.cyan("Review")} by ${chalk121.bold(comment3.user)} ${stateColor(`[${comment3.state}]`)}`,
11439
+ `${chalk120.cyan("Review")} by ${chalk120.bold(comment3.user)} ${stateColor(`[${comment3.state}]`)}`,
11336
11440
  comment3.body,
11337
11441
  ""
11338
11442
  ].join("\n");
11339
11443
  }
11340
11444
  const location = comment3.line ? `:${comment3.line}` : "";
11341
11445
  return [
11342
- `${chalk121.cyan("Line comment")} by ${chalk121.bold(comment3.user)} on ${chalk121.dim(`${comment3.path}${location}`)}`,
11343
- chalk121.dim(comment3.diff_hunk.split("\n").slice(-3).join("\n")),
11446
+ `${chalk120.cyan("Line comment")} by ${chalk120.bold(comment3.user)} on ${chalk120.dim(`${comment3.path}${location}`)}`,
11447
+ chalk120.dim(comment3.diff_hunk.split("\n").slice(-3).join("\n")),
11344
11448
  comment3.body,
11345
11449
  ""
11346
11450
  ].join("\n");
@@ -11424,19 +11528,19 @@ async function listComments() {
11424
11528
  }
11425
11529
 
11426
11530
  // src/commands/prs/prs/index.ts
11427
- import { execSync as execSync37 } from "child_process";
11531
+ import { execSync as execSync38 } from "child_process";
11428
11532
 
11429
11533
  // src/commands/prs/prs/displayPaginated/index.ts
11430
11534
  import enquirer9 from "enquirer";
11431
11535
 
11432
11536
  // src/commands/prs/prs/displayPaginated/printPr.ts
11433
- import chalk122 from "chalk";
11537
+ import chalk121 from "chalk";
11434
11538
  var STATUS_MAP = {
11435
- MERGED: (pr) => pr.mergedAt ? { label: chalk122.magenta("merged"), date: pr.mergedAt } : null,
11436
- CLOSED: (pr) => pr.closedAt ? { label: chalk122.red("closed"), date: pr.closedAt } : null
11539
+ MERGED: (pr) => pr.mergedAt ? { label: chalk121.magenta("merged"), date: pr.mergedAt } : null,
11540
+ CLOSED: (pr) => pr.closedAt ? { label: chalk121.red("closed"), date: pr.closedAt } : null
11437
11541
  };
11438
11542
  function defaultStatus(pr) {
11439
- return { label: chalk122.green("opened"), date: pr.createdAt };
11543
+ return { label: chalk121.green("opened"), date: pr.createdAt };
11440
11544
  }
11441
11545
  function getStatus2(pr) {
11442
11546
  return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
@@ -11445,11 +11549,11 @@ function formatDate(dateStr) {
11445
11549
  return new Date(dateStr).toISOString().split("T")[0];
11446
11550
  }
11447
11551
  function formatPrHeader(pr, status2) {
11448
- return `${chalk122.cyan(`#${pr.number}`)} ${pr.title} ${chalk122.dim(`(${pr.author.login},`)} ${status2.label} ${chalk122.dim(`${formatDate(status2.date)})`)}`;
11552
+ return `${chalk121.cyan(`#${pr.number}`)} ${pr.title} ${chalk121.dim(`(${pr.author.login},`)} ${status2.label} ${chalk121.dim(`${formatDate(status2.date)})`)}`;
11449
11553
  }
11450
11554
  function logPrDetails(pr) {
11451
11555
  console.log(
11452
- chalk122.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
11556
+ chalk121.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
11453
11557
  );
11454
11558
  console.log();
11455
11559
  }
@@ -11531,7 +11635,7 @@ async function prs(options2) {
11531
11635
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
11532
11636
  try {
11533
11637
  const { org, repo } = getRepoInfo();
11534
- const result = execSync37(
11638
+ const result = execSync38(
11535
11639
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100 -R ${org}/${repo}`,
11536
11640
  { encoding: "utf-8" }
11537
11641
  );
@@ -11553,8 +11657,75 @@ async function prs(options2) {
11553
11657
  }
11554
11658
  }
11555
11659
 
11660
+ // src/commands/prs/raise.ts
11661
+ import { execSync as execSync39 } from "child_process";
11662
+
11663
+ // src/commands/prs/buildCreateArgs.ts
11664
+ function buildCreateArgs(title, body, options2) {
11665
+ const args = [
11666
+ "gh pr create",
11667
+ `--title ${shellQuote(title)}`,
11668
+ `--body ${shellQuote(body)}`
11669
+ ];
11670
+ const valueFlags = [
11671
+ ["--base", options2.base],
11672
+ ["--head", options2.head],
11673
+ ["--milestone", options2.milestone]
11674
+ ];
11675
+ for (const [flag, value] of valueFlags) {
11676
+ if (value) args.push(`${flag} ${shellQuote(value)}`);
11677
+ }
11678
+ if (options2.draft) args.push("--draft");
11679
+ if (options2.web) args.push("--web");
11680
+ const repeatableFlags = [
11681
+ ["--label", options2.label],
11682
+ ["--assignee", options2.assignee],
11683
+ ["--reviewer", options2.reviewer]
11684
+ ];
11685
+ for (const [flag, values] of repeatableFlags) {
11686
+ for (const value of values ?? []) {
11687
+ args.push(`${flag} ${shellQuote(value)}`);
11688
+ }
11689
+ }
11690
+ return args;
11691
+ }
11692
+
11693
+ // src/commands/prs/raise.ts
11694
+ function raise(options2) {
11695
+ if (!options2.title || !options2.what || !options2.why) {
11696
+ console.error(
11697
+ "Usage: assist prs raise --title <title> --what <what> --why <why> [--how <how>] [--resolves <key>] [--force]"
11698
+ );
11699
+ process.exit(1);
11700
+ }
11701
+ const body = buildPrBody({
11702
+ what: options2.what,
11703
+ why: options2.why,
11704
+ how: options2.how,
11705
+ resolves: options2.resolves
11706
+ });
11707
+ validatePrContent(options2.title, body);
11708
+ const existing = findCurrentPrNumber();
11709
+ if (existing !== null && !options2.force) {
11710
+ console.error(
11711
+ `Error: A pull request already exists for this branch (#${existing}). Pass --force to overwrite it, or use 'assist prs edit' to update individual sections.`
11712
+ );
11713
+ process.exit(1);
11714
+ }
11715
+ const args = existing !== null ? [
11716
+ `gh pr edit ${existing}`,
11717
+ `--title ${shellQuote(options2.title)}`,
11718
+ `--body ${shellQuote(body)}`
11719
+ ] : buildCreateArgs(options2.title, body, options2);
11720
+ try {
11721
+ execSync39(args.join(" "), { stdio: "inherit" });
11722
+ } catch (_error) {
11723
+ process.exit(1);
11724
+ }
11725
+ }
11726
+
11556
11727
  // src/commands/prs/wontfix.ts
11557
- import { execSync as execSync38 } from "child_process";
11728
+ import { execSync as execSync40 } from "child_process";
11558
11729
  function validateReason(reason) {
11559
11730
  const lowerReason = reason.toLowerCase();
11560
11731
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -11571,7 +11742,7 @@ function validateShaReferences(reason) {
11571
11742
  const invalidShas = [];
11572
11743
  for (const sha of shas) {
11573
11744
  try {
11574
- execSync38(`git cat-file -t ${sha}`, { stdio: "pipe" });
11745
+ execSync40(`git cat-file -t ${sha}`, { stdio: "pipe" });
11575
11746
  } catch {
11576
11747
  invalidShas.push(sha);
11577
11748
  }
@@ -11598,30 +11769,54 @@ function wontfix(commentId, reason) {
11598
11769
  }
11599
11770
  }
11600
11771
 
11601
- // src/commands/registerPrsCreate.ts
11772
+ // src/commands/registerPrsEdit.ts
11602
11773
  function collect2(value, previous) {
11603
11774
  return previous.concat([value]);
11604
11775
  }
11605
- function registerPrsCreate(prsCommand) {
11606
- prsCommand.command("create").description(
11607
- "Create a pull request via gh pr create, validating the title and body first"
11608
- ).option("-t, --title <title>", "Title for the pull request").option("-b, --body <body>", "Body for the pull request").option("-B, --base <branch>", "Branch into which the pull request merges").option("-H, --head <branch>", "Branch that contains the commits").option("-d, --draft", "Mark the pull request as a draft").option("-w, --web", "Open the browser to create the pull request").option("-l, --label <label>", "Add a label (repeatable)", collect2, []).option(
11776
+ function registerPrsEdit(prsCommand) {
11777
+ prsCommand.command("edit").description(
11778
+ "Update individual sections of the current branch's pull request"
11779
+ ).option("-t, --title <title>", "New title for the pull request").option("--what <what>", "Replace the ## What section").option("--why <why>", "Replace the ## Why section").option("--how <how>", "Replace the ## How section").option(
11780
+ "--resolves <key>",
11781
+ "Jira issue key resolved by this PR, appended to ## Why (repeatable)",
11782
+ collect2,
11783
+ []
11784
+ ).action(edit);
11785
+ }
11786
+
11787
+ // src/commands/registerPrsRaise.ts
11788
+ function collect3(value, previous) {
11789
+ return previous.concat([value]);
11790
+ }
11791
+ function registerPrsRaise(prsCommand) {
11792
+ prsCommand.command("raise").description(
11793
+ "Raise a pull request, assembling the body from discrete sections"
11794
+ ).option("-t, --title <title>", "Title for the pull request").option("--what <what>", "What the change does (## What section)").option("--why <why>", "Why the change is needed (## Why section)").option("--how <how>", "How the change works (optional ## How section)").option(
11795
+ "--resolves <key>",
11796
+ "Jira issue key resolved by this PR, appended to ## Why (repeatable)",
11797
+ collect3,
11798
+ []
11799
+ ).option(
11800
+ "--force",
11801
+ "Overwrite the title and body of an existing pull request"
11802
+ ).option("-B, --base <branch>", "Branch into which the pull request merges").option("-H, --head <branch>", "Branch that contains the commits").option("-d, --draft", "Mark the pull request as a draft").option("-w, --web", "Open the browser to create the pull request").option("-l, --label <label>", "Add a label (repeatable)", collect3, []).option(
11609
11803
  "-a, --assignee <login>",
11610
11804
  "Assign a person by login (repeatable)",
11611
- collect2,
11805
+ collect3,
11612
11806
  []
11613
11807
  ).option(
11614
11808
  "-r, --reviewer <handle>",
11615
11809
  "Request a review (repeatable)",
11616
- collect2,
11810
+ collect3,
11617
11811
  []
11618
- ).option("-m, --milestone <name>", "Add the pull request to a milestone").action(create);
11812
+ ).option("-m, --milestone <name>", "Add the pull request to a milestone").action(raise);
11619
11813
  }
11620
11814
 
11621
11815
  // src/commands/registerPrs.ts
11622
11816
  function registerPrs(program2) {
11623
11817
  const prsCommand = program2.command("prs").description("Pull request utilities").option("--open", "List only open pull requests").option("--closed", "List only closed pull requests").action(prs);
11624
- registerPrsCreate(prsCommand);
11818
+ registerPrsRaise(prsCommand);
11819
+ registerPrsEdit(prsCommand);
11625
11820
  prsCommand.command("list-comments").description("List all comments on the current branch's pull request").action(() => {
11626
11821
  listComments().then(printComments2);
11627
11822
  });
@@ -11637,10 +11832,10 @@ function registerPrs(program2) {
11637
11832
  }
11638
11833
 
11639
11834
  // src/commands/ravendb/ravendbAuth.ts
11640
- import chalk128 from "chalk";
11835
+ import chalk127 from "chalk";
11641
11836
 
11642
11837
  // src/shared/createConnectionAuth.ts
11643
- import chalk123 from "chalk";
11838
+ import chalk122 from "chalk";
11644
11839
  function listConnections(connections, format2) {
11645
11840
  if (connections.length === 0) {
11646
11841
  console.log("No connections configured.");
@@ -11653,7 +11848,7 @@ function listConnections(connections, format2) {
11653
11848
  function removeConnection(connections, name, save) {
11654
11849
  const filtered = connections.filter((c) => c.name !== name);
11655
11850
  if (filtered.length === connections.length) {
11656
- console.error(chalk123.red(`Connection "${name}" not found.`));
11851
+ console.error(chalk122.red(`Connection "${name}" not found.`));
11657
11852
  process.exit(1);
11658
11853
  }
11659
11854
  save(filtered);
@@ -11699,17 +11894,17 @@ function saveConnections(connections) {
11699
11894
  }
11700
11895
 
11701
11896
  // src/commands/ravendb/promptConnection.ts
11702
- import chalk126 from "chalk";
11897
+ import chalk125 from "chalk";
11703
11898
 
11704
11899
  // src/commands/ravendb/selectOpSecret.ts
11705
- import chalk125 from "chalk";
11900
+ import chalk124 from "chalk";
11706
11901
  import Enquirer2 from "enquirer";
11707
11902
 
11708
11903
  // src/commands/ravendb/searchItems.ts
11709
- import { execSync as execSync39 } from "child_process";
11710
- import chalk124 from "chalk";
11904
+ import { execSync as execSync41 } from "child_process";
11905
+ import chalk123 from "chalk";
11711
11906
  function opExec(args) {
11712
- return execSync39(`op ${args}`, {
11907
+ return execSync41(`op ${args}`, {
11713
11908
  encoding: "utf-8",
11714
11909
  stdio: ["pipe", "pipe", "pipe"]
11715
11910
  }).trim();
@@ -11720,7 +11915,7 @@ function searchItems(search2) {
11720
11915
  items2 = JSON.parse(opExec("item list --format=json"));
11721
11916
  } catch {
11722
11917
  console.error(
11723
- chalk124.red(
11918
+ chalk123.red(
11724
11919
  "Failed to search 1Password. Ensure the CLI is installed and you are signed in."
11725
11920
  )
11726
11921
  );
@@ -11734,7 +11929,7 @@ function getItemFields(itemId) {
11734
11929
  const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
11735
11930
  return item.fields.filter((f) => f.reference && f.label);
11736
11931
  } catch {
11737
- console.error(chalk124.red("Failed to get item details from 1Password."));
11932
+ console.error(chalk123.red("Failed to get item details from 1Password."));
11738
11933
  process.exit(1);
11739
11934
  }
11740
11935
  }
@@ -11753,7 +11948,7 @@ async function selectOpSecret(searchTerm) {
11753
11948
  }).run();
11754
11949
  const items2 = searchItems(search2);
11755
11950
  if (items2.length === 0) {
11756
- console.error(chalk125.red(`No items found matching "${search2}".`));
11951
+ console.error(chalk124.red(`No items found matching "${search2}".`));
11757
11952
  process.exit(1);
11758
11953
  }
11759
11954
  const itemId = await selectOne(
@@ -11762,7 +11957,7 @@ async function selectOpSecret(searchTerm) {
11762
11957
  );
11763
11958
  const fields = getItemFields(itemId);
11764
11959
  if (fields.length === 0) {
11765
- console.error(chalk125.red("No fields with references found on this item."));
11960
+ console.error(chalk124.red("No fields with references found on this item."));
11766
11961
  process.exit(1);
11767
11962
  }
11768
11963
  const ref = await selectOne(
@@ -11776,7 +11971,7 @@ async function selectOpSecret(searchTerm) {
11776
11971
  async function promptConnection(existingNames) {
11777
11972
  const name = await promptInput("name", "Connection name:");
11778
11973
  if (existingNames.includes(name)) {
11779
- console.error(chalk126.red(`Connection "${name}" already exists.`));
11974
+ console.error(chalk125.red(`Connection "${name}" already exists.`));
11780
11975
  process.exit(1);
11781
11976
  }
11782
11977
  const url = await promptInput(
@@ -11785,22 +11980,22 @@ async function promptConnection(existingNames) {
11785
11980
  );
11786
11981
  const database = await promptInput("database", "Database name:");
11787
11982
  if (!name || !url || !database) {
11788
- console.error(chalk126.red("All fields are required."));
11983
+ console.error(chalk125.red("All fields are required."));
11789
11984
  process.exit(1);
11790
11985
  }
11791
11986
  const apiKeyRef = await selectOpSecret();
11792
- console.log(chalk126.dim(`Using: ${apiKeyRef}`));
11987
+ console.log(chalk125.dim(`Using: ${apiKeyRef}`));
11793
11988
  return { name, url, database, apiKeyRef };
11794
11989
  }
11795
11990
 
11796
11991
  // src/commands/ravendb/ravendbSetConnection.ts
11797
- import chalk127 from "chalk";
11992
+ import chalk126 from "chalk";
11798
11993
  function ravendbSetConnection(name) {
11799
11994
  const raw = loadGlobalConfigRaw();
11800
11995
  const ravendb = raw.ravendb ?? {};
11801
11996
  const connections = ravendb.connections ?? [];
11802
11997
  if (!connections.some((c) => c.name === name)) {
11803
- console.error(chalk127.red(`Connection "${name}" not found.`));
11998
+ console.error(chalk126.red(`Connection "${name}" not found.`));
11804
11999
  console.error(
11805
12000
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
11806
12001
  );
@@ -11816,16 +12011,16 @@ function ravendbSetConnection(name) {
11816
12011
  var ravendbAuth = createConnectionAuth({
11817
12012
  load: loadConnections,
11818
12013
  save: saveConnections,
11819
- format: (c) => `${chalk128.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
12014
+ format: (c) => `${chalk127.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
11820
12015
  promptNew: promptConnection,
11821
12016
  onFirst: (c) => ravendbSetConnection(c.name)
11822
12017
  });
11823
12018
 
11824
12019
  // src/commands/ravendb/ravendbCollections.ts
11825
- import chalk132 from "chalk";
12020
+ import chalk131 from "chalk";
11826
12021
 
11827
12022
  // src/commands/ravendb/ravenFetch.ts
11828
- import chalk130 from "chalk";
12023
+ import chalk129 from "chalk";
11829
12024
 
11830
12025
  // src/commands/ravendb/getAccessToken.ts
11831
12026
  var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
@@ -11861,21 +12056,21 @@ ${errorText}`
11861
12056
  }
11862
12057
 
11863
12058
  // src/commands/ravendb/resolveOpSecret.ts
11864
- import { execSync as execSync40 } from "child_process";
11865
- import chalk129 from "chalk";
12059
+ import { execSync as execSync42 } from "child_process";
12060
+ import chalk128 from "chalk";
11866
12061
  function resolveOpSecret(reference) {
11867
12062
  if (!reference.startsWith("op://")) {
11868
- console.error(chalk129.red(`Invalid secret reference: must start with op://`));
12063
+ console.error(chalk128.red(`Invalid secret reference: must start with op://`));
11869
12064
  process.exit(1);
11870
12065
  }
11871
12066
  try {
11872
- return execSync40(`op read "${reference}"`, {
12067
+ return execSync42(`op read "${reference}"`, {
11873
12068
  encoding: "utf-8",
11874
12069
  stdio: ["pipe", "pipe", "pipe"]
11875
12070
  }).trim();
11876
12071
  } catch {
11877
12072
  console.error(
11878
- chalk129.red(
12073
+ chalk128.red(
11879
12074
  "Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
11880
12075
  )
11881
12076
  );
@@ -11902,7 +12097,7 @@ async function ravenFetch(connection, path54) {
11902
12097
  if (!response.ok) {
11903
12098
  const body = await response.text();
11904
12099
  console.error(
11905
- chalk130.red(`RavenDB error: ${response.status} ${response.statusText}`)
12100
+ chalk129.red(`RavenDB error: ${response.status} ${response.statusText}`)
11906
12101
  );
11907
12102
  console.error(body.substring(0, 500));
11908
12103
  process.exit(1);
@@ -11911,7 +12106,7 @@ async function ravenFetch(connection, path54) {
11911
12106
  }
11912
12107
 
11913
12108
  // src/commands/ravendb/resolveConnection.ts
11914
- import chalk131 from "chalk";
12109
+ import chalk130 from "chalk";
11915
12110
  function loadRavendb() {
11916
12111
  const raw = loadGlobalConfigRaw();
11917
12112
  const ravendb = raw.ravendb;
@@ -11925,7 +12120,7 @@ function resolveConnection(name) {
11925
12120
  const connectionName = name ?? defaultConnection;
11926
12121
  if (!connectionName) {
11927
12122
  console.error(
11928
- chalk131.red(
12123
+ chalk130.red(
11929
12124
  "No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
11930
12125
  )
11931
12126
  );
@@ -11933,7 +12128,7 @@ function resolveConnection(name) {
11933
12128
  }
11934
12129
  const connection = connections.find((c) => c.name === connectionName);
11935
12130
  if (!connection) {
11936
- console.error(chalk131.red(`Connection "${connectionName}" not found.`));
12131
+ console.error(chalk130.red(`Connection "${connectionName}" not found.`));
11937
12132
  console.error(
11938
12133
  `Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
11939
12134
  );
@@ -11964,15 +12159,15 @@ async function ravendbCollections(connectionName) {
11964
12159
  return;
11965
12160
  }
11966
12161
  for (const c of collections) {
11967
- console.log(`${chalk132.bold(c.Name)} ${c.CountOfDocuments} docs`);
12162
+ console.log(`${chalk131.bold(c.Name)} ${c.CountOfDocuments} docs`);
11968
12163
  }
11969
12164
  }
11970
12165
 
11971
12166
  // src/commands/ravendb/ravendbQuery.ts
11972
- import chalk134 from "chalk";
12167
+ import chalk133 from "chalk";
11973
12168
 
11974
12169
  // src/commands/ravendb/fetchAllPages.ts
11975
- import chalk133 from "chalk";
12170
+ import chalk132 from "chalk";
11976
12171
 
11977
12172
  // src/commands/ravendb/buildQueryPath.ts
11978
12173
  function buildQueryPath(opts) {
@@ -12010,7 +12205,7 @@ async function fetchAllPages(connection, opts) {
12010
12205
  allResults.push(...results);
12011
12206
  start3 += results.length;
12012
12207
  process.stderr.write(
12013
- `\r${chalk133.dim(`Fetched ${allResults.length}/${totalResults}`)}`
12208
+ `\r${chalk132.dim(`Fetched ${allResults.length}/${totalResults}`)}`
12014
12209
  );
12015
12210
  if (start3 >= totalResults) break;
12016
12211
  if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
@@ -12025,7 +12220,7 @@ async function fetchAllPages(connection, opts) {
12025
12220
  async function ravendbQuery(connectionName, collection, options2) {
12026
12221
  const resolved = resolveArgs(connectionName, collection);
12027
12222
  if (!resolved.collection && !options2.query) {
12028
- console.error(chalk134.red("Provide a collection name or --query filter."));
12223
+ console.error(chalk133.red("Provide a collection name or --query filter."));
12029
12224
  process.exit(1);
12030
12225
  }
12031
12226
  const { collection: col } = resolved;
@@ -12063,7 +12258,7 @@ import { spawn as spawn5 } from "child_process";
12063
12258
  import * as path26 from "path";
12064
12259
 
12065
12260
  // src/commands/refactor/logViolations.ts
12066
- import chalk135 from "chalk";
12261
+ import chalk134 from "chalk";
12067
12262
  var DEFAULT_MAX_LINES = 100;
12068
12263
  function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
12069
12264
  if (violations.length === 0) {
@@ -12072,43 +12267,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
12072
12267
  }
12073
12268
  return;
12074
12269
  }
12075
- console.error(chalk135.red(`
12270
+ console.error(chalk134.red(`
12076
12271
  Refactor check failed:
12077
12272
  `));
12078
- console.error(chalk135.red(` The following files exceed ${maxLines} lines:
12273
+ console.error(chalk134.red(` The following files exceed ${maxLines} lines:
12079
12274
  `));
12080
12275
  for (const violation of violations) {
12081
- console.error(chalk135.red(` ${violation.file} (${violation.lines} lines)`));
12276
+ console.error(chalk134.red(` ${violation.file} (${violation.lines} lines)`));
12082
12277
  }
12083
12278
  console.error(
12084
- chalk135.yellow(
12279
+ chalk134.yellow(
12085
12280
  `
12086
12281
  Each file needs to be sensibly refactored, or if there is no sensible
12087
12282
  way to refactor it, ignore it with:
12088
12283
  `
12089
12284
  )
12090
12285
  );
12091
- console.error(chalk135.gray(` assist refactor ignore <file>
12286
+ console.error(chalk134.gray(` assist refactor ignore <file>
12092
12287
  `));
12093
12288
  if (process.env.CLAUDECODE) {
12094
- console.error(chalk135.cyan(`
12289
+ console.error(chalk134.cyan(`
12095
12290
  ## Extracting Code to New Files
12096
12291
  `));
12097
12292
  console.error(
12098
- chalk135.cyan(
12293
+ chalk134.cyan(
12099
12294
  ` When extracting logic from one file to another, consider where the extracted code belongs:
12100
12295
  `
12101
12296
  )
12102
12297
  );
12103
12298
  console.error(
12104
- chalk135.cyan(
12299
+ chalk134.cyan(
12105
12300
  ` 1. Keep related logic together: If the extracted code is tightly coupled to the
12106
12301
  original file's domain, create a new folder containing both the original and extracted files.
12107
12302
  `
12108
12303
  )
12109
12304
  );
12110
12305
  console.error(
12111
- chalk135.cyan(
12306
+ chalk134.cyan(
12112
12307
  ` 2. Share common utilities: If the extracted code can be reused across multiple
12113
12308
  domains, move it to a common/shared folder.
12114
12309
  `
@@ -12118,7 +12313,7 @@ Refactor check failed:
12118
12313
  }
12119
12314
 
12120
12315
  // src/commands/refactor/check/getViolations/index.ts
12121
- import { execSync as execSync41 } from "child_process";
12316
+ import { execSync as execSync43 } from "child_process";
12122
12317
  import fs18 from "fs";
12123
12318
  import { minimatch as minimatch5 } from "minimatch";
12124
12319
 
@@ -12168,7 +12363,7 @@ function getGitFiles(options2) {
12168
12363
  }
12169
12364
  const files = /* @__PURE__ */ new Set();
12170
12365
  if (options2.staged || options2.modified) {
12171
- const staged = execSync41("git diff --cached --name-only", {
12366
+ const staged = execSync43("git diff --cached --name-only", {
12172
12367
  encoding: "utf-8"
12173
12368
  });
12174
12369
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -12176,7 +12371,7 @@ function getGitFiles(options2) {
12176
12371
  }
12177
12372
  }
12178
12373
  if (options2.unstaged || options2.modified) {
12179
- const unstaged = execSync41("git diff --name-only", { encoding: "utf-8" });
12374
+ const unstaged = execSync43("git diff --name-only", { encoding: "utf-8" });
12180
12375
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
12181
12376
  files.add(file);
12182
12377
  }
@@ -12264,7 +12459,7 @@ async function check(pattern2, options2) {
12264
12459
 
12265
12460
  // src/commands/refactor/extract/index.ts
12266
12461
  import path33 from "path";
12267
- import chalk138 from "chalk";
12462
+ import chalk137 from "chalk";
12268
12463
 
12269
12464
  // src/commands/refactor/extract/applyExtraction.ts
12270
12465
  import { SyntaxKind as SyntaxKind4 } from "ts-morph";
@@ -12839,23 +13034,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
12839
13034
 
12840
13035
  // src/commands/refactor/extract/displayPlan.ts
12841
13036
  import path30 from "path";
12842
- import chalk136 from "chalk";
13037
+ import chalk135 from "chalk";
12843
13038
  function section(title) {
12844
13039
  return `
12845
- ${chalk136.cyan(title)}`;
13040
+ ${chalk135.cyan(title)}`;
12846
13041
  }
12847
13042
  function displayImporters(plan2, cwd) {
12848
13043
  if (plan2.importersToUpdate.length === 0) return;
12849
13044
  console.log(section("Update importers:"));
12850
13045
  for (const imp of plan2.importersToUpdate) {
12851
13046
  const rel = path30.relative(cwd, imp.file.getFilePath());
12852
- console.log(` ${chalk136.dim(rel)}: \u2192 import from "${imp.relPath}"`);
13047
+ console.log(` ${chalk135.dim(rel)}: \u2192 import from "${imp.relPath}"`);
12853
13048
  }
12854
13049
  }
12855
13050
  function displayPlan(functionName, relDest, plan2, cwd) {
12856
- console.log(chalk136.bold(`Extract: ${functionName} \u2192 ${relDest}
13051
+ console.log(chalk135.bold(`Extract: ${functionName} \u2192 ${relDest}
12857
13052
  `));
12858
- console.log(` ${chalk136.cyan("Functions to move:")}`);
13053
+ console.log(` ${chalk135.cyan("Functions to move:")}`);
12859
13054
  for (const name of plan2.extractedNames) {
12860
13055
  console.log(` ${name}`);
12861
13056
  }
@@ -12889,7 +13084,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
12889
13084
 
12890
13085
  // src/commands/refactor/extract/loadProjectFile.ts
12891
13086
  import path32 from "path";
12892
- import chalk137 from "chalk";
13087
+ import chalk136 from "chalk";
12893
13088
  import { Project as Project4 } from "ts-morph";
12894
13089
 
12895
13090
  // src/commands/refactor/extract/findTsConfig.ts
@@ -12949,7 +13144,7 @@ function loadProjectFile(file) {
12949
13144
  });
12950
13145
  const sourceFile = project.getSourceFile(sourcePath);
12951
13146
  if (!sourceFile) {
12952
- console.log(chalk137.red(`File not found in project: ${file}`));
13147
+ console.log(chalk136.red(`File not found in project: ${file}`));
12953
13148
  process.exit(1);
12954
13149
  }
12955
13150
  return { project, sourceFile };
@@ -12972,19 +13167,19 @@ async function extract(file, functionName, destination, options2 = {}) {
12972
13167
  displayPlan(functionName, relDest, plan2, cwd);
12973
13168
  if (options2.apply) {
12974
13169
  await applyExtraction(functionName, sourceFile, destPath, plan2, project);
12975
- console.log(chalk138.green("\nExtraction complete"));
13170
+ console.log(chalk137.green("\nExtraction complete"));
12976
13171
  } else {
12977
- console.log(chalk138.dim("\nDry run. Use --apply to execute."));
13172
+ console.log(chalk137.dim("\nDry run. Use --apply to execute."));
12978
13173
  }
12979
13174
  }
12980
13175
 
12981
13176
  // src/commands/refactor/ignore.ts
12982
13177
  import fs20 from "fs";
12983
- import chalk139 from "chalk";
13178
+ import chalk138 from "chalk";
12984
13179
  var REFACTOR_YML_PATH2 = "refactor.yml";
12985
13180
  function ignore(file) {
12986
13181
  if (!fs20.existsSync(file)) {
12987
- console.error(chalk139.red(`Error: File does not exist: ${file}`));
13182
+ console.error(chalk138.red(`Error: File does not exist: ${file}`));
12988
13183
  process.exit(1);
12989
13184
  }
12990
13185
  const content = fs20.readFileSync(file, "utf-8");
@@ -13000,7 +13195,7 @@ function ignore(file) {
13000
13195
  fs20.writeFileSync(REFACTOR_YML_PATH2, entry);
13001
13196
  }
13002
13197
  console.log(
13003
- chalk139.green(
13198
+ chalk138.green(
13004
13199
  `Added ${file} to refactor ignore list (max ${maxLines} lines)`
13005
13200
  )
13006
13201
  );
@@ -13008,25 +13203,25 @@ function ignore(file) {
13008
13203
 
13009
13204
  // src/commands/refactor/rename/index.ts
13010
13205
  import path34 from "path";
13011
- import chalk140 from "chalk";
13206
+ import chalk139 from "chalk";
13012
13207
  async function rename(source, destination, options2 = {}) {
13013
13208
  const destPath = path34.resolve(destination);
13014
13209
  const cwd = process.cwd();
13015
13210
  const relSource = path34.relative(cwd, path34.resolve(source));
13016
13211
  const relDest = path34.relative(cwd, destPath);
13017
13212
  const { project, sourceFile } = loadProjectFile(source);
13018
- console.log(chalk140.bold(`Rename: ${relSource} \u2192 ${relDest}`));
13213
+ console.log(chalk139.bold(`Rename: ${relSource} \u2192 ${relDest}`));
13019
13214
  if (options2.apply) {
13020
13215
  sourceFile.move(destPath);
13021
13216
  await project.save();
13022
- console.log(chalk140.green("Done"));
13217
+ console.log(chalk139.green("Done"));
13023
13218
  } else {
13024
- console.log(chalk140.dim("Dry run. Use --apply to execute."));
13219
+ console.log(chalk139.dim("Dry run. Use --apply to execute."));
13025
13220
  }
13026
13221
  }
13027
13222
 
13028
13223
  // src/commands/refactor/renameSymbol/index.ts
13029
- import chalk141 from "chalk";
13224
+ import chalk140 from "chalk";
13030
13225
 
13031
13226
  // src/commands/refactor/renameSymbol/findSymbol.ts
13032
13227
  import { SyntaxKind as SyntaxKind14 } from "ts-morph";
@@ -13072,33 +13267,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
13072
13267
  const { project, sourceFile } = loadProjectFile(file);
13073
13268
  const symbol = findSymbol(sourceFile, oldName);
13074
13269
  if (!symbol) {
13075
- console.log(chalk141.red(`Symbol "${oldName}" not found in ${file}`));
13270
+ console.log(chalk140.red(`Symbol "${oldName}" not found in ${file}`));
13076
13271
  process.exit(1);
13077
13272
  }
13078
13273
  const grouped = groupReferences(symbol, cwd);
13079
13274
  const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
13080
13275
  console.log(
13081
- chalk141.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
13276
+ chalk140.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
13082
13277
  `)
13083
13278
  );
13084
13279
  for (const [refFile, lines] of grouped) {
13085
13280
  console.log(
13086
- ` ${chalk141.dim(refFile)}: lines ${chalk141.cyan(lines.join(", "))}`
13281
+ ` ${chalk140.dim(refFile)}: lines ${chalk140.cyan(lines.join(", "))}`
13087
13282
  );
13088
13283
  }
13089
13284
  if (options2.apply) {
13090
13285
  symbol.rename(newName);
13091
13286
  await project.save();
13092
- console.log(chalk141.green(`
13287
+ console.log(chalk140.green(`
13093
13288
  Renamed ${oldName} \u2192 ${newName}`));
13094
13289
  } else {
13095
- console.log(chalk141.dim("\nDry run. Use --apply to execute."));
13290
+ console.log(chalk140.dim("\nDry run. Use --apply to execute."));
13096
13291
  }
13097
13292
  }
13098
13293
 
13099
13294
  // src/commands/refactor/restructure/index.ts
13100
13295
  import path44 from "path";
13101
- import chalk144 from "chalk";
13296
+ import chalk143 from "chalk";
13102
13297
 
13103
13298
  // src/commands/refactor/restructure/buildImportGraph/index.ts
13104
13299
  import path36 from "path";
@@ -13341,50 +13536,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
13341
13536
 
13342
13537
  // src/commands/refactor/restructure/displayPlan.ts
13343
13538
  import path40 from "path";
13344
- import chalk142 from "chalk";
13539
+ import chalk141 from "chalk";
13345
13540
  function relPath(filePath) {
13346
13541
  return path40.relative(process.cwd(), filePath);
13347
13542
  }
13348
13543
  function displayMoves(plan2) {
13349
13544
  if (plan2.moves.length === 0) return;
13350
- console.log(chalk142.bold("\nFile moves:"));
13545
+ console.log(chalk141.bold("\nFile moves:"));
13351
13546
  for (const move of plan2.moves) {
13352
13547
  console.log(
13353
- ` ${chalk142.red(relPath(move.from))} \u2192 ${chalk142.green(relPath(move.to))}`
13548
+ ` ${chalk141.red(relPath(move.from))} \u2192 ${chalk141.green(relPath(move.to))}`
13354
13549
  );
13355
- console.log(chalk142.dim(` ${move.reason}`));
13550
+ console.log(chalk141.dim(` ${move.reason}`));
13356
13551
  }
13357
13552
  }
13358
13553
  function displayRewrites(rewrites) {
13359
13554
  if (rewrites.length === 0) return;
13360
13555
  const affectedFiles = new Set(rewrites.map((r) => r.file));
13361
- console.log(chalk142.bold(`
13556
+ console.log(chalk141.bold(`
13362
13557
  Import rewrites (${affectedFiles.size} files):`));
13363
13558
  for (const file of affectedFiles) {
13364
- console.log(` ${chalk142.cyan(relPath(file))}:`);
13559
+ console.log(` ${chalk141.cyan(relPath(file))}:`);
13365
13560
  for (const { oldSpecifier, newSpecifier } of rewrites.filter(
13366
13561
  (r) => r.file === file
13367
13562
  )) {
13368
13563
  console.log(
13369
- ` ${chalk142.red(`"${oldSpecifier}"`)} \u2192 ${chalk142.green(`"${newSpecifier}"`)}`
13564
+ ` ${chalk141.red(`"${oldSpecifier}"`)} \u2192 ${chalk141.green(`"${newSpecifier}"`)}`
13370
13565
  );
13371
13566
  }
13372
13567
  }
13373
13568
  }
13374
13569
  function displayPlan2(plan2) {
13375
13570
  if (plan2.warnings.length > 0) {
13376
- console.log(chalk142.yellow("\nWarnings:"));
13377
- for (const w of plan2.warnings) console.log(chalk142.yellow(` ${w}`));
13571
+ console.log(chalk141.yellow("\nWarnings:"));
13572
+ for (const w of plan2.warnings) console.log(chalk141.yellow(` ${w}`));
13378
13573
  }
13379
13574
  if (plan2.newDirectories.length > 0) {
13380
- console.log(chalk142.bold("\nNew directories:"));
13575
+ console.log(chalk141.bold("\nNew directories:"));
13381
13576
  for (const dir of plan2.newDirectories)
13382
- console.log(chalk142.green(` ${dir}/`));
13577
+ console.log(chalk141.green(` ${dir}/`));
13383
13578
  }
13384
13579
  displayMoves(plan2);
13385
13580
  displayRewrites(plan2.rewrites);
13386
13581
  console.log(
13387
- chalk142.dim(
13582
+ chalk141.dim(
13388
13583
  `
13389
13584
  Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
13390
13585
  )
@@ -13394,18 +13589,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
13394
13589
  // src/commands/refactor/restructure/executePlan.ts
13395
13590
  import fs22 from "fs";
13396
13591
  import path41 from "path";
13397
- import chalk143 from "chalk";
13592
+ import chalk142 from "chalk";
13398
13593
  function executePlan(plan2) {
13399
13594
  const updatedContents = applyRewrites(plan2.rewrites);
13400
13595
  for (const [file, content] of updatedContents) {
13401
13596
  fs22.writeFileSync(file, content, "utf-8");
13402
13597
  console.log(
13403
- chalk143.cyan(` Rewrote imports in ${path41.relative(process.cwd(), file)}`)
13598
+ chalk142.cyan(` Rewrote imports in ${path41.relative(process.cwd(), file)}`)
13404
13599
  );
13405
13600
  }
13406
13601
  for (const dir of plan2.newDirectories) {
13407
13602
  fs22.mkdirSync(dir, { recursive: true });
13408
- console.log(chalk143.green(` Created ${path41.relative(process.cwd(), dir)}/`));
13603
+ console.log(chalk142.green(` Created ${path41.relative(process.cwd(), dir)}/`));
13409
13604
  }
13410
13605
  for (const move of plan2.moves) {
13411
13606
  const targetDir = path41.dirname(move.to);
@@ -13414,7 +13609,7 @@ function executePlan(plan2) {
13414
13609
  }
13415
13610
  fs22.renameSync(move.from, move.to);
13416
13611
  console.log(
13417
- chalk143.white(
13612
+ chalk142.white(
13418
13613
  ` Moved ${path41.relative(process.cwd(), move.from)} \u2192 ${path41.relative(process.cwd(), move.to)}`
13419
13614
  )
13420
13615
  );
@@ -13429,7 +13624,7 @@ function removeEmptyDirectories(dirs) {
13429
13624
  if (entries.length === 0) {
13430
13625
  fs22.rmdirSync(dir);
13431
13626
  console.log(
13432
- chalk143.dim(
13627
+ chalk142.dim(
13433
13628
  ` Removed empty directory ${path41.relative(process.cwd(), dir)}`
13434
13629
  )
13435
13630
  );
@@ -13562,22 +13757,22 @@ async function restructure(pattern2, options2 = {}) {
13562
13757
  const targetPattern = pattern2 ?? "src";
13563
13758
  const files = findSourceFiles2(targetPattern);
13564
13759
  if (files.length === 0) {
13565
- console.log(chalk144.yellow("No files found matching pattern"));
13760
+ console.log(chalk143.yellow("No files found matching pattern"));
13566
13761
  return;
13567
13762
  }
13568
13763
  const tsConfigPath = path44.resolve("tsconfig.json");
13569
13764
  const plan2 = buildPlan3(files, tsConfigPath);
13570
13765
  if (plan2.moves.length === 0) {
13571
- console.log(chalk144.green("No restructuring needed"));
13766
+ console.log(chalk143.green("No restructuring needed"));
13572
13767
  return;
13573
13768
  }
13574
13769
  displayPlan2(plan2);
13575
13770
  if (options2.apply) {
13576
- console.log(chalk144.bold("\nApplying changes..."));
13771
+ console.log(chalk143.bold("\nApplying changes..."));
13577
13772
  executePlan(plan2);
13578
- console.log(chalk144.green("\nRestructuring complete"));
13773
+ console.log(chalk143.green("\nRestructuring complete"));
13579
13774
  } else {
13580
- console.log(chalk144.dim("\nDry run. Use --apply to execute."));
13775
+ console.log(chalk143.dim("\nDry run. Use --apply to execute."));
13581
13776
  }
13582
13777
  }
13583
13778
 
@@ -13752,9 +13947,9 @@ function buildReviewPaths(repoRoot, key) {
13752
13947
  }
13753
13948
 
13754
13949
  // src/commands/review/fetchExistingComments.ts
13755
- import { execSync as execSync42 } from "child_process";
13950
+ import { execSync as execSync44 } from "child_process";
13756
13951
  function fetchRawComments(org, repo, prNumber) {
13757
- const out = execSync42(
13952
+ const out = execSync44(
13758
13953
  `gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
13759
13954
  { encoding: "utf-8", maxBuffer: 64 * 1024 * 1024 }
13760
13955
  );
@@ -13785,14 +13980,14 @@ function fetchExistingComments() {
13785
13980
  }
13786
13981
 
13787
13982
  // src/commands/review/gatherContext.ts
13788
- import { execSync as execSync45 } from "child_process";
13983
+ import { execSync as execSync47 } from "child_process";
13789
13984
 
13790
13985
  // src/commands/review/fetchPrDiff.ts
13791
- import { execSync as execSync43 } from "child_process";
13986
+ import { execSync as execSync45 } from "child_process";
13792
13987
  function fetchPrDiff(prNumber, baseSha, headSha) {
13793
13988
  const { org, repo } = getRepoInfo();
13794
13989
  try {
13795
- return execSync43(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
13990
+ return execSync45(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
13796
13991
  encoding: "utf-8",
13797
13992
  maxBuffer: 256 * 1024 * 1024,
13798
13993
  stdio: ["ignore", "pipe", "pipe"]
@@ -13807,19 +14002,19 @@ function isDiffTooLarge(error) {
13807
14002
  }
13808
14003
  function fetchDiffViaGit(baseSha, headSha) {
13809
14004
  try {
13810
- execSync43(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
14005
+ execSync45(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
13811
14006
  } catch {
13812
14007
  }
13813
- return execSync43(`git diff ${baseSha}...${headSha}`, {
14008
+ return execSync45(`git diff ${baseSha}...${headSha}`, {
13814
14009
  encoding: "utf-8",
13815
14010
  maxBuffer: 256 * 1024 * 1024
13816
14011
  });
13817
14012
  }
13818
14013
 
13819
14014
  // src/commands/review/fetchPrDiffInfo.ts
13820
- import { execSync as execSync44 } from "child_process";
14015
+ import { execSync as execSync46 } from "child_process";
13821
14016
  function getCurrentBranch2() {
13822
- return execSync44("git rev-parse --abbrev-ref HEAD", {
14017
+ return execSync46("git rev-parse --abbrev-ref HEAD", {
13823
14018
  encoding: "utf-8"
13824
14019
  }).trim();
13825
14020
  }
@@ -13829,7 +14024,7 @@ function fetchPrDiffInfo() {
13829
14024
  const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
13830
14025
  let raw;
13831
14026
  try {
13832
- raw = execSync44(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
14027
+ raw = execSync46(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
13833
14028
  encoding: "utf-8",
13834
14029
  stdio: ["ignore", "pipe", "pipe"]
13835
14030
  });
@@ -13853,7 +14048,7 @@ function fetchPrDiffInfo() {
13853
14048
  }
13854
14049
  function fetchPrChangedFiles(prNumber) {
13855
14050
  const { org, repo } = getRepoInfo();
13856
- const out = execSync44(
14051
+ const out = execSync46(
13857
14052
  `gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
13858
14053
  {
13859
14054
  encoding: "utf-8",
@@ -13865,11 +14060,11 @@ function fetchPrChangedFiles(prNumber) {
13865
14060
 
13866
14061
  // src/commands/review/gatherContext.ts
13867
14062
  function gatherContext() {
13868
- const branch = execSync45("git rev-parse --abbrev-ref HEAD", {
14063
+ const branch = execSync47("git rev-parse --abbrev-ref HEAD", {
13869
14064
  encoding: "utf-8"
13870
14065
  }).trim();
13871
- const sha = execSync45("git rev-parse HEAD", { encoding: "utf-8" }).trim();
13872
- const shortSha = execSync45("git rev-parse --short=7 HEAD", {
14066
+ const sha = execSync47("git rev-parse HEAD", { encoding: "utf-8" }).trim();
14067
+ const shortSha = execSync47("git rev-parse --short=7 HEAD", {
13873
14068
  encoding: "utf-8"
13874
14069
  }).trim();
13875
14070
  const prInfo = fetchPrDiffInfo();
@@ -14146,18 +14341,18 @@ function partitionFindingsByDiff(findings, index2) {
14146
14341
  }
14147
14342
 
14148
14343
  // src/commands/review/warnOutOfDiff.ts
14149
- import chalk145 from "chalk";
14344
+ import chalk144 from "chalk";
14150
14345
  function warnOutOfDiff(outOfDiff) {
14151
14346
  if (outOfDiff.length === 0) return;
14152
14347
  console.warn(
14153
- chalk145.yellow(
14348
+ chalk144.yellow(
14154
14349
  `Skipped ${outOfDiff.length} finding(s) whose lines fall outside the PR diff (GitHub would silently drop these):`
14155
14350
  )
14156
14351
  );
14157
14352
  for (const finding of outOfDiff) {
14158
14353
  const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
14159
14354
  console.warn(
14160
- ` ${chalk145.yellow("\xB7")} ${finding.title} ${chalk145.dim(
14355
+ ` ${chalk144.yellow("\xB7")} ${finding.title} ${chalk144.dim(
14161
14356
  `(${finding.file}:${range})`
14162
14357
  )}`
14163
14358
  );
@@ -14176,18 +14371,18 @@ function selectInDiffFindings(lineBound, prDiff) {
14176
14371
  }
14177
14372
 
14178
14373
  // src/commands/review/warnUnlocated.ts
14179
- import chalk146 from "chalk";
14374
+ import chalk145 from "chalk";
14180
14375
  function warnUnlocated(unlocated) {
14181
14376
  if (unlocated.length === 0) return;
14182
14377
  console.warn(
14183
- chalk146.yellow(
14378
+ chalk145.yellow(
14184
14379
  `Skipped ${unlocated.length} finding(s) without a parseable file:line:`
14185
14380
  )
14186
14381
  );
14187
14382
  for (const finding of unlocated) {
14188
- const where = finding.location || chalk146.dim("missing");
14383
+ const where = finding.location || chalk145.dim("missing");
14189
14384
  console.warn(
14190
- ` ${chalk146.yellow("\xB7")} ${finding.title} ${chalk146.dim(`(${where})`)}`
14385
+ ` ${chalk145.yellow("\xB7")} ${finding.title} ${chalk145.dim(`(${where})`)}`
14191
14386
  );
14192
14387
  }
14193
14388
  }
@@ -15360,7 +15555,7 @@ function registerReview(program2) {
15360
15555
  }
15361
15556
 
15362
15557
  // src/commands/seq/seqAuth.ts
15363
- import chalk148 from "chalk";
15558
+ import chalk147 from "chalk";
15364
15559
 
15365
15560
  // src/commands/seq/loadConnections.ts
15366
15561
  function loadConnections2() {
@@ -15389,10 +15584,10 @@ function setDefaultConnection(name) {
15389
15584
  }
15390
15585
 
15391
15586
  // src/shared/assertUniqueName.ts
15392
- import chalk147 from "chalk";
15587
+ import chalk146 from "chalk";
15393
15588
  function assertUniqueName(existingNames, name) {
15394
15589
  if (existingNames.includes(name)) {
15395
- console.error(chalk147.red(`Connection "${name}" already exists.`));
15590
+ console.error(chalk146.red(`Connection "${name}" already exists.`));
15396
15591
  process.exit(1);
15397
15592
  }
15398
15593
  }
@@ -15410,16 +15605,16 @@ async function promptConnection2(existingNames) {
15410
15605
  var seqAuth = createConnectionAuth({
15411
15606
  load: loadConnections2,
15412
15607
  save: saveConnections2,
15413
- format: (c) => `${chalk148.bold(c.name)} ${c.url}`,
15608
+ format: (c) => `${chalk147.bold(c.name)} ${c.url}`,
15414
15609
  promptNew: promptConnection2,
15415
15610
  onFirst: (c) => setDefaultConnection(c.name)
15416
15611
  });
15417
15612
 
15418
15613
  // src/commands/seq/seqQuery.ts
15419
- import chalk152 from "chalk";
15614
+ import chalk151 from "chalk";
15420
15615
 
15421
15616
  // src/commands/seq/fetchSeq.ts
15422
- import chalk149 from "chalk";
15617
+ import chalk148 from "chalk";
15423
15618
  async function fetchSeq(conn, path54, params) {
15424
15619
  const url = `${conn.url}${path54}?${params}`;
15425
15620
  const response = await fetch(url, {
@@ -15430,7 +15625,7 @@ async function fetchSeq(conn, path54, params) {
15430
15625
  });
15431
15626
  if (!response.ok) {
15432
15627
  const body = await response.text();
15433
- console.error(chalk149.red(`Seq returned ${response.status}: ${body}`));
15628
+ console.error(chalk148.red(`Seq returned ${response.status}: ${body}`));
15434
15629
  process.exit(1);
15435
15630
  }
15436
15631
  return response;
@@ -15485,23 +15680,23 @@ async function fetchSeqEvents(conn, params) {
15485
15680
  }
15486
15681
 
15487
15682
  // src/commands/seq/formatEvent.ts
15488
- import chalk150 from "chalk";
15683
+ import chalk149 from "chalk";
15489
15684
  function levelColor(level) {
15490
15685
  switch (level) {
15491
15686
  case "Fatal":
15492
- return chalk150.bgRed.white;
15687
+ return chalk149.bgRed.white;
15493
15688
  case "Error":
15494
- return chalk150.red;
15689
+ return chalk149.red;
15495
15690
  case "Warning":
15496
- return chalk150.yellow;
15691
+ return chalk149.yellow;
15497
15692
  case "Information":
15498
- return chalk150.cyan;
15693
+ return chalk149.cyan;
15499
15694
  case "Debug":
15500
- return chalk150.gray;
15695
+ return chalk149.gray;
15501
15696
  case "Verbose":
15502
- return chalk150.dim;
15697
+ return chalk149.dim;
15503
15698
  default:
15504
- return chalk150.white;
15699
+ return chalk149.white;
15505
15700
  }
15506
15701
  }
15507
15702
  function levelAbbrev(level) {
@@ -15542,12 +15737,12 @@ function formatTimestamp(iso) {
15542
15737
  function formatEvent(event) {
15543
15738
  const color = levelColor(event.Level);
15544
15739
  const abbrev = levelAbbrev(event.Level);
15545
- const ts8 = chalk150.dim(formatTimestamp(event.Timestamp));
15740
+ const ts8 = chalk149.dim(formatTimestamp(event.Timestamp));
15546
15741
  const msg = renderMessage(event);
15547
15742
  const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
15548
15743
  if (event.Exception) {
15549
15744
  for (const line of event.Exception.split("\n")) {
15550
- lines.push(chalk150.red(` ${line}`));
15745
+ lines.push(chalk149.red(` ${line}`));
15551
15746
  }
15552
15747
  }
15553
15748
  return lines.join("\n");
@@ -15580,11 +15775,11 @@ function rejectTimestampFilter(filter) {
15580
15775
  }
15581
15776
 
15582
15777
  // src/shared/resolveNamedConnection.ts
15583
- import chalk151 from "chalk";
15778
+ import chalk150 from "chalk";
15584
15779
  function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
15585
15780
  if (connections.length === 0) {
15586
15781
  console.error(
15587
- chalk151.red(
15782
+ chalk150.red(
15588
15783
  `No ${kind} connections configured. Run '${authCommand}' first.`
15589
15784
  )
15590
15785
  );
@@ -15593,7 +15788,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
15593
15788
  const target = requested ?? defaultName ?? connections[0].name;
15594
15789
  const connection = connections.find((c) => c.name === target);
15595
15790
  if (!connection) {
15596
- console.error(chalk151.red(`${kind} connection "${target}" not found.`));
15791
+ console.error(chalk150.red(`${kind} connection "${target}" not found.`));
15597
15792
  process.exit(1);
15598
15793
  }
15599
15794
  return connection;
@@ -15622,7 +15817,7 @@ async function seqQuery(filter, options2) {
15622
15817
  new URLSearchParams({ filter, count: String(count6) })
15623
15818
  );
15624
15819
  if (events.length === 0) {
15625
- console.log(chalk152.yellow("No events found."));
15820
+ console.log(chalk151.yellow("No events found."));
15626
15821
  return;
15627
15822
  }
15628
15823
  if (options2.json) {
@@ -15633,11 +15828,11 @@ async function seqQuery(filter, options2) {
15633
15828
  for (const event of chronological) {
15634
15829
  console.log(formatEvent(event));
15635
15830
  }
15636
- console.log(chalk152.dim(`
15831
+ console.log(chalk151.dim(`
15637
15832
  ${events.length} events`));
15638
15833
  if (events.length >= count6) {
15639
15834
  console.log(
15640
- chalk152.yellow(
15835
+ chalk151.yellow(
15641
15836
  `Results limited to ${count6}. Use --count to retrieve more.`
15642
15837
  )
15643
15838
  );
@@ -15645,10 +15840,10 @@ ${events.length} events`));
15645
15840
  }
15646
15841
 
15647
15842
  // src/shared/setNamedDefaultConnection.ts
15648
- import chalk153 from "chalk";
15843
+ import chalk152 from "chalk";
15649
15844
  function setNamedDefaultConnection(connections, name, setDefault, kind) {
15650
15845
  if (!connections.find((c) => c.name === name)) {
15651
- console.error(chalk153.red(`Connection "${name}" not found.`));
15846
+ console.error(chalk152.red(`Connection "${name}" not found.`));
15652
15847
  process.exit(1);
15653
15848
  }
15654
15849
  setDefault(name);
@@ -15696,7 +15891,7 @@ function registerSignal(program2) {
15696
15891
  }
15697
15892
 
15698
15893
  // src/commands/sql/sqlAuth.ts
15699
- import chalk155 from "chalk";
15894
+ import chalk154 from "chalk";
15700
15895
 
15701
15896
  // src/commands/sql/loadConnections.ts
15702
15897
  function loadConnections3() {
@@ -15725,7 +15920,7 @@ function setDefaultConnection2(name) {
15725
15920
  }
15726
15921
 
15727
15922
  // src/commands/sql/promptConnection.ts
15728
- import chalk154 from "chalk";
15923
+ import chalk153 from "chalk";
15729
15924
  async function promptConnection3(existingNames) {
15730
15925
  const name = await promptInput("name", "Connection name:", "default");
15731
15926
  assertUniqueName(existingNames, name);
@@ -15733,7 +15928,7 @@ async function promptConnection3(existingNames) {
15733
15928
  const portStr = await promptInput("port", "Port:", "1433");
15734
15929
  const port = Number.parseInt(portStr, 10);
15735
15930
  if (!Number.isFinite(port)) {
15736
- console.error(chalk154.red(`Invalid port "${portStr}".`));
15931
+ console.error(chalk153.red(`Invalid port "${portStr}".`));
15737
15932
  process.exit(1);
15738
15933
  }
15739
15934
  const user = await promptInput("user", "User:");
@@ -15746,13 +15941,13 @@ async function promptConnection3(existingNames) {
15746
15941
  var sqlAuth = createConnectionAuth({
15747
15942
  load: loadConnections3,
15748
15943
  save: saveConnections3,
15749
- format: (c) => `${chalk155.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
15944
+ format: (c) => `${chalk154.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
15750
15945
  promptNew: promptConnection3,
15751
15946
  onFirst: (c) => setDefaultConnection2(c.name)
15752
15947
  });
15753
15948
 
15754
15949
  // src/commands/sql/printTable.ts
15755
- import chalk156 from "chalk";
15950
+ import chalk155 from "chalk";
15756
15951
  function formatCell(value) {
15757
15952
  if (value === null || value === void 0) return "";
15758
15953
  if (value instanceof Date) return value.toISOString();
@@ -15761,7 +15956,7 @@ function formatCell(value) {
15761
15956
  }
15762
15957
  function printTable(rows) {
15763
15958
  if (rows.length === 0) {
15764
- console.log(chalk156.yellow("(no rows)"));
15959
+ console.log(chalk155.yellow("(no rows)"));
15765
15960
  return;
15766
15961
  }
15767
15962
  const columns = Object.keys(rows[0]);
@@ -15769,13 +15964,13 @@ function printTable(rows) {
15769
15964
  (col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
15770
15965
  );
15771
15966
  const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
15772
- console.log(chalk156.dim(header));
15773
- console.log(chalk156.dim("-".repeat(header.length)));
15967
+ console.log(chalk155.dim(header));
15968
+ console.log(chalk155.dim("-".repeat(header.length)));
15774
15969
  for (const row of rows) {
15775
15970
  const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
15776
15971
  console.log(line);
15777
15972
  }
15778
- console.log(chalk156.dim(`
15973
+ console.log(chalk155.dim(`
15779
15974
  ${rows.length} row${rows.length === 1 ? "" : "s"}`));
15780
15975
  }
15781
15976
 
@@ -15835,7 +16030,7 @@ async function sqlColumns(table, connectionName) {
15835
16030
  }
15836
16031
 
15837
16032
  // src/commands/sql/sqlMutate.ts
15838
- import chalk157 from "chalk";
16033
+ import chalk156 from "chalk";
15839
16034
 
15840
16035
  // src/commands/sql/isMutation.ts
15841
16036
  var MUTATION_KEYWORDS = [
@@ -15869,7 +16064,7 @@ function isMutation(sql4) {
15869
16064
  async function sqlMutate(query, connectionName) {
15870
16065
  if (!isMutation(query)) {
15871
16066
  console.error(
15872
- chalk157.red(
16067
+ chalk156.red(
15873
16068
  "assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
15874
16069
  )
15875
16070
  );
@@ -15879,18 +16074,18 @@ async function sqlMutate(query, connectionName) {
15879
16074
  const pool = await sqlConnect(conn);
15880
16075
  try {
15881
16076
  const result = await pool.request().query(query);
15882
- console.log(chalk157.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
16077
+ console.log(chalk156.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
15883
16078
  } finally {
15884
16079
  await pool.close();
15885
16080
  }
15886
16081
  }
15887
16082
 
15888
16083
  // src/commands/sql/sqlQuery.ts
15889
- import chalk158 from "chalk";
16084
+ import chalk157 from "chalk";
15890
16085
  async function sqlQuery(query, connectionName) {
15891
16086
  if (isMutation(query)) {
15892
16087
  console.error(
15893
- chalk158.red(
16088
+ chalk157.red(
15894
16089
  "assist sql query refuses mutating statements. Use `assist sql mutate` instead."
15895
16090
  )
15896
16091
  );
@@ -15905,7 +16100,7 @@ async function sqlQuery(query, connectionName) {
15905
16100
  printTable(rows);
15906
16101
  } else {
15907
16102
  console.log(
15908
- chalk158.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
16103
+ chalk157.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
15909
16104
  );
15910
16105
  }
15911
16106
  } finally {
@@ -16485,14 +16680,14 @@ import {
16485
16680
  import { dirname as dirname22, join as join42 } from "path";
16486
16681
 
16487
16682
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
16488
- import chalk159 from "chalk";
16683
+ import chalk158 from "chalk";
16489
16684
  var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
16490
16685
  function validateStagedContent(filename, content) {
16491
16686
  const firstLine = content.split("\n")[0];
16492
16687
  const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
16493
16688
  if (!match) {
16494
16689
  console.error(
16495
- chalk159.red(
16690
+ chalk158.red(
16496
16691
  `Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
16497
16692
  )
16498
16693
  );
@@ -16501,7 +16696,7 @@ function validateStagedContent(filename, content) {
16501
16696
  const contentAfterLink = content.slice(firstLine.length).trim();
16502
16697
  if (!contentAfterLink) {
16503
16698
  console.error(
16504
- chalk159.red(
16699
+ chalk158.red(
16505
16700
  `Staged file ${filename} has no summary content after the transcript link.`
16506
16701
  )
16507
16702
  );
@@ -16705,7 +16900,7 @@ import { mkdirSync as mkdirSync18 } from "fs";
16705
16900
  import { join as join47 } from "path";
16706
16901
 
16707
16902
  // src/commands/voice/checkLockFile.ts
16708
- import { execSync as execSync46 } from "child_process";
16903
+ import { execSync as execSync48 } from "child_process";
16709
16904
  import { existsSync as existsSync45, mkdirSync as mkdirSync17, readFileSync as readFileSync35, writeFileSync as writeFileSync29 } from "fs";
16710
16905
  import { join as join46 } from "path";
16711
16906
  function isProcessAlive2(pid) {
@@ -16734,7 +16929,7 @@ function bootstrapVenv() {
16734
16929
  if (existsSync45(getVenvPython())) return;
16735
16930
  console.log("Setting up Python environment...");
16736
16931
  const pythonDir = getPythonDir();
16737
- execSync46(
16932
+ execSync48(
16738
16933
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
16739
16934
  {
16740
16935
  stdio: "inherit",
@@ -16898,51 +17093,7 @@ function registerVoice(program2) {
16898
17093
 
16899
17094
  // src/commands/roam/auth.ts
16900
17095
  import { randomBytes } from "crypto";
16901
- import chalk160 from "chalk";
16902
-
16903
- // src/lib/openBrowser.ts
16904
- import { execSync as execSync47 } from "child_process";
16905
- function tryExec(commands) {
16906
- for (const cmd of commands) {
16907
- try {
16908
- execSync47(cmd);
16909
- return true;
16910
- } catch {
16911
- }
16912
- }
16913
- return false;
16914
- }
16915
- function openBrowser2(url) {
16916
- const platform = detectPlatform();
16917
- const quoted = JSON.stringify(url);
16918
- const commands = [];
16919
- switch (platform) {
16920
- case "macos":
16921
- commands.push(
16922
- `open -a "Google Chrome" ${quoted}`,
16923
- `open -a "Microsoft Edge" ${quoted}`,
16924
- `open -a "Safari" ${quoted}`
16925
- );
16926
- break;
16927
- case "linux":
16928
- commands.push(
16929
- `google-chrome ${quoted}`,
16930
- `chromium-browser ${quoted}`,
16931
- `microsoft-edge ${quoted}`
16932
- );
16933
- break;
16934
- case "windows":
16935
- commands.push(`start chrome ${quoted}`, `start msedge ${quoted}`);
16936
- break;
16937
- case "wsl":
16938
- commands.push(`wslview ${quoted}`);
16939
- break;
16940
- }
16941
- if (!tryExec(commands)) {
16942
- console.log(`Open this URL in Chrome, Edge, or Safari:
16943
- ${url}`);
16944
- }
16945
- }
17096
+ import chalk159 from "chalk";
16946
17097
 
16947
17098
  // src/commands/roam/waitForCallback.ts
16948
17099
  import { createServer as createServer2 } from "http";
@@ -17006,7 +17157,7 @@ function buildAuthorizeUrl(clientId, state) {
17006
17157
  return `https://ro.am/oauth/authorize?${params}`;
17007
17158
  }
17008
17159
  async function authorizeInBrowser(clientId, state) {
17009
- openBrowser2(buildAuthorizeUrl(clientId, state));
17160
+ openBrowser(buildAuthorizeUrl(clientId, state));
17010
17161
  const code = await waitForCallback(PORT, state);
17011
17162
  return { code, redirectUri: REDIRECT_URI };
17012
17163
  }
@@ -17073,13 +17224,13 @@ async function auth() {
17073
17224
  saveGlobalConfig(config);
17074
17225
  const state = randomBytes(16).toString("hex");
17075
17226
  console.log(
17076
- chalk160.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
17227
+ chalk159.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
17077
17228
  );
17078
- console.log(chalk160.white("http://localhost:14523/callback\n"));
17079
- console.log(chalk160.blue("Opening browser for authorization..."));
17080
- console.log(chalk160.dim("Waiting for authorization callback..."));
17229
+ console.log(chalk159.white("http://localhost:14523/callback\n"));
17230
+ console.log(chalk159.blue("Opening browser for authorization..."));
17231
+ console.log(chalk159.dim("Waiting for authorization callback..."));
17081
17232
  const { code, redirectUri } = await authorizeInBrowser(clientId, state);
17082
- console.log(chalk160.dim("Exchanging code for tokens..."));
17233
+ console.log(chalk159.dim("Exchanging code for tokens..."));
17083
17234
  const tokens = await exchangeToken({
17084
17235
  code,
17085
17236
  clientId,
@@ -17095,7 +17246,7 @@ async function auth() {
17095
17246
  };
17096
17247
  saveGlobalConfig(config);
17097
17248
  console.log(
17098
- chalk160.green("Roam credentials and tokens saved to ~/.assist.yml")
17249
+ chalk159.green("Roam credentials and tokens saved to ~/.assist.yml")
17099
17250
  );
17100
17251
  }
17101
17252
 
@@ -17255,11 +17406,11 @@ function resolveParams(params, cliArgs) {
17255
17406
  }
17256
17407
 
17257
17408
  // src/commands/run/runPreCommands.ts
17258
- import { execSync as execSync48 } from "child_process";
17409
+ import { execSync as execSync49 } from "child_process";
17259
17410
  function runPreCommands(pre, cwd) {
17260
17411
  for (const cmd of pre) {
17261
17412
  try {
17262
- execSync48(cmd, { stdio: "inherit", cwd });
17413
+ execSync49(cmd, { stdio: "inherit", cwd });
17263
17414
  } catch (err) {
17264
17415
  const code = err && typeof err === "object" && "status" in err ? err.status : 1;
17265
17416
  process.exit(code);
@@ -17543,11 +17694,11 @@ function registerRun(program2) {
17543
17694
  }
17544
17695
 
17545
17696
  // src/commands/screenshot/index.ts
17546
- import { execSync as execSync49 } from "child_process";
17697
+ import { execSync as execSync50 } from "child_process";
17547
17698
  import { existsSync as existsSync50, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync32 } from "fs";
17548
17699
  import { tmpdir as tmpdir7 } from "os";
17549
17700
  import { join as join53, resolve as resolve13 } from "path";
17550
- import chalk161 from "chalk";
17701
+ import chalk160 from "chalk";
17551
17702
 
17552
17703
  // src/commands/screenshot/captureWindowPs1.ts
17553
17704
  var captureWindowPs1 = `
@@ -17686,7 +17837,7 @@ function runPowerShellScript(processName, outputPath) {
17686
17837
  const scriptPath = join53(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
17687
17838
  writeFileSync32(scriptPath, captureWindowPs1, "utf-8");
17688
17839
  try {
17689
- execSync49(
17840
+ execSync50(
17690
17841
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
17691
17842
  { stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
17692
17843
  );
@@ -17698,13 +17849,13 @@ function screenshot(processName) {
17698
17849
  const config = loadConfig();
17699
17850
  const outputDir = resolve13(config.screenshot.outputDir);
17700
17851
  const outputPath = buildOutputPath(outputDir, processName);
17701
- console.log(chalk161.gray(`Capturing window for process "${processName}" ...`));
17852
+ console.log(chalk160.gray(`Capturing window for process "${processName}" ...`));
17702
17853
  try {
17703
17854
  runPowerShellScript(processName, outputPath);
17704
- console.log(chalk161.green(`Screenshot saved: ${outputPath}`));
17855
+ console.log(chalk160.green(`Screenshot saved: ${outputPath}`));
17705
17856
  } catch (error) {
17706
17857
  const msg = error instanceof Error ? error.message : String(error);
17707
- console.error(chalk161.red(`Failed to capture screenshot: ${msg}`));
17858
+ console.error(chalk160.red(`Failed to capture screenshot: ${msg}`));
17708
17859
  process.exit(1);
17709
17860
  }
17710
17861
  }
@@ -18604,8 +18755,8 @@ var SessionManager = class {
18604
18755
  watchActivity(session, this.notify);
18605
18756
  return session.id;
18606
18757
  }
18607
- spawnWith(create2) {
18608
- return this.add(create2(String(this.nextId++)));
18758
+ spawnWith(create) {
18759
+ return this.add(create(String(this.nextId++)));
18609
18760
  }
18610
18761
  spawn(prompt, cwd) {
18611
18762
  return this.spawnWith((id) => createSession(id, prompt, cwd));
@@ -18984,7 +19135,7 @@ function registerDaemon(program2) {
18984
19135
 
18985
19136
  // src/commands/sessions/summarise/index.ts
18986
19137
  import * as fs31 from "fs";
18987
- import chalk162 from "chalk";
19138
+ import chalk161 from "chalk";
18988
19139
 
18989
19140
  // src/commands/sessions/summarise/shared.ts
18990
19141
  import * as fs29 from "fs";
@@ -19111,22 +19262,22 @@ ${firstMessage}`);
19111
19262
  async function summarise4(options2) {
19112
19263
  const files = await discoverSessionJsonlPaths();
19113
19264
  if (files.length === 0) {
19114
- console.log(chalk162.yellow("No sessions found."));
19265
+ console.log(chalk161.yellow("No sessions found."));
19115
19266
  return;
19116
19267
  }
19117
19268
  const toProcess = selectCandidates(files, options2);
19118
19269
  if (toProcess.length === 0) {
19119
- console.log(chalk162.green("All sessions already summarised."));
19270
+ console.log(chalk161.green("All sessions already summarised."));
19120
19271
  return;
19121
19272
  }
19122
19273
  console.log(
19123
- chalk162.cyan(
19274
+ chalk161.cyan(
19124
19275
  `Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
19125
19276
  )
19126
19277
  );
19127
19278
  const { succeeded, failed: failed2 } = processSessions(toProcess);
19128
19279
  console.log(
19129
- chalk162.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk162.yellow(`, ${failed2} skipped`) : "")
19280
+ chalk161.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk161.yellow(`, ${failed2} skipped`) : "")
19130
19281
  );
19131
19282
  }
19132
19283
  function selectCandidates(files, options2) {
@@ -19146,16 +19297,16 @@ function processSessions(files) {
19146
19297
  let failed2 = 0;
19147
19298
  for (let i = 0; i < files.length; i++) {
19148
19299
  const file = files[i];
19149
- process.stdout.write(chalk162.dim(` [${i + 1}/${files.length}] `));
19300
+ process.stdout.write(chalk161.dim(` [${i + 1}/${files.length}] `));
19150
19301
  const summary = summariseSession(file);
19151
19302
  if (summary) {
19152
19303
  writeSummary(file, summary);
19153
19304
  succeeded++;
19154
- process.stdout.write(`${chalk162.green("\u2713")} ${summary}
19305
+ process.stdout.write(`${chalk161.green("\u2713")} ${summary}
19155
19306
  `);
19156
19307
  } else {
19157
19308
  failed2++;
19158
- process.stdout.write(` ${chalk162.yellow("skip")}
19309
+ process.stdout.write(` ${chalk161.yellow("skip")}
19159
19310
  `);
19160
19311
  }
19161
19312
  }
@@ -19164,16 +19315,16 @@ function processSessions(files) {
19164
19315
 
19165
19316
  // src/commands/sessions/registerSessions.ts
19166
19317
  function registerSessions(program2) {
19167
- const cmd = program2.command("sessions").description("Web dashboard for Claude Code sessions").action(() => web({ port: "3100" }));
19168
- cmd.command("web").description("Start the sessions web dashboard").option("-p, --port <number>", "Port to listen on", "3100").action(web);
19318
+ const cmd = program2.command("sessions").description("Web dashboard for Claude Code sessions").option("--no-open", "Do not open a browser on startup").action((options2) => web({ port: "3100", open: options2.open }));
19319
+ cmd.command("web").description("Start the sessions web dashboard").option("-p, --port <number>", "Port to listen on", "3100").option("--no-open", "Do not open a browser on startup").action(web);
19169
19320
  cmd.command("summarise").description("Generate one-line summaries for Claude sessions").option("-f, --force", "Re-generate all summaries, even existing ones").option("-n, --limit <count>", "Maximum number of sessions to summarise").action(summarise4);
19170
19321
  }
19171
19322
 
19172
19323
  // src/commands/statusLine.ts
19173
- import chalk164 from "chalk";
19324
+ import chalk163 from "chalk";
19174
19325
 
19175
19326
  // src/commands/buildLimitsSegment.ts
19176
- import chalk163 from "chalk";
19327
+ import chalk162 from "chalk";
19177
19328
  var FIVE_HOUR_SECONDS = 5 * 3600;
19178
19329
  var SEVEN_DAY_SECONDS = 7 * 86400;
19179
19330
  function formatTimeLeft(resetsAt) {
@@ -19196,10 +19347,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
19196
19347
  function colorizeRateLimit(pct, resetsAt, windowSeconds) {
19197
19348
  const label2 = `${Math.round(pct)}%`;
19198
19349
  const projected = projectUsage(pct, resetsAt, windowSeconds);
19199
- if (projected == null) return chalk163.green(label2);
19200
- if (projected > 100) return chalk163.red(label2);
19201
- if (projected > 75) return chalk163.yellow(label2);
19202
- return chalk163.green(label2);
19350
+ if (projected == null) return chalk162.green(label2);
19351
+ if (projected > 100) return chalk162.red(label2);
19352
+ if (projected > 75) return chalk162.yellow(label2);
19353
+ return chalk162.green(label2);
19203
19354
  }
19204
19355
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
19205
19356
  const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
@@ -19225,14 +19376,14 @@ function buildLimitsSegment(rateLimits) {
19225
19376
  }
19226
19377
 
19227
19378
  // src/commands/statusLine.ts
19228
- chalk164.level = 3;
19379
+ chalk163.level = 3;
19229
19380
  function formatNumber(num) {
19230
19381
  return num.toLocaleString("en-US");
19231
19382
  }
19232
19383
  function colorizePercent(pct) {
19233
19384
  const label2 = `${Math.round(pct)}%`;
19234
- if (pct > 80) return chalk164.red(label2);
19235
- if (pct > 40) return chalk164.yellow(label2);
19385
+ if (pct > 80) return chalk163.red(label2);
19386
+ if (pct > 40) return chalk163.yellow(label2);
19236
19387
  return label2;
19237
19388
  }
19238
19389
  async function statusLine() {
@@ -19255,7 +19406,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
19255
19406
  // src/commands/sync/syncClaudeMd.ts
19256
19407
  import * as fs32 from "fs";
19257
19408
  import * as path50 from "path";
19258
- import chalk165 from "chalk";
19409
+ import chalk164 from "chalk";
19259
19410
  async function syncClaudeMd(claudeDir, targetBase, options2) {
19260
19411
  const source = path50.join(claudeDir, "CLAUDE.md");
19261
19412
  const target = path50.join(targetBase, "CLAUDE.md");
@@ -19264,12 +19415,12 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
19264
19415
  const targetContent = fs32.readFileSync(target, "utf-8");
19265
19416
  if (sourceContent !== targetContent) {
19266
19417
  console.log(
19267
- chalk165.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
19418
+ chalk164.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
19268
19419
  );
19269
19420
  console.log();
19270
19421
  printDiff(targetContent, sourceContent);
19271
19422
  const confirm = options2?.yes || await promptConfirm(
19272
- chalk165.red("Overwrite existing CLAUDE.md?"),
19423
+ chalk164.red("Overwrite existing CLAUDE.md?"),
19273
19424
  false
19274
19425
  );
19275
19426
  if (!confirm) {
@@ -19285,7 +19436,7 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
19285
19436
  // src/commands/sync/syncSettings.ts
19286
19437
  import * as fs33 from "fs";
19287
19438
  import * as path51 from "path";
19288
- import chalk166 from "chalk";
19439
+ import chalk165 from "chalk";
19289
19440
  async function syncSettings(claudeDir, targetBase, options2) {
19290
19441
  const source = path51.join(claudeDir, "settings.json");
19291
19442
  const target = path51.join(targetBase, "settings.json");
@@ -19301,14 +19452,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
19301
19452
  if (mergedContent !== normalizedTarget) {
19302
19453
  if (!options2?.yes) {
19303
19454
  console.log(
19304
- chalk166.yellow(
19455
+ chalk165.yellow(
19305
19456
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
19306
19457
  )
19307
19458
  );
19308
19459
  console.log();
19309
19460
  printDiff(targetContent, mergedContent);
19310
19461
  const confirm = await promptConfirm(
19311
- chalk166.red("Overwrite existing settings.json?"),
19462
+ chalk165.red("Overwrite existing settings.json?"),
19312
19463
  false
19313
19464
  );
19314
19465
  if (!confirm) {
@@ -19347,7 +19498,7 @@ function syncCommands(claudeDir, targetBase) {
19347
19498
  }
19348
19499
 
19349
19500
  // src/commands/update.ts
19350
- import { execSync as execSync50 } from "child_process";
19501
+ import { execSync as execSync51 } from "child_process";
19351
19502
  import * as path53 from "path";
19352
19503
  function isGlobalNpmInstall(dir) {
19353
19504
  try {
@@ -19355,7 +19506,7 @@ function isGlobalNpmInstall(dir) {
19355
19506
  if (resolved.split(path53.sep).includes("node_modules")) {
19356
19507
  return true;
19357
19508
  }
19358
- const globalPrefix = execSync50("npm prefix -g", { stdio: "pipe" }).toString().trim();
19509
+ const globalPrefix = execSync51("npm prefix -g", { stdio: "pipe" }).toString().trim();
19359
19510
  return resolved.toLowerCase().startsWith(path53.resolve(globalPrefix).toLowerCase());
19360
19511
  } catch {
19361
19512
  return false;
@@ -19366,18 +19517,18 @@ async function update2() {
19366
19517
  console.log(`Assist is installed at: ${installDir}`);
19367
19518
  if (isGitRepo(installDir)) {
19368
19519
  console.log("Detected git repo installation, pulling latest...");
19369
- execSync50("git pull", { cwd: installDir, stdio: "inherit" });
19520
+ execSync51("git pull", { cwd: installDir, stdio: "inherit" });
19370
19521
  console.log("Installing dependencies...");
19371
- execSync50("npm i", { cwd: installDir, stdio: "inherit" });
19522
+ execSync51("npm i", { cwd: installDir, stdio: "inherit" });
19372
19523
  console.log("Building...");
19373
- execSync50("npm run build", { cwd: installDir, stdio: "inherit" });
19524
+ execSync51("npm run build", { cwd: installDir, stdio: "inherit" });
19374
19525
  console.log("Syncing commands...");
19375
- execSync50("assist sync", { stdio: "inherit" });
19526
+ execSync51("assist sync", { stdio: "inherit" });
19376
19527
  } else if (isGlobalNpmInstall(installDir)) {
19377
19528
  console.log("Detected global npm installation, updating...");
19378
- execSync50("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
19529
+ execSync51("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
19379
19530
  console.log("Syncing commands...");
19380
- execSync50("assist sync", { stdio: "inherit" });
19531
+ execSync51("assist sync", { stdio: "inherit" });
19381
19532
  } else {
19382
19533
  console.error(
19383
19534
  "Could not determine installation method. Expected a git repo or global npm install."
@@ -19388,7 +19539,7 @@ async function update2() {
19388
19539
 
19389
19540
  // src/index.ts
19390
19541
  var program = new Command();
19391
- program.name("assist").description("CLI application").version(package_default.version).action(() => web({ port: "3100" }));
19542
+ program.name("assist").description("CLI application").version(package_default.version).option("--no-open", "Do not open a browser on startup").action((options2) => web({ port: "3100", open: options2.open }));
19392
19543
  program.command("sync").description("Copy command files to ~/.claude/commands").option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
19393
19544
  program.command("init").description("Initialize VS Code and verify configurations").action(init4);
19394
19545
  program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <message> [files...]").action(commit);