@staff0rd/assist 0.299.0 → 0.300.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.299.0",
9
+ version: "0.300.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -1074,8 +1074,8 @@ var options = [
1074
1074
  ];
1075
1075
 
1076
1076
  // src/commands/verify/init/getAvailableOptions/index.ts
1077
- function resolveDescription(desc4, setup2) {
1078
- return typeof desc4 === "function" ? desc4(setup2) : desc4;
1077
+ function resolveDescription(desc5, setup2) {
1078
+ return typeof desc5 === "function" ? desc5(setup2) : desc5;
1079
1079
  }
1080
1080
  function toVerifyOption(def, setup2) {
1081
1081
  return {
@@ -1665,8 +1665,8 @@ var MACHINE_DIRECTIVES = [
1665
1665
  "v8 ignore",
1666
1666
  "c8 ignore"
1667
1667
  ];
1668
- function isCommentExempt(text4, markers) {
1669
- const lower = text4.toLowerCase();
1668
+ function isCommentExempt(text5, markers) {
1669
+ const lower = text5.toLowerCase();
1670
1670
  if (MACHINE_DIRECTIVES.some((d) => lower.includes(d))) return true;
1671
1671
  return markers.some((m) => lower.includes(m.toLowerCase()));
1672
1672
  }
@@ -1709,8 +1709,8 @@ function parseDiffAddedLines(diff2) {
1709
1709
 
1710
1710
  // src/commands/verify/commentPolicy/findAddedComments.ts
1711
1711
  var SOURCE_EXTENSIONS = [".ts", ".tsx", ".cts", ".mts", ".js", ".jsx"];
1712
- function toSingleLine(text4) {
1713
- return text4.replace(/\s+/g, " ").trim();
1712
+ function toSingleLine(text5) {
1713
+ return text5.replace(/\s+/g, " ").trim();
1714
1714
  }
1715
1715
  function shouldScan(file, ignoreGlobs) {
1716
1716
  if (!SOURCE_EXTENSIONS.some((ext) => file.endsWith(ext))) return false;
@@ -1731,11 +1731,11 @@ function findAddedComments(options2) {
1731
1731
  for (const [file, lines] of addedLines) {
1732
1732
  if (!shouldScan(file, options2.ignoreGlobs)) continue;
1733
1733
  const sourceFile = project.addSourceFileAtPath(file);
1734
- for (const { pos, text: text4 } of collectComments(sourceFile)) {
1734
+ for (const { pos, text: text5 } of collectComments(sourceFile)) {
1735
1735
  const { line } = sourceFile.getLineAndColumnAtPos(pos);
1736
1736
  if (!lines.has(line)) continue;
1737
- if (isCommentExempt(text4, options2.markers)) continue;
1738
- findings.push({ file, line, text: toSingleLine(text4) });
1737
+ if (isCommentExempt(text5, options2.markers)) continue;
1738
+ findings.push({ file, line, text: toSingleLine(text5) });
1739
1739
  }
1740
1740
  }
1741
1741
  findings.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
@@ -1754,8 +1754,8 @@ function commentPolicy() {
1754
1754
  process.exit(0);
1755
1755
  }
1756
1756
  console.log("Comments added on changed lines:\n");
1757
- for (const { file, line, text: text4 } of findings) {
1758
- console.log(`${file}:${line} \u2192 ${text4}`);
1757
+ for (const { file, line, text: text5 } of findings) {
1758
+ console.log(`${file}:${line} \u2192 ${text5}`);
1759
1759
  }
1760
1760
  console.log(`
1761
1761
  Total: ${findings.length} comment(s)`);
@@ -2865,9 +2865,9 @@ import {
2865
2865
  foreignKey,
2866
2866
  index as index2,
2867
2867
  integer as integer2,
2868
- pgTable as pgTable2,
2869
- primaryKey,
2870
- text as text2
2868
+ pgTable as pgTable3,
2869
+ primaryKey as primaryKey2,
2870
+ text as text3
2871
2871
  } from "drizzle-orm/pg-core";
2872
2872
 
2873
2873
  // src/shared/db/handovers.ts
@@ -2885,73 +2885,91 @@ var handovers = pgTable(
2885
2885
  (t) => [index("handovers_origin_idx").on(t.origin)]
2886
2886
  );
2887
2887
 
2888
+ // src/shared/db/usagePeaks.ts
2889
+ import {
2890
+ bigint,
2891
+ doublePrecision,
2892
+ pgTable as pgTable2,
2893
+ primaryKey,
2894
+ text as text2
2895
+ } from "drizzle-orm/pg-core";
2896
+ var usagePeaks = pgTable2(
2897
+ "usage_peaks",
2898
+ {
2899
+ window: text2().$type().notNull(),
2900
+ resetsAt: bigint("resets_at", { mode: "number" }).notNull(),
2901
+ usedPercentage: doublePrecision("used_percentage").notNull()
2902
+ },
2903
+ (t) => [primaryKey({ columns: [t.window, t.resetsAt] })]
2904
+ );
2905
+
2888
2906
  // src/shared/db/schema.ts
2889
- var items = pgTable2(
2907
+ var items = pgTable3(
2890
2908
  "items",
2891
2909
  {
2892
2910
  id: integer2().generatedByDefaultAsIdentity().primaryKey(),
2893
- origin: text2().notNull(),
2894
- type: text2().notNull().default("story"),
2895
- name: text2().notNull(),
2896
- description: text2(),
2897
- acceptanceCriteria: text2("acceptance_criteria").notNull().default("[]"),
2898
- status: text2().notNull().default("todo"),
2911
+ origin: text3().notNull(),
2912
+ type: text3().notNull().default("story"),
2913
+ name: text3().notNull(),
2914
+ description: text3(),
2915
+ acceptanceCriteria: text3("acceptance_criteria").notNull().default("[]"),
2916
+ status: text3().notNull().default("todo"),
2899
2917
  currentPhase: integer2("current_phase"),
2900
2918
  starred: boolean().notNull().default(false)
2901
2919
  },
2902
2920
  (t) => [index2("items_origin_idx").on(t.origin)]
2903
2921
  );
2904
- var comments = pgTable2("comments", {
2922
+ var comments = pgTable3("comments", {
2905
2923
  id: integer2().generatedByDefaultAsIdentity().primaryKey(),
2906
2924
  itemId: integer2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
2907
2925
  idx: integer2().notNull(),
2908
- text: text2().notNull(),
2926
+ text: text3().notNull(),
2909
2927
  phase: integer2(),
2910
- timestamp: text2().notNull(),
2911
- type: text2().notNull().default("comment")
2928
+ timestamp: text3().notNull(),
2929
+ type: text3().notNull().default("comment")
2912
2930
  });
2913
- var links = pgTable2(
2931
+ var links = pgTable3(
2914
2932
  "links",
2915
2933
  {
2916
2934
  itemId: integer2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
2917
- type: text2().notNull(),
2935
+ type: text3().notNull(),
2918
2936
  targetId: integer2("target_id").notNull()
2919
2937
  },
2920
- (t) => [primaryKey({ columns: [t.itemId, t.type, t.targetId] })]
2938
+ (t) => [primaryKey2({ columns: [t.itemId, t.type, t.targetId] })]
2921
2939
  );
2922
- var planPhases = pgTable2(
2940
+ var planPhases = pgTable3(
2923
2941
  "plan_phases",
2924
2942
  {
2925
2943
  itemId: integer2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
2926
2944
  idx: integer2().notNull(),
2927
- name: text2().notNull(),
2928
- manualChecks: text2("manual_checks")
2945
+ name: text3().notNull(),
2946
+ manualChecks: text3("manual_checks")
2929
2947
  },
2930
- (t) => [primaryKey({ columns: [t.itemId, t.idx] })]
2948
+ (t) => [primaryKey2({ columns: [t.itemId, t.idx] })]
2931
2949
  );
2932
- var planTasks = pgTable2(
2950
+ var planTasks = pgTable3(
2933
2951
  "plan_tasks",
2934
2952
  {
2935
2953
  itemId: integer2("item_id").notNull(),
2936
2954
  phaseIdx: integer2("phase_idx").notNull(),
2937
2955
  idx: integer2().notNull(),
2938
- task: text2().notNull()
2956
+ task: text3().notNull()
2939
2957
  },
2940
2958
  (t) => [
2941
- primaryKey({ columns: [t.itemId, t.phaseIdx, t.idx] }),
2959
+ primaryKey2({ columns: [t.itemId, t.phaseIdx, t.idx] }),
2942
2960
  foreignKey({
2943
2961
  columns: [t.itemId, t.phaseIdx],
2944
2962
  foreignColumns: [planPhases.itemId, planPhases.idx]
2945
2963
  }).onDelete("cascade")
2946
2964
  ]
2947
2965
  );
2948
- var metadata = pgTable2("metadata", {
2949
- key: text2().primaryKey(),
2950
- value: text2().notNull()
2966
+ var metadata = pgTable3("metadata", {
2967
+ key: text3().primaryKey(),
2968
+ value: text3().notNull()
2951
2969
  });
2952
- var feeds = pgTable2("feeds", {
2970
+ var feeds = pgTable3("feeds", {
2953
2971
  id: integer2().generatedByDefaultAsIdentity().primaryKey(),
2954
- url: text2().notNull().unique()
2972
+ url: text3().notNull().unique()
2955
2973
  });
2956
2974
  var schema = {
2957
2975
  items,
@@ -2961,7 +2979,8 @@ var schema = {
2961
2979
  planTasks,
2962
2980
  metadata,
2963
2981
  feeds,
2964
- handovers
2982
+ handovers,
2983
+ usagePeaks
2965
2984
  };
2966
2985
 
2967
2986
  // src/commands/backlog/itemColumns.ts
@@ -3402,6 +3421,13 @@ var SCHEMA = `
3402
3421
  );
3403
3422
 
3404
3423
  CREATE INDEX IF NOT EXISTS handovers_origin_idx ON handovers (origin);
3424
+
3425
+ CREATE TABLE IF NOT EXISTS usage_peaks (
3426
+ "window" TEXT NOT NULL,
3427
+ resets_at BIGINT NOT NULL,
3428
+ used_percentage DOUBLE PRECISION NOT NULL,
3429
+ PRIMARY KEY ("window", resets_at)
3430
+ );
3405
3431
  `;
3406
3432
  async function ensureSchema(exec3) {
3407
3433
  await exec3(SCHEMA);
@@ -3449,7 +3475,7 @@ function getDb() {
3449
3475
  );
3450
3476
  });
3451
3477
  _pool = pool;
3452
- await ensureSchema((sql5) => pool.query(sql5));
3478
+ await ensureSchema((sql6) => pool.query(sql6));
3453
3479
  _orm = makeOrmFromPool(pool);
3454
3480
  await seedNewsFeeds(_orm);
3455
3481
  return _orm;
@@ -4217,11 +4243,11 @@ import chalk37 from "chalk";
4217
4243
 
4218
4244
  // src/commands/backlog/appendComment.ts
4219
4245
  import { sql as sql2 } from "drizzle-orm";
4220
- async function appendComment(orm, itemId, text4, opts = {}) {
4246
+ async function appendComment(orm, itemId, text5, opts = {}) {
4221
4247
  await orm.insert(comments).values({
4222
4248
  itemId,
4223
4249
  idx: sql2`(SELECT COALESCE(MAX(${comments.idx}) + 1, 0) FROM ${comments} WHERE ${comments.itemId} = ${itemId})`,
4224
- text: text4,
4250
+ text: text5,
4225
4251
  phase: opts.phase ?? null,
4226
4252
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4227
4253
  type: opts.type ?? "comment"
@@ -5234,9 +5260,9 @@ function excerpt(xml, ...tags) {
5234
5260
  for (const tag of tags) {
5235
5261
  const raw = extractText(xml, tag);
5236
5262
  if (!raw) continue;
5237
- const text4 = stripHtml(raw);
5238
- if (text4.length <= MAX_EXCERPT) return text4;
5239
- return `${text4.slice(0, MAX_EXCERPT)}\u2026`;
5263
+ const text5 = stripHtml(raw);
5264
+ if (text5.length <= MAX_EXCERPT) return text5;
5265
+ return `${text5.slice(0, MAX_EXCERPT)}\u2026`;
5240
5266
  }
5241
5267
  return "";
5242
5268
  }
@@ -5313,6 +5339,17 @@ async function listNewsItems(_req, res) {
5313
5339
  respondJson(res, 200, cachedItems);
5314
5340
  }
5315
5341
 
5342
+ // src/shared/db/listUsagePeaks.ts
5343
+ import { desc } from "drizzle-orm";
5344
+ async function listUsagePeaks(db) {
5345
+ return db.select().from(usagePeaks).orderBy(desc(usagePeaks.resetsAt), usagePeaks.window);
5346
+ }
5347
+
5348
+ // src/commands/sessions/web/listUsageHistory.ts
5349
+ async function listUsageHistory(_req, res) {
5350
+ respondJson(res, 200, await listUsagePeaks(await getDb()));
5351
+ }
5352
+
5316
5353
  // src/commands/sessions/web/openInCode.ts
5317
5354
  import { exec } from "child_process";
5318
5355
  import { promisify as promisify2 } from "util";
@@ -5462,7 +5499,8 @@ var routes2 = {
5462
5499
  "POST /api/restart": restartWeb,
5463
5500
  "GET /api/github-url": githubUrl,
5464
5501
  "GET /api/git-status": gitStatus,
5465
- "GET /api/news/items": listNewsItems
5502
+ "GET /api/news/items": listNewsItems,
5503
+ "GET /api/usage/history": listUsageHistory
5466
5504
  };
5467
5505
  var handleRequest = createFallbackHandler(
5468
5506
  routes2,
@@ -5877,10 +5915,10 @@ async function web2(options2) {
5877
5915
 
5878
5916
  // src/commands/backlog/comment/index.ts
5879
5917
  import chalk48 from "chalk";
5880
- async function comment(id2, text4) {
5918
+ async function comment(id2, text5) {
5881
5919
  const found = await findOneItem(id2);
5882
5920
  if (!found) process.exit(1);
5883
- await appendComment(found.orm, found.item.id, text4);
5921
+ await appendComment(found.orm, found.item.id, text5);
5884
5922
  console.log(chalk48.green(`Comment added to item #${id2}.`));
5885
5923
  }
5886
5924
 
@@ -5993,8 +6031,8 @@ async function buildDump(copyOut) {
5993
6031
  // src/commands/backlog/dump/copyTableOut.ts
5994
6032
  import { to as copyTo } from "pg-copy-streams";
5995
6033
  async function copyTableOut(client, table) {
5996
- const sql5 = `COPY ${table.name} (${table.columns.join(", ")}) TO STDOUT`;
5997
- const stream = client.query(copyTo(sql5));
6034
+ const sql6 = `COPY ${table.name} (${table.columns.join(", ")}) TO STDOUT`;
6035
+ const stream = client.query(copyTo(sql6));
5998
6036
  const chunks = [];
5999
6037
  for await (const chunk of stream) {
6000
6038
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
@@ -6050,9 +6088,9 @@ function readLine(dump, start3) {
6050
6088
  return { text: dump.subarray(start3, eol).toString("utf8"), next: eol + 1 };
6051
6089
  }
6052
6090
  function parseHeader(dump) {
6053
- const { text: text4, next: next3 } = readLine(dump, 0);
6091
+ const { text: text5, next: next3 } = readLine(dump, 0);
6054
6092
  try {
6055
- return { header: JSON.parse(text4), bodyStart: next3 };
6093
+ return { header: JSON.parse(text5), bodyStart: next3 };
6056
6094
  } catch {
6057
6095
  return invalid("header is not valid JSON.");
6058
6096
  }
@@ -6061,9 +6099,9 @@ function parseSections(dump, bodyStart) {
6061
6099
  const sections = /* @__PURE__ */ new Map();
6062
6100
  let cursor = bodyStart;
6063
6101
  while (cursor < dump.length) {
6064
- const { text: text4, next: next3 } = readLine(dump, cursor);
6065
- const match = text4.match(/^@table (\S+) (\d+)$/);
6066
- if (!match) invalid(`malformed table marker "${text4}".`);
6102
+ const { text: text5, next: next3 } = readLine(dump, cursor);
6103
+ const match = text5.match(/^@table (\S+) (\d+)$/);
6104
+ if (!match) invalid(`malformed table marker "${text5}".`);
6067
6105
  const [, name, bytes] = match;
6068
6106
  const end = next3 + Number(bytes);
6069
6107
  if (end > dump.length) invalid(`section "${name}" overruns the dump.`);
@@ -6144,8 +6182,8 @@ async function readStdinBuffer() {
6144
6182
  import { finished } from "stream/promises";
6145
6183
  import { from as copyFrom } from "pg-copy-streams";
6146
6184
  async function copyTableIn(client, table, data) {
6147
- const sql5 = `COPY ${table.name} (${table.columns.join(", ")}) FROM STDIN`;
6148
- const stream = client.query(copyFrom(sql5));
6185
+ const sql6 = `COPY ${table.name} (${table.columns.join(", ")}) FROM STDIN`;
6186
+ const stream = client.query(copyFrom(sql6));
6149
6187
  stream.end(data);
6150
6188
  await finished(stream);
6151
6189
  }
@@ -6314,9 +6352,9 @@ import chalk56 from "chalk";
6314
6352
  import { count, eq as eq17 } from "drizzle-orm";
6315
6353
 
6316
6354
  // src/commands/backlog/shiftPhasesUp.ts
6317
- import { and as and3, desc, eq as eq16, gte } from "drizzle-orm";
6355
+ import { and as and3, desc as desc2, eq as eq16, gte } from "drizzle-orm";
6318
6356
  async function shiftPhasesUp(db, itemId, fromIdx) {
6319
- const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and3(eq16(planPhases.itemId, itemId), gte(planPhases.idx, fromIdx))).orderBy(desc(planPhases.idx));
6357
+ const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and3(eq16(planPhases.itemId, itemId), gte(planPhases.idx, fromIdx))).orderBy(desc2(planPhases.idx));
6320
6358
  for (const p of toShift) {
6321
6359
  await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and3(eq16(planTasks.itemId, itemId), eq16(planTasks.phaseIdx, p.idx)));
6322
6360
  await db.update(planPhases).set({ idx: p.idx + 1 }).where(and3(eq16(planPhases.itemId, itemId), eq16(planPhases.idx, p.idx)));
@@ -7191,8 +7229,8 @@ function applyAcMutations(current, options2) {
7191
7229
  // src/commands/backlog/update/buildUpdateValues.ts
7192
7230
  import chalk78 from "chalk";
7193
7231
  function buildUpdateValues(options2) {
7194
- const { name, desc: desc4, type, ac } = options2;
7195
- if (!name && !desc4 && !type && !ac) {
7232
+ const { name, desc: desc5, type, ac } = options2;
7233
+ if (!name && !desc5 && !type && !ac) {
7196
7234
  console.log(chalk78.red("Nothing to update. Provide at least one flag."));
7197
7235
  process.exitCode = 1;
7198
7236
  return void 0;
@@ -7208,8 +7246,8 @@ function buildUpdateValues(options2) {
7208
7246
  set.name = name;
7209
7247
  fieldNames.push("name");
7210
7248
  }
7211
- if (desc4) {
7212
- set.description = desc4;
7249
+ if (desc5) {
7250
+ set.description = desc5;
7213
7251
  fieldNames.push("description");
7214
7252
  }
7215
7253
  if (type) {
@@ -8325,8 +8363,8 @@ function formatHuman(cli, commands) {
8325
8363
  `];
8326
8364
  for (const cmd of sorted) {
8327
8365
  const full = `${cli} ${cmd.path.join(" ")}`;
8328
- const text4 = cmd.description ? `${full} \u2014 ${cmd.description}` : full;
8329
- lines.push(`${prefix(classifyVerb(cmd.path))}${text4}`);
8366
+ const text5 = cmd.description ? `${full} \u2014 ${cmd.description}` : full;
8367
+ lines.push(`${prefix(classifyVerb(cmd.path))}${text5}`);
8330
8368
  }
8331
8369
  return lines.join("\n");
8332
8370
  }
@@ -10722,13 +10760,13 @@ async function load(options2 = {}) {
10722
10760
  }
10723
10761
 
10724
10762
  // src/commands/handover/listPendingHandovers.ts
10725
- import { and as and11, desc as desc2, eq as eq30, isNull as isNull2 } from "drizzle-orm";
10763
+ import { and as and11, desc as desc3, eq as eq30, isNull as isNull2 } from "drizzle-orm";
10726
10764
  async function listPendingHandovers(orm, origin) {
10727
10765
  return orm.select({
10728
10766
  id: handovers.id,
10729
10767
  summary: handovers.summary,
10730
10768
  createdAt: handovers.createdAt
10731
- }).from(handovers).where(and11(eq30(handovers.origin, origin), isNull2(handovers.recalledAt))).orderBy(desc2(handovers.createdAt), desc2(handovers.id));
10769
+ }).from(handovers).where(and11(eq30(handovers.origin, origin), isNull2(handovers.recalledAt))).orderBy(desc3(handovers.createdAt), desc3(handovers.id));
10732
10770
  }
10733
10771
 
10734
10772
  // src/commands/handover/printPendingHandovers.ts
@@ -10741,7 +10779,7 @@ async function printPendingHandovers() {
10741
10779
  }
10742
10780
 
10743
10781
  // src/commands/handover/recallHandover.ts
10744
- import { and as and12, desc as desc3, eq as eq31, isNull as isNull3 } from "drizzle-orm";
10782
+ import { and as and12, desc as desc4, eq as eq31, isNull as isNull3 } from "drizzle-orm";
10745
10783
  async function recallHandover(orm, origin, id2) {
10746
10784
  const [row] = await orm.select().from(handovers).where(
10747
10785
  and12(
@@ -10749,7 +10787,7 @@ async function recallHandover(orm, origin, id2) {
10749
10787
  isNull3(handovers.recalledAt),
10750
10788
  ...id2 === void 0 ? [] : [eq31(handovers.id, id2)]
10751
10789
  )
10752
- ).orderBy(desc3(handovers.createdAt), desc3(handovers.id)).limit(1);
10790
+ ).orderBy(desc4(handovers.createdAt), desc4(handovers.id)).limit(1);
10753
10791
  if (!row) return void 0;
10754
10792
  await orm.update(handovers).set({ recalledAt: /* @__PURE__ */ new Date() }).where(eq31(handovers.id, row.id));
10755
10793
  return row.content;
@@ -10805,9 +10843,9 @@ import chalk115 from "chalk";
10805
10843
 
10806
10844
  // src/commands/jira/adfToText.ts
10807
10845
  function renderInline(node) {
10808
- const text4 = node.text ?? "";
10809
- if (node.marks?.some((m) => m.type === "code")) return `\`${text4}\``;
10810
- return text4;
10846
+ const text5 = node.text ?? "";
10847
+ if (node.marks?.some((m) => m.type === "code")) return `\`${text5}\``;
10848
+ return text5;
10811
10849
  }
10812
10850
  function renderChildren(node, indent2) {
10813
10851
  return renderNodes(node.content ?? [], indent2);
@@ -10849,8 +10887,8 @@ function isListNode(node) {
10849
10887
  function renderListChild(child, indent2, pad, marker, isFirst) {
10850
10888
  if (isListNode(child)) return renderNodes([child], indent2 + 1);
10851
10889
  if (child.type !== "paragraph") return renderNode(child, indent2);
10852
- const text4 = renderChildren(child, indent2);
10853
- return isFirst ? `${pad}${marker} ${text4}` : `${pad} ${text4}`;
10890
+ const text5 = renderChildren(child, indent2);
10891
+ return isFirst ? `${pad}${marker} ${text5}` : `${pad} ${text5}`;
10854
10892
  }
10855
10893
  function renderListItem(node, indent2, marker) {
10856
10894
  const pad = " ".repeat(indent2);
@@ -11540,8 +11578,8 @@ function isWallOfText(lines) {
11540
11578
  if (lines.some(isListLine)) {
11541
11579
  return false;
11542
11580
  }
11543
- const text4 = lines.join(" ").trim();
11544
- return text4.length > MAX_PARAGRAPH_CHARS || countSentences(text4) > MAX_PARAGRAPH_SENTENCES;
11581
+ const text5 = lines.join(" ").trim();
11582
+ return text5.length > MAX_PARAGRAPH_CHARS || countSentences(text5) > MAX_PARAGRAPH_SENTENCES;
11545
11583
  }
11546
11584
  function validatePrContent(title, body) {
11547
11585
  if (title.toLowerCase().includes("claude")) {
@@ -13202,9 +13240,9 @@ function resolveImports(target, dependencies, sourceFile, statements = []) {
13202
13240
  function extractTexts(target, allFunctions, statements) {
13203
13241
  const stmtTexts = statements.map((v) => v.getFullText().trim());
13204
13242
  const fnTexts = allFunctions.map((fn) => {
13205
- const text4 = fn.getFullText().trim();
13206
- if (fn === target && !text4.startsWith("export ")) return `export ${text4}`;
13207
- return text4;
13243
+ const text5 = fn.getFullText().trim();
13244
+ if (fn === target && !text5.startsWith("export ")) return `export ${text5}`;
13245
+ return text5;
13208
13246
  });
13209
13247
  return [...stmtTexts, ...fnTexts];
13210
13248
  }
@@ -15040,9 +15078,9 @@ var MultiSpinner = class {
15040
15078
  elapsedPrefix: prefix2
15041
15079
  });
15042
15080
  }
15043
- failRemaining(text4) {
15081
+ failRemaining(text5) {
15044
15082
  for (const entry of this.entries) {
15045
- if (entry.state === "running") this.resolve(entry, "failed", text4);
15083
+ if (entry.state === "running") this.resolve(entry, "failed", text5);
15046
15084
  }
15047
15085
  }
15048
15086
  add(entry) {
@@ -15055,14 +15093,14 @@ var MultiSpinner = class {
15055
15093
  set text(value) {
15056
15094
  entry.text = value;
15057
15095
  },
15058
- succeed: (text4) => this.resolve(entry, "succeeded", text4),
15059
- fail: (text4) => this.resolve(entry, "failed", text4)
15096
+ succeed: (text5) => this.resolve(entry, "succeeded", text5),
15097
+ fail: (text5) => this.resolve(entry, "failed", text5)
15060
15098
  };
15061
15099
  }
15062
- resolve(entry, state, text4) {
15100
+ resolve(entry, state, text5) {
15063
15101
  if (entry.state !== "running") return;
15064
15102
  entry.state = state;
15065
- if (text4 !== void 0) entry.text = text4;
15103
+ if (text5 !== void 0) entry.text = text5;
15066
15104
  entry.elapsedStart = void 0;
15067
15105
  this.render();
15068
15106
  this.maybeFinish();
@@ -15137,12 +15175,12 @@ function skippedCodexResult(outputPath) {
15137
15175
  // src/commands/review/formatReviewerFailure.ts
15138
15176
  var FAST_FAIL_MS = 1e3;
15139
15177
  var STDOUT_TAIL_LINES = 20;
15140
- function indent(text4) {
15141
- return text4.split(/\r?\n/).map((line) => ` ${line}`);
15178
+ function indent(text5) {
15179
+ return text5.split(/\r?\n/).map((line) => ` ${line}`);
15142
15180
  }
15143
- function tailLines(text4, maxLines) {
15144
- const lines = text4.split(/\r?\n/);
15145
- return lines.length <= maxLines ? text4 : lines.slice(-maxLines).join("\n");
15181
+ function tailLines(text5, maxLines) {
15182
+ const lines = text5.split(/\r?\n/);
15183
+ return lines.length <= maxLines ? text5 : lines.slice(-maxLines).join("\n");
15146
15184
  }
15147
15185
  function isFastFail(input) {
15148
15186
  return input.exitCode !== 0 && input.elapsedMs !== void 0 && input.elapsedMs < FAST_FAIL_MS;
@@ -16062,8 +16100,8 @@ function filterToSql(filter) {
16062
16100
  // src/commands/seq/fetchSeqData.ts
16063
16101
  function buildDataParams(filter, count6, from, to) {
16064
16102
  const sqlFilter = filterToSql(filter);
16065
- const sql5 = `select @Timestamp, @Level, @Exception, @Message from stream where ${sqlFilter} order by @Timestamp desc limit ${count6}`;
16066
- const params = new URLSearchParams({ q: sql5 });
16103
+ const sql6 = `select @Timestamp, @Level, @Exception, @Message from stream where ${sqlFilter} order by @Timestamp desc limit ${count6}`;
16104
+ const params = new URLSearchParams({ q: sql6 });
16067
16105
  if (from) params.set("rangeStartUtc", from);
16068
16106
  if (to) params.set("rangeEndUtc", to);
16069
16107
  return params;
@@ -16323,26 +16361,26 @@ import chalk159 from "chalk";
16323
16361
  // src/commands/sql/loadConnections.ts
16324
16362
  function loadConnections3() {
16325
16363
  const raw = loadGlobalConfigRaw();
16326
- const sql5 = raw.sql;
16327
- return sql5?.connections ?? [];
16364
+ const sql6 = raw.sql;
16365
+ return sql6?.connections ?? [];
16328
16366
  }
16329
16367
  function saveConnections3(connections) {
16330
16368
  const raw = loadGlobalConfigRaw();
16331
- const sql5 = raw.sql ?? {};
16332
- sql5.connections = connections;
16333
- raw.sql = sql5;
16369
+ const sql6 = raw.sql ?? {};
16370
+ sql6.connections = connections;
16371
+ raw.sql = sql6;
16334
16372
  saveGlobalConfig(raw);
16335
16373
  }
16336
16374
  function getDefaultConnection2() {
16337
16375
  const raw = loadGlobalConfigRaw();
16338
- const sql5 = raw.sql;
16339
- return sql5?.defaultConnection;
16376
+ const sql6 = raw.sql;
16377
+ return sql6?.defaultConnection;
16340
16378
  }
16341
16379
  function setDefaultConnection2(name) {
16342
16380
  const raw = loadGlobalConfigRaw();
16343
- const sql5 = raw.sql ?? {};
16344
- sql5.defaultConnection = name;
16345
- raw.sql = sql5;
16381
+ const sql6 = raw.sql ?? {};
16382
+ sql6.defaultConnection = name;
16383
+ raw.sql = sql6;
16346
16384
  saveGlobalConfig(raw);
16347
16385
  }
16348
16386
 
@@ -16478,11 +16516,11 @@ var MUTATION_PATTERN = new RegExp(
16478
16516
  `\\b(${MUTATION_KEYWORDS.join("|")})\\b`,
16479
16517
  "i"
16480
16518
  );
16481
- function stripComments(sql5) {
16482
- return sql5.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*/g, " ");
16519
+ function stripComments(sql6) {
16520
+ return sql6.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*/g, " ");
16483
16521
  }
16484
- function isMutation(sql5) {
16485
- const stripped = stripComments(sql5);
16522
+ function isMutation(sql6) {
16523
+ const stripped = stripComments(sql6);
16486
16524
  if (MUTATION_PATTERN.test(stripped)) return true;
16487
16525
  return /\bSELECT\b[\s\S]+\bINTO\s+\w/i.test(stripped);
16488
16526
  }
@@ -16778,8 +16816,8 @@ import { existsSync as existsSync38, mkdirSync as mkdirSync14, readFileSync as r
16778
16816
  import { basename as basename9, dirname as dirname21, join as join41 } from "path";
16779
16817
 
16780
16818
  // src/commands/transcript/cleanText.ts
16781
- function cleanText(text4) {
16782
- const words = text4.split(/\s+/);
16819
+ function cleanText(text5) {
16820
+ const words = text5.split(/\s+/);
16783
16821
  const cleaned = [];
16784
16822
  for (let i = 0; i < words.length; i++) {
16785
16823
  let isRepeat = false;
@@ -16799,8 +16837,8 @@ function cleanText(text4) {
16799
16837
  }
16800
16838
 
16801
16839
  // src/commands/transcript/format/processVttFile/parseVtt/deduplicateCues/removeSubstringDuplicates.ts
16802
- function normalizeText(text4) {
16803
- return text4.toLowerCase().trim();
16840
+ function normalizeText(text5) {
16841
+ return text5.toLowerCase().trim();
16804
16842
  }
16805
16843
  function checkSubstringRelation(textI, textJ) {
16806
16844
  if (textI.includes(textJ) && textI.length > textJ.length)
@@ -16929,13 +16967,13 @@ function parseTimestampLine(line) {
16929
16967
  return { startMs: parseTimestamp(startStr), endMs: parseTimestamp(endStr) };
16930
16968
  }
16931
16969
  function buildCue(startMs, endMs, fullText) {
16932
- const { speaker, text: text4 } = extractSpeaker(fullText);
16933
- return text4 ? { startMs, endMs, speaker, text: text4 } : null;
16970
+ const { speaker, text: text5 } = extractSpeaker(fullText);
16971
+ return text5 ? { startMs, endMs, speaker, text: text5 } : null;
16934
16972
  }
16935
16973
  function parseCueLine(lines, i) {
16936
16974
  const { startMs, endMs } = parseTimestampLine(lines[i]);
16937
- const { text: text4, nextIndex: nextIndex2 } = collectTextLines(lines, i + 1);
16938
- return { cue: buildCue(startMs, endMs, text4), nextIndex: nextIndex2 };
16975
+ const { text: text5, nextIndex: nextIndex2 } = collectTextLines(lines, i + 1);
16976
+ return { cue: buildCue(startMs, endMs, text5), nextIndex: nextIndex2 };
16939
16977
  }
16940
16978
  function isCueSeparator(line) {
16941
16979
  return line.trim().includes("-->");
@@ -17604,8 +17642,8 @@ async function exchangeToken(params) {
17604
17642
  body: body.toString()
17605
17643
  });
17606
17644
  if (!response.ok) {
17607
- const text4 = await response.text();
17608
- throw new Error(`Token exchange failed (${response.status}): ${text4}`);
17645
+ const text5 = await response.text();
17646
+ throw new Error(`Token exchange failed (${response.status}): ${text5}`);
17609
17647
  }
17610
17648
  return response.json();
17611
17649
  }
@@ -18517,6 +18555,7 @@ function toSessionInfo({
18517
18555
  assistArgs,
18518
18556
  cwd,
18519
18557
  restored,
18558
+ error,
18520
18559
  activity: activity2,
18521
18560
  autoRun,
18522
18561
  autoAdvance
@@ -18532,6 +18571,7 @@ function toSessionInfo({
18532
18571
  assistArgs,
18533
18572
  cwd,
18534
18573
  restored,
18574
+ error,
18535
18575
  activity: activity2,
18536
18576
  autoRun,
18537
18577
  autoAdvance
@@ -18549,12 +18589,50 @@ function broadcastSessions(sessions, clients, windowsSessions = [], active) {
18549
18589
  });
18550
18590
  }
18551
18591
 
18592
+ // src/shared/db/recordUsagePeak.ts
18593
+ import { sql as sql5 } from "drizzle-orm";
18594
+ var WINDOWS = ["five_hour", "seven_day"];
18595
+ async function recordUsagePeak(db, rateLimits) {
18596
+ const rows = WINDOWS.flatMap((window) => {
18597
+ const w = rateLimits[window];
18598
+ if (!w) return [];
18599
+ if (typeof w.resets_at !== "number" || typeof w.used_percentage !== "number")
18600
+ return [];
18601
+ return [
18602
+ { window, resetsAt: w.resets_at, usedPercentage: w.used_percentage }
18603
+ ];
18604
+ });
18605
+ if (rows.length === 0) return;
18606
+ await db.insert(usagePeaks).values(rows).onConflictDoUpdate({
18607
+ target: [usagePeaks.window, usagePeaks.resetsAt],
18608
+ set: {
18609
+ usedPercentage: sql5`GREATEST(${usagePeaks.usedPercentage}, excluded.used_percentage)`
18610
+ }
18611
+ });
18612
+ }
18613
+
18614
+ // src/commands/sessions/daemon/persistUsagePeak.ts
18615
+ async function persistUsagePeak(rateLimits) {
18616
+ try {
18617
+ if (!process.env.ASSIST_DATABASE_URL && !loadConfig().database.url) return;
18618
+ await recordUsagePeak(await getDb(), rateLimits);
18619
+ } catch (error) {
18620
+ daemonLog(`usage-peak persist failed: ${String(error)}`);
18621
+ }
18622
+ }
18623
+
18552
18624
  // src/commands/sessions/daemon/ClientHub.ts
18553
18625
  var ClientHub = class extends Set {
18626
+ // why: the daemon injects a best-effort persister; left undefined elsewhere so `new ClientHub()` works and broadcasting never depends on it.
18627
+ constructor(persistPeak) {
18628
+ super();
18629
+ this.persistPeak = persistPeak;
18630
+ }
18554
18631
  latestLimits;
18555
18632
  updateLimits(rateLimits) {
18556
18633
  this.latestLimits = rateLimits;
18557
18634
  broadcast(this, { type: "limits", rateLimits });
18635
+ this.persistPeak?.(rateLimits);
18558
18636
  }
18559
18637
  greet(client) {
18560
18638
  if (this.latestLimits) {
@@ -18722,12 +18800,6 @@ function makeStatusChangeHandler(dismiss, notify2, reuseForRun) {
18722
18800
  return (s, status2, exitCode) => applyStatusChange(s, status2, exitCode, dismiss, notify2, reuseForRun);
18723
18801
  }
18724
18802
 
18725
- // src/commands/sessions/daemon/backlogRunArgs.ts
18726
- function backlogRunArgs(persisted) {
18727
- const args = ["assist", ...persisted.assistArgs];
18728
- return persisted.claudeSessionId ? [...args, "--resume-session", persisted.claudeSessionId] : args;
18729
- }
18730
-
18731
18803
  // src/commands/sessions/daemon/restoreBase.ts
18732
18804
  function restoreBase(id2, persisted) {
18733
18805
  return {
@@ -18742,6 +18814,26 @@ function restoreBase(id2, persisted) {
18742
18814
  };
18743
18815
  }
18744
18816
 
18817
+ // src/commands/sessions/daemon/errorSession.ts
18818
+ function errorSession(id2, persisted, error) {
18819
+ return {
18820
+ ...restoreBase(id2, persisted),
18821
+ status: "error",
18822
+ startedAt: persisted.startedAt,
18823
+ pty: null,
18824
+ runName: persisted.runName,
18825
+ runArgs: persisted.runArgs,
18826
+ error,
18827
+ restored: false
18828
+ };
18829
+ }
18830
+
18831
+ // src/commands/sessions/daemon/backlogRunArgs.ts
18832
+ function backlogRunArgs(persisted) {
18833
+ const args = ["assist", ...persisted.assistArgs];
18834
+ return persisted.claudeSessionId ? [...args, "--resume-session", persisted.claudeSessionId] : args;
18835
+ }
18836
+
18745
18837
  // src/commands/sessions/daemon/runningSession.ts
18746
18838
  function runningSession(base, persisted, pty2) {
18747
18839
  return {
@@ -18769,6 +18861,13 @@ function restoreSession(id2, persisted) {
18769
18861
  });
18770
18862
  return runningSession(base, persisted, pty2);
18771
18863
  }
18864
+ if (persisted.commandType === "claude") {
18865
+ return errorSession(
18866
+ id2,
18867
+ persisted,
18868
+ "no claude session id was recorded before the daemon stopped, so the conversation cannot be resumed"
18869
+ );
18870
+ }
18772
18871
  return {
18773
18872
  ...base,
18774
18873
  status: "done",
@@ -18783,6 +18882,28 @@ function isBacklogRun(persisted) {
18783
18882
  return persisted.commandType === "assist" && persisted.assistArgs?.[0] === "backlog" && persisted.assistArgs?.[1] === "run";
18784
18883
  }
18785
18884
 
18885
+ // src/commands/sessions/daemon/restoreOne.ts
18886
+ function restoreOne(persisted, spawn12, sessions) {
18887
+ try {
18888
+ const id2 = spawn12((sid) => restoreSession(sid, persisted));
18889
+ logUnresumable(persisted.name, id2, sessions.get(id2));
18890
+ } catch (error) {
18891
+ const reason = logRestoreError(persisted.name, error);
18892
+ spawn12((id2) => errorSession(id2, persisted, reason));
18893
+ }
18894
+ }
18895
+ function logUnresumable(name, id2, session) {
18896
+ if (session?.status === "error")
18897
+ daemonLog(
18898
+ `could not resume restored session "${name}" (id ${id2}): ${session.error}`
18899
+ );
18900
+ }
18901
+ function logRestoreError(name, error) {
18902
+ const reason = error instanceof Error ? error.message : String(error);
18903
+ daemonLog(`failed to restore session "${name}": ${reason}`);
18904
+ return reason;
18905
+ }
18906
+
18786
18907
  // src/commands/sessions/daemon/resumeSession.ts
18787
18908
  function resumeSession(id2, sessionId, cwd, name) {
18788
18909
  return {
@@ -18874,7 +18995,14 @@ function wirePtyEvents(session, clients, onStatusChange) {
18874
18995
  session.pty.onExit(({ exitCode }) => {
18875
18996
  clearIdle(session);
18876
18997
  refreshActivity(session);
18877
- onStatusChange(session, "done", exitCode);
18998
+ const failedResume = session.restored === true && exitCode !== 0 && session.scrollback.length === 0;
18999
+ if (failedResume) {
19000
+ session.error = `resume process exited with code ${exitCode} before producing any output`;
19001
+ daemonLog(
19002
+ `could not resume restored session "${session.name}" (id ${session.id}): ${session.error}`
19003
+ );
19004
+ }
19005
+ onStatusChange(session, failedResume ? "error" : "done", exitCode);
18878
19006
  });
18879
19007
  scheduleIdle(session, () => onStatusChange(session, "waiting"));
18880
19008
  }
@@ -19488,8 +19616,8 @@ function deriveSessionType(commandName, name) {
19488
19616
  }
19489
19617
 
19490
19618
  // src/commands/sessions/shared/backlogRunMarkers.ts
19491
- function backlogRunMarkers(text4) {
19492
- const match = text4.match(/backlog item #(\d+):[ \t]*([^\n]*)/);
19619
+ function backlogRunMarkers(text5) {
19620
+ const match = text5.match(/backlog item #(\d+):[ \t]*([^\n]*)/);
19493
19621
  if (!match) return { commandName: "", commandArgs: "" };
19494
19622
  const title = match[2].trim();
19495
19623
  return {
@@ -19543,11 +19671,11 @@ function messageText(entry) {
19543
19671
  const content = msg?.content;
19544
19672
  return typeof content === "string" ? content : Array.isArray(content) ? content.find((c) => c.type === "text")?.text ?? "" : "";
19545
19673
  }
19546
- function stripMarkers(text4) {
19547
- return text4.replace(/<command-[^>]*>[^<]*<\/command-[^>]*>/g, "").trim().slice(0, 80);
19674
+ function stripMarkers(text5) {
19675
+ return text5.replace(/<command-[^>]*>[^<]*<\/command-[^>]*>/g, "").trim().slice(0, 80);
19548
19676
  }
19549
- function matchMarker(text4, tag) {
19550
- const match = text4.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`));
19677
+ function matchMarker(text5, tag) {
19678
+ const match = text5.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`));
19551
19679
  return match ? match[1].trim() : "";
19552
19680
  }
19553
19681
 
@@ -19757,7 +19885,7 @@ var SessionManager = class {
19757
19885
  sessions = /* @__PURE__ */ new Map();
19758
19886
  // why: dispatch calls active.set() on card click; broadcasts include active.toJSON()
19759
19887
  active = new ActiveSelection(() => this.notify());
19760
- clients = new ClientHub();
19888
+ clients = new ClientHub(persistUsagePeak);
19761
19889
  nextId = 1;
19762
19890
  shuttingDown = false;
19763
19891
  // why: dispatch calls windowsProxy.route() to forward windows-origin sessions
@@ -19778,7 +19906,7 @@ var SessionManager = class {
19778
19906
  }
19779
19907
  restore() {
19780
19908
  return loadPersistedSessions().map((persisted) => {
19781
- this.spawnWith((id2) => restoreSession(id2, persisted));
19909
+ restoreOne(persisted, this.spawnWith, this.sessions);
19782
19910
  return persisted.name;
19783
19911
  });
19784
19912
  }
@@ -19788,9 +19916,7 @@ var SessionManager = class {
19788
19916
  watchActivity(session, this.notify);
19789
19917
  return session.id;
19790
19918
  }
19791
- spawnWith(create) {
19792
- return this.add(create(String(this.nextId++)));
19793
- }
19919
+ spawnWith = (create) => this.add(create(String(this.nextId++)));
19794
19920
  spawn(prompt, cwd) {
19795
19921
  return this.spawnWith((id2) => createSession(id2, prompt, cwd));
19796
19922
  }
@@ -19871,17 +19997,17 @@ function entryMessages(entry) {
19871
19997
  return [];
19872
19998
  }
19873
19999
  function userMessages(content) {
19874
- if (typeof content === "string") return text3("user", cleanUserText(content));
20000
+ if (typeof content === "string") return text4("user", cleanUserText(content));
19875
20001
  if (!Array.isArray(content)) return [];
19876
- return content.filter((c) => c.type === "text").flatMap((c) => text3("user", cleanUserText(c.text ?? "")));
20002
+ return content.filter((c) => c.type === "text").flatMap((c) => text4("user", cleanUserText(c.text ?? "")));
19877
20003
  }
19878
20004
  function assistantMessages(content) {
19879
- if (typeof content === "string") return text3("assistant", content.trim());
20005
+ if (typeof content === "string") return text4("assistant", content.trim());
19880
20006
  if (!Array.isArray(content)) return [];
19881
20007
  return content.flatMap((c) => assistantItem(c));
19882
20008
  }
19883
20009
  function assistantItem(c) {
19884
- if (c.type === "text") return text3("assistant", (c.text ?? "").trim());
20010
+ if (c.type === "text") return text4("assistant", (c.text ?? "").trim());
19885
20011
  if (c.type === "tool_use")
19886
20012
  return [
19887
20013
  {
@@ -19892,7 +20018,7 @@ function assistantItem(c) {
19892
20018
  ];
19893
20019
  return [];
19894
20020
  }
19895
- function text3(role, value) {
20021
+ function text4(role, value) {
19896
20022
  return value ? [{ role, text: value }] : [];
19897
20023
  }
19898
20024
  function cleanUserText(value) {
@@ -20223,16 +20349,16 @@ function parseUserLine(line) {
20223
20349
  if (entry.type !== "user") return void 0;
20224
20350
  const msg = entry.message;
20225
20351
  const c = msg?.content;
20226
- let text4;
20352
+ let text5;
20227
20353
  if (typeof c === "string") {
20228
- text4 = c;
20354
+ text5 = c;
20229
20355
  } else if (Array.isArray(c)) {
20230
20356
  const collected = c.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n");
20231
- text4 = collected || void 0;
20357
+ text5 = collected || void 0;
20232
20358
  }
20233
- if (!text4) return void 0;
20359
+ if (!text5) return void 0;
20234
20360
  return {
20235
- text: text4,
20361
+ text: text5,
20236
20362
  entrypoint: typeof entry.entrypoint === "string" ? entry.entrypoint : void 0
20237
20363
  };
20238
20364
  }
@@ -20261,13 +20387,13 @@ function* iterateUserMessages(filePath, maxBytes = 65536) {
20261
20387
 
20262
20388
  // src/commands/sessions/summarise/extractFirstUserMessage.ts
20263
20389
  function extractFirstUserMessage(filePath) {
20264
- for (const text4 of iterateUserMessages(filePath)) {
20265
- return truncate3(text4);
20390
+ for (const text5 of iterateUserMessages(filePath)) {
20391
+ return truncate3(text5);
20266
20392
  }
20267
20393
  return void 0;
20268
20394
  }
20269
- function truncate3(text4, maxChars = 500) {
20270
- const trimmed = text4.trim();
20395
+ function truncate3(text5, maxChars = 500) {
20396
+ const trimmed = text5.trim();
20271
20397
  if (trimmed.length <= maxChars) return trimmed;
20272
20398
  return `${trimmed.slice(0, maxChars)}\u2026`;
20273
20399
  }
@@ -20275,28 +20401,28 @@ function truncate3(text4, maxChars = 500) {
20275
20401
  // src/commands/sessions/summarise/scanSessionBacklogRefs.ts
20276
20402
  function scanSessionBacklogRefs(filePath) {
20277
20403
  const ids = /* @__PURE__ */ new Set();
20278
- for (const text4 of iterateUserMessages(filePath, Number.MAX_SAFE_INTEGER)) {
20279
- for (const id2 of extractBacklogIds(text4)) {
20404
+ for (const text5 of iterateUserMessages(filePath, Number.MAX_SAFE_INTEGER)) {
20405
+ for (const id2 of extractBacklogIds(text5)) {
20280
20406
  ids.add(id2);
20281
20407
  }
20282
20408
  }
20283
20409
  return [...ids].sort((a, b) => a - b);
20284
20410
  }
20285
- function extractBacklogIds(text4) {
20411
+ function extractBacklogIds(text5) {
20286
20412
  const ids = [];
20287
- for (const m of text4.matchAll(/backlog\s+run\s+(\d+)/gi)) {
20413
+ for (const m of text5.matchAll(/backlog\s+run\s+(\d+)/gi)) {
20288
20414
  ids.push(Number.parseInt(m[1], 10));
20289
20415
  }
20290
- for (const m of text4.matchAll(/backlog\s+(?:item\s+)?#(\d+)/gi)) {
20416
+ for (const m of text5.matchAll(/backlog\s+(?:item\s+)?#(\d+)/gi)) {
20291
20417
  ids.push(Number.parseInt(m[1], 10));
20292
20418
  }
20293
- for (const m of text4.matchAll(/backlog\s+phase-done\s+(\d+)/gi)) {
20419
+ for (const m of text5.matchAll(/backlog\s+phase-done\s+(\d+)/gi)) {
20294
20420
  ids.push(Number.parseInt(m[1], 10));
20295
20421
  }
20296
- for (const m of text4.matchAll(/backlog\s+comment\s+(\d+)/gi)) {
20422
+ for (const m of text5.matchAll(/backlog\s+comment\s+(\d+)/gi)) {
20297
20423
  ids.push(Number.parseInt(m[1], 10));
20298
20424
  }
20299
- for (const m of text4.matchAll(/(?:^|[\s(])#(\d{1,4})(?=[\s).,;:!?]|$)/gm)) {
20425
+ for (const m of text5.matchAll(/(?:^|[\s(])#(\d{1,4})(?=[\s).,;:!?]|$)/gm)) {
20300
20426
  ids.push(Number.parseInt(m[1], 10));
20301
20427
  }
20302
20428
  return ids;