@staff0rd/assist 0.630.2 → 0.632.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.630.2",
9
+ version: "0.632.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -675,7 +675,10 @@ var assistConfigShape = {
675
675
  required: z3.boolean().default(false),
676
676
  promptJira: z3.boolean().default(false),
677
677
  draft: z3.boolean().default(false),
678
- readingWordsPerMinute: z3.number().int().positive().default(80)
678
+ readingWordsPerMinute: z3.number().int().positive().optional()
679
+ }).optional(),
680
+ readTime: z3.strictObject({
681
+ wordsPerMinute: z3.number().int().positive().default(200)
679
682
  }).optional(),
680
683
  worktree: z3.strictObject({
681
684
  enabled: z3.boolean().default(false),
@@ -1420,8 +1423,8 @@ var options = [
1420
1423
  ];
1421
1424
 
1422
1425
  // src/commands/verify/init/getAvailableOptions/index.ts
1423
- function resolveDescription(desc6, setup2) {
1424
- return typeof desc6 === "function" ? desc6(setup2) : desc6;
1426
+ function resolveDescription(desc7, setup2) {
1427
+ return typeof desc7 === "function" ? desc7(setup2) : desc7;
1425
1428
  }
1426
1429
  function toVerifyOption(def, setup2) {
1427
1430
  return {
@@ -3126,13 +3129,6 @@ var prsRaiseConfigHelp = [
3126
3129
  note: "'assist prs raise' creates a draft PR when neither --draft nor --no-draft is passed (default false)"
3127
3130
  }
3128
3131
  ];
3129
- var prsReadTimeConfigHelp = [
3130
- {
3131
- key: "prs.readingWordsPerMinute",
3132
- setter: "assist config set prs.readingWordsPerMinute 150",
3133
- note: "prose reading speed 'assist prs read-time' estimates with (default 80, measured on real pull request descriptions; fenced code counts at half that)"
3134
- }
3135
- ];
3136
3132
  var prsConfigHelp = [
3137
3133
  {
3138
3134
  key: "prs.slack",
@@ -3144,8 +3140,7 @@ var prsConfigHelp = [
3144
3140
  setter: "assist config set prs.required true",
3145
3141
  note: "require a branch when running a backlog item"
3146
3142
  },
3147
- ...prsRaiseConfigHelp,
3148
- ...prsReadTimeConfigHelp
3143
+ ...prsRaiseConfigHelp
3149
3144
  ];
3150
3145
 
3151
3146
  // src/commands/ravendb/ravendbConfigHelp.ts
@@ -3162,6 +3157,20 @@ var ravendbConfigHelp = [
3162
3157
  }
3163
3158
  ];
3164
3159
 
3160
+ // src/commands/readTime/readTimeConfigHelp.ts
3161
+ var readTimeConfigHelp = [
3162
+ {
3163
+ key: "readTime.wordsPerMinute",
3164
+ setter: "assist config set readTime.wordsPerMinute 250",
3165
+ note: "nominal prose reading speed 'assist read-time' estimates with (default 200); the effective rate decays with length, so a 500-word document reads at ~70 wpm, and fenced code counts double"
3166
+ },
3167
+ {
3168
+ key: "prs.readingWordsPerMinute",
3169
+ setter: "assist config set prs.readingWordsPerMinute 250",
3170
+ note: "same speed under the command's former name, read only when readTime.wordsPerMinute is unset"
3171
+ }
3172
+ ];
3173
+
3165
3174
  // src/commands/refactor/refactorConfigHelp.ts
3166
3175
  var refactorConfigHelp = [
3167
3176
  {
@@ -3495,6 +3504,7 @@ var configHelpEntries = [
3495
3504
  ...miroConfigHelp,
3496
3505
  ...prsConfigHelp,
3497
3506
  ...ravendbConfigHelp,
3507
+ ...readTimeConfigHelp,
3498
3508
  ...refactorConfigHelp,
3499
3509
  ...roamConfigHelp,
3500
3510
  ...runConfigHelp,
@@ -5579,8 +5589,8 @@ async function assertMigrationsInSync(exec3) {
5579
5589
  // src/shared/db/migrations/MigrationExecutor.ts
5580
5590
  function pgExecutor(queryable) {
5581
5591
  return {
5582
- exec: (sql25) => queryable.query(sql25),
5583
- query: async (sql25, params) => (await queryable.query(sql25, params)).rows
5592
+ exec: (sql28) => queryable.query(sql28),
5593
+ query: async (sql28, params) => (await queryable.query(sql28, params)).rows
5584
5594
  };
5585
5595
  }
5586
5596
 
@@ -5901,8 +5911,8 @@ async function buildDump(tables, copyOut) {
5901
5911
  // src/commands/backlog/dump/copyTableOut.ts
5902
5912
  import { to as copyTo } from "pg-copy-streams";
5903
5913
  async function copyTableOut(client, table) {
5904
- const sql25 = `COPY ${table.name} (${table.columns.join(", ")}) TO STDOUT`;
5905
- const stream = client.query(copyTo(sql25));
5914
+ const sql28 = `COPY ${table.name} (${table.columns.join(", ")}) TO STDOUT`;
5915
+ const stream = client.query(copyTo(sql28));
5906
5916
  const chunks = [];
5907
5917
  for await (const chunk of stream) {
5908
5918
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
@@ -9874,7 +9884,7 @@ function incompleteSubtaskCounts(orm) {
9874
9884
  }).from(itemSubtasks).where(ne(itemSubtasks.status, "done")).groupBy(itemSubtasks.itemId).as("incomplete_counts");
9875
9885
  }
9876
9886
 
9877
- // src/commands/backlog/planPhaseCounts.ts
9887
+ // src/shared/db/planPhaseCounts.ts
9878
9888
  import { sql as sql14 } from "drizzle-orm";
9879
9889
  function planPhaseCounts(orm) {
9880
9890
  return orm.select({
@@ -9883,11 +9893,12 @@ function planPhaseCounts(orm) {
9883
9893
  }).from(planPhases).groupBy(planPhases.itemId).as("plan_phase_counts");
9884
9894
  }
9885
9895
 
9886
- // src/commands/backlog/phaseUsageTotals.ts
9896
+ // src/shared/db/phaseUsageTotals.ts
9887
9897
  import { sql as sql15 } from "drizzle-orm";
9888
9898
  function phaseUsageTotals(orm) {
9889
9899
  return orm.select({
9890
9900
  itemId: phaseUsage.itemId,
9901
+ recordedPhases: sql15`count(*)::int`.as("recorded_phases"),
9891
9902
  tokensUp: sql15`sum(${phaseUsage.tokensUp})::bigint`.as(
9892
9903
  "total_tokens_up"
9893
9904
  ),
@@ -11695,24 +11706,103 @@ async function listUsagePeaks(db, options2) {
11695
11706
  return query;
11696
11707
  }
11697
11708
 
11698
- // src/commands/sessions/web/listUsageHistory.ts
11709
+ // src/commands/sessions/web/respondPagedRows.ts
11699
11710
  var DEFAULT_PAGE_SIZE = 30;
11700
- function parseWindow(value) {
11701
- return value === "five_hour" || value === "seven_day" ? value : void 0;
11702
- }
11703
- async function listUsageHistory(req, res) {
11711
+ async function respondPagedRows(req, res, load3) {
11704
11712
  const params = new URL(req.url ?? "/", "http://localhost").searchParams;
11705
11713
  const page = Math.max(0, Number(params.get("page")) || 0);
11706
- const pageSize = Number(params.get("pageSize")) || DEFAULT_PAGE_SIZE;
11707
- const window = parseWindow(params.get("window"));
11708
- const db = await getDb();
11709
- const [rows, total] = await Promise.all([
11710
- listUsagePeaks(db, { limit: pageSize, offset: page * pageSize, window }),
11711
- countUsagePeaks(db, window)
11712
- ]);
11714
+ const limit = Number(params.get("pageSize")) || DEFAULT_PAGE_SIZE;
11715
+ const [rows, total] = await load3({ limit, offset: page * limit }, params);
11713
11716
  respondJson(res, 200, { rows, total });
11714
11717
  }
11715
11718
 
11719
+ // src/commands/sessions/web/listUsageHistory.ts
11720
+ function parseWindow(value) {
11721
+ return value === "five_hour" || value === "seven_day" ? value : void 0;
11722
+ }
11723
+ function listUsageHistory(req, res) {
11724
+ return respondPagedRows(req, res, async (range, params) => {
11725
+ const window = parseWindow(params.get("window"));
11726
+ const db = await getDb();
11727
+ return Promise.all([
11728
+ listUsagePeaks(db, { ...range, window }),
11729
+ countUsagePeaks(db, window)
11730
+ ]);
11731
+ });
11732
+ }
11733
+
11734
+ // src/shared/db/countItemUsageSummaries.ts
11735
+ import { sql as sql17 } from "drizzle-orm";
11736
+ async function countItemUsageSummaries(db) {
11737
+ const [row] = await db.select({
11738
+ value: sql17`count(distinct ${phaseUsage.itemId})::int`
11739
+ }).from(phaseUsage);
11740
+ return row?.value ?? 0;
11741
+ }
11742
+
11743
+ // src/shared/db/listItemUsageSummaries.ts
11744
+ import { desc as desc3, eq as eq20, sql as sql19 } from "drizzle-orm";
11745
+
11746
+ // src/shared/db/lastPhaseActivity.ts
11747
+ import { sql as sql18 } from "drizzle-orm";
11748
+ function lastPhaseActivity(db) {
11749
+ return db.select({
11750
+ itemId: phaseSessions.itemId,
11751
+ at: sql18`max(${phaseSessions.createdAt})`.as("last_phase_at"),
11752
+ atIso: sql18`to_char(max(${phaseSessions.createdAt}) at time zone 'utc', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`.as(
11753
+ "last_phase_at_iso"
11754
+ )
11755
+ }).from(phaseSessions).groupBy(phaseSessions.itemId).as("last_phase_activity");
11756
+ }
11757
+
11758
+ // src/shared/db/toItemUsageSummary.ts
11759
+ function toItemUsageSummary(row) {
11760
+ return {
11761
+ ...row,
11762
+ phaseCount: row.phaseCount ?? 0,
11763
+ recordedPhases: Number(row.recordedPhases),
11764
+ tokensUp: Number(row.tokensUp),
11765
+ tokensDown: Number(row.tokensDown),
11766
+ activeMs: Number(row.activeMs),
11767
+ peakContextPct: Number(row.peakContextPct),
11768
+ lastPhaseAt: row.lastPhaseAt ?? null
11769
+ };
11770
+ }
11771
+
11772
+ // src/shared/db/listItemUsageSummaries.ts
11773
+ async function listItemUsageSummaries(db, options2) {
11774
+ const totals = phaseUsageTotals(db);
11775
+ const planned = planPhaseCounts(db);
11776
+ const lastPhase = lastPhaseActivity(db);
11777
+ const query = db.select({
11778
+ id: items.id,
11779
+ origin: items.origin,
11780
+ type: items.type,
11781
+ name: items.name,
11782
+ status: items.status,
11783
+ phaseCount: planned.count,
11784
+ recordedPhases: totals.recordedPhases,
11785
+ tokensUp: totals.tokensUp,
11786
+ tokensDown: totals.tokensDown,
11787
+ activeMs: totals.activeMs,
11788
+ peakContextPct: totals.peakContextPct,
11789
+ lastPhaseAt: lastPhase.atIso
11790
+ }).from(items).innerJoin(totals, eq20(totals.itemId, items.id)).leftJoin(planned, eq20(planned.itemId, items.id)).leftJoin(lastPhase, eq20(lastPhase.itemId, items.id)).orderBy(sql19`${lastPhase.at} desc nulls last`, desc3(items.id));
11791
+ const rows = options2?.limit === void 0 ? await query : await query.limit(options2.limit).offset(options2.offset ?? 0);
11792
+ return rows.map(toItemUsageSummary);
11793
+ }
11794
+
11795
+ // src/commands/sessions/web/listUsageItems.ts
11796
+ function listUsageItems(req, res) {
11797
+ return respondPagedRows(req, res, async (range) => {
11798
+ const db = await getDb();
11799
+ return Promise.all([
11800
+ listItemUsageSummaries(db, range),
11801
+ countItemUsageSummaries(db)
11802
+ ]);
11803
+ });
11804
+ }
11805
+
11716
11806
  // src/commands/sessions/web/openInCode.ts
11717
11807
  import { exec } from "child_process";
11718
11808
  import { promisify as promisify4 } from "util";
@@ -12699,7 +12789,7 @@ async function runGhImage(filePath, cwd) {
12699
12789
  );
12700
12790
  }
12701
12791
  const lines2 = stdout.split("\n").map((line) => line.trim()).filter(Boolean);
12702
- const markdown = lines2.find((line) => /^!\[.*]\(.+\)$/.test(line)) ?? lines2.find((line) => line.includes("http")) ?? lines2[0];
12792
+ const markdown = lines2.find((line) => /^!\[.*]\(.+\)$/.test(line)) ?? lines2.find((line) => /^https?:\/\/\S+$/.test(line)) ?? lines2.find((line) => line.includes("http")) ?? lines2[0];
12703
12793
  if (!markdown) throw new Error("gh image produced no output");
12704
12794
  return markdown;
12705
12795
  }
@@ -12731,12 +12821,23 @@ var EXT_BY_MIME = {
12731
12821
  "image/webp": "webp",
12732
12822
  "image/svg+xml": "svg",
12733
12823
  "image/bmp": "bmp",
12734
- "image/avif": "avif"
12824
+ "image/avif": "avif",
12825
+ "video/mp4": "mp4",
12826
+ "video/webm": "webm",
12827
+ "video/quicktime": "mov",
12828
+ "video/ogg": "ogv"
12735
12829
  };
12830
+ function extensionFromMime(contentType) {
12831
+ const mime = contentType.split(";")[0].trim().toLowerCase();
12832
+ const known = EXT_BY_MIME[mime];
12833
+ if (known) return known;
12834
+ const subtype = mime.split("/")[1]?.replace(/^x-/, "").replace(/\+.*$/, "");
12835
+ return subtype && /^[a-z0-9]+$/.test(subtype) ? subtype : void 0;
12836
+ }
12736
12837
  function pickExtension(name, contentType) {
12737
12838
  const fromName = extname(name).replace(/^\./, "").toLowerCase();
12738
12839
  if (fromName) return fromName;
12739
- return EXT_BY_MIME[contentType.split(";")[0].trim().toLowerCase()] ?? "png";
12840
+ return extensionFromMime(contentType) ?? "png";
12740
12841
  }
12741
12842
  function safeBaseName(name) {
12742
12843
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-");
@@ -12949,6 +13050,7 @@ var routes2 = {
12949
13050
  "GET /api/pr-list": prList,
12950
13051
  "GET /api/news/items": listNewsItems,
12951
13052
  "GET /api/usage/history": listUsageHistory,
13053
+ "GET /api/usage/items": listUsageItems,
12952
13054
  "GET /api/backups/list": getBackups,
12953
13055
  "GET /api/config": getConfig,
12954
13056
  "POST /api/config/set": setConfig,
@@ -13520,11 +13622,11 @@ function registerActivityCommands(cmd) {
13520
13622
 
13521
13623
  // src/commands/backlog/associate-github/index.ts
13522
13624
  import chalk66 from "chalk";
13523
- import { eq as eq21 } from "drizzle-orm";
13625
+ import { eq as eq22 } from "drizzle-orm";
13524
13626
 
13525
13627
  // src/commands/backlog/beginAssociation.ts
13526
13628
  import chalk65 from "chalk";
13527
- import { eq as eq20 } from "drizzle-orm";
13629
+ import { eq as eq21 } from "drizzle-orm";
13528
13630
  async function beginAssociation(id, options2, clearPatch, label2) {
13529
13631
  const found = await findOneItem(id);
13530
13632
  if (!found) {
@@ -13534,7 +13636,7 @@ async function beginAssociation(id, options2, clearPatch, label2) {
13534
13636
  const { orm } = found;
13535
13637
  const itemId2 = found.item.id;
13536
13638
  if (options2.clear) {
13537
- await orm.update(items).set(clearPatch).where(eq20(items.id, itemId2));
13639
+ await orm.update(items).set(clearPatch).where(eq21(items.id, itemId2));
13538
13640
  console.log(
13539
13641
  chalk65.green(
13540
13642
  `Cleared ${label2} association on item ${formatItemId(itemId2)}.`
@@ -13602,7 +13704,7 @@ async function associateGithub(id, issue, options2) {
13602
13704
  return;
13603
13705
  }
13604
13706
  const title = fetchGithubIssueTitle(normalized);
13605
- await orm.update(items).set({ githubIssue: normalized, jiraKey: null }).where(eq21(items.id, itemId2));
13707
+ await orm.update(items).set({ githubIssue: normalized, jiraKey: null }).where(eq22(items.id, itemId2));
13606
13708
  console.log(
13607
13709
  chalk66.green(`Associated ${normalized} with item ${formatItemId(itemId2)}.`),
13608
13710
  title ? chalk66.dim(`(${title})`) : ""
@@ -13616,7 +13718,7 @@ function registerAssociateGithubCommand(cmd) {
13616
13718
 
13617
13719
  // src/commands/backlog/associate-jira/index.ts
13618
13720
  import chalk68 from "chalk";
13619
- import { eq as eq22 } from "drizzle-orm";
13721
+ import { eq as eq23 } from "drizzle-orm";
13620
13722
 
13621
13723
  // src/commands/jira/fetchIssue.ts
13622
13724
  import { execSync as execSync27 } from "child_process";
@@ -13681,7 +13783,7 @@ async function associateJira(id, key, options2) {
13681
13783
  const parsed = fetchIssue(normalized, "summary");
13682
13784
  const fields = parsed?.fields;
13683
13785
  const summary = fields?.summary;
13684
- await orm.update(items).set({ jiraKey: normalized, githubIssue: null }).where(eq22(items.id, itemId2));
13786
+ await orm.update(items).set({ jiraKey: normalized, githubIssue: null }).where(eq23(items.id, itemId2));
13685
13787
  console.log(
13686
13788
  chalk68.green(`Associated ${normalized} with item ${formatItemId(itemId2)}.`),
13687
13789
  summary ? chalk68.dim(`(${summary})`) : ""
@@ -14085,8 +14187,8 @@ async function readStdinBuffer() {
14085
14187
  import { finished } from "stream/promises";
14086
14188
  import { from as copyFrom } from "pg-copy-streams";
14087
14189
  async function copyTableIn(client, table, data) {
14088
- const sql25 = `COPY ${table.name} (${table.columns.join(", ")}) FROM STDIN`;
14089
- const stream = client.query(copyFrom(sql25));
14190
+ const sql28 = `COPY ${table.name} (${table.columns.join(", ")}) FROM STDIN`;
14191
+ const stream = client.query(copyFrom(sql28));
14090
14192
  stream.end(data);
14091
14193
  await finished(stream);
14092
14194
  }
@@ -14188,15 +14290,15 @@ function isClaudeCode() {
14188
14290
  }
14189
14291
 
14190
14292
  // src/commands/backlog/insertPhaseAt.ts
14191
- import { eq as eq24 } from "drizzle-orm";
14293
+ import { eq as eq25 } from "drizzle-orm";
14192
14294
 
14193
14295
  // src/commands/backlog/shiftPhasesUp.ts
14194
- import { and as and9, desc as desc3, eq as eq23, gte } from "drizzle-orm";
14296
+ import { and as and9, desc as desc4, eq as eq24, gte } from "drizzle-orm";
14195
14297
  async function shiftPhasesUp(db, itemId2, fromIdx) {
14196
- const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and9(eq23(planPhases.itemId, itemId2), gte(planPhases.idx, fromIdx))).orderBy(desc3(planPhases.idx));
14298
+ const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and9(eq24(planPhases.itemId, itemId2), gte(planPhases.idx, fromIdx))).orderBy(desc4(planPhases.idx));
14197
14299
  for (const p of toShift) {
14198
- await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and9(eq23(planTasks.itemId, itemId2), eq23(planTasks.phaseIdx, p.idx)));
14199
- await db.update(planPhases).set({ idx: p.idx + 1 }).where(and9(eq23(planPhases.itemId, itemId2), eq23(planPhases.idx, p.idx)));
14300
+ await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and9(eq24(planTasks.itemId, itemId2), eq24(planTasks.phaseIdx, p.idx)));
14301
+ await db.update(planPhases).set({ idx: p.idx + 1 }).where(and9(eq24(planPhases.itemId, itemId2), eq24(planPhases.idx, p.idx)));
14200
14302
  }
14201
14303
  }
14202
14304
 
@@ -14209,17 +14311,17 @@ async function insertPhaseAt(orm, itemId2, phaseIdx, name, tasks, manualChecks,
14209
14311
  await tx.insert(planTasks).values(tasks.map((task, i) => ({ itemId: itemId2, phaseIdx, idx: i, task })));
14210
14312
  }
14211
14313
  if (currentPhase !== void 0 && currentPhase - 1 >= phaseIdx) {
14212
- await tx.update(items).set({ currentPhase: phaseIdx + 1 }).where(eq24(items.id, itemId2));
14314
+ await tx.update(items).set({ currentPhase: phaseIdx + 1 }).where(eq25(items.id, itemId2));
14213
14315
  }
14214
14316
  });
14215
14317
  }
14216
14318
 
14217
14319
  // src/commands/backlog/insertSubtask.ts
14218
- import { sql as sql17 } from "drizzle-orm";
14320
+ import { sql as sql20 } from "drizzle-orm";
14219
14321
  async function insertSubtask(orm, itemId2, title, description) {
14220
14322
  await orm.insert(itemSubtasks).values({
14221
14323
  itemId: itemId2,
14222
- idx: sql17`(SELECT COALESCE(MAX(${itemSubtasks.idx}) + 1, 0) FROM ${itemSubtasks} WHERE ${itemSubtasks.itemId} = ${itemId2})`,
14324
+ idx: sql20`(SELECT COALESCE(MAX(${itemSubtasks.idx}) + 1, 0) FROM ${itemSubtasks} WHERE ${itemSubtasks.itemId} = ${itemId2})`,
14223
14325
  title,
14224
14326
  description: description ?? null,
14225
14327
  status: "todo"
@@ -14381,9 +14483,9 @@ import chalk78 from "chalk";
14381
14483
 
14382
14484
  // src/commands/backlog/resolveInsertPosition.ts
14383
14485
  import chalk77 from "chalk";
14384
- import { count as count3, eq as eq25 } from "drizzle-orm";
14486
+ import { count as count3, eq as eq26 } from "drizzle-orm";
14385
14487
  async function resolveInsertPosition(orm, itemId2, position) {
14386
- const [row] = await orm.select({ cnt: count3() }).from(planPhases).where(eq25(planPhases.itemId, itemId2));
14488
+ const [row] = await orm.select({ cnt: count3() }).from(planPhases).where(eq26(planPhases.itemId, itemId2));
14387
14489
  const phaseCount = row?.cnt ?? 0;
14388
14490
  if (position === void 0) return phaseCount;
14389
14491
  const pos = Number.parseInt(position, 10);
@@ -14678,9 +14780,9 @@ function hasCycle(adjacency, fromId, toId) {
14678
14780
  }
14679
14781
 
14680
14782
  // src/commands/backlog/loadDependencyGraph.ts
14681
- import { eq as eq26 } from "drizzle-orm";
14783
+ import { eq as eq27 } from "drizzle-orm";
14682
14784
  async function loadDependencyGraph(orm) {
14683
- const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(eq26(links.type, "depends-on"));
14785
+ const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(eq27(links.type, "depends-on"));
14684
14786
  const graph = /* @__PURE__ */ new Map();
14685
14787
  for (const { itemId: itemId2, targetId } of rows) {
14686
14788
  const bucket = graph.get(itemId2);
@@ -14747,7 +14849,7 @@ async function link(fromId, toId, opts) {
14747
14849
 
14748
14850
  // src/commands/backlog/unlink.ts
14749
14851
  import chalk85 from "chalk";
14750
- import { and as and10, eq as eq27 } from "drizzle-orm";
14852
+ import { and as and10, eq as eq28 } from "drizzle-orm";
14751
14853
  async function unlink(fromId, toId) {
14752
14854
  const fromNum = parseItemId(fromId);
14753
14855
  const toNum = parseItemId(toId);
@@ -14771,7 +14873,7 @@ async function unlink(fromId, toId) {
14771
14873
  );
14772
14874
  return;
14773
14875
  }
14774
- await orm.delete(links).where(and10(eq27(links.itemId, fromNum), eq27(links.targetId, toNum)));
14876
+ await orm.delete(links).where(and10(eq28(links.itemId, fromNum), eq28(links.targetId, toNum)));
14775
14877
  console.log(
14776
14878
  chalk85.green(
14777
14879
  `Removed link from ${formatItemId(fromNum)} to ${formatItemId(toNum)}.`
@@ -14791,7 +14893,7 @@ function registerLinkCommands(cmd) {
14791
14893
 
14792
14894
  // src/commands/backlog/move-repo/index.ts
14793
14895
  import chalk87 from "chalk";
14794
- import { eq as eq29 } from "drizzle-orm";
14896
+ import { eq as eq30 } from "drizzle-orm";
14795
14897
 
14796
14898
  // src/commands/backlog/move-repo/confirmMove.ts
14797
14899
  import chalk86 from "chalk";
@@ -14806,9 +14908,9 @@ async function confirmMove(cnt, oldOrigin, newOrigin) {
14806
14908
  }
14807
14909
 
14808
14910
  // src/commands/backlog/move-repo/countByOrigin.ts
14809
- import { count as count4, eq as eq28 } from "drizzle-orm";
14911
+ import { count as count4, eq as eq29 } from "drizzle-orm";
14810
14912
  async function countByOrigin(orm, origin) {
14811
- const [{ cnt }] = await orm.select({ cnt: count4() }).from(items).where(eq28(items.origin, origin));
14913
+ const [{ cnt }] = await orm.select({ cnt: count4() }).from(items).where(eq29(items.origin, origin));
14812
14914
  return cnt;
14813
14915
  }
14814
14916
 
@@ -14851,7 +14953,7 @@ async function moveRepo(oldOriginRaw, newOriginRaw, options2 = {}) {
14851
14953
  console.log(chalk87.yellow("Move cancelled; no changes made."));
14852
14954
  return;
14853
14955
  }
14854
- await orm.update(items).set({ origin: newOrigin }).where(eq29(items.origin, oldOrigin));
14956
+ await orm.update(items).set({ origin: newOrigin }).where(eq30(items.origin, oldOrigin));
14855
14957
  console.log(
14856
14958
  chalk87.green(
14857
14959
  `Moved ${pluralItems(cnt)} from "${oldOrigin}" to "${newOrigin}".`
@@ -15251,10 +15353,10 @@ async function start(id) {
15251
15353
 
15252
15354
  // src/commands/backlog/stop/index.ts
15253
15355
  import chalk99 from "chalk";
15254
- import { and as and11, eq as eq30 } from "drizzle-orm";
15356
+ import { and as and11, eq as eq31 } from "drizzle-orm";
15255
15357
  async function stop() {
15256
15358
  const { orm } = await getReady();
15257
- const stopped = await orm.update(items).set({ status: "todo", currentPhase: 1 }).where(and11(eq30(items.status, "in-progress"), eq30(items.origin, getOrigin()))).returning({ id: items.id, name: items.name });
15359
+ const stopped = await orm.update(items).set({ status: "todo", currentPhase: 1 }).where(and11(eq31(items.status, "in-progress"), eq31(items.origin, getOrigin()))).returning({ id: items.id, name: items.name });
15258
15360
  if (stopped.length === 0) {
15259
15361
  console.log(chalk99.yellow("No in-progress items to stop."));
15260
15362
  return;
@@ -15371,13 +15473,13 @@ async function findSubtask(id, index3) {
15371
15473
  }
15372
15474
 
15373
15475
  // src/commands/backlog/updateSubtask.ts
15374
- import { and as and12, eq as eq31 } from "drizzle-orm";
15476
+ import { and as and12, eq as eq32 } from "drizzle-orm";
15375
15477
  async function updateSubtask(orm, itemId2, idx, fields) {
15376
15478
  const set = {};
15377
15479
  if (fields.title !== void 0) set.title = fields.title;
15378
15480
  if (fields.description !== void 0) set.description = fields.description;
15379
15481
  if (fields.status !== void 0) set.status = fields.status;
15380
- const [row] = await orm.update(itemSubtasks).set(set).where(and12(eq31(itemSubtasks.itemId, itemId2), eq31(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
15482
+ const [row] = await orm.update(itemSubtasks).set(set).where(and12(eq32(itemSubtasks.itemId, itemId2), eq32(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
15381
15483
  return row?.title;
15382
15484
  }
15383
15485
 
@@ -15432,16 +15534,16 @@ async function editSubtask(id, index3, options2) {
15432
15534
  import chalk105 from "chalk";
15433
15535
 
15434
15536
  // src/commands/backlog/deleteSubtask.ts
15435
- import { and as and13, asc as asc8, eq as eq32 } from "drizzle-orm";
15537
+ import { and as and13, asc as asc8, eq as eq33 } from "drizzle-orm";
15436
15538
  async function deleteSubtask(orm, itemId2, idx) {
15437
- const [row] = await orm.delete(itemSubtasks).where(and13(eq32(itemSubtasks.itemId, itemId2), eq32(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
15539
+ const [row] = await orm.delete(itemSubtasks).where(and13(eq33(itemSubtasks.itemId, itemId2), eq33(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
15438
15540
  if (!row) return void 0;
15439
- const remaining = await orm.select({ idx: itemSubtasks.idx }).from(itemSubtasks).where(eq32(itemSubtasks.itemId, itemId2)).orderBy(asc8(itemSubtasks.idx));
15541
+ const remaining = await orm.select({ idx: itemSubtasks.idx }).from(itemSubtasks).where(eq33(itemSubtasks.itemId, itemId2)).orderBy(asc8(itemSubtasks.idx));
15440
15542
  for (let i = 0; i < remaining.length; i++) {
15441
15543
  const oldIdx = remaining[i].idx;
15442
15544
  if (oldIdx === i) continue;
15443
15545
  await orm.update(itemSubtasks).set({ idx: i }).where(
15444
- and13(eq32(itemSubtasks.itemId, itemId2), eq32(itemSubtasks.idx, oldIdx))
15546
+ and13(eq33(itemSubtasks.itemId, itemId2), eq33(itemSubtasks.idx, oldIdx))
15445
15547
  );
15446
15548
  }
15447
15549
  return row.title;
@@ -15510,20 +15612,20 @@ function registerSubtaskCommands(cmd) {
15510
15612
 
15511
15613
  // src/commands/backlog/movePhase.ts
15512
15614
  import chalk107 from "chalk";
15513
- import { count as count6, eq as eq35 } from "drizzle-orm";
15615
+ import { count as count6, eq as eq36 } from "drizzle-orm";
15514
15616
 
15515
15617
  // src/commands/backlog/reorderPhaseRows.ts
15516
- import { and as and15, asc as asc10, eq as eq34 } from "drizzle-orm";
15618
+ import { and as and15, asc as asc10, eq as eq35 } from "drizzle-orm";
15517
15619
 
15518
15620
  // src/commands/backlog/reindexPhases.ts
15519
- import { and as and14, asc as asc9, count as count5, eq as eq33 } from "drizzle-orm";
15621
+ import { and as and14, asc as asc9, count as count5, eq as eq34 } from "drizzle-orm";
15520
15622
  async function reindexPhases(db, itemId2) {
15521
- const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq33(planPhases.itemId, itemId2)).orderBy(asc9(planPhases.idx));
15623
+ const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq34(planPhases.itemId, itemId2)).orderBy(asc9(planPhases.idx));
15522
15624
  for (let i = 0; i < remaining.length; i++) {
15523
15625
  const oldIdx = remaining[i].idx;
15524
15626
  if (oldIdx === i) continue;
15525
- await db.update(planTasks).set({ phaseIdx: i }).where(and14(eq33(planTasks.itemId, itemId2), eq33(planTasks.phaseIdx, oldIdx)));
15526
- await db.update(planPhases).set({ idx: i }).where(and14(eq33(planPhases.itemId, itemId2), eq33(planPhases.idx, oldIdx)));
15627
+ await db.update(planTasks).set({ phaseIdx: i }).where(and14(eq34(planTasks.itemId, itemId2), eq34(planTasks.phaseIdx, oldIdx)));
15628
+ await db.update(planPhases).set({ idx: i }).where(and14(eq34(planPhases.itemId, itemId2), eq34(planPhases.idx, oldIdx)));
15527
15629
  }
15528
15630
  }
15529
15631
  async function adjustCurrentPhase(db, item, removedIdx) {
@@ -15531,24 +15633,24 @@ async function adjustCurrentPhase(db, item, removedIdx) {
15531
15633
  if (currentPhase === void 0) return;
15532
15634
  const currentIdx = currentPhase - 1;
15533
15635
  if (removedIdx < currentIdx) {
15534
- await db.update(items).set({ currentPhase: currentPhase - 1 }).where(eq33(items.id, item.id));
15636
+ await db.update(items).set({ currentPhase: currentPhase - 1 }).where(eq34(items.id, item.id));
15535
15637
  return;
15536
15638
  }
15537
15639
  if (removedIdx !== currentIdx) return;
15538
- const [row] = await db.select({ cnt: count5() }).from(planPhases).where(eq33(planPhases.itemId, item.id));
15640
+ const [row] = await db.select({ cnt: count5() }).from(planPhases).where(eq34(planPhases.itemId, item.id));
15539
15641
  const cnt = row?.cnt ?? 0;
15540
- await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(eq33(items.id, item.id));
15642
+ await db.update(items).set({ currentPhase: cnt === 0 ? null : Math.min(currentPhase, cnt) }).where(eq34(items.id, item.id));
15541
15643
  }
15542
15644
 
15543
15645
  // src/commands/backlog/reorderPhaseRows.ts
15544
15646
  async function reorderPhaseRows(orm, itemId2, fromIdx, toIdx) {
15545
15647
  await orm.transaction(async (tx) => {
15546
- const [phaseRow] = await tx.select({ name: planPhases.name, manualChecks: planPhases.manualChecks }).from(planPhases).where(and15(eq34(planPhases.itemId, itemId2), eq34(planPhases.idx, fromIdx)));
15547
- const tasks = await tx.select({ idx: planTasks.idx, task: planTasks.task }).from(planTasks).where(and15(eq34(planTasks.itemId, itemId2), eq34(planTasks.phaseIdx, fromIdx))).orderBy(asc10(planTasks.idx));
15648
+ const [phaseRow] = await tx.select({ name: planPhases.name, manualChecks: planPhases.manualChecks }).from(planPhases).where(and15(eq35(planPhases.itemId, itemId2), eq35(planPhases.idx, fromIdx)));
15649
+ const tasks = await tx.select({ idx: planTasks.idx, task: planTasks.task }).from(planTasks).where(and15(eq35(planTasks.itemId, itemId2), eq35(planTasks.phaseIdx, fromIdx))).orderBy(asc10(planTasks.idx));
15548
15650
  await tx.delete(planTasks).where(
15549
- and15(eq34(planTasks.itemId, itemId2), eq34(planTasks.phaseIdx, fromIdx))
15651
+ and15(eq35(planTasks.itemId, itemId2), eq35(planTasks.phaseIdx, fromIdx))
15550
15652
  );
15551
- await tx.delete(planPhases).where(and15(eq34(planPhases.itemId, itemId2), eq34(planPhases.idx, fromIdx)));
15653
+ await tx.delete(planPhases).where(and15(eq35(planPhases.itemId, itemId2), eq35(planPhases.idx, fromIdx)));
15552
15654
  await reindexPhases(tx, itemId2);
15553
15655
  await shiftPhasesUp(tx, itemId2, toIdx);
15554
15656
  await tx.insert(planPhases).values({
@@ -15589,7 +15691,7 @@ async function movePhase(id, from, to) {
15589
15691
  if (!found) return;
15590
15692
  const { orm, item } = found;
15591
15693
  const itemId2 = item.id;
15592
- const [row] = await orm.select({ cnt: count6() }).from(planPhases).where(eq35(planPhases.itemId, itemId2));
15694
+ const [row] = await orm.select({ cnt: count6() }).from(planPhases).where(eq36(planPhases.itemId, itemId2));
15593
15695
  const phaseCount = row?.cnt ?? 0;
15594
15696
  const fromIdx = toIndex2(from, phaseCount);
15595
15697
  if (fromIdx === void 0) return;
@@ -15605,22 +15707,22 @@ async function movePhase(id, from, to) {
15605
15707
  import chalk109 from "chalk";
15606
15708
 
15607
15709
  // src/commands/backlog/applyPhaseUpdate.ts
15608
- import { and as and16, eq as eq36 } from "drizzle-orm";
15710
+ import { and as and16, eq as eq37 } from "drizzle-orm";
15609
15711
  async function applyPhaseUpdate(orm, itemId2, phaseIdx, fields) {
15610
15712
  await orm.transaction(async (tx) => {
15611
15713
  if (fields.name) {
15612
15714
  await tx.update(planPhases).set({ name: fields.name }).where(
15613
- and16(eq36(planPhases.itemId, itemId2), eq36(planPhases.idx, phaseIdx))
15715
+ and16(eq37(planPhases.itemId, itemId2), eq37(planPhases.idx, phaseIdx))
15614
15716
  );
15615
15717
  }
15616
15718
  if (fields.manualCheck) {
15617
15719
  await tx.update(planPhases).set({ manualChecks: JSON.stringify(fields.manualCheck) }).where(
15618
- and16(eq36(planPhases.itemId, itemId2), eq36(planPhases.idx, phaseIdx))
15720
+ and16(eq37(planPhases.itemId, itemId2), eq37(planPhases.idx, phaseIdx))
15619
15721
  );
15620
15722
  }
15621
15723
  if (fields.task) {
15622
15724
  await tx.delete(planTasks).where(
15623
- and16(eq36(planTasks.itemId, itemId2), eq36(planTasks.phaseIdx, phaseIdx))
15725
+ and16(eq37(planTasks.itemId, itemId2), eq37(planTasks.phaseIdx, phaseIdx))
15624
15726
  );
15625
15727
  if (fields.task.length) {
15626
15728
  await tx.insert(planTasks).values(
@@ -15638,14 +15740,14 @@ async function applyPhaseUpdate(orm, itemId2, phaseIdx, fields) {
15638
15740
 
15639
15741
  // src/commands/backlog/findPhase.ts
15640
15742
  import chalk108 from "chalk";
15641
- import { and as and17, count as count7, eq as eq37 } from "drizzle-orm";
15743
+ import { and as and17, count as count7, eq as eq38 } from "drizzle-orm";
15642
15744
  async function findPhase(id, phase) {
15643
15745
  const found = await findOneItem(id);
15644
15746
  if (!found) return void 0;
15645
15747
  const { orm, item } = found;
15646
15748
  const itemId2 = item.id;
15647
15749
  const phaseIdx = Number.parseInt(phase, 10) - 1;
15648
- const [row] = await orm.select({ cnt: count7() }).from(planPhases).where(and17(eq37(planPhases.itemId, itemId2), eq37(planPhases.idx, phaseIdx)));
15750
+ const [row] = await orm.select({ cnt: count7() }).from(planPhases).where(and17(eq38(planPhases.itemId, itemId2), eq38(planPhases.idx, phaseIdx)));
15649
15751
  if (!row || row.cnt === 0) {
15650
15752
  console.log(
15651
15753
  chalk108.red(
@@ -15818,16 +15920,16 @@ function registerUpdatePhaseCommand(cmd) {
15818
15920
 
15819
15921
  // src/commands/backlog/removePhase.ts
15820
15922
  import chalk110 from "chalk";
15821
- import { and as and18, eq as eq38 } from "drizzle-orm";
15923
+ import { and as and18, eq as eq39 } from "drizzle-orm";
15822
15924
  async function removePhase(id, phase) {
15823
15925
  const found = await findPhase(id, phase);
15824
15926
  if (!found) return;
15825
15927
  const { item, orm, itemId: itemId2, phaseIdx } = found;
15826
15928
  await orm.transaction(async (tx) => {
15827
15929
  await tx.delete(planTasks).where(
15828
- and18(eq38(planTasks.itemId, itemId2), eq38(planTasks.phaseIdx, phaseIdx))
15930
+ and18(eq39(planTasks.itemId, itemId2), eq39(planTasks.phaseIdx, phaseIdx))
15829
15931
  );
15830
- await tx.delete(planPhases).where(and18(eq38(planPhases.itemId, itemId2), eq38(planPhases.idx, phaseIdx)));
15932
+ await tx.delete(planPhases).where(and18(eq39(planPhases.itemId, itemId2), eq39(planPhases.idx, phaseIdx)));
15831
15933
  await reindexPhases(tx, itemId2);
15832
15934
  await adjustCurrentPhase(tx, item, phaseIdx);
15833
15935
  });
@@ -15840,13 +15942,13 @@ async function removePhase(id, phase) {
15840
15942
 
15841
15943
  // src/commands/backlog/update/update.ts
15842
15944
  import chalk114 from "chalk";
15843
- import { eq as eq39 } from "drizzle-orm";
15945
+ import { eq as eq40 } from "drizzle-orm";
15844
15946
 
15845
15947
  // src/commands/backlog/update/buildUpdateValues.ts
15846
15948
  import chalk111 from "chalk";
15847
15949
  function buildUpdateValues(options2) {
15848
- const { name, desc: desc6, type, ac, origin } = options2;
15849
- if (!name && !desc6 && !type && !ac && !origin) {
15950
+ const { name, desc: desc7, type, ac, origin } = options2;
15951
+ if (!name && !desc7 && !type && !ac && !origin) {
15850
15952
  console.log(chalk111.red("Nothing to update. Provide at least one flag."));
15851
15953
  process.exitCode = 1;
15852
15954
  return void 0;
@@ -15862,8 +15964,8 @@ function buildUpdateValues(options2) {
15862
15964
  set.name = name;
15863
15965
  fieldNames.push("name");
15864
15966
  }
15865
- if (desc6) {
15866
- set.description = desc6.replaceAll(String.raw`\n`, "\n");
15967
+ if (desc7) {
15968
+ set.description = desc7.replaceAll(String.raw`\n`, "\n");
15867
15969
  fieldNames.push("description");
15868
15970
  }
15869
15971
  if (type) {
@@ -15951,7 +16053,7 @@ async function update(id, options2) {
15951
16053
  if (!built) return;
15952
16054
  const { orm } = found;
15953
16055
  const itemId2 = found.item.id;
15954
- await orm.update(items).set(built.set).where(eq39(items.id, itemId2));
16056
+ await orm.update(items).set(built.set).where(eq40(items.id, itemId2));
15955
16057
  console.log(
15956
16058
  chalk114.green(`Updated ${built.fields} on item ${formatItemId(itemId2)}.`)
15957
16059
  );
@@ -15972,7 +16074,7 @@ function readPlanUpdate(source) {
15972
16074
  }
15973
16075
 
15974
16076
  // src/commands/backlog/updatePlan/replacePlan.ts
15975
- import { eq as eq40 } from "drizzle-orm";
16077
+ import { eq as eq41 } from "drizzle-orm";
15976
16078
 
15977
16079
  // src/commands/backlog/updatePlan/clampCurrentPhase.ts
15978
16080
  function clampCurrentPhase(currentPhase, phaseCount) {
@@ -15983,8 +16085,8 @@ function clampCurrentPhase(currentPhase, phaseCount) {
15983
16085
  // src/commands/backlog/updatePlan/replacePlan.ts
15984
16086
  async function replacePlan(orm, itemId2, phases, currentPhase) {
15985
16087
  await orm.transaction(async (tx) => {
15986
- await tx.delete(planTasks).where(eq40(planTasks.itemId, itemId2));
15987
- await tx.delete(planPhases).where(eq40(planPhases.itemId, itemId2));
16088
+ await tx.delete(planTasks).where(eq41(planTasks.itemId, itemId2));
16089
+ await tx.delete(planPhases).where(eq41(planPhases.itemId, itemId2));
15988
16090
  if (phases.length > 0) {
15989
16091
  await tx.insert(planPhases).values(
15990
16092
  phases.map((phase, idx) => ({
@@ -16002,7 +16104,7 @@ async function replacePlan(orm, itemId2, phases, currentPhase) {
16002
16104
  if (currentPhase === void 0) return;
16003
16105
  const clamped = clampCurrentPhase(currentPhase, phases.length);
16004
16106
  if (clamped === currentPhase) return;
16005
- await tx.update(items).set({ currentPhase: clamped }).where(eq40(items.id, itemId2));
16107
+ await tx.update(items).set({ currentPhase: clamped }).where(eq41(items.id, itemId2));
16006
16108
  });
16007
16109
  }
16008
16110
 
@@ -22767,9 +22869,9 @@ function registerGithub(program2) {
22767
22869
  }
22768
22870
 
22769
22871
  // src/commands/handover/countPendingHandovers.ts
22770
- import { and as and19, eq as eq41, isNull, sql as sql18 } from "drizzle-orm";
22872
+ import { and as and19, eq as eq42, isNull, sql as sql21 } from "drizzle-orm";
22771
22873
  async function countPendingHandovers(orm, origin) {
22772
- const [row] = await orm.select({ count: sql18`count(*)::int` }).from(handovers).where(and19(eq41(handovers.origin, origin), isNull(handovers.recalledAt)));
22874
+ const [row] = await orm.select({ count: sql21`count(*)::int` }).from(handovers).where(and19(eq42(handovers.origin, origin), isNull(handovers.recalledAt)));
22773
22875
  return row?.count ?? 0;
22774
22876
  }
22775
22877
 
@@ -22909,13 +23011,13 @@ async function load2(options2 = {}) {
22909
23011
  }
22910
23012
 
22911
23013
  // src/commands/handover/listPendingHandovers.ts
22912
- import { and as and20, desc as desc4, eq as eq42, isNull as isNull2 } from "drizzle-orm";
23014
+ import { and as and20, desc as desc5, eq as eq43, isNull as isNull2 } from "drizzle-orm";
22913
23015
  async function listPendingHandovers(orm, origin) {
22914
23016
  return orm.select({
22915
23017
  id: handovers.id,
22916
23018
  summary: handovers.summary,
22917
23019
  createdAt: handovers.createdAt
22918
- }).from(handovers).where(and20(eq42(handovers.origin, origin), isNull2(handovers.recalledAt))).orderBy(desc4(handovers.createdAt), desc4(handovers.id));
23020
+ }).from(handovers).where(and20(eq43(handovers.origin, origin), isNull2(handovers.recalledAt))).orderBy(desc5(handovers.createdAt), desc5(handovers.id));
22919
23021
  }
22920
23022
 
22921
23023
  // src/commands/handover/printPendingHandovers.ts
@@ -22928,17 +23030,17 @@ async function printPendingHandovers() {
22928
23030
  }
22929
23031
 
22930
23032
  // src/commands/handover/recallHandover.ts
22931
- import { and as and21, desc as desc5, eq as eq43, isNull as isNull3 } from "drizzle-orm";
23033
+ import { and as and21, desc as desc6, eq as eq44, isNull as isNull3 } from "drizzle-orm";
22932
23034
  async function recallHandover(orm, origin, id) {
22933
23035
  const [row] = await orm.select().from(handovers).where(
22934
23036
  and21(
22935
- eq43(handovers.origin, origin),
23037
+ eq44(handovers.origin, origin),
22936
23038
  isNull3(handovers.recalledAt),
22937
- ...id === void 0 ? [] : [eq43(handovers.id, id)]
23039
+ ...id === void 0 ? [] : [eq44(handovers.id, id)]
22938
23040
  )
22939
- ).orderBy(desc5(handovers.createdAt), desc5(handovers.id)).limit(1);
23041
+ ).orderBy(desc6(handovers.createdAt), desc6(handovers.id)).limit(1);
22940
23042
  if (!row) return void 0;
22941
- await orm.update(handovers).set({ recalledAt: /* @__PURE__ */ new Date() }).where(eq43(handovers.id, row.id));
23043
+ await orm.update(handovers).set({ recalledAt: /* @__PURE__ */ new Date() }).where(eq44(handovers.id, row.id));
22942
23044
  return row.content;
22943
23045
  }
22944
23046
 
@@ -26610,155 +26712,6 @@ async function raise(options2, command) {
26610
26712
  await placePr(existing, title, body, resolved);
26611
26713
  }
26612
26714
 
26613
- // src/commands/prs/readTime.ts
26614
- import { readFileSync as readFileSync45 } from "fs";
26615
-
26616
- // src/commands/prs/countReadingWords.ts
26617
- var FENCE_PATTERN = /^\s*(```|~~~)/;
26618
- var IMAGE_PATTERN = /!\[[^\]]*\]\([^)]*\)/g;
26619
- var HTML_TAG_PATTERN = /<[^\s>][^>]*>/g;
26620
- var URL_PATTERN3 = /https?:\/\/\S+/g;
26621
- var SINGLE_WORD_PATTERNS = [IMAGE_PATTERN, HTML_TAG_PATTERN, URL_PATTERN3];
26622
- function countReadingWords(body) {
26623
- let prose = 0;
26624
- let code = 0;
26625
- let inCode = false;
26626
- for (const line of body.split("\n")) {
26627
- if (FENCE_PATTERN.test(line)) {
26628
- inCode = !inCode;
26629
- } else if (inCode) {
26630
- code += countTokens(line);
26631
- } else {
26632
- prose += countProseWords(line);
26633
- }
26634
- }
26635
- return { prose, code };
26636
- }
26637
- function countProseWords(line) {
26638
- let singles = 0;
26639
- let remaining = line;
26640
- for (const pattern2 of SINGLE_WORD_PATTERNS) {
26641
- remaining = remaining.replace(pattern2, () => {
26642
- singles += 1;
26643
- return " ";
26644
- });
26645
- }
26646
- return singles + countTokens(remaining);
26647
- }
26648
- function countTokens(text18) {
26649
- return text18.split(/\s+/).filter((token) => /[A-Za-z0-9]/.test(token)).length;
26650
- }
26651
-
26652
- // src/commands/prs/formatReadDuration.ts
26653
- function formatReadDuration(seconds) {
26654
- if (seconds < 60) return `${seconds}s`;
26655
- const minutes = Math.floor(seconds / 60);
26656
- const remainder = seconds % 60;
26657
- return remainder === 0 ? `${minutes}m` : `${minutes}m ${remainder}s`;
26658
- }
26659
-
26660
- // src/commands/prs/parseReadBudget.ts
26661
- var BUDGET_PATTERN = /^(?:(\d+)m)?(?:(\d+)s)?$/;
26662
- function parseReadBudget(value) {
26663
- const match = BUDGET_PATTERN.exec(value.trim());
26664
- const minutes = match?.[1];
26665
- const seconds = match?.[2];
26666
- if (minutes === void 0 && seconds === void 0) {
26667
- throw new Error(
26668
- `Invalid budget "${value}". Use a duration like 45s, 1m30s or 2m.`
26669
- );
26670
- }
26671
- const total = Number(minutes ?? 0) * 60 + Number(seconds ?? 0);
26672
- if (total === 0) {
26673
- throw new Error(`Invalid budget "${value}". Value must be at least 1s.`);
26674
- }
26675
- return total;
26676
- }
26677
-
26678
- // src/commands/prs/resolveReadTimeTarget.ts
26679
- var PR_URL_PATTERN = /^(https:\/\/github\.com\/[^/\s]+\/[^/\s]+)\/pull\/(\d+)(?:[/?#].*)?$/;
26680
- function resolveReadTimeTarget(target) {
26681
- const trimmed = target.trim();
26682
- if (trimmed === "-") return { kind: "stdin" };
26683
- if (/^\d+$/.test(trimmed)) {
26684
- return { kind: "pr", number: Number(trimmed), repo: null };
26685
- }
26686
- const url = PR_URL_PATTERN.exec(trimmed);
26687
- if (url) {
26688
- const repo = parseGitHubUrl(url[1]);
26689
- if (repo) return { kind: "pr", number: Number(url[2]), repo };
26690
- }
26691
- return { kind: "file", path: target };
26692
- }
26693
-
26694
- // src/commands/prs/fetchPrBody.ts
26695
- import { execSync as execSync51 } from "child_process";
26696
- function fetchPrBody(number, repo) {
26697
- const { org, repo: name } = repo ?? getRepoInfo();
26698
- try {
26699
- const raw = execSync51(`gh pr view ${number} --json body -R ${org}/${name}`, {
26700
- encoding: "utf8"
26701
- });
26702
- return JSON.parse(raw).body ?? "";
26703
- } catch (error) {
26704
- if (isGhNotInstalled(error)) {
26705
- console.error("Error: GitHub CLI (gh) is not installed.");
26706
- console.error("Install it from https://cli.github.com/");
26707
- process.exit(1);
26708
- }
26709
- if (isNotFound(error)) {
26710
- console.error(`Error: Pull request ${org}/${name}#${number} not found.`);
26711
- process.exit(1);
26712
- }
26713
- throw error;
26714
- }
26715
- }
26716
-
26717
- // src/commands/prs/readTime.ts
26718
- var DEFAULT_WORDS_PER_MINUTE = 80;
26719
- var DEFAULT_BUDGET_SECONDS = 60;
26720
- var CODE_WORDS_PER_PROSE_WORD = 2;
26721
- async function readTime(target, options2 = {}) {
26722
- const budgetSeconds = resolveBudget(options2.budget);
26723
- const body = await loadBody(resolveReadTimeTarget(target));
26724
- const { prose, code } = countReadingWords(body);
26725
- const words = prose + code;
26726
- const wordsPerMinute = loadConfig().prs?.readingWordsPerMinute ?? DEFAULT_WORDS_PER_MINUTE;
26727
- const seconds = Math.round(
26728
- (prose + code * CODE_WORDS_PER_PROSE_WORD) / wordsPerMinute * 60
26729
- );
26730
- const label2 = words === 1 ? "word" : "words";
26731
- const verdict = seconds > budgetSeconds ? ` \xB7 over the ~${formatReadDuration(budgetSeconds)} budget` : "";
26732
- console.log(
26733
- `${words} ${label2} \xB7 ~${formatReadDuration(seconds)} read${verdict}`
26734
- );
26735
- }
26736
- function resolveBudget(budget) {
26737
- if (budget === void 0) return DEFAULT_BUDGET_SECONDS;
26738
- try {
26739
- return parseReadBudget(budget);
26740
- } catch (error) {
26741
- console.error(`Error: ${error.message}`);
26742
- process.exit(1);
26743
- }
26744
- }
26745
- async function loadBody(target) {
26746
- if (target.kind === "stdin") return readBodyArgument("-");
26747
- if (target.kind === "file") return readDraftFile(target.path);
26748
- return fetchPrBody(target.number, target.repo);
26749
- }
26750
- function readDraftFile(path90) {
26751
- try {
26752
- return readFileSync45(path90, "utf8");
26753
- } catch {
26754
- console.error(`Error: Could not read \`${path90}\`.`);
26755
- console.error(
26756
- "Pass a pull request number, a GitHub pull request URL, - for stdin, or a path to a file."
26757
- );
26758
- process.exit(1);
26759
- }
26760
- }
26761
-
26762
26715
  // src/commands/prs/reply.ts
26763
26716
  function validateBody2(body) {
26764
26717
  const lowerBody = body.toLowerCase();
@@ -26786,7 +26739,7 @@ async function reply(commentId, body) {
26786
26739
  }
26787
26740
 
26788
26741
  // src/commands/prs/wontfix.ts
26789
- import { execSync as execSync52 } from "child_process";
26742
+ import { execSync as execSync51 } from "child_process";
26790
26743
  function validateReason(reason4) {
26791
26744
  const lowerReason = reason4.toLowerCase();
26792
26745
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -26803,7 +26756,7 @@ function validateShaReferences(reason4) {
26803
26756
  const invalidShas = [];
26804
26757
  for (const sha of shas) {
26805
26758
  try {
26806
- execSync52(`git cat-file -t ${sha}`, { stdio: "pipe" });
26759
+ execSync51(`git cat-file -t ${sha}`, { stdio: "pipe" });
26807
26760
  } catch {
26808
26761
  invalidShas.push(sha);
26809
26762
  }
@@ -27070,17 +27023,189 @@ function registerPrsRaise(prsCommand) {
27070
27023
  configHelp(raiseCommand, prsRaiseConfigHelp);
27071
27024
  }
27072
27025
 
27073
- // src/commands/registerPrsReadTime.ts
27074
- function registerPrsReadTime(prsCommand) {
27075
- const readTimeCommand = prsCommand.command("read-time <target>").description(
27076
- "Estimate how long a pull request description takes to read (target is a PR number, a GitHub PR URL, - for stdin, or a file path)"
27026
+ // src/commands/readTime/readTime.ts
27027
+ import { readFileSync as readFileSync45 } from "fs";
27028
+
27029
+ // src/commands/readTime/countReadingWords.ts
27030
+ var FENCE_PATTERN = /^\s*(```|~~~)/;
27031
+ var IMAGE_PATTERN = /!\[[^\]]*\]\([^)]*\)/g;
27032
+ var HTML_TAG_PATTERN = /<[^\s>][^>]*>/g;
27033
+ var URL_PATTERN3 = /https?:\/\/\S+/g;
27034
+ var SINGLE_WORD_PATTERNS = [IMAGE_PATTERN, HTML_TAG_PATTERN, URL_PATTERN3];
27035
+ function countReadingWords(body) {
27036
+ let prose = 0;
27037
+ let code = 0;
27038
+ let inCode = false;
27039
+ for (const line of body.split("\n")) {
27040
+ if (FENCE_PATTERN.test(line)) {
27041
+ inCode = !inCode;
27042
+ } else if (inCode) {
27043
+ code += countTokens(line);
27044
+ } else {
27045
+ prose += countProseWords(line);
27046
+ }
27047
+ }
27048
+ return { prose, code };
27049
+ }
27050
+ function countProseWords(line) {
27051
+ let singles = 0;
27052
+ let remaining = line;
27053
+ for (const pattern2 of SINGLE_WORD_PATTERNS) {
27054
+ remaining = remaining.replace(pattern2, () => {
27055
+ singles += 1;
27056
+ return " ";
27057
+ });
27058
+ }
27059
+ return singles + countTokens(remaining);
27060
+ }
27061
+ function countTokens(text18) {
27062
+ return text18.split(/\s+/).filter((token) => /[A-Za-z0-9]/.test(token)).length;
27063
+ }
27064
+
27065
+ // src/commands/readTime/estimateReadSeconds.ts
27066
+ var LENGTH_DECAY_FITTED_TO_TIMED_PR_READINGS = 0.17;
27067
+ function estimateReadSeconds(words, wordsPerMinute) {
27068
+ const load3 = words ** (1 + LENGTH_DECAY_FITTED_TO_TIMED_PR_READINGS);
27069
+ return Math.round(load3 / wordsPerMinute * 60);
27070
+ }
27071
+
27072
+ // src/commands/readTime/formatReadDuration.ts
27073
+ function formatReadDuration(seconds) {
27074
+ if (seconds < 60) return `${seconds}s`;
27075
+ const minutes = Math.floor(seconds / 60);
27076
+ const remainder = seconds % 60;
27077
+ return remainder === 0 ? `${minutes}m` : `${minutes}m ${remainder}s`;
27078
+ }
27079
+
27080
+ // src/commands/readTime/parseReadBudget.ts
27081
+ var BUDGET_PATTERN = /^(?:(\d+)m)?(?:(\d+)s)?$/;
27082
+ function parseReadBudget(value) {
27083
+ const match = BUDGET_PATTERN.exec(value.trim());
27084
+ const minutes = match?.[1];
27085
+ const seconds = match?.[2];
27086
+ if (minutes === void 0 && seconds === void 0) {
27087
+ throw new Error(
27088
+ `Invalid budget "${value}". Use a duration like 45s, 1m30s or 2m.`
27089
+ );
27090
+ }
27091
+ const total = Number(minutes ?? 0) * 60 + Number(seconds ?? 0);
27092
+ if (total === 0) {
27093
+ throw new Error(`Invalid budget "${value}". Value must be at least 1s.`);
27094
+ }
27095
+ return total;
27096
+ }
27097
+
27098
+ // src/commands/readTime/resolveReadTimeTarget.ts
27099
+ var PR_URL_PATTERN = /^(https:\/\/github\.com\/[^/\s]+\/[^/\s]+)\/pull\/(\d+)(?:[/?#].*)?$/;
27100
+ function resolveReadTimeTarget(target) {
27101
+ const trimmed = target.trim();
27102
+ if (trimmed === "-") return { kind: "stdin" };
27103
+ if (/^\d+$/.test(trimmed)) {
27104
+ return { kind: "pr", number: Number(trimmed), repo: null };
27105
+ }
27106
+ const url = PR_URL_PATTERN.exec(trimmed);
27107
+ if (url) {
27108
+ const repo = parseGitHubUrl(url[1]);
27109
+ if (repo) return { kind: "pr", number: Number(url[2]), repo };
27110
+ }
27111
+ return { kind: "file", path: target };
27112
+ }
27113
+
27114
+ // src/commands/prs/fetchPrBody.ts
27115
+ import { execSync as execSync52 } from "child_process";
27116
+ function exitGhNotInstalled() {
27117
+ console.error("Error: GitHub CLI (gh) is not installed.");
27118
+ console.error("Install it from https://cli.github.com/");
27119
+ process.exit(1);
27120
+ }
27121
+ function currentRepo() {
27122
+ try {
27123
+ return getRepoInfo();
27124
+ } catch (error) {
27125
+ if (isGhNotInstalled(error)) exitGhNotInstalled();
27126
+ console.error("Error: Could not resolve the current GitHub repository.");
27127
+ console.error(
27128
+ "Pass a pull request URL, - for stdin, or a path to a file instead of a number."
27129
+ );
27130
+ process.exit(1);
27131
+ }
27132
+ }
27133
+ function fetchPrBody(number, repo) {
27134
+ const { org, repo: name } = repo ?? currentRepo();
27135
+ try {
27136
+ const raw = execSync52(`gh pr view ${number} --json body -R ${org}/${name}`, {
27137
+ encoding: "utf8",
27138
+ stdio: ["pipe", "pipe", "pipe"]
27139
+ });
27140
+ return JSON.parse(raw).body ?? "";
27141
+ } catch (error) {
27142
+ if (isGhNotInstalled(error)) exitGhNotInstalled();
27143
+ if (isNotFound(error)) {
27144
+ console.error(`Error: Pull request ${org}/${name}#${number} not found.`);
27145
+ process.exit(1);
27146
+ }
27147
+ throw error;
27148
+ }
27149
+ }
27150
+
27151
+ // src/commands/readTime/readTime.ts
27152
+ var DEFAULT_WORDS_PER_MINUTE = 200;
27153
+ var DEFAULT_BUDGET_SECONDS = 60;
27154
+ var CODE_WORDS_PER_PROSE_WORD = 2;
27155
+ async function readTime(target, options2 = {}) {
27156
+ const budgetSeconds = resolveBudget(options2.budget);
27157
+ const body = await loadBody(resolveReadTimeTarget(target));
27158
+ const { prose, code } = countReadingWords(body);
27159
+ const words = prose + code;
27160
+ const config = loadConfig();
27161
+ const wordsPerMinute = config.readTime?.wordsPerMinute ?? config.prs?.readingWordsPerMinute ?? DEFAULT_WORDS_PER_MINUTE;
27162
+ const seconds = estimateReadSeconds(
27163
+ prose + code * CODE_WORDS_PER_PROSE_WORD,
27164
+ wordsPerMinute
27165
+ );
27166
+ const label2 = words === 1 ? "word" : "words";
27167
+ const verdict = seconds > budgetSeconds ? ` \xB7 over the ~${formatReadDuration(budgetSeconds)} budget` : "";
27168
+ console.log(
27169
+ `${words} ${label2} \xB7 ~${formatReadDuration(seconds)} read${verdict}`
27170
+ );
27171
+ }
27172
+ function resolveBudget(budget) {
27173
+ if (budget === void 0) return DEFAULT_BUDGET_SECONDS;
27174
+ try {
27175
+ return parseReadBudget(budget);
27176
+ } catch (error) {
27177
+ console.error(`Error: ${error.message}`);
27178
+ process.exit(1);
27179
+ }
27180
+ }
27181
+ async function loadBody(target) {
27182
+ if (target.kind === "stdin") return readBodyArgument("-");
27183
+ if (target.kind === "file") return readDraftFile(target.path);
27184
+ return fetchPrBody(target.number, target.repo);
27185
+ }
27186
+ function readDraftFile(path90) {
27187
+ try {
27188
+ return readFileSync45(path90, "utf8");
27189
+ } catch {
27190
+ console.error(`Error: Could not read \`${path90}\`.`);
27191
+ console.error(
27192
+ "Pass a pull request number, a GitHub pull request URL, - for stdin, or a path to a file."
27193
+ );
27194
+ process.exit(1);
27195
+ }
27196
+ }
27197
+
27198
+ // src/commands/registerReadTime.ts
27199
+ function registerReadTime(parent) {
27200
+ const readTimeCommand = parent.command("read-time <target>").description(
27201
+ "Estimate how long a document takes to read (target is a pull request number, a GitHub pull request URL, - for stdin, or a file path)"
27077
27202
  ).option(
27078
27203
  "--budget <duration>",
27079
27204
  "read-time budget the estimate is judged against, e.g. 45s, 1m30s, 2m (default 1m)"
27080
27205
  ).action(async (target, options2) => {
27081
27206
  await readTime(target, options2);
27082
27207
  });
27083
- configHelp(readTimeCommand, prsReadTimeConfigHelp);
27208
+ configHelp(readTimeCommand, readTimeConfigHelp);
27084
27209
  }
27085
27210
 
27086
27211
  // src/commands/registerPrs.ts
@@ -27089,7 +27214,7 @@ function registerPrs(program2) {
27089
27214
  registerPrsRaise(prsCommand);
27090
27215
  registerPrsEdit(prsCommand);
27091
27216
  registerPrsComments(prsCommand);
27092
- registerPrsReadTime(prsCommand);
27217
+ registerReadTime(prsCommand);
27093
27218
  configHelp(prsCommand, prsConfigHelp);
27094
27219
  }
27095
27220
 
@@ -31435,8 +31560,8 @@ function filterToSql(filter) {
31435
31560
  // src/commands/seq/fetchSeqData.ts
31436
31561
  function buildDataParams(filter, count8, from, to) {
31437
31562
  const sqlFilter = filterToSql(filter);
31438
- const sql25 = `select @Timestamp, @Level, @Exception, @Message from stream where ${sqlFilter} order by @Timestamp desc limit ${count8}`;
31439
- const params = new URLSearchParams({ q: sql25 });
31563
+ const sql28 = `select @Timestamp, @Level, @Exception, @Message from stream where ${sqlFilter} order by @Timestamp desc limit ${count8}`;
31564
+ const params = new URLSearchParams({ q: sql28 });
31440
31565
  if (from) params.set("rangeStartUtc", from);
31441
31566
  if (to) params.set("rangeEndUtc", to);
31442
31567
  return params;
@@ -31797,26 +31922,26 @@ import chalk222 from "chalk";
31797
31922
  // src/commands/sql/loadConnections.ts
31798
31923
  function loadConnections3() {
31799
31924
  const raw = loadGlobalConfigRaw();
31800
- const sql25 = raw.sql;
31801
- return sql25?.connections ?? [];
31925
+ const sql28 = raw.sql;
31926
+ return sql28?.connections ?? [];
31802
31927
  }
31803
31928
  function saveConnections3(connections) {
31804
31929
  const raw = loadGlobalConfigRaw();
31805
- const sql25 = raw.sql ?? {};
31806
- sql25.connections = connections;
31807
- raw.sql = sql25;
31930
+ const sql28 = raw.sql ?? {};
31931
+ sql28.connections = connections;
31932
+ raw.sql = sql28;
31808
31933
  saveGlobalConfig(raw);
31809
31934
  }
31810
31935
  function getDefaultConnection2() {
31811
31936
  const raw = loadGlobalConfigRaw();
31812
- const sql25 = raw.sql;
31813
- return sql25?.defaultConnection;
31937
+ const sql28 = raw.sql;
31938
+ return sql28?.defaultConnection;
31814
31939
  }
31815
31940
  function setDefaultConnection2(name) {
31816
31941
  const raw = loadGlobalConfigRaw();
31817
- const sql25 = raw.sql ?? {};
31818
- sql25.defaultConnection = name;
31819
- raw.sql = sql25;
31942
+ const sql28 = raw.sql ?? {};
31943
+ sql28.defaultConnection = name;
31944
+ raw.sql = sql28;
31820
31945
  saveGlobalConfig(raw);
31821
31946
  }
31822
31947
 
@@ -31887,9 +32012,9 @@ function resolveConnection3(name) {
31887
32012
  }
31888
32013
 
31889
32014
  // src/commands/sql/sqlConnect.ts
31890
- import sql19 from "mssql";
32015
+ import sql22 from "mssql";
31891
32016
  async function sqlConnect(conn) {
31892
- return await sql19.connect({
32017
+ return await sql22.connect({
31893
32018
  server: conn.server,
31894
32019
  port: conn.port,
31895
32020
  user: conn.user,
@@ -31952,11 +32077,11 @@ var MUTATION_PATTERN = new RegExp(
31952
32077
  `\\b(${MUTATION_KEYWORDS.join("|")})\\b`,
31953
32078
  "i"
31954
32079
  );
31955
- function stripComments(sql25) {
31956
- return sql25.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*/g, " ");
32080
+ function stripComments(sql28) {
32081
+ return sql28.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\n]*/g, " ");
31957
32082
  }
31958
- function isMutation(sql25) {
31959
- const stripped = stripComments(sql25);
32083
+ function isMutation(sql28) {
32084
+ const stripped = stripComments(sql28);
31960
32085
  if (MUTATION_PATTERN.test(stripped)) return true;
31961
32086
  return /\bSELECT\b[\s\S]+\bINTO\s+\w/i.test(stripped);
31962
32087
  }
@@ -35970,13 +36095,13 @@ function drainSessions(sessions, notify2) {
35970
36095
  }
35971
36096
 
35972
36097
  // src/shared/db/recordPhaseActiveMs.ts
35973
- import { sql as sql20 } from "drizzle-orm";
36098
+ import { sql as sql23 } from "drizzle-orm";
35974
36099
  async function recordPhaseActiveMs(db, itemId2, phaseIdx, activeMs) {
35975
36100
  if (activeMs <= 0) return;
35976
36101
  await db.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, activeMs }).onConflictDoUpdate({
35977
36102
  target: [phaseUsage.itemId, phaseUsage.phaseIdx],
35978
36103
  set: {
35979
- activeMs: sql20`${phaseUsage.activeMs} + excluded.active_ms`
36104
+ activeMs: sql23`${phaseUsage.activeMs} + excluded.active_ms`
35980
36105
  }
35981
36106
  });
35982
36107
  }
@@ -36414,10 +36539,10 @@ function applyReviewPause(session, activity2) {
36414
36539
  }
36415
36540
 
36416
36541
  // src/shared/db/getPhaseActiveMs.ts
36417
- import { and as and22, eq as eq44 } from "drizzle-orm";
36542
+ import { and as and22, eq as eq45 } from "drizzle-orm";
36418
36543
  async function getPhaseActiveMs(db, itemId2, phaseIdx) {
36419
36544
  const [row] = await db.select({ activeMs: phaseUsage.activeMs }).from(phaseUsage).where(
36420
- and22(eq44(phaseUsage.itemId, itemId2), eq44(phaseUsage.phaseIdx, phaseIdx))
36545
+ and22(eq45(phaseUsage.itemId, itemId2), eq45(phaseUsage.phaseIdx, phaseIdx))
36421
36546
  );
36422
36547
  return row?.activeMs ?? 0;
36423
36548
  }
@@ -37186,7 +37311,7 @@ function makeSessionSpawner(sessions, clients, counter, onStatusChange, notify2)
37186
37311
  }
37187
37312
 
37188
37313
  // src/shared/db/recordPhaseCycleContext.ts
37189
- import { sql as sql21 } from "drizzle-orm";
37314
+ import { sql as sql24 } from "drizzle-orm";
37190
37315
  async function recordPhaseCycleContext(db, itemId2, phaseIdx, window, resetsAt, pct) {
37191
37316
  if (pct <= 0) return;
37192
37317
  await db.insert(phaseCycleContext).values({ itemId: itemId2, phaseIdx, window, resetsAt, peakContextPct: pct }).onConflictDoUpdate({
@@ -37197,24 +37322,24 @@ async function recordPhaseCycleContext(db, itemId2, phaseIdx, window, resetsAt,
37197
37322
  phaseCycleContext.resetsAt
37198
37323
  ],
37199
37324
  set: {
37200
- peakContextPct: sql21`GREATEST(${phaseCycleContext.peakContextPct}, ${pct})`
37325
+ peakContextPct: sql24`GREATEST(${phaseCycleContext.peakContextPct}, ${pct})`
37201
37326
  }
37202
37327
  });
37203
37328
  }
37204
37329
 
37205
37330
  // src/shared/db/recordPhasePeakContext.ts
37206
- import { sql as sql22 } from "drizzle-orm";
37331
+ import { sql as sql25 } from "drizzle-orm";
37207
37332
  async function recordPhasePeakContext(db, itemId2, phaseIdx, pct) {
37208
37333
  await db.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, peakContextPct: pct }).onConflictDoUpdate({
37209
37334
  target: [phaseUsage.itemId, phaseUsage.phaseIdx],
37210
37335
  set: {
37211
- peakContextPct: sql22`GREATEST(${phaseUsage.peakContextPct}, ${pct})`
37336
+ peakContextPct: sql25`GREATEST(${phaseUsage.peakContextPct}, ${pct})`
37212
37337
  }
37213
37338
  });
37214
37339
  }
37215
37340
 
37216
37341
  // src/shared/db/recordPhaseTranscriptUsage.ts
37217
- import { sql as sql23 } from "drizzle-orm";
37342
+ import { sql as sql26 } from "drizzle-orm";
37218
37343
  async function recordPhaseTranscriptUsage(db, itemId2, phaseIdx, responses) {
37219
37344
  const byId = /* @__PURE__ */ new Map();
37220
37345
  for (const r of responses) byId.set(r.messageId, r);
@@ -37234,8 +37359,8 @@ async function recordPhaseTranscriptUsage(db, itemId2, phaseIdx, responses) {
37234
37359
  await tx.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, tokensUp, tokensDown }).onConflictDoUpdate({
37235
37360
  target: [phaseUsage.itemId, phaseUsage.phaseIdx],
37236
37361
  set: {
37237
- tokensUp: sql23`${phaseUsage.tokensUp} + ${tokensUp}`,
37238
- tokensDown: sql23`${phaseUsage.tokensDown} + ${tokensDown}`
37362
+ tokensUp: sql26`${phaseUsage.tokensUp} + ${tokensUp}`,
37363
+ tokensDown: sql26`${phaseUsage.tokensDown} + ${tokensDown}`
37239
37364
  }
37240
37365
  });
37241
37366
  return { tokensUp, tokensDown };
@@ -37243,17 +37368,17 @@ async function recordPhaseTranscriptUsage(db, itemId2, phaseIdx, responses) {
37243
37368
  }
37244
37369
 
37245
37370
  // src/shared/db/recordWindowTokens.ts
37246
- import { and as and23, eq as eq45, sql as sql24 } from "drizzle-orm";
37371
+ import { and as and23, eq as eq46, sql as sql27 } from "drizzle-orm";
37247
37372
  async function recordWindowTokens(db, window, resetsAt, tokensUp, tokensDown) {
37248
37373
  if (tokensUp <= 0 && tokensDown <= 0) return;
37249
37374
  await db.update(usagePeaks).set({
37250
- tokensUp: sql24`${usagePeaks.tokensUp} + ${tokensUp}`,
37251
- tokensDown: sql24`${usagePeaks.tokensDown} + ${tokensDown}`
37375
+ tokensUp: sql27`${usagePeaks.tokensUp} + ${tokensUp}`,
37376
+ tokensDown: sql27`${usagePeaks.tokensDown} + ${tokensDown}`
37252
37377
  }).where(
37253
37378
  and23(
37254
- eq45(usagePeaks.window, window),
37255
- eq45(usagePeaks.resetsAt, resetsAt),
37256
- eq45(usagePeaks.segment, 0)
37379
+ eq46(usagePeaks.window, window),
37380
+ eq46(usagePeaks.resetsAt, resetsAt),
37381
+ eq46(usagePeaks.segment, 0)
37257
37382
  )
37258
37383
  );
37259
37384
  }
@@ -41209,6 +41334,7 @@ registerJira(program);
41209
41334
  registerMermaid(program);
41210
41335
  registerMiro(program);
41211
41336
  registerPrs(program);
41337
+ registerReadTime(program);
41212
41338
  registerRoam(program);
41213
41339
  registerBacklog(program);
41214
41340
  registerBranch(program);