@staff0rd/assist 0.372.0 → 0.374.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.372.0",
9
+ version: "0.374.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -27,7 +27,15 @@ var package_default = {
27
27
  build: "tsup",
28
28
  start: "node dist/index.js",
29
29
  "check:types": "tsc --noEmit",
30
- test: "vitest run"
30
+ test: "vitest run",
31
+ "verify:lint": "oxlint --config .oxlintrc.json src",
32
+ "verify:format": "oxfmt .",
33
+ "verify:knip": "knip --no-progress --treat-config-hints-as-errors",
34
+ "verify:duplicate-code": 'jscpd --format typescript,tsx,python --exitCode 1 --ignore "**/*.test.*,**/.venv/**" -r consoleFull src',
35
+ "verify:test": "vitest run --changed --passWithNoTests --reporter dot",
36
+ "verify:config-keys": "tsx src/index.ts verify config-keys",
37
+ "verify:react-build": "esbuild src/commands/sessions/web/ui/App.tsx --bundle --minify --format=iife --target=es2020 --outfile=dist/commands/sessions/web/bundle.verify.js --jsx=automatic --jsx-import-source=react --define:process.env.NODE_ENV='production'",
38
+ "verify:circular-deps": "skott --displayMode=raw --showCircularDependencies --exitCodeOnCircularDependencies=1 src/index.ts"
31
39
  },
32
40
  overrides: {
33
41
  lodash: "^4.18.0",
@@ -107,7 +115,9 @@ var package_default = {
107
115
  "react-dom": "^19.2.4",
108
116
  "react-router": "^7.14.0",
109
117
  "semantic-release": "^25.0.2",
118
+ skott: "^0.35.11",
110
119
  tsup: "^8.5.1",
120
+ tsx: "^4.23.0",
111
121
  vitest: "^4.0.18"
112
122
  }
113
123
  };
@@ -120,8 +130,8 @@ var ITEM_ID_ENV = "ASSIST_BACKLOG_ITEM_ID";
120
130
  function resolveSessionItemId() {
121
131
  const raw = process.env[ITEM_ID_ENV];
122
132
  if (!raw) return null;
123
- const id2 = Number.parseInt(raw, 10);
124
- return Number.isInteger(id2) && id2 > 0 ? id2 : null;
133
+ const id = Number.parseInt(raw, 10);
134
+ return Number.isInteger(id) && id > 0 ? id : null;
125
135
  }
126
136
 
127
137
  // src/shared/db/getDb.ts
@@ -1005,9 +1015,9 @@ async function closeDb() {
1005
1015
  }
1006
1016
 
1007
1017
  // src/shared/db/recordGitRef.ts
1008
- async function recordGitRef(db, itemId, ref) {
1018
+ async function recordGitRef(db, itemId2, ref) {
1009
1019
  await db.insert(itemGitRefs).values({
1010
- itemId,
1020
+ itemId: itemId2,
1011
1021
  kind: ref.kind,
1012
1022
  ref: ref.ref,
1013
1023
  title: ref.title ?? null,
@@ -1025,15 +1035,15 @@ async function recordGitRef(db, itemId, ref) {
1025
1035
 
1026
1036
  // src/shared/db/recordSessionRefs.ts
1027
1037
  async function recordSessionRefs(refs) {
1028
- const itemId = resolveSessionItemId();
1029
- if (itemId === null || refs.length === 0) return;
1030
- await persist(itemId, refs).catch(ignore);
1038
+ const itemId2 = resolveSessionItemId();
1039
+ if (itemId2 === null || refs.length === 0) return;
1040
+ await persist(itemId2, refs).catch(ignore);
1031
1041
  await closeDb().catch(ignore);
1032
1042
  }
1033
- async function persist(itemId, refs) {
1043
+ async function persist(itemId2, refs) {
1034
1044
  const db = await getDb();
1035
1045
  for (const ref of refs) {
1036
- await recordGitRef(db, itemId, ref);
1046
+ await recordGitRef(db, itemId2, ref);
1037
1047
  }
1038
1048
  }
1039
1049
  function ignore() {
@@ -2583,7 +2593,7 @@ function collectHashComments(content, options2) {
2583
2593
  function collectComments(sourceFile) {
2584
2594
  const seen = /* @__PURE__ */ new Set();
2585
2595
  const comments3 = [];
2586
- const collect5 = (node) => {
2596
+ const collect6 = (node) => {
2587
2597
  for (const range of [
2588
2598
  ...node.getLeadingCommentRanges(),
2589
2599
  ...node.getTrailingCommentRanges()
@@ -2594,8 +2604,8 @@ function collectComments(sourceFile) {
2594
2604
  comments3.push({ pos, text: range.getText() });
2595
2605
  }
2596
2606
  };
2597
- collect5(sourceFile);
2598
- sourceFile.forEachDescendant(collect5);
2607
+ collect6(sourceFile);
2608
+ sourceFile.forEachDescendant(collect6);
2599
2609
  return comments3;
2600
2610
  }
2601
2611
 
@@ -2780,6 +2790,104 @@ Total: ${findings.length} comment(s)`);
2780
2790
  process.exit(1);
2781
2791
  }
2782
2792
 
2793
+ // src/shared/configHelp.ts
2794
+ var documentedKeys = /* @__PURE__ */ new Set();
2795
+ function getDocumentedConfigKeys() {
2796
+ return documentedKeys;
2797
+ }
2798
+ function renderConfigHelp(entries, preamble) {
2799
+ const width = Math.max(...entries.map((entry) => entry.setter.length));
2800
+ const lines = entries.map(
2801
+ (entry) => ` ${entry.setter.padEnd(width)} # ${entry.note}`
2802
+ );
2803
+ const body = preamble ? ["", preamble, "", "Config:", ...lines] : ["", "Config:", ...lines];
2804
+ return body.join("\n");
2805
+ }
2806
+ function configHelp(command, entries, preamble) {
2807
+ for (const entry of entries) documentedKeys.add(entry.key);
2808
+ return command.addHelpText(
2809
+ "after",
2810
+ () => renderConfigHelp(entries, preamble)
2811
+ );
2812
+ }
2813
+
2814
+ // src/shared/enumerateConfigLeafKeys.ts
2815
+ var WRAPPER_TYPES = /* @__PURE__ */ new Set([
2816
+ "optional",
2817
+ "default",
2818
+ "nullable",
2819
+ "nullish",
2820
+ "readonly",
2821
+ "catch"
2822
+ ]);
2823
+ function unwrap(node) {
2824
+ let current = node;
2825
+ while (current.def && WRAPPER_TYPES.has(current.def.type ?? "") && current.def.innerType) {
2826
+ current = current.def.innerType;
2827
+ }
2828
+ return current;
2829
+ }
2830
+ function collect(node, prefix2, out) {
2831
+ const unwrapped = unwrap(node);
2832
+ const shape = unwrapped.def?.shape;
2833
+ if (unwrapped.def?.type === "object" && shape) {
2834
+ for (const [key, child] of Object.entries(shape)) {
2835
+ collect(child, prefix2 ? `${prefix2}.${key}` : key, out);
2836
+ }
2837
+ return;
2838
+ }
2839
+ out.push(prefix2);
2840
+ }
2841
+ function enumerateConfigLeafKeys(schema2) {
2842
+ const out = [];
2843
+ collect(schema2, "", out);
2844
+ return out.sort();
2845
+ }
2846
+
2847
+ // src/commands/verify/pendingConfigDocumentation.ts
2848
+ var pendingConfigDocumentation = /* @__PURE__ */ new Set();
2849
+
2850
+ // src/commands/verify/configKeys.ts
2851
+ function section(label2, keys) {
2852
+ if (keys.length === 0) return void 0;
2853
+ const list5 = keys.sort().map((key) => ` ${key}`).join("\n");
2854
+ return `${label2}:
2855
+ ${list5}`;
2856
+ }
2857
+ function configKeys() {
2858
+ const schemaKeys = new Set(enumerateConfigLeafKeys(assistConfigSchema));
2859
+ const documented = getDocumentedConfigKeys();
2860
+ const pending = pendingConfigDocumentation;
2861
+ const problems = [
2862
+ section(
2863
+ "Config keys documented by no command (surface them with configHelp)",
2864
+ [...schemaKeys].filter(
2865
+ (key) => !documented.has(key) && !pending.has(key)
2866
+ )
2867
+ ),
2868
+ section(
2869
+ "Documented config keys not present in assistConfigSchema",
2870
+ [...documented].filter((key) => !schemaKeys.has(key))
2871
+ ),
2872
+ section(
2873
+ "Keys now documented but still in pendingConfigDocumentation (remove them)",
2874
+ [...pending].filter((key) => documented.has(key))
2875
+ ),
2876
+ section(
2877
+ "pendingConfigDocumentation lists keys not in assistConfigSchema (remove them)",
2878
+ [...pending].filter((key) => !schemaKeys.has(key))
2879
+ )
2880
+ ].filter((problem) => problem !== void 0);
2881
+ if (problems.length > 0) {
2882
+ console.log(problems.join("\n\n"));
2883
+ process.exit(1);
2884
+ }
2885
+ console.log(
2886
+ `All ${schemaKeys.size} config keys are surfaced in --help or pending documentation.`
2887
+ );
2888
+ process.exit(0);
2889
+ }
2890
+
2783
2891
  // src/commands/verify/forbiddenStrings/index.ts
2784
2892
  import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
2785
2893
 
@@ -4082,6 +4190,13 @@ function registerBackup(program2) {
4082
4190
  scheduleCommand.command("remove").description(
4083
4191
  "Remove the marked backup schedule block, leaving other crontab lines intact"
4084
4192
  ).action(scheduleRemove);
4193
+ configHelp(backupCommand, [
4194
+ {
4195
+ key: "backup.dir",
4196
+ setter: "assist config set backup.dir ~/.assist/backups",
4197
+ note: "directory dumps are written to (default: ~/.assist/backups)"
4198
+ }
4199
+ ]);
4085
4200
  }
4086
4201
 
4087
4202
  // src/commands/backlog/next.ts
@@ -4120,6 +4235,24 @@ function hasLocalChanges() {
4120
4235
  }
4121
4236
  }
4122
4237
 
4238
+ // src/commands/backlog/formatItemId.ts
4239
+ var InvalidItemIdError = class extends Error {
4240
+ name = "InvalidItemIdError";
4241
+ };
4242
+ function formatItemId(id) {
4243
+ return `a${id}`;
4244
+ }
4245
+ var itemIdPattern = /^a?(\d+)$/;
4246
+ function parseItemId(input) {
4247
+ const match = itemIdPattern.exec(input.trim());
4248
+ if (!match) {
4249
+ throw new InvalidItemIdError(
4250
+ `Invalid backlog item id "${input}" (e.g. a574 or 574).`
4251
+ );
4252
+ }
4253
+ return Number.parseInt(match[1], 10);
4254
+ }
4255
+
4123
4256
  // src/commands/backlog/acquireLock.ts
4124
4257
  import {
4125
4258
  existsSync as existsSync16,
@@ -4133,8 +4266,8 @@ import { join as join12 } from "path";
4133
4266
  function getLocksDir() {
4134
4267
  return join12(homedir4(), ".assist", "locks");
4135
4268
  }
4136
- function getLockPath(itemId) {
4137
- return join12(getLocksDir(), `lock-${itemId}.json`);
4269
+ function getLockPath(itemId2) {
4270
+ return join12(getLocksDir(), `lock-${itemId2}.json`);
4138
4271
  }
4139
4272
  function isProcessAlive(pid) {
4140
4273
  try {
@@ -4144,8 +4277,8 @@ function isProcessAlive(pid) {
4144
4277
  return false;
4145
4278
  }
4146
4279
  }
4147
- function isLockedByOther(itemId) {
4148
- const lockPath = getLockPath(itemId);
4280
+ function isLockedByOther(itemId2) {
4281
+ const lockPath = getLockPath(itemId2);
4149
4282
  if (!existsSync16(lockPath)) return false;
4150
4283
  try {
4151
4284
  const lock2 = JSON.parse(readFileSync12(lockPath, "utf8"));
@@ -4155,15 +4288,15 @@ function isLockedByOther(itemId) {
4155
4288
  return false;
4156
4289
  }
4157
4290
  }
4158
- function acquireLock(itemId) {
4291
+ function acquireLock(itemId2) {
4159
4292
  mkdirSync4(getLocksDir(), { recursive: true });
4160
4293
  writeFileSync14(
4161
- getLockPath(itemId),
4294
+ getLockPath(itemId2),
4162
4295
  JSON.stringify({ pid: process.pid, timestamp: (/* @__PURE__ */ new Date()).toISOString() })
4163
4296
  );
4164
4297
  }
4165
- function releaseLock(itemId) {
4166
- const lockPath = getLockPath(itemId);
4298
+ function releaseLock(itemId2) {
4299
+ const lockPath = getLockPath(itemId2);
4167
4300
  try {
4168
4301
  unlinkSync2(lockPath);
4169
4302
  } catch {
@@ -4366,27 +4499,27 @@ import { join as join14 } from "path";
4366
4499
  function getControlsDir() {
4367
4500
  return join14(homedir6(), ".assist", "controls");
4368
4501
  }
4369
- function getPausePath(itemId) {
4370
- return join14(getControlsDir(), `pause-${itemId}.json`);
4502
+ function getPausePath(itemId2) {
4503
+ return join14(getControlsDir(), `pause-${itemId2}.json`);
4371
4504
  }
4372
- function requestPause(itemId) {
4505
+ function requestPause(itemId2) {
4373
4506
  mkdirSync6(getControlsDir(), { recursive: true });
4374
4507
  writeFileSync16(
4375
- getPausePath(itemId),
4508
+ getPausePath(itemId2),
4376
4509
  JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString() })
4377
4510
  );
4378
4511
  }
4379
- function isPausePending(itemId) {
4380
- return existsSync17(getPausePath(itemId));
4512
+ function isPausePending(itemId2) {
4513
+ return existsSync17(getPausePath(itemId2));
4381
4514
  }
4382
- function clearPause(itemId) {
4515
+ function clearPause(itemId2) {
4383
4516
  try {
4384
- unlinkSync3(getPausePath(itemId));
4517
+ unlinkSync3(getPausePath(itemId2));
4385
4518
  } catch {
4386
4519
  }
4387
4520
  }
4388
- function consumePause(itemId) {
4389
- const pausePath = getPausePath(itemId);
4521
+ function consumePause(itemId2) {
4522
+ const pausePath = getPausePath(itemId2);
4390
4523
  if (!existsSync17(pausePath)) return false;
4391
4524
  try {
4392
4525
  unlinkSync3(pausePath);
@@ -4716,8 +4849,8 @@ function rowToGitRef(r) {
4716
4849
  if (r.createdAt != null) ref.createdAt = new Date(r.createdAt).toISOString();
4717
4850
  return ref;
4718
4851
  }
4719
- function attachGitRefs(item, rel, id2) {
4720
- const gitRefs = (rel.gitRefs.get(id2) ?? []).map(rowToGitRef);
4852
+ function attachGitRefs(item, rel, id) {
4853
+ const gitRefs = (rel.gitRefs.get(id) ?? []).map(rowToGitRef);
4721
4854
  if (gitRefs.length > 0) item.gitRefs = gitRefs;
4722
4855
  }
4723
4856
 
@@ -4730,8 +4863,8 @@ function rowToSubtask(s) {
4730
4863
  if (s.description != null) subtask.description = s.description;
4731
4864
  return subtask;
4732
4865
  }
4733
- function attachSubtasks(item, rel, id2) {
4734
- const subtasks = (rel.subtasks.get(id2) ?? []).map(rowToSubtask);
4866
+ function attachSubtasks(item, rel, id) {
4867
+ const subtasks = (rel.subtasks.get(id) ?? []).map(rowToSubtask);
4735
4868
  if (subtasks.length > 0) item.subtasks = subtasks;
4736
4869
  }
4737
4870
 
@@ -4744,8 +4877,8 @@ function rowToUsage(u) {
4744
4877
  activeMs: u.activeMs
4745
4878
  };
4746
4879
  }
4747
- function attachUsage(item, rel, id2) {
4748
- const usage = (rel.usage.get(id2) ?? []).map(rowToUsage);
4880
+ function attachUsage(item, rel, id) {
4881
+ const usage = (rel.usage.get(id) ?? []).map(rowToUsage);
4749
4882
  if (usage.length > 0) item.phaseUsage = usage;
4750
4883
  }
4751
4884
 
@@ -4804,17 +4937,17 @@ function baseItem(row) {
4804
4937
  assignOptionalColumns(item, row);
4805
4938
  return item;
4806
4939
  }
4807
- function attachComments(item, rel, id2) {
4808
- const comments3 = (rel.comments.get(id2) ?? []).map(rowToComment);
4940
+ function attachComments(item, rel, id) {
4941
+ const comments3 = (rel.comments.get(id) ?? []).map(rowToComment);
4809
4942
  if (comments3.length > 0) item.comments = comments3;
4810
4943
  }
4811
- function attachLinks(item, rel, id2) {
4812
- const links2 = (rel.links.get(id2) ?? []).map(rowToLink);
4944
+ function attachLinks(item, rel, id) {
4945
+ const links2 = (rel.links.get(id) ?? []).map(rowToLink);
4813
4946
  if (links2.length > 0) item.links = links2;
4814
4947
  }
4815
- function attachPlan(item, rel, id2) {
4816
- const phases = rel.phases.get(id2) ?? [];
4817
- if (phases.length > 0) item.plan = buildPlan(phases, rel.tasks.get(id2) ?? []);
4948
+ function attachPlan(item, rel, id) {
4949
+ const phases = rel.phases.get(id) ?? [];
4950
+ if (phases.length > 0) item.plan = buildPlan(phases, rel.tasks.get(id) ?? []);
4818
4951
  }
4819
4952
  function rowToItem(row, rel) {
4820
4953
  const item = baseItem(row);
@@ -4966,8 +5099,8 @@ async function ensureMigrated(orm, dir, origin) {
4966
5099
 
4967
5100
  // src/commands/backlog/deleteItem.ts
4968
5101
  import { eq as eq4 } from "drizzle-orm";
4969
- async function deleteItem(orm, id2) {
4970
- const [row] = await orm.delete(items).where(eq4(items.id, id2)).returning({ name: items.name });
5102
+ async function deleteItem(orm, id) {
5103
+ const [row] = await orm.delete(items).where(eq4(items.id, id)).returning({ name: items.name });
4971
5104
  return row?.name;
4972
5105
  }
4973
5106
 
@@ -5047,10 +5180,10 @@ function getCurrentOrigin(cwd) {
5047
5180
 
5048
5181
  // src/commands/backlog/loadItem.ts
5049
5182
  import { eq as eq5 } from "drizzle-orm";
5050
- async function loadItem(orm, id2) {
5051
- const [row] = await orm.select().from(items).where(eq5(items.id, id2));
5183
+ async function loadItem(orm, id) {
5184
+ const [row] = await orm.select().from(items).where(eq5(items.id, id));
5052
5185
  if (!row) return void 0;
5053
- const rel = await loadRelations(orm, [id2], {
5186
+ const rel = await loadRelations(orm, [id], {
5054
5187
  includeUsage: true,
5055
5188
  includeGitRefs: true
5056
5189
  });
@@ -5087,14 +5220,14 @@ async function searchItemIds(orm, query, origin) {
5087
5220
 
5088
5221
  // src/commands/backlog/updateCurrentPhase.ts
5089
5222
  import { eq as eq9 } from "drizzle-orm";
5090
- async function updateCurrentPhase(orm, id2, phase) {
5091
- await orm.update(items).set({ currentPhase: phase }).where(eq9(items.id, id2));
5223
+ async function updateCurrentPhase(orm, id, phase) {
5224
+ await orm.update(items).set({ currentPhase: phase }).where(eq9(items.id, id));
5092
5225
  }
5093
5226
 
5094
5227
  // src/commands/backlog/updateStatus.ts
5095
5228
  import { eq as eq10 } from "drizzle-orm";
5096
- async function updateStatus(orm, id2, status2) {
5097
- const [row] = await orm.update(items).set({ status: status2 }).where(eq10(items.id, id2)).returning({ name: items.name });
5229
+ async function updateStatus(orm, id, status2) {
5230
+ const [row] = await orm.update(items).set({ status: status2 }).where(eq10(items.id, id)).returning({ name: items.name });
5098
5231
  return row?.name;
5099
5232
  }
5100
5233
 
@@ -5126,35 +5259,39 @@ async function searchBacklog(query) {
5126
5259
  const allItems = await loadAllItems(orm, origin);
5127
5260
  return allItems.filter((item) => ids.includes(item.id));
5128
5261
  }
5129
- async function findOneItem(id2) {
5130
- const numId = Number.parseInt(id2, 10);
5262
+ async function findOneItem(id) {
5263
+ const numId = parseItemId(id);
5131
5264
  const { orm } = await getReady();
5132
- const item = Number.isNaN(numId) ? void 0 : await loadItem(orm, numId);
5265
+ const item = await loadItem(orm, numId);
5133
5266
  if (!item) {
5134
- console.log(chalk37.red(`Item #${id2} not found.`));
5267
+ console.log(chalk37.red(`Item ${formatItemId(numId)} not found.`));
5135
5268
  return void 0;
5136
5269
  }
5137
5270
  return { orm, item };
5138
5271
  }
5139
- async function setStatus(id2, status2) {
5272
+ async function setStatus(id, status2) {
5140
5273
  const { orm } = await getReady();
5141
- const name = await updateStatus(orm, Number.parseInt(id2, 10), status2);
5142
- if (name === void 0) console.log(chalk37.red(`Item #${id2} not found.`));
5274
+ const numId = parseItemId(id);
5275
+ const name = await updateStatus(orm, numId, status2);
5276
+ if (name === void 0)
5277
+ console.log(chalk37.red(`Item ${formatItemId(numId)} not found.`));
5143
5278
  return name;
5144
5279
  }
5145
- async function setCurrentPhase(id2, phase) {
5280
+ async function setCurrentPhase(id, phase) {
5146
5281
  const { orm } = await getReady();
5147
- await updateCurrentPhase(orm, Number.parseInt(id2, 10), phase);
5282
+ await updateCurrentPhase(orm, parseItemId(id), phase);
5148
5283
  }
5149
- async function removeItem(id2) {
5284
+ async function removeItem(id) {
5150
5285
  const { orm } = await getReady();
5151
- const name = await deleteItem(orm, Number.parseInt(id2, 10));
5152
- if (name === void 0) console.log(chalk37.red(`Item #${id2} not found.`));
5286
+ const numId = parseItemId(id);
5287
+ const name = await deleteItem(orm, numId);
5288
+ if (name === void 0)
5289
+ console.log(chalk37.red(`Item ${formatItemId(numId)} not found.`));
5153
5290
  return name;
5154
5291
  }
5155
5292
 
5156
5293
  // src/commands/backlog/handleReviewResult.ts
5157
- async function handleReviewResult(id2, review2) {
5294
+ async function handleReviewResult(id, review2) {
5158
5295
  if (review2.kind === "fail" || review2.kind === "abort")
5159
5296
  return { kind: "stop", success: false };
5160
5297
  if (review2.kind === "paused") return { kind: "stop", success: true };
@@ -5164,12 +5301,12 @@ async function handleReviewResult(id2, review2) {
5164
5301
  startPhase: review2.targetPhase,
5165
5302
  plan: review2.plan
5166
5303
  };
5167
- await ensureDone(id2);
5304
+ await ensureDone(id);
5168
5305
  return { kind: "stop", success: true };
5169
5306
  }
5170
- async function ensureDone(id2) {
5307
+ async function ensureDone(id) {
5171
5308
  try {
5172
- await setStatus(id2, "done");
5309
+ await setStatus(id, "done");
5173
5310
  } catch {
5174
5311
  }
5175
5312
  }
@@ -5191,20 +5328,24 @@ function resolvePlan(item) {
5191
5328
  }
5192
5329
 
5193
5330
  // src/commands/backlog/prepareRun.ts
5194
- async function prepareRun(id2) {
5195
- const found = await findOneItem(id2);
5331
+ async function prepareRun(id) {
5332
+ const found = await findOneItem(id);
5196
5333
  if (!found) return void 0;
5197
5334
  const { item } = found;
5198
5335
  const plan2 = resolvePlan(item);
5199
5336
  const startPhase = (item.currentPhase ?? 1) - 1;
5200
5337
  if (item.status === "done") {
5201
- console.log(chalk38.green(`Already done: #${id2}: ${item.name}`));
5338
+ console.log(
5339
+ chalk38.green(`Already done: ${formatItemId(item.id)}: ${item.name}`)
5340
+ );
5202
5341
  return void 0;
5203
5342
  }
5204
5343
  if (startPhase > plan2.length) {
5205
- await setStatus(id2, "done");
5344
+ await setStatus(id, "done");
5206
5345
  console.log(
5207
- chalk38.green(`All phases already complete for #${id2}: ${item.name}`)
5346
+ chalk38.green(
5347
+ `All phases already complete for ${formatItemId(item.id)}: ${item.name}`
5348
+ )
5208
5349
  );
5209
5350
  return void 0;
5210
5351
  }
@@ -5284,10 +5425,10 @@ function buildCommentLines(comments3) {
5284
5425
  return ["", "Comments:", ...comments3.map(formatPromptComment)];
5285
5426
  }
5286
5427
  function formatPromptComment(entry) {
5287
- const id2 = entry.id !== void 0 ? `#${entry.id} ` : "";
5428
+ const id = entry.id !== void 0 ? `#${entry.id} ` : "";
5288
5429
  const tag = entry.type === "summary" ? "[summary]" : "[comment]";
5289
5430
  const phase = entry.phase !== void 0 ? ` (phase ${entry.phase})` : "";
5290
- return `${id2}${tag}${phase} ${entry.timestamp}
5431
+ return `${id}${tag}${phase} ${entry.timestamp}
5291
5432
  ${entry.text}`;
5292
5433
  }
5293
5434
 
@@ -5305,16 +5446,16 @@ function buildAuthoredPhasePrompt(item, phaseNumber, phase) {
5305
5446
  "When you have completed all tasks for this phase, run /verify to check your work.",
5306
5447
  ...buildManualCheckLines(manualChecks),
5307
5448
  "",
5308
- `Post concise comments for any notable findings or changes using \`assist backlog comment ${item.id} "<text>"\`.`,
5449
+ `Post concise comments for any notable findings or changes using \`assist backlog comment ${formatItemId(item.id)} "<text>"\`.`,
5309
5450
  "",
5310
- `Once verify passes${confirmSuffix}, run: assist backlog phase-done ${item.id} ${phaseNumber} "<summary>"`,
5451
+ `Once verify passes${confirmSuffix}, run: assist backlog phase-done ${formatItemId(item.id)} ${phaseNumber} "<summary>"`,
5311
5452
  "Replace <summary> with a concise summary of what was done in this phase."
5312
5453
  ].filter((line) => line !== void 0).join("\n");
5313
5454
  }
5314
5455
  function buildContextLines(item, phaseNumber, phase) {
5315
5456
  const ac = item.acceptanceCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n");
5316
5457
  return [
5317
- `You are implementing phase ${phaseNumber} of backlog item #${item.id}: ${item.name}`,
5458
+ `You are implementing phase ${phaseNumber} of backlog item ${formatItemId(item.id)}: ${item.name}`,
5318
5459
  "",
5319
5460
  item.description ? `Description: ${item.description}` : "",
5320
5461
  "",
@@ -5355,8 +5496,9 @@ function formatTasks(phase) {
5355
5496
  // src/commands/backlog/buildReviewPrompt.ts
5356
5497
  function buildReviewPrompt(item, phaseNumber) {
5357
5498
  const acLines = item.acceptanceCriteria.map((ac, i) => `${i + 1}. ${ac}`).join("\n");
5499
+ const itemId2 = formatItemId(item.id);
5358
5500
  return [
5359
- `You are reviewing backlog item #${item.id}: ${item.name}`,
5501
+ `You are reviewing backlog item ${itemId2}: ${item.name}`,
5360
5502
  "",
5361
5503
  item.description ? `Description: ${item.description}` : "",
5362
5504
  "",
@@ -5369,9 +5511,9 @@ function buildReviewPrompt(item, phaseNumber) {
5369
5511
  "",
5370
5512
  "If any criterion fails, fix the issue and re-verify.",
5371
5513
  "",
5372
- `Any sub-tasks on this item must all be done before it can be completed: \`assist backlog done\` and completing this Review phase both fail while any sub-task is not done. Check them with \`assist backlog show ${item.id}\` and mark each finished one done via \`assist backlog subtask-status ${item.id} <idx> done\`.`,
5514
+ `Any sub-tasks on this item must all be done before it can be completed: \`assist backlog done\` and completing this Review phase both fail while any sub-task is not done. Check them with \`assist backlog show ${itemId2}\` and mark each finished one done via \`assist backlog subtask-status ${itemId2} <idx> done\`.`,
5373
5515
  "",
5374
- `Post concise comments for any notable findings or changes using \`assist backlog comment ${item.id} "<text>"\`.`,
5516
+ `Post concise comments for any notable findings or changes using \`assist backlog comment ${itemId2} "<text>"\`.`,
5375
5517
  "",
5376
5518
  "After all criteria pass, ask the user to confirm any manual checks",
5377
5519
  "(e.g. end-to-end behaviour they need to verify themselves).",
@@ -5384,13 +5526,13 @@ function buildReviewPrompt(item, phaseNumber) {
5384
5526
  "",
5385
5527
  "Once the user gives that explicit completion instruction:",
5386
5528
  "1. Run: /commit",
5387
- `2. Run: assist backlog done ${item.id} "<summary>"`,
5388
- `3. Run: assist backlog phase-done ${item.id} ${phaseNumber} "done"`,
5529
+ `2. Run: assist backlog done ${itemId2} "<summary>"`,
5530
+ `3. Run: assist backlog phase-done ${itemId2} ${phaseNumber} "done"`,
5389
5531
  "",
5390
5532
  "Precedence rules \u2014 read carefully:",
5391
5533
  "- An explicit completion instruction plus a successful commit means the work is complete. Always finish with done + phase-done; never rewind already-approved, committed work as an automatic response.",
5392
5534
  "- If the implementation has diverged from the recorded acceptance criteria but the user has approved it, the default is still to complete the item. You may optionally offer to update the acceptance criteria, but stale criteria are not a reason to rewind.",
5393
- `- Rewinding is a confirm-first exception, not the normal path. If you believe a criterion genuinely no longer fits and the work should return to an earlier phase, you must ask the user and get explicit confirmation first. Only after they confirm may you run \`assist backlog rewind ${item.id} <phase> --reason "<reason>"\`. Never rewind silently.`
5535
+ `- Rewinding is a confirm-first exception, not the normal path. If you believe a criterion genuinely no longer fits and the work should return to an earlier phase, you must ask the user and get explicit confirmation first. Only after they confirm may you run \`assist backlog rewind ${itemId2} <phase> --reason "<reason>"\`. Never rewind silently.`
5394
5536
  ].filter((line) => line !== void 0).join("\n");
5395
5537
  }
5396
5538
 
@@ -5525,15 +5667,15 @@ function cleanupSignal() {
5525
5667
  unlinkSync4(statusPath);
5526
5668
  }
5527
5669
  }
5528
- async function isTerminalStatus(itemId) {
5670
+ async function isTerminalStatus(itemId2) {
5529
5671
  const { orm } = await getReady();
5530
- const item = await loadItem(orm, itemId);
5672
+ const item = await loadItem(orm, itemId2);
5531
5673
  return item?.status === "done" || item?.status === "wontdo";
5532
5674
  }
5533
- async function resolvePhaseResult(phaseIndex, itemId) {
5675
+ async function resolvePhaseResult(phaseIndex, itemId2) {
5534
5676
  const signalPath = getSignalPath();
5535
5677
  if (!signalPath || !existsSync22(signalPath)) {
5536
- if (await isTerminalStatus(itemId)) return -1;
5678
+ if (await isTerminalStatus(itemId2)) return -1;
5537
5679
  const action = await handleIncompletePhase();
5538
5680
  if (action === "abort") return -1;
5539
5681
  return action === "skip" ? phaseIndex + 1 : phaseIndex;
@@ -5617,8 +5759,8 @@ async function executePhase(item, phaseIndex, phases, spawnOptions, totalPhases
5617
5759
  }
5618
5760
 
5619
5761
  // src/commands/backlog/reloadPlan.ts
5620
- async function reloadPlan(id2) {
5621
- const found = await findOneItem(String(id2));
5762
+ async function reloadPlan(id) {
5763
+ const found = await findOneItem(String(id));
5622
5764
  if (!found) return void 0;
5623
5765
  return resolvePlan(found.item);
5624
5766
  }
@@ -5690,23 +5832,23 @@ async function runOnce(item, startPhase, plan2, spawnOptions) {
5690
5832
  }
5691
5833
 
5692
5834
  // src/commands/backlog/run.ts
5693
- async function run2(id2, spawnOptions) {
5694
- const prepared = await prepareRun(id2);
5835
+ async function run2(id, spawnOptions) {
5836
+ const prepared = await prepareRun(id);
5695
5837
  if (!prepared) return false;
5696
5838
  await ensureStoryBranch(prepared.item);
5697
- await setStatus(id2, "in-progress");
5839
+ await setStatus(id, "in-progress");
5698
5840
  discardStalePause(prepared.item.id);
5699
- logProgress(id2, prepared);
5700
- return runPrepared(id2, prepared, spawnOptions);
5841
+ logProgress(prepared);
5842
+ return runPrepared(id, prepared, spawnOptions);
5701
5843
  }
5702
- function discardStalePause(itemId) {
5703
- if (!isPausePending(itemId)) return;
5704
- clearPause(itemId);
5844
+ function discardStalePause(itemId2) {
5845
+ if (!isPausePending(itemId2)) return;
5846
+ clearPause(itemId2);
5705
5847
  appendDaemonLog(
5706
- `backlog run ${itemId}: discarded stale pause file at run start; this run starts auto-advancing (Continue on) regardless of a prior run's pause`
5848
+ `backlog run ${itemId2}: discarded stale pause file at run start; this run starts auto-advancing (Continue on) regardless of a prior run's pause`
5707
5849
  );
5708
5850
  }
5709
- async function runPrepared(id2, prepared, spawnOptions) {
5851
+ async function runPrepared(id, prepared, spawnOptions) {
5710
5852
  const { item } = prepared;
5711
5853
  let { plan: plan2, startPhase } = prepared;
5712
5854
  acquireLock(item.id);
@@ -5714,7 +5856,7 @@ async function runPrepared(id2, prepared, spawnOptions) {
5714
5856
  while (true) {
5715
5857
  const review2 = await runOnce(item, startPhase, plan2, spawnOptions);
5716
5858
  spawnOptions = withoutResumeSession(spawnOptions);
5717
- const outcome = await handleReviewResult(id2, review2);
5859
+ const outcome = await handleReviewResult(id, review2);
5718
5860
  if (outcome.kind === "stop") {
5719
5861
  return outcome.success;
5720
5862
  }
@@ -5725,8 +5867,10 @@ async function runPrepared(id2, prepared, spawnOptions) {
5725
5867
  releaseLock(item.id);
5726
5868
  }
5727
5869
  }
5728
- function logProgress(id2, { plan: plan2, startPhase, item }) {
5729
- console.log(chalk42.bold(`Running plan for #${id2}: ${item.name}`));
5870
+ function logProgress({ plan: plan2, startPhase, item }) {
5871
+ console.log(
5872
+ chalk42.bold(`Running plan for ${formatItemId(item.id)}: ${item.name}`)
5873
+ );
5730
5874
  const totalPhases = plan2.length + 1;
5731
5875
  if (startPhase > 0) {
5732
5876
  const phaseNumber = startPhase + 1;
@@ -5742,7 +5886,7 @@ function logProgress(id2, { plan: plan2, startPhase, item }) {
5742
5886
 
5743
5887
  // src/commands/backlog/next.ts
5744
5888
  function toChoice(item, items2) {
5745
- const name = `${typeLabel(item.type)} #${item.id}: ${item.name}`;
5889
+ const name = `${typeLabel(item.type)} ${formatItemId(item.id)}: ${item.name}`;
5746
5890
  return isBlocked(item, items2) ? { name, disabled: chalk43.red("[blocked]") } : { name };
5747
5891
  }
5748
5892
  async function selectItem(todo, items2) {
@@ -5754,20 +5898,24 @@ async function selectItem(todo, items2) {
5754
5898
  choices: todo.map((i) => toChoice(i, items2))
5755
5899
  })
5756
5900
  );
5757
- return selected.match(/#(\d+)/)?.[1] ?? "";
5901
+ return selected.match(/(a\d+):/)?.[1] ?? "";
5758
5902
  }
5759
5903
  function pickResumable(items2) {
5760
5904
  const resumable = findResumable(items2);
5761
5905
  if (!resumable) return void 0;
5762
5906
  console.log(
5763
- chalk43.bold(`Resuming in-progress item #${resumable.id}: ${resumable.name}`)
5907
+ chalk43.bold(
5908
+ `Resuming in-progress item ${formatItemId(resumable.id)}: ${resumable.name}`
5909
+ )
5764
5910
  );
5765
- return String(resumable.id);
5911
+ return formatItemId(resumable.id);
5766
5912
  }
5767
5913
  function autoSelect(unblocked) {
5768
5914
  const item = unblocked[0];
5769
- console.log(chalk43.bold(`Auto-selecting item #${item.id}: ${item.name}`));
5770
- return String(item.id);
5915
+ console.log(
5916
+ chalk43.bold(`Auto-selecting item ${formatItemId(item.id)}: ${item.name}`)
5917
+ );
5918
+ return formatItemId(item.id);
5771
5919
  }
5772
5920
  async function pickItem(items2, firstPick = false) {
5773
5921
  const resumable = pickResumable(items2);
@@ -5783,11 +5931,11 @@ async function next(options2, startId) {
5783
5931
  let pendingId = startId;
5784
5932
  let firstPick = true;
5785
5933
  while (true) {
5786
- const id2 = pendingId ?? await pickItem(await loadBacklog(), firstPick);
5934
+ const id = pendingId ?? await pickItem(await loadBacklog(), firstPick);
5787
5935
  pendingId = void 0;
5788
5936
  firstPick = false;
5789
- if (id2 === void 0) return;
5790
- const completed = await run2(id2, options2);
5937
+ if (id === void 0) return;
5938
+ const completed = await run2(id, options2);
5791
5939
  if (!completed || options2?.once) return;
5792
5940
  }
5793
5941
  }
@@ -5797,10 +5945,10 @@ import chalk45 from "chalk";
5797
5945
 
5798
5946
  // src/commands/backlog/appendComment.ts
5799
5947
  import { sql as sql4 } from "drizzle-orm";
5800
- async function appendComment(orm, itemId, text9, opts = {}) {
5948
+ async function appendComment(orm, itemId2, text9, opts = {}) {
5801
5949
  await orm.insert(comments).values({
5802
- itemId,
5803
- idx: sql4`(SELECT COALESCE(MAX(${comments.idx}) + 1, 0) FROM ${comments} WHERE ${comments.itemId} = ${itemId})`,
5950
+ itemId: itemId2,
5951
+ idx: sql4`(SELECT COALESCE(MAX(${comments.idx}) + 1, 0) FROM ${comments} WHERE ${comments.itemId} = ${itemId2})`,
5804
5952
  text: text9,
5805
5953
  phase: opts.phase ?? null,
5806
5954
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -5810,12 +5958,12 @@ async function appendComment(orm, itemId, text9, opts = {}) {
5810
5958
 
5811
5959
  // src/commands/backlog/checkSubtasksComplete.ts
5812
5960
  import chalk44 from "chalk";
5813
- function checkSubtasksComplete(id2, item) {
5961
+ function checkSubtasksComplete(item) {
5814
5962
  const pending = (item.subtasks ?? []).filter((s) => s.status !== "done");
5815
5963
  if (pending.length === 0) return true;
5816
5964
  console.log(
5817
5965
  chalk44.red(
5818
- `Cannot complete item #${id2}: ${pending.length} incomplete sub-task(s):`
5966
+ `Cannot complete item ${formatItemId(item.id)}: ${pending.length} incomplete sub-task(s):`
5819
5967
  )
5820
5968
  );
5821
5969
  for (const subtask of pending) {
@@ -5825,48 +5973,51 @@ function checkSubtasksComplete(id2, item) {
5825
5973
  }
5826
5974
 
5827
5975
  // src/commands/backlog/phaseDone.ts
5828
- async function phaseDone(id2, phase, summary) {
5976
+ async function phaseDone(id, phase, summary) {
5829
5977
  const phaseNumber = Number.parseInt(phase, 10);
5830
5978
  const phaseIndex = phaseNumber - 1;
5831
- const itemId = Number.parseInt(id2, 10);
5979
+ const itemId2 = parseItemId(id);
5980
+ const label2 = formatItemId(itemId2);
5832
5981
  const { orm } = await getReady();
5833
- const item = await loadItem(orm, itemId);
5982
+ const item = await loadItem(orm, itemId2);
5834
5983
  if (item === void 0) {
5835
- console.log(chalk45.red(`Item #${id2} not found.`));
5984
+ console.log(chalk45.red(`Item ${label2} not found.`));
5836
5985
  return;
5837
5986
  }
5838
5987
  function signal() {
5839
5988
  writeSignal("phase-done", {
5840
- itemId,
5989
+ itemId: itemId2,
5841
5990
  phaseIndex,
5842
5991
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
5843
5992
  });
5844
5993
  }
5845
5994
  if (item.status === "done") {
5846
5995
  signal();
5847
- console.log(chalk45.dim(`Item #${id2} already done, skipping phase advance.`));
5996
+ console.log(
5997
+ chalk45.dim(`Item ${label2} already done, skipping phase advance.`)
5998
+ );
5848
5999
  return;
5849
6000
  }
5850
6001
  const reviewPhaseNumber = resolvePlan(item).length + 1;
5851
- if (phaseNumber === reviewPhaseNumber && !checkSubtasksComplete(id2, item)) {
6002
+ if (phaseNumber === reviewPhaseNumber && !checkSubtasksComplete(item)) {
5852
6003
  process.exitCode = 1;
5853
6004
  return;
5854
6005
  }
5855
6006
  signal();
5856
- await appendComment(orm, itemId, summary, {
6007
+ await appendComment(orm, itemId2, summary, {
5857
6008
  phase: phaseNumber,
5858
6009
  type: "summary"
5859
6010
  });
5860
- await setCurrentPhase(id2, phaseNumber + 1);
6011
+ await setCurrentPhase(id, phaseNumber + 1);
5861
6012
  console.log(
5862
- chalk45.green(`Phase ${phaseNumber} of item #${id2} marked as complete.`)
6013
+ chalk45.green(`Phase ${phaseNumber} of item ${label2} marked as complete.`)
5863
6014
  );
5864
6015
  }
5865
6016
 
5866
6017
  // src/commands/backlog/plan.ts
5867
6018
  import chalk46 from "chalk";
5868
- async function plan(id2) {
5869
- const found = await findOneItem(id2);
6019
+ async function plan(id) {
6020
+ const found = await findOneItem(id);
5870
6021
  if (!found) return;
5871
6022
  const { item } = found;
5872
6023
  if (!item.plan || item.plan.length === 0) {
@@ -5890,11 +6041,11 @@ import chalk53 from "chalk";
5890
6041
  // src/commands/backlog/formatComment.ts
5891
6042
  import chalk47 from "chalk";
5892
6043
  function formatComment(entry) {
5893
- const id2 = entry.id !== void 0 ? chalk47.dim(`#${entry.id} `) : "";
6044
+ const id = entry.id !== void 0 ? chalk47.dim(`#${entry.id} `) : "";
5894
6045
  const tag = entry.type === "summary" ? chalk47.magenta("[summary]") : chalk47.cyan("[comment]");
5895
6046
  const phase = entry.phase !== void 0 ? chalk47.dim(` (phase ${entry.phase})`) : "";
5896
6047
  const time = chalk47.dim(entry.timestamp);
5897
- return `${id2}${tag}${phase} ${time}
6048
+ return `${id}${tag}${phase} ${time}
5898
6049
  ${entry.text}`;
5899
6050
  }
5900
6051
 
@@ -5991,11 +6142,11 @@ async function printLinks(orm, item) {
5991
6142
  const typeLabel2 = link3.type === "depends-on" ? chalk49.red("depends-on") : chalk49.blue("relates-to");
5992
6143
  if (target) {
5993
6144
  console.log(
5994
- ` ${typeLabel2} #${target.id} ${target.name} ${chalk49.dim(`(${target.status})`)}`
6145
+ ` ${typeLabel2} ${formatItemId(target.id)} ${target.name} ${chalk49.dim(`(${target.status})`)}`
5995
6146
  );
5996
6147
  } else {
5997
6148
  console.log(
5998
- ` ${typeLabel2} #${link3.targetId} ${chalk49.dim("(not found)")}`
6149
+ ` ${typeLabel2} ${formatItemId(link3.targetId)} ${chalk49.dim("(not found)")}`
5999
6150
  );
6000
6151
  }
6001
6152
  }
@@ -6061,7 +6212,7 @@ function printSubtasks(item) {
6061
6212
 
6062
6213
  // src/commands/backlog/show/index.ts
6063
6214
  function printHeader(item) {
6064
- console.log(chalk53.bold(`#${item.id} ${item.name}`));
6215
+ console.log(chalk53.bold(`${formatItemId(item.id)} ${item.name}`));
6065
6216
  console.log(
6066
6217
  `${chalk53.dim("Type:")} ${item.type} ${chalk53.dim("Status:")} ${item.status}`
6067
6218
  );
@@ -6087,8 +6238,8 @@ function printComments(item) {
6087
6238
  }
6088
6239
  console.log();
6089
6240
  }
6090
- async function show(id2) {
6091
- const found = await findOneItem(id2);
6241
+ async function show(id) {
6242
+ const found = await findOneItem(id);
6092
6243
  if (!found) process.exit(1);
6093
6244
  const { orm, item } = found;
6094
6245
  printHeader(item);
@@ -6518,18 +6669,18 @@ async function getBacklogSummary(req, res) {
6518
6669
 
6519
6670
  // src/commands/backlog/deleteComment.ts
6520
6671
  import { and as and4, eq as eq13 } from "drizzle-orm";
6521
- async function deleteComment(orm, itemId, commentId) {
6522
- const [row] = await orm.select({ type: comments.type }).from(comments).where(and4(eq13(comments.id, commentId), eq13(comments.itemId, itemId)));
6672
+ async function deleteComment(orm, itemId2, commentId) {
6673
+ const [row] = await orm.select({ type: comments.type }).from(comments).where(and4(eq13(comments.id, commentId), eq13(comments.itemId, itemId2)));
6523
6674
  if (!row) return "not-found";
6524
6675
  if (row.type === "summary") return "is-summary";
6525
- await orm.delete(comments).where(and4(eq13(comments.id, commentId), eq13(comments.itemId, itemId)));
6676
+ await orm.delete(comments).where(and4(eq13(comments.id, commentId), eq13(comments.itemId, itemId2)));
6526
6677
  return "deleted";
6527
6678
  }
6528
6679
 
6529
6680
  // src/commands/backlog/updateStarred.ts
6530
6681
  import { eq as eq14 } from "drizzle-orm";
6531
- async function updateStarred(orm, id2, starred) {
6532
- const [row] = await orm.update(items).set({ starred }).where(eq14(items.id, id2)).returning({ name: items.name });
6682
+ async function updateStarred(orm, id, starred) {
6683
+ const [row] = await orm.update(items).set({ starred }).where(eq14(items.id, id)).returning({ name: items.name });
6533
6684
  return row?.name;
6534
6685
  }
6535
6686
 
@@ -6581,50 +6732,50 @@ async function listItems(req, res) {
6581
6732
  const items2 = await loadVisibleItems(req);
6582
6733
  respondJson(res, 200, items2.slice().reverse());
6583
6734
  }
6584
- async function findItemOr404(res, id2) {
6735
+ async function findItemOr404(res, id) {
6585
6736
  const { orm } = await getReady();
6586
- const item = await loadItem(orm, id2);
6737
+ const item = await loadItem(orm, id);
6587
6738
  if (!item) {
6588
6739
  respondJson(res, 404, { error: "Not found" });
6589
6740
  return void 0;
6590
6741
  }
6591
6742
  return { orm, item };
6592
6743
  }
6593
- async function getItemById(res, id2) {
6594
- const result = await findItemOr404(res, id2);
6744
+ async function getItemById(res, id) {
6745
+ const result = await findItemOr404(res, id);
6595
6746
  if (result) respondJson(res, 200, withReviewPhase(result.item));
6596
6747
  }
6597
- async function deleteItem2(res, id2) {
6598
- const result = await findItemOr404(res, id2);
6748
+ async function deleteItem2(res, id) {
6749
+ const result = await findItemOr404(res, id);
6599
6750
  if (!result) return;
6600
- await deleteItem(result.orm, id2);
6751
+ await deleteItem(result.orm, id);
6601
6752
  respondJson(res, 200, result.item);
6602
6753
  }
6603
- async function patchItemStatus(req, res, id2) {
6754
+ async function patchItemStatus(req, res, id) {
6604
6755
  const { status: status2 } = await parseStatusBody(req);
6605
- const result = await findItemOr404(res, id2);
6756
+ const result = await findItemOr404(res, id);
6606
6757
  if (!result) return;
6607
- await updateStatus(result.orm, id2, status2);
6758
+ await updateStatus(result.orm, id, status2);
6608
6759
  const updated = { ...result.item, status: status2 };
6609
6760
  respondJson(res, 200, updated);
6610
6761
  }
6611
- async function patchItemStar(req, res, id2) {
6762
+ async function patchItemStar(req, res, id) {
6612
6763
  const { starred } = await parseStarBody(req);
6613
- const result = await findItemOr404(res, id2);
6764
+ const result = await findItemOr404(res, id);
6614
6765
  if (!result) return;
6615
- await updateStarred(result.orm, id2, starred);
6766
+ await updateStarred(result.orm, id, starred);
6616
6767
  const updated = { ...result.item, starred };
6617
6768
  respondJson(res, 200, updated);
6618
6769
  }
6619
6770
 
6620
6771
  // src/commands/backlog/web/deleteItemComment.ts
6621
- async function deleteItemComment(res, itemId, commentId) {
6622
- const result = await findItemOr404(res, itemId);
6772
+ async function deleteItemComment(res, itemId2, commentId) {
6773
+ const result = await findItemOr404(res, itemId2);
6623
6774
  if (!result) return;
6624
- const outcome = await deleteComment(result.orm, itemId, commentId);
6775
+ const outcome = await deleteComment(result.orm, itemId2, commentId);
6625
6776
  if (outcome === "not-found") {
6626
6777
  respondJson(res, 404, {
6627
- error: `Comment #${commentId} not found on item #${itemId}.`
6778
+ error: `Comment #${commentId} not found on item ${formatItemId(itemId2)}.`
6628
6779
  });
6629
6780
  return;
6630
6781
  }
@@ -6634,19 +6785,19 @@ async function deleteItemComment(res, itemId, commentId) {
6634
6785
  });
6635
6786
  return;
6636
6787
  }
6637
- respondJson(res, 200, await loadItem(result.orm, itemId));
6788
+ respondJson(res, 200, await loadItem(result.orm, itemId2));
6638
6789
  }
6639
6790
 
6640
6791
  // src/commands/backlog/updateSubtaskStatus.ts
6641
6792
  import { and as and5, eq as eq15 } from "drizzle-orm";
6642
- async function updateSubtaskStatus(orm, itemId, idx, status2) {
6643
- const [row] = await orm.update(itemSubtasks).set({ status: status2 }).where(and5(eq15(itemSubtasks.itemId, itemId), eq15(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
6793
+ async function updateSubtaskStatus(orm, itemId2, idx, status2) {
6794
+ const [row] = await orm.update(itemSubtasks).set({ status: status2 }).where(and5(eq15(itemSubtasks.itemId, itemId2), eq15(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
6644
6795
  return row?.title;
6645
6796
  }
6646
6797
 
6647
6798
  // src/commands/backlog/web/patchSubtaskStatus.ts
6648
6799
  var validStatuses = ["todo", "in-progress", "done"];
6649
- async function patchSubtaskStatus(req, res, id2, idx) {
6800
+ async function patchSubtaskStatus(req, res, id, idx) {
6650
6801
  const { status: status2 } = await parseStatusBody(req);
6651
6802
  if (!validStatuses.includes(status2)) {
6652
6803
  respondJson(res, 400, {
@@ -6654,16 +6805,18 @@ async function patchSubtaskStatus(req, res, id2, idx) {
6654
6805
  });
6655
6806
  return;
6656
6807
  }
6657
- const result = await findItemOr404(res, id2);
6808
+ const result = await findItemOr404(res, id);
6658
6809
  if (!result) return;
6659
6810
  const { orm, item } = result;
6660
6811
  const subtasks = item.subtasks ?? [];
6661
6812
  if (idx < 0 || idx >= subtasks.length) {
6662
- respondJson(res, 400, { error: `Item #${id2} has no sub-task ${idx}.` });
6813
+ respondJson(res, 400, {
6814
+ error: `Item ${formatItemId(id)} has no sub-task ${idx}.`
6815
+ });
6663
6816
  return;
6664
6817
  }
6665
- await updateSubtaskStatus(orm, id2, idx, status2);
6666
- respondJson(res, 200, await loadItem(orm, id2));
6818
+ await updateSubtaskStatus(orm, id, idx, status2);
6819
+ respondJson(res, 200, await loadItem(orm, id));
6667
6820
  }
6668
6821
 
6669
6822
  // src/commands/backlog/rewindItemToPhase.ts
@@ -6696,9 +6849,9 @@ async function rewindItemToPhase(orm, item, phaseNumber, reason) {
6696
6849
  }
6697
6850
 
6698
6851
  // src/commands/backlog/web/rewindItemPhase.ts
6699
- async function rewindItemPhase(req, res, id2) {
6852
+ async function rewindItemPhase(req, res, id) {
6700
6853
  const { phase, reason } = await parseRewindBody(req);
6701
- const result = await findItemOr404(res, id2);
6854
+ const result = await findItemOr404(res, id);
6702
6855
  if (!result) return;
6703
6856
  const { orm, item } = result;
6704
6857
  const outcome = await rewindItemToPhase(orm, item, phase, reason);
@@ -6706,46 +6859,47 @@ async function rewindItemPhase(req, res, id2) {
6706
6859
  respondJson(res, 400, { error: outcome.error });
6707
6860
  return;
6708
6861
  }
6709
- respondJson(res, 200, await loadItem(orm, id2));
6862
+ respondJson(res, 200, await loadItem(orm, id));
6710
6863
  }
6711
6864
 
6712
6865
  // src/commands/backlog/web/handleItemRoute.ts
6713
- var id = (match, group = 1) => Number.parseInt(match[group], 10);
6866
+ var itemId = (match, group = 1) => parseItemId(match[group]);
6867
+ var subId = (match, group) => Number.parseInt(match[group], 10);
6714
6868
  var routes = [
6715
6869
  {
6716
- pattern: /^\/api\/items\/(\d+)\/rewind$/,
6870
+ pattern: /^\/api\/items\/(a?\d+)\/rewind$/,
6717
6871
  method: "POST",
6718
- run: (req, res, m) => rewindItemPhase(req, res, id(m))
6872
+ run: (req, res, m) => rewindItemPhase(req, res, itemId(m))
6719
6873
  },
6720
6874
  {
6721
- pattern: /^\/api\/items\/(\d+)\/star$/,
6875
+ pattern: /^\/api\/items\/(a?\d+)\/star$/,
6722
6876
  method: "POST",
6723
- run: (req, res, m) => patchItemStar(req, res, id(m))
6877
+ run: (req, res, m) => patchItemStar(req, res, itemId(m))
6724
6878
  },
6725
6879
  {
6726
- pattern: /^\/api\/items\/(\d+)\/comments\/(\d+)$/,
6880
+ pattern: /^\/api\/items\/(a?\d+)\/comments\/(\d+)$/,
6727
6881
  method: "DELETE",
6728
- run: (_req, res, m) => deleteItemComment(res, id(m), id(m, 2))
6882
+ run: (_req, res, m) => deleteItemComment(res, itemId(m), subId(m, 2))
6729
6883
  },
6730
6884
  {
6731
- pattern: /^\/api\/items\/(\d+)\/subtasks\/(\d+)$/,
6885
+ pattern: /^\/api\/items\/(a?\d+)\/subtasks\/(\d+)$/,
6732
6886
  method: "PATCH",
6733
- run: (req, res, m) => patchSubtaskStatus(req, res, id(m), id(m, 2))
6887
+ run: (req, res, m) => patchSubtaskStatus(req, res, itemId(m), subId(m, 2))
6734
6888
  },
6735
6889
  {
6736
- pattern: /^\/api\/items\/(\d+)$/,
6890
+ pattern: /^\/api\/items\/(a?\d+)$/,
6737
6891
  method: "GET",
6738
- run: (_req, res, m) => getItemById(res, id(m))
6892
+ run: (_req, res, m) => getItemById(res, itemId(m))
6739
6893
  },
6740
6894
  {
6741
- pattern: /^\/api\/items\/(\d+)$/,
6895
+ pattern: /^\/api\/items\/(a?\d+)$/,
6742
6896
  method: "PATCH",
6743
- run: (req, res, m) => patchItemStatus(req, res, id(m))
6897
+ run: (req, res, m) => patchItemStatus(req, res, itemId(m))
6744
6898
  },
6745
6899
  {
6746
- pattern: /^\/api\/items\/(\d+)$/,
6900
+ pattern: /^\/api\/items\/(a?\d+)$/,
6747
6901
  method: "DELETE",
6748
- run: (_req, res, m) => deleteItem2(res, id(m))
6902
+ run: (_req, res, m) => deleteItem2(res, itemId(m))
6749
6903
  }
6750
6904
  ];
6751
6905
  async function handleItemRoute(req, res, pathname) {
@@ -7816,9 +7970,23 @@ async function web2(options2) {
7816
7970
  });
7817
7971
  }
7818
7972
 
7973
+ // src/commands/backlog/backlogConfigHelp.ts
7974
+ var backlogConfigHelp = [
7975
+ {
7976
+ key: "database.url",
7977
+ setter: "assist config set database.url postgresql://...",
7978
+ note: "Postgres connection string for backlog storage (or ASSIST_DATABASE_URL)"
7979
+ },
7980
+ {
7981
+ key: "subtasks",
7982
+ setter: 'assist config set subtasks.0.title "Review"',
7983
+ note: "default sub-tasks seeded onto every new backlog item"
7984
+ }
7985
+ ];
7986
+
7819
7987
  // src/commands/backlog/addActivity.ts
7820
7988
  import chalk60 from "chalk";
7821
- async function addActivity(id2, kind, ref, options2) {
7989
+ async function addActivity(id, kind, ref, options2) {
7822
7990
  const parsedKind = gitRefKindSchema.safeParse(kind);
7823
7991
  if (!parsedKind.success) {
7824
7992
  console.log(
@@ -7829,7 +7997,7 @@ async function addActivity(id2, kind, ref, options2) {
7829
7997
  process.exitCode = 1;
7830
7998
  return;
7831
7999
  }
7832
- const found = await findOneItem(id2);
8000
+ const found = await findOneItem(id);
7833
8001
  if (!found) {
7834
8002
  process.exitCode = 1;
7835
8003
  return;
@@ -7844,7 +8012,9 @@ async function addActivity(id2, kind, ref, options2) {
7844
8012
  state: options2.state
7845
8013
  });
7846
8014
  console.log(
7847
- chalk60.green(`Attached ${parsedKind.data} "${ref}" to item #${id2}.`)
8015
+ chalk60.green(
8016
+ `Attached ${parsedKind.data} "${ref}" to item ${formatItemId(item.id)}.`
8017
+ )
7848
8018
  );
7849
8019
  }
7850
8020
 
@@ -7890,17 +8060,19 @@ function fetchIssue(issueKey, fields) {
7890
8060
 
7891
8061
  // src/commands/backlog/associate-jira/index.ts
7892
8062
  var JIRA_KEY_PATTERN = /^[A-Z]+-\d+$/;
7893
- async function associateJira(id2, key, options2) {
7894
- const found = await findOneItem(id2);
8063
+ async function associateJira(id, key, options2) {
8064
+ const found = await findOneItem(id);
7895
8065
  if (!found) {
7896
8066
  process.exitCode = 1;
7897
8067
  return;
7898
8068
  }
7899
8069
  const { orm } = found;
7900
- const itemId = found.item.id;
8070
+ const itemId2 = found.item.id;
7901
8071
  if (options2.clear) {
7902
- await orm.update(items).set({ jiraKey: null }).where(eq16(items.id, itemId));
7903
- console.log(chalk62.green(`Cleared Jira association on item #${itemId}.`));
8072
+ await orm.update(items).set({ jiraKey: null }).where(eq16(items.id, itemId2));
8073
+ console.log(
8074
+ chalk62.green(`Cleared Jira association on item ${formatItemId(itemId2)}.`)
8075
+ );
7904
8076
  return;
7905
8077
  }
7906
8078
  if (!key) {
@@ -7918,9 +8090,9 @@ async function associateJira(id2, key, options2) {
7918
8090
  const parsed = fetchIssue(key, "summary");
7919
8091
  const fields = parsed?.fields;
7920
8092
  const summary = fields?.summary;
7921
- await orm.update(items).set({ jiraKey: key }).where(eq16(items.id, itemId));
8093
+ await orm.update(items).set({ jiraKey: key }).where(eq16(items.id, itemId2));
7922
8094
  console.log(
7923
- chalk62.green(`Associated ${key} with item #${itemId}.`),
8095
+ chalk62.green(`Associated ${key} with item ${formatItemId(itemId2)}.`),
7924
8096
  summary ? chalk62.dim(`(${summary})`) : ""
7925
8097
  );
7926
8098
  }
@@ -7932,26 +8104,30 @@ function registerAssociateJiraCommand(cmd) {
7932
8104
 
7933
8105
  // src/commands/backlog/comment/index.ts
7934
8106
  import chalk63 from "chalk";
7935
- async function comment(id2, text9) {
7936
- const found = await findOneItem(id2);
8107
+ async function comment(id, text9) {
8108
+ const found = await findOneItem(id);
7937
8109
  if (!found) process.exit(1);
7938
8110
  await appendComment(found.orm, found.item.id, text9);
7939
- console.log(chalk63.green(`Comment added to item #${id2}.`));
8111
+ console.log(
8112
+ chalk63.green(`Comment added to item ${formatItemId(found.item.id)}.`)
8113
+ );
7940
8114
  }
7941
8115
 
7942
8116
  // src/commands/backlog/comments/index.ts
7943
8117
  import chalk64 from "chalk";
7944
- async function comments2(id2) {
7945
- const found = await findOneItem(id2);
8118
+ async function comments2(id) {
8119
+ const found = await findOneItem(id);
7946
8120
  if (!found) process.exit(1);
7947
8121
  const { item } = found;
7948
8122
  const entries = item.comments ?? [];
7949
8123
  if (entries.length === 0) {
7950
- console.log(chalk64.dim(`No comments on item #${id2}.`));
8124
+ console.log(chalk64.dim(`No comments on item ${formatItemId(item.id)}.`));
7951
8125
  return;
7952
8126
  }
7953
- console.log(chalk64.bold(`Comments for #${id2}: ${item.name}
7954
- `));
8127
+ console.log(
8128
+ chalk64.bold(`Comments for ${formatItemId(item.id)}: ${item.name}
8129
+ `)
8130
+ );
7955
8131
  for (const entry of entries) {
7956
8132
  console.log(`${formatComment(entry)}
7957
8133
  `);
@@ -7960,22 +8136,29 @@ async function comments2(id2) {
7960
8136
 
7961
8137
  // src/commands/backlog/delete-comment/index.ts
7962
8138
  import chalk65 from "chalk";
7963
- async function deleteCommentCmd(id2, commentId) {
7964
- const found = await findOneItem(id2);
8139
+ async function deleteCommentCmd(id, commentId) {
8140
+ const found = await findOneItem(id);
7965
8141
  if (!found) process.exit(1);
8142
+ const itemId2 = found.item.id;
7966
8143
  const outcome = await deleteComment(
7967
8144
  found.orm,
7968
- found.item.id,
8145
+ itemId2,
7969
8146
  Number.parseInt(commentId, 10)
7970
8147
  );
7971
8148
  switch (outcome) {
7972
8149
  case "deleted":
7973
8150
  console.log(
7974
- chalk65.green(`Comment #${commentId} deleted from item #${id2}.`)
8151
+ chalk65.green(
8152
+ `Comment #${commentId} deleted from item ${formatItemId(itemId2)}.`
8153
+ )
7975
8154
  );
7976
8155
  break;
7977
8156
  case "not-found":
7978
- console.log(chalk65.red(`Comment #${commentId} not found on item #${id2}.`));
8157
+ console.log(
8158
+ chalk65.red(
8159
+ `Comment #${commentId} not found on item ${formatItemId(itemId2)}.`
8160
+ )
8161
+ );
7979
8162
  process.exit(1);
7980
8163
  break;
7981
8164
  case "is-summary":
@@ -8060,7 +8243,7 @@ function parseDump(dump) {
8060
8243
  function validateDump({ header, sections }) {
8061
8244
  const tables = header.tables ?? [];
8062
8245
  const missing = tables.find(({ name }) => !sections.has(name))?.name;
8063
- const checks = [
8246
+ const checks2 = [
8064
8247
  [
8065
8248
  header.format === DUMP_FORMAT,
8066
8249
  `Unrecognised dump format "${header.format}" (expected "${DUMP_FORMAT}").`
@@ -8072,7 +8255,7 @@ function validateDump({ header, sections }) {
8072
8255
  [tables.length > 0, "Dump header lists no tables; cannot restore."],
8073
8256
  [!missing, `Invalid dump: missing data section for "${missing}".`]
8074
8257
  ];
8075
- const failure = checks.find(([ok]) => !ok);
8258
+ const failure = checks2.find(([ok]) => !ok);
8076
8259
  if (failure) throw new Error(failure[1]);
8077
8260
  }
8078
8261
 
@@ -8220,37 +8403,37 @@ import { count as count2, eq as eq18 } from "drizzle-orm";
8220
8403
 
8221
8404
  // src/commands/backlog/shiftPhasesUp.ts
8222
8405
  import { and as and6, desc as desc3, eq as eq17, gte } from "drizzle-orm";
8223
- async function shiftPhasesUp(db, itemId, fromIdx) {
8224
- const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and6(eq17(planPhases.itemId, itemId), gte(planPhases.idx, fromIdx))).orderBy(desc3(planPhases.idx));
8406
+ async function shiftPhasesUp(db, itemId2, fromIdx) {
8407
+ const toShift = await db.select({ idx: planPhases.idx }).from(planPhases).where(and6(eq17(planPhases.itemId, itemId2), gte(planPhases.idx, fromIdx))).orderBy(desc3(planPhases.idx));
8225
8408
  for (const p of toShift) {
8226
- await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and6(eq17(planTasks.itemId, itemId), eq17(planTasks.phaseIdx, p.idx)));
8227
- await db.update(planPhases).set({ idx: p.idx + 1 }).where(and6(eq17(planPhases.itemId, itemId), eq17(planPhases.idx, p.idx)));
8409
+ await db.update(planTasks).set({ phaseIdx: p.idx + 1 }).where(and6(eq17(planTasks.itemId, itemId2), eq17(planTasks.phaseIdx, p.idx)));
8410
+ await db.update(planPhases).set({ idx: p.idx + 1 }).where(and6(eq17(planPhases.itemId, itemId2), eq17(planPhases.idx, p.idx)));
8228
8411
  }
8229
8412
  }
8230
8413
 
8231
8414
  // src/commands/backlog/insertPhaseAt.ts
8232
- async function insertPhaseAt(orm, itemId, phaseIdx, name, tasks, manualChecks, currentPhase) {
8415
+ async function insertPhaseAt(orm, itemId2, phaseIdx, name, tasks, manualChecks, currentPhase) {
8233
8416
  await orm.transaction(async (tx) => {
8234
- const [row] = await tx.select({ cnt: count2() }).from(planPhases).where(eq18(planPhases.itemId, itemId));
8417
+ const [row] = await tx.select({ cnt: count2() }).from(planPhases).where(eq18(planPhases.itemId, itemId2));
8235
8418
  const phaseCount = row?.cnt ?? 0;
8236
- await shiftPhasesUp(tx, itemId, phaseIdx);
8237
- await tx.insert(planPhases).values({ itemId, idx: phaseIdx, name, manualChecks });
8419
+ await shiftPhasesUp(tx, itemId2, phaseIdx);
8420
+ await tx.insert(planPhases).values({ itemId: itemId2, idx: phaseIdx, name, manualChecks });
8238
8421
  if (tasks.length) {
8239
- await tx.insert(planTasks).values(tasks.map((task, i) => ({ itemId, phaseIdx, idx: i, task })));
8422
+ await tx.insert(planTasks).values(tasks.map((task, i) => ({ itemId: itemId2, phaseIdx, idx: i, task })));
8240
8423
  }
8241
8424
  if (currentPhase !== void 0 && currentPhase - 1 >= phaseIdx) {
8242
8425
  const atReviewSlot = currentPhase - 1 >= phaseCount;
8243
- await tx.update(items).set({ currentPhase: atReviewSlot ? phaseIdx + 1 : currentPhase + 1 }).where(eq18(items.id, itemId));
8426
+ await tx.update(items).set({ currentPhase: atReviewSlot ? phaseIdx + 1 : currentPhase + 1 }).where(eq18(items.id, itemId2));
8244
8427
  }
8245
8428
  });
8246
8429
  }
8247
8430
 
8248
8431
  // src/commands/backlog/insertSubtask.ts
8249
8432
  import { sql as sql6 } from "drizzle-orm";
8250
- async function insertSubtask(orm, itemId, title, description) {
8433
+ async function insertSubtask(orm, itemId2, title, description) {
8251
8434
  await orm.insert(itemSubtasks).values({
8252
- itemId,
8253
- idx: sql6`(SELECT COALESCE(MAX(${itemSubtasks.idx}) + 1, 0) FROM ${itemSubtasks} WHERE ${itemSubtasks.itemId} = ${itemId})`,
8435
+ itemId: itemId2,
8436
+ idx: sql6`(SELECT COALESCE(MAX(${itemSubtasks.idx}) + 1, 0) FROM ${itemSubtasks} WHERE ${itemSubtasks.itemId} = ${itemId2})`,
8254
8437
  title,
8255
8438
  description: description ?? null,
8256
8439
  status: "todo"
@@ -8348,7 +8531,7 @@ async function add(options2) {
8348
8531
  const description = options2.desc?.replaceAll(String.raw`\n`, "\n") ?? await promptDescription();
8349
8532
  const acceptanceCriteria2 = options2.ac ?? await promptAcceptanceCriteria();
8350
8533
  const orm = await getDb();
8351
- const id2 = await insertItem(
8534
+ const id = await insertItem(
8352
8535
  orm,
8353
8536
  {
8354
8537
  type,
@@ -8361,12 +8544,12 @@ async function add(options2) {
8361
8544
  getOrigin()
8362
8545
  );
8363
8546
  if (type === "bug") {
8364
- await insertPhaseAt(orm, id2, 0, "Fix", ["Fix the bug"], null, void 0);
8547
+ await insertPhaseAt(orm, id, 0, "Fix", ["Fix the bug"], null, void 0);
8365
8548
  }
8366
8549
  for (const subtask of loadConfig().subtasks ?? []) {
8367
- await insertSubtask(orm, id2, subtask.title, subtask.description);
8550
+ await insertSubtask(orm, id, subtask.title, subtask.description);
8368
8551
  }
8369
- console.log(chalk69.green(`Added item #${id2}: ${name}`));
8552
+ console.log(chalk69.green(`Added item ${formatItemId(id)}: ${name}`));
8370
8553
  }
8371
8554
 
8372
8555
  // src/commands/backlog/addPhase.ts
@@ -8375,8 +8558,8 @@ import chalk71 from "chalk";
8375
8558
  // src/commands/backlog/resolveInsertPosition.ts
8376
8559
  import chalk70 from "chalk";
8377
8560
  import { count as count3, eq as eq19 } from "drizzle-orm";
8378
- async function resolveInsertPosition(orm, itemId, position) {
8379
- const [row] = await orm.select({ cnt: count3() }).from(planPhases).where(eq19(planPhases.itemId, itemId));
8561
+ async function resolveInsertPosition(orm, itemId2, position) {
8562
+ const [row] = await orm.select({ cnt: count3() }).from(planPhases).where(eq19(planPhases.itemId, itemId2));
8380
8563
  const phaseCount = row?.cnt ?? 0;
8381
8564
  if (position === void 0) return phaseCount;
8382
8565
  const pos = Number.parseInt(position, 10);
@@ -8398,9 +8581,9 @@ function serializeManualChecks(manualCheck) {
8398
8581
  }
8399
8582
 
8400
8583
  // src/commands/backlog/addPhase.ts
8401
- async function addPhase(id2, name, options2) {
8584
+ async function addPhase(id, name, options2) {
8402
8585
  if (!ensureRemoteOrigin()) return;
8403
- const found = await findOneItem(id2);
8586
+ const found = await findOneItem(id);
8404
8587
  if (!found) return;
8405
8588
  const tasks = options2.task ?? [];
8406
8589
  if (tasks.length === 0) {
@@ -8409,12 +8592,12 @@ async function addPhase(id2, name, options2) {
8409
8592
  return;
8410
8593
  }
8411
8594
  const { orm } = found;
8412
- const itemId = found.item.id;
8413
- const phaseIdx = await resolveInsertPosition(orm, itemId, options2.position);
8595
+ const itemId2 = found.item.id;
8596
+ const phaseIdx = await resolveInsertPosition(orm, itemId2, options2.position);
8414
8597
  if (phaseIdx === void 0) return;
8415
8598
  await insertPhaseAt(
8416
8599
  orm,
8417
- itemId,
8600
+ itemId2,
8418
8601
  phaseIdx,
8419
8602
  name,
8420
8603
  tasks,
@@ -8424,7 +8607,7 @@ async function addPhase(id2, name, options2) {
8424
8607
  const verb = options2.position !== void 0 ? "Inserted" : "Added";
8425
8608
  console.log(
8426
8609
  chalk71.green(
8427
- `${verb} phase ${phaseIdx + 1} "${name}" to item #${itemId} with ${tasks.length} task(s).`
8610
+ `${verb} phase ${phaseIdx + 1} "${name}" to item ${formatItemId(itemId2)} with ${tasks.length} task(s).`
8428
8611
  )
8429
8612
  );
8430
8613
  }
@@ -8437,6 +8620,15 @@ function filterItems(items2, options2) {
8437
8620
  return items2.filter((i) => i.status !== "done" && i.status !== "wontdo");
8438
8621
  return items2;
8439
8622
  }
8623
+ function repoPrefixer(items2, allRepos) {
8624
+ if (!allRepos) return () => "";
8625
+ const labels = originDisplayLabels(
8626
+ items2.flatMap((i) => i.origin ? [i.origin] : [])
8627
+ );
8628
+ const repoNameOf = (item) => item.origin ? labels.get(item.origin) ?? "" : "";
8629
+ const width = Math.max(0, ...items2.map((i) => repoNameOf(i).length));
8630
+ return (item) => `${chalk72.dim(repoNameOf(item).padEnd(width))} `;
8631
+ }
8440
8632
  async function list2(options2) {
8441
8633
  const allItems = await loadBacklog(options2.allRepos);
8442
8634
  const items2 = filterItems(allItems, options2);
@@ -8444,15 +8636,10 @@ async function list2(options2) {
8444
8636
  console.log(chalk72.dim("Backlog is empty."));
8445
8637
  return;
8446
8638
  }
8447
- const labels = originDisplayLabels(
8448
- items2.flatMap((i) => i.origin ? [i.origin] : [])
8449
- );
8450
- const repoNameOf = (item) => item.origin ? labels.get(item.origin) ?? "" : "";
8451
- const prefixWidth = options2.allRepos ? Math.max(0, ...items2.map((i) => repoNameOf(i).length)) : 0;
8639
+ const prefixOf = repoPrefixer(items2, !!options2.allRepos);
8452
8640
  for (const item of items2) {
8453
- const repoPrefix = options2.allRepos ? `${chalk72.dim(repoNameOf(item).padEnd(prefixWidth))} ` : "";
8454
8641
  console.log(
8455
- `${repoPrefix}${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk72.dim(`#${item.id}`)} ${starMarker(item)}${item.name}${phaseLabel(item)}${dependencyLabel(item, allItems)}`
8642
+ `${prefixOf(item)}${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk72.dim(formatItemId(item.id))} ${starMarker(item)}${item.name}${phaseLabel(item)}${dependencyLabel(item, allItems)}`
8456
8643
  );
8457
8644
  if (options2.verbose) {
8458
8645
  printVerboseDetails(item);
@@ -8504,10 +8691,10 @@ import { eq as eq20 } from "drizzle-orm";
8504
8691
  async function loadDependencyGraph(orm) {
8505
8692
  const rows = await orm.select({ itemId: links.itemId, targetId: links.targetId }).from(links).where(eq20(links.type, "depends-on"));
8506
8693
  const graph = /* @__PURE__ */ new Map();
8507
- for (const { itemId, targetId } of rows) {
8508
- const bucket = graph.get(itemId);
8694
+ for (const { itemId: itemId2, targetId } of rows) {
8695
+ const bucket = graph.get(itemId2);
8509
8696
  if (bucket) bucket.push(targetId);
8510
- else graph.set(itemId, [targetId]);
8697
+ else graph.set(itemId2, [targetId]);
8511
8698
  }
8512
8699
  return graph;
8513
8700
  }
@@ -8520,7 +8707,9 @@ function validateLinkTarget(fromItem, fromNum, toNum, linkType) {
8520
8707
  );
8521
8708
  if (duplicate) {
8522
8709
  console.log(
8523
- chalk73.yellow(`Link already exists: #${fromNum} ${linkType} #${toNum}`)
8710
+ chalk73.yellow(
8711
+ `Link already exists: ${formatItemId(fromNum)} ${linkType} ${formatItemId(toNum)}`
8712
+ )
8524
8713
  );
8525
8714
  return false;
8526
8715
  }
@@ -8541,50 +8730,62 @@ async function createsCycle(orm, linkType, fromNum, toNum) {
8541
8730
  if (linkType !== "depends-on") return false;
8542
8731
  const graph = await loadDependencyGraph(orm);
8543
8732
  if (!hasCycle(graph, fromNum, toNum)) return false;
8544
- fail2(`Cannot add dependency: #${fromNum} \u2192 #${toNum} would create a cycle.`);
8733
+ fail2(
8734
+ `Cannot add dependency: ${formatItemId(fromNum)} \u2192 ${formatItemId(toNum)} would create a cycle.`
8735
+ );
8545
8736
  return true;
8546
8737
  }
8547
8738
  async function link(fromId, toId, opts) {
8548
8739
  const linkType = parseLinkType(opts.type);
8549
8740
  if (!linkType) return;
8550
- const fromNum = Number.parseInt(fromId, 10);
8551
- const toNum = Number.parseInt(toId, 10);
8741
+ const fromNum = parseItemId(fromId);
8742
+ const toNum = parseItemId(toId);
8552
8743
  if (fromNum === toNum) return void fail2("Cannot link an item to itself.");
8744
+ const from = formatItemId(fromNum);
8745
+ const to = formatItemId(toNum);
8553
8746
  const { orm } = await getReady();
8554
8747
  const fromItem = await loadItem(orm, fromNum);
8555
- if (!fromItem) return void fail2(`Item #${fromNum} not found.`);
8748
+ if (!fromItem) return void fail2(`Item ${from} not found.`);
8556
8749
  const toItem = await loadItem(orm, toNum);
8557
- if (!toItem) return void fail2(`Item #${toNum} not found.`);
8750
+ if (!toItem) return void fail2(`Item ${to} not found.`);
8558
8751
  if (!validateLinkTarget(fromItem, fromNum, toNum, linkType)) return;
8559
8752
  if (await createsCycle(orm, linkType, fromNum, toNum)) return;
8560
8753
  await orm.insert(links).values({ itemId: fromNum, type: linkType, targetId: toNum });
8561
- console.log(
8562
- chalk74.green(`Linked #${fromNum} ${linkType} #${toNum} (${toItem.name})`)
8563
- );
8754
+ console.log(chalk74.green(`Linked ${from} ${linkType} ${to} (${toItem.name})`));
8564
8755
  }
8565
8756
 
8566
8757
  // src/commands/backlog/unlink.ts
8567
8758
  import chalk75 from "chalk";
8568
8759
  import { and as and7, eq as eq21 } from "drizzle-orm";
8569
8760
  async function unlink(fromId, toId) {
8570
- const fromNum = Number.parseInt(fromId, 10);
8571
- const toNum = Number.parseInt(toId, 10);
8761
+ const fromNum = parseItemId(fromId);
8762
+ const toNum = parseItemId(toId);
8572
8763
  const { orm } = await getReady();
8573
8764
  const fromItem = await loadItem(orm, fromNum);
8574
8765
  if (!fromItem) {
8575
- console.log(chalk75.red(`Item #${fromId} not found.`));
8766
+ console.log(chalk75.red(`Item ${formatItemId(fromNum)} not found.`));
8576
8767
  return;
8577
8768
  }
8578
8769
  if (!fromItem.links || fromItem.links.length === 0) {
8579
- console.log(chalk75.yellow(`No links found on item #${fromId}.`));
8770
+ console.log(
8771
+ chalk75.yellow(`No links found on item ${formatItemId(fromNum)}.`)
8772
+ );
8580
8773
  return;
8581
8774
  }
8582
8775
  if (!fromItem.links.some((l) => l.targetId === toNum)) {
8583
- console.log(chalk75.yellow(`No link from #${fromId} to #${toId} found.`));
8776
+ console.log(
8777
+ chalk75.yellow(
8778
+ `No link from ${formatItemId(fromNum)} to ${formatItemId(toNum)} found.`
8779
+ )
8780
+ );
8584
8781
  return;
8585
8782
  }
8586
8783
  await orm.delete(links).where(and7(eq21(links.itemId, fromNum), eq21(links.targetId, toNum)));
8587
- console.log(chalk75.green(`Removed link from #${fromId} to #${toId}.`));
8784
+ console.log(
8785
+ chalk75.green(
8786
+ `Removed link from ${formatItemId(fromNum)} to ${formatItemId(toNum)}.`
8787
+ )
8788
+ );
8588
8789
  }
8589
8790
 
8590
8791
  // src/commands/backlog/registerLinkCommands.ts
@@ -8679,7 +8880,7 @@ function registerMoveRepoCommand(cmd) {
8679
8880
  // src/commands/backlog/registerNextCommand.ts
8680
8881
  function registerNextCommand(cmd) {
8681
8882
  cmd.command("next").argument("[id]", "Backlog item ID to run first").description("Pick and run the next backlog item, or open /draft if none").option("-w, --write", "Run Claude with auto permission mode (default)").option("--no-write", "Run Claude without auto permission mode").option("--once", "Exit after the first completed item run").action(
8682
- (id2, opts) => next({ allowEdits: opts.write !== false, once: opts.once }, id2)
8883
+ (id, opts) => next({ allowEdits: opts.write !== false, once: opts.once }, id)
8683
8884
  );
8684
8885
  }
8685
8886
 
@@ -8700,9 +8901,14 @@ import { randomUUID as randomUUID2 } from "crypto";
8700
8901
  import chalk79 from "chalk";
8701
8902
 
8702
8903
  // src/commands/backlog/surfaceCreatedItem.ts
8703
- async function surfaceCreatedItem(slashCommand, id2) {
8704
- const numericId = Number.parseInt(id2, 10);
8705
- if (Number.isNaN(numericId)) return;
8904
+ async function surfaceCreatedItem(slashCommand, id) {
8905
+ let numericId;
8906
+ try {
8907
+ numericId = parseItemId(id);
8908
+ } catch (error) {
8909
+ if (error instanceof InvalidItemIdError) return;
8910
+ throw error;
8911
+ }
8706
8912
  const { orm } = await getReady();
8707
8913
  const item = await loadItem(orm, numericId);
8708
8914
  if (!item) return;
@@ -8716,33 +8922,34 @@ async function surfaceCreatedItem(slashCommand, id2) {
8716
8922
 
8717
8923
  // src/commands/backlog/tryRunById.ts
8718
8924
  import chalk78 from "chalk";
8719
- async function tryRunById(id2, options2) {
8720
- const numericId = Number.parseInt(id2, 10);
8925
+ async function tryRunById(id, options2) {
8926
+ const numericId = parseItemId(id);
8927
+ const label2 = formatItemId(numericId);
8721
8928
  const { orm } = await getReady();
8722
- const item = Number.isNaN(numericId) ? void 0 : await loadItem(orm, numericId);
8929
+ const item = await loadItem(orm, numericId);
8723
8930
  if (!item) {
8724
- console.log(chalk78.red(`Item #${id2} not found.`));
8931
+ console.log(chalk78.red(`Item ${label2} not found.`));
8725
8932
  return false;
8726
8933
  }
8727
8934
  if (item.status === "done") {
8728
- console.log(chalk78.red(`Item #${id2} is already done.`));
8935
+ console.log(chalk78.red(`Item ${label2} is already done.`));
8729
8936
  return false;
8730
8937
  }
8731
8938
  if (item.status === "wontdo") {
8732
- console.log(chalk78.red(`Item #${id2} is marked won't do.`));
8939
+ console.log(chalk78.red(`Item ${label2} is marked won't do.`));
8733
8940
  return false;
8734
8941
  }
8735
8942
  const hasDeps = (item.links ?? []).some((l) => l.type === "depends-on");
8736
8943
  if (hasDeps && isBlocked(item, await loadItemSummaries(orm, getOrigin()))) {
8737
8944
  console.log(
8738
- chalk78.red(`Item #${id2} is blocked by unresolved dependencies.`)
8945
+ chalk78.red(`Item ${label2} is blocked by unresolved dependencies.`)
8739
8946
  );
8740
8947
  return false;
8741
8948
  }
8742
8949
  console.log(chalk78.bold(`
8743
- Running backlog item #${id2}...
8950
+ Running backlog item ${label2}...
8744
8951
  `));
8745
- await run2(id2, options2);
8952
+ await run2(id, options2);
8746
8953
  return true;
8747
8954
  }
8748
8955
 
@@ -8803,8 +9010,10 @@ async function pickItemForRefine() {
8803
9010
  }
8804
9011
  if (active.length === 1) {
8805
9012
  const item = active[0];
8806
- console.log(chalk80.bold(`Auto-selecting item #${item.id}: ${item.name}`));
8807
- return String(item.id);
9013
+ console.log(
9014
+ chalk80.bold(`Auto-selecting item ${formatItemId(item.id)}: ${item.name}`)
9015
+ );
9016
+ return formatItemId(item.id);
8808
9017
  }
8809
9018
  const { selected } = await exitOnCancel(
8810
9019
  enquirer7.prompt({
@@ -8812,18 +9021,18 @@ async function pickItemForRefine() {
8812
9021
  name: "selected",
8813
9022
  message: "Choose a backlog item to refine:",
8814
9023
  choices: active.map((item) => ({
8815
- name: `${typeLabel(item.type)} #${item.id}: ${item.name}`
9024
+ name: `${typeLabel(item.type)} ${formatItemId(item.id)}: ${item.name}`
8816
9025
  }))
8817
9026
  })
8818
9027
  );
8819
- return selected.match(/#(\d+)/)?.[1] ?? "";
9028
+ return selected.match(/(a\d+):/)?.[1] ?? "";
8820
9029
  }
8821
- async function refine(id2, options2) {
8822
- const itemId = id2 ?? await pickItemForRefine();
8823
- if (!itemId) return;
8824
- const numericId = Number.parseInt(itemId, 10);
8825
- const item = Number.isNaN(numericId) ? void 0 : await loadItem((await getReady()).orm, numericId);
8826
- await launchMode(`refine ${itemId}`, {
9030
+ async function refine(id, options2) {
9031
+ const itemId2 = id ?? await pickItemForRefine();
9032
+ if (!itemId2) return;
9033
+ const numericId = parseItemId(itemId2);
9034
+ const item = await loadItem((await getReady()).orm, numericId);
9035
+ await launchMode(`refine ${itemId2}`, {
8827
9036
  ...options2,
8828
9037
  itemId: item ? numericId : void 0,
8829
9038
  itemName: item?.name
@@ -8833,20 +9042,17 @@ async function refine(id2, options2) {
8833
9042
  // src/commands/backlog/registerRefineCommand.ts
8834
9043
  function registerRefineCommand(cmd) {
8835
9044
  cmd.command("refine").argument("[id]", "Backlog item ID").description("Alias for refine").option("--once", "Exit when the initial task completes").action(
8836
- (id2, opts) => refine(id2, { once: opts.once })
9045
+ (id, opts) => refine(id, { once: opts.once })
8837
9046
  );
8838
9047
  }
8839
9048
 
8840
9049
  // src/commands/backlog/rewindPhase.ts
8841
9050
  import chalk81 from "chalk";
8842
- async function rewindPhase(id2, phase, opts) {
9051
+ async function rewindPhase(id, phase, opts) {
8843
9052
  const phaseNumber = Number.parseInt(phase, 10);
8844
- const { orm } = await getReady();
8845
- const item = await loadItem(orm, Number.parseInt(id2, 10));
8846
- if (!item) {
8847
- console.log(chalk81.red(`Item #${id2} not found.`));
8848
- return;
8849
- }
9053
+ const found = await findOneItem(id);
9054
+ if (!found) return;
9055
+ const { orm, item } = found;
8850
9056
  const result = await rewindItemToPhase(orm, item, phaseNumber, opts.reason);
8851
9057
  if (!result.ok) {
8852
9058
  console.log(chalk81.red(result.error));
@@ -8855,7 +9061,7 @@ async function rewindPhase(id2, phase, opts) {
8855
9061
  }
8856
9062
  console.log(
8857
9063
  chalk81.green(
8858
- `Rewound item #${id2} to phase ${phaseNumber} (${result.phaseName}).`
9064
+ `Rewound item ${formatItemId(item.id)} to phase ${phaseNumber} (${result.phaseName}).`
8859
9065
  )
8860
9066
  );
8861
9067
  }
@@ -8871,9 +9077,9 @@ function registerRunCommand(cmd) {
8871
9077
  "--resume-session <id>",
8872
9078
  "Resume an interrupted Claude session for the current phase (used by the sessions daemon on restart)"
8873
9079
  ).action(
8874
- async (id2, opts) => {
9080
+ async (id, opts) => {
8875
9081
  if (!opts.resumeSession) pullIfConfigured();
8876
- await run2(id2, {
9082
+ await run2(id, {
8877
9083
  allowEdits: opts.write !== false,
8878
9084
  resumeSessionId: opts.resumeSession
8879
9085
  });
@@ -8897,7 +9103,7 @@ async function search(query) {
8897
9103
  );
8898
9104
  for (const item of items2) {
8899
9105
  console.log(
8900
- `${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk82.dim(`#${item.id}`)} ${item.name}`
9106
+ `${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk82.dim(formatItemId(item.id))} ${item.name}`
8901
9107
  );
8902
9108
  }
8903
9109
  }
@@ -8909,20 +9115,22 @@ function registerSearchCommand(cmd) {
8909
9115
 
8910
9116
  // src/commands/backlog/delete/index.ts
8911
9117
  import chalk83 from "chalk";
8912
- async function del(id2) {
8913
- const name = await removeItem(id2);
9118
+ async function del(id) {
9119
+ const name = await removeItem(id);
8914
9120
  if (name) {
8915
- console.log(chalk83.green(`Deleted item #${id2}: ${name}`));
9121
+ console.log(
9122
+ chalk83.green(`Deleted item ${formatItemId(parseItemId(id))}: ${name}`)
9123
+ );
8916
9124
  }
8917
9125
  }
8918
9126
 
8919
9127
  // src/commands/backlog/done/index.ts
8920
9128
  import chalk84 from "chalk";
8921
- async function done(id2, summary) {
8922
- const found = await findOneItem(id2);
9129
+ async function done(id, summary) {
9130
+ const found = await findOneItem(id);
8923
9131
  if (!found) return;
8924
9132
  const { orm, item } = found;
8925
- if (!checkSubtasksComplete(id2, item)) {
9133
+ if (!checkSubtasksComplete(item)) {
8926
9134
  process.exitCode = 1;
8927
9135
  return;
8928
9136
  }
@@ -8932,7 +9140,7 @@ async function done(id2, summary) {
8932
9140
  if (pending.length > 0) {
8933
9141
  console.log(
8934
9142
  chalk84.red(
8935
- `Cannot complete item #${id2}: ${pending.length} pending phase(s):`
9143
+ `Cannot complete item ${formatItemId(item.id)}: ${pending.length} pending phase(s):`
8936
9144
  )
8937
9145
  );
8938
9146
  for (const phase of pending) {
@@ -8947,7 +9155,9 @@ async function done(id2, summary) {
8947
9155
  const phase = item.currentPhase ?? 1;
8948
9156
  await appendComment(orm, item.id, summary, { phase, type: "summary" });
8949
9157
  }
8950
- console.log(chalk84.green(`Completed item #${id2}: ${item.name}`));
9158
+ console.log(
9159
+ chalk84.green(`Completed item ${formatItemId(item.id)}: ${item.name}`)
9160
+ );
8951
9161
  }
8952
9162
 
8953
9163
  // src/commands/backlog/set-status/index.ts
@@ -8958,7 +9168,7 @@ var allowedStatuses = [
8958
9168
  "done",
8959
9169
  "wontdo"
8960
9170
  ];
8961
- async function setStatusCommand(id2, status2) {
9171
+ async function setStatusCommand(id, status2) {
8962
9172
  if (!allowedStatuses.includes(status2)) {
8963
9173
  console.log(
8964
9174
  chalk85.red(
@@ -8968,9 +9178,13 @@ async function setStatusCommand(id2, status2) {
8968
9178
  process.exitCode = 1;
8969
9179
  return;
8970
9180
  }
8971
- const name = await setStatus(id2, status2);
9181
+ const name = await setStatus(id, status2);
8972
9182
  if (name) {
8973
- console.log(chalk85.green(`Set item #${id2} to ${status2}: ${name}`));
9183
+ console.log(
9184
+ chalk85.green(
9185
+ `Set item ${formatItemId(parseItemId(id))} to ${status2}: ${name}`
9186
+ )
9187
+ );
8974
9188
  }
8975
9189
  }
8976
9190
 
@@ -8979,27 +9193,33 @@ import chalk87 from "chalk";
8979
9193
 
8980
9194
  // src/commands/backlog/setStarred.ts
8981
9195
  import chalk86 from "chalk";
8982
- async function setStarred(id2, starred) {
9196
+ async function setStarred(id, starred) {
8983
9197
  const { orm } = await getReady();
8984
- const name = await updateStarred(orm, Number.parseInt(id2, 10), starred);
8985
- if (name === void 0) console.log(chalk86.red(`Item #${id2} not found.`));
9198
+ const numId = parseItemId(id);
9199
+ const name = await updateStarred(orm, numId, starred);
9200
+ if (name === void 0)
9201
+ console.log(chalk86.red(`Item ${formatItemId(numId)} not found.`));
8986
9202
  return name;
8987
9203
  }
8988
9204
 
8989
9205
  // src/commands/backlog/star/index.ts
8990
- async function star(id2) {
8991
- const name = await setStarred(id2, true);
9206
+ async function star(id) {
9207
+ const name = await setStarred(id, true);
8992
9208
  if (name) {
8993
- console.log(chalk87.green(`Starred item #${id2}: ${name}`));
9209
+ console.log(
9210
+ chalk87.green(`Starred item ${formatItemId(parseItemId(id))}: ${name}`)
9211
+ );
8994
9212
  }
8995
9213
  }
8996
9214
 
8997
9215
  // src/commands/backlog/start/index.ts
8998
9216
  import chalk88 from "chalk";
8999
- async function start(id2) {
9000
- const name = await setStatus(id2, "in-progress");
9217
+ async function start(id) {
9218
+ const name = await setStatus(id, "in-progress");
9001
9219
  if (name) {
9002
- console.log(chalk88.green(`Started item #${id2}: ${name}`));
9220
+ console.log(
9221
+ chalk88.green(`Started item ${formatItemId(parseItemId(id))}: ${name}`)
9222
+ );
9003
9223
  }
9004
9224
  }
9005
9225
 
@@ -9014,23 +9234,27 @@ async function stop() {
9014
9234
  return;
9015
9235
  }
9016
9236
  for (const item of stopped) {
9017
- console.log(chalk89.yellow(`Stopped item #${item.id}: ${item.name}`));
9237
+ console.log(
9238
+ chalk89.yellow(`Stopped item ${formatItemId(item.id)}: ${item.name}`)
9239
+ );
9018
9240
  }
9019
9241
  }
9020
9242
 
9021
9243
  // src/commands/backlog/unstar/index.ts
9022
9244
  import chalk90 from "chalk";
9023
- async function unstar(id2) {
9024
- const name = await setStarred(id2, false);
9245
+ async function unstar(id) {
9246
+ const name = await setStarred(id, false);
9025
9247
  if (name) {
9026
- console.log(chalk90.green(`Unstarred item #${id2}: ${name}`));
9248
+ console.log(
9249
+ chalk90.green(`Unstarred item ${formatItemId(parseItemId(id))}: ${name}`)
9250
+ );
9027
9251
  }
9028
9252
  }
9029
9253
 
9030
9254
  // src/commands/backlog/wontdo/index.ts
9031
9255
  import chalk91 from "chalk";
9032
- async function wontdo(id2, reason) {
9033
- const found = await findOneItem(id2);
9256
+ async function wontdo(id, reason) {
9257
+ const found = await findOneItem(id);
9034
9258
  if (!found) return;
9035
9259
  const { orm, item } = found;
9036
9260
  await updateStatus(orm, item.id, "wontdo");
@@ -9038,7 +9262,9 @@ async function wontdo(id2, reason) {
9038
9262
  const phase = item.currentPhase ?? 1;
9039
9263
  await appendComment(orm, item.id, reason, { phase, type: "summary" });
9040
9264
  }
9041
- console.log(chalk91.red(`Won't do item #${id2}: ${item.name}`));
9265
+ console.log(
9266
+ chalk91.red(`Won't do item ${formatItemId(item.id)}: ${item.name}`)
9267
+ );
9042
9268
  }
9043
9269
 
9044
9270
  // src/commands/backlog/registerStatusCommands.ts
@@ -9057,7 +9283,7 @@ function registerStatusCommands(cmd) {
9057
9283
 
9058
9284
  // src/commands/backlog/addSubtask.ts
9059
9285
  import chalk92 from "chalk";
9060
- async function addSubtask(id2, options2) {
9286
+ async function addSubtask(id, options2) {
9061
9287
  const title = options2.title?.trim();
9062
9288
  if (!title) {
9063
9289
  console.log(chalk92.red("A sub-task title is required (--title)."));
@@ -9073,7 +9299,7 @@ async function addSubtask(id2, options2) {
9073
9299
  process.exitCode = 1;
9074
9300
  return;
9075
9301
  }
9076
- const found = await findOneItem(id2);
9302
+ const found = await findOneItem(id);
9077
9303
  if (!found) {
9078
9304
  process.exitCode = 1;
9079
9305
  return;
@@ -9081,7 +9307,9 @@ async function addSubtask(id2, options2) {
9081
9307
  const { orm, item } = found;
9082
9308
  const description = options2.desc?.replaceAll(String.raw`\n`, "\n");
9083
9309
  await insertSubtask(orm, item.id, title, description);
9084
- console.log(chalk92.green(`Added sub-task to item #${id2}: ${title}`));
9310
+ console.log(
9311
+ chalk92.green(`Added sub-task to item ${formatItemId(item.id)}: ${title}`)
9312
+ );
9085
9313
  }
9086
9314
 
9087
9315
  // src/commands/backlog/editSubtask.ts
@@ -9089,13 +9317,13 @@ import chalk94 from "chalk";
9089
9317
 
9090
9318
  // src/commands/backlog/resolveSubtaskIndex.ts
9091
9319
  import chalk93 from "chalk";
9092
- function resolveSubtaskIndex(id2, index3, item) {
9320
+ function resolveSubtaskIndex(index3, item) {
9093
9321
  const position = Number.parseInt(index3, 10);
9094
9322
  const subtasks = item.subtasks ?? [];
9095
9323
  if (Number.isNaN(position) || position < 1 || position > subtasks.length) {
9096
9324
  console.log(
9097
9325
  chalk93.red(
9098
- `Item #${id2} has no sub-task ${index3}${subtasks.length > 0 ? ` (1-${subtasks.length})` : ""}.`
9326
+ `Item ${formatItemId(item.id)} has no sub-task ${index3}${subtasks.length > 0 ? ` (1-${subtasks.length})` : ""}.`
9099
9327
  )
9100
9328
  );
9101
9329
  process.exitCode = 1;
@@ -9105,25 +9333,25 @@ function resolveSubtaskIndex(id2, index3, item) {
9105
9333
  }
9106
9334
 
9107
9335
  // src/commands/backlog/findSubtask.ts
9108
- async function findSubtask(id2, index3) {
9109
- const found = await findOneItem(id2);
9336
+ async function findSubtask(id, index3) {
9337
+ const found = await findOneItem(id);
9110
9338
  if (!found) {
9111
9339
  process.exitCode = 1;
9112
9340
  return void 0;
9113
9341
  }
9114
- const idx = resolveSubtaskIndex(id2, index3, found.item);
9342
+ const idx = resolveSubtaskIndex(index3, found.item);
9115
9343
  if (idx === void 0) return void 0;
9116
9344
  return { orm: found.orm, item: found.item, idx };
9117
9345
  }
9118
9346
 
9119
9347
  // src/commands/backlog/updateSubtask.ts
9120
9348
  import { and as and9, eq as eq25 } from "drizzle-orm";
9121
- async function updateSubtask(orm, itemId, idx, fields) {
9349
+ async function updateSubtask(orm, itemId2, idx, fields) {
9122
9350
  const set = {};
9123
9351
  if (fields.title !== void 0) set.title = fields.title;
9124
9352
  if (fields.description !== void 0) set.description = fields.description;
9125
9353
  if (fields.status !== void 0) set.status = fields.status;
9126
- const [row] = await orm.update(itemSubtasks).set(set).where(and9(eq25(itemSubtasks.itemId, itemId), eq25(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
9354
+ const [row] = await orm.update(itemSubtasks).set(set).where(and9(eq25(itemSubtasks.itemId, itemId2), eq25(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
9127
9355
  return row?.title;
9128
9356
  }
9129
9357
 
@@ -9156,8 +9384,8 @@ function buildUpdate(options2) {
9156
9384
  }
9157
9385
  return fields;
9158
9386
  }
9159
- async function editSubtask(id2, index3, options2) {
9160
- const found = await findSubtask(id2, index3);
9387
+ async function editSubtask(id, index3, options2) {
9388
+ const found = await findSubtask(id, index3);
9161
9389
  if (!found) return;
9162
9390
  const fields = buildUpdate(options2);
9163
9391
  if (typeof fields === "string") {
@@ -9168,7 +9396,9 @@ async function editSubtask(id2, index3, options2) {
9168
9396
  const { orm, item, idx } = found;
9169
9397
  const title = await updateSubtask(orm, item.id, idx, fields);
9170
9398
  console.log(
9171
- chalk94.green(`Updated sub-task ${idx + 1} of item #${id2}: ${title}`)
9399
+ chalk94.green(
9400
+ `Updated sub-task ${idx + 1} of item ${formatItemId(item.id)}: ${title}`
9401
+ )
9172
9402
  );
9173
9403
  }
9174
9404
 
@@ -9177,34 +9407,36 @@ import chalk95 from "chalk";
9177
9407
 
9178
9408
  // src/commands/backlog/deleteSubtask.ts
9179
9409
  import { and as and10, asc as asc6, eq as eq26 } from "drizzle-orm";
9180
- async function deleteSubtask(orm, itemId, idx) {
9181
- const [row] = await orm.delete(itemSubtasks).where(and10(eq26(itemSubtasks.itemId, itemId), eq26(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
9410
+ async function deleteSubtask(orm, itemId2, idx) {
9411
+ const [row] = await orm.delete(itemSubtasks).where(and10(eq26(itemSubtasks.itemId, itemId2), eq26(itemSubtasks.idx, idx))).returning({ title: itemSubtasks.title });
9182
9412
  if (!row) return void 0;
9183
- const remaining = await orm.select({ idx: itemSubtasks.idx }).from(itemSubtasks).where(eq26(itemSubtasks.itemId, itemId)).orderBy(asc6(itemSubtasks.idx));
9413
+ const remaining = await orm.select({ idx: itemSubtasks.idx }).from(itemSubtasks).where(eq26(itemSubtasks.itemId, itemId2)).orderBy(asc6(itemSubtasks.idx));
9184
9414
  for (let i = 0; i < remaining.length; i++) {
9185
9415
  const oldIdx = remaining[i].idx;
9186
9416
  if (oldIdx === i) continue;
9187
9417
  await orm.update(itemSubtasks).set({ idx: i }).where(
9188
- and10(eq26(itemSubtasks.itemId, itemId), eq26(itemSubtasks.idx, oldIdx))
9418
+ and10(eq26(itemSubtasks.itemId, itemId2), eq26(itemSubtasks.idx, oldIdx))
9189
9419
  );
9190
9420
  }
9191
9421
  return row.title;
9192
9422
  }
9193
9423
 
9194
9424
  // src/commands/backlog/removeSubtask.ts
9195
- async function removeSubtask(id2, index3) {
9196
- const found = await findSubtask(id2, index3);
9425
+ async function removeSubtask(id, index3) {
9426
+ const found = await findSubtask(id, index3);
9197
9427
  if (!found) return;
9198
9428
  const { orm, item, idx } = found;
9199
9429
  const title = await deleteSubtask(orm, item.id, idx);
9200
9430
  console.log(
9201
- chalk95.green(`Removed sub-task ${idx + 1} of item #${id2}: ${title}`)
9431
+ chalk95.green(
9432
+ `Removed sub-task ${idx + 1} of item ${formatItemId(item.id)}: ${title}`
9433
+ )
9202
9434
  );
9203
9435
  }
9204
9436
 
9205
9437
  // src/commands/backlog/subtaskStatus.ts
9206
9438
  import chalk96 from "chalk";
9207
- async function subtaskStatus(id2, index3, status2) {
9439
+ async function subtaskStatus(id, index3, status2) {
9208
9440
  if (!validSubtaskStatuses.includes(status2)) {
9209
9441
  console.log(
9210
9442
  chalk96.red(
@@ -9214,7 +9446,7 @@ async function subtaskStatus(id2, index3, status2) {
9214
9446
  process.exitCode = 1;
9215
9447
  return;
9216
9448
  }
9217
- const found = await findSubtask(id2, index3);
9449
+ const found = await findSubtask(id, index3);
9218
9450
  if (!found) return;
9219
9451
  const { orm, item, idx } = found;
9220
9452
  const title = await updateSubtaskStatus(
@@ -9225,7 +9457,7 @@ async function subtaskStatus(id2, index3, status2) {
9225
9457
  );
9226
9458
  console.log(
9227
9459
  chalk96.green(
9228
- `Set sub-task ${idx + 1} of item #${id2} to ${status2}: ${title}`
9460
+ `Set sub-task ${idx + 1} of item ${formatItemId(item.id)} to ${status2}: ${title}`
9229
9461
  )
9230
9462
  );
9231
9463
  }
@@ -9259,13 +9491,13 @@ import { and as and12, asc as asc8, eq as eq28 } from "drizzle-orm";
9259
9491
 
9260
9492
  // src/commands/backlog/reindexPhases.ts
9261
9493
  import { and as and11, asc as asc7, count as count5, eq as eq27 } from "drizzle-orm";
9262
- async function reindexPhases(db, itemId) {
9263
- const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq27(planPhases.itemId, itemId)).orderBy(asc7(planPhases.idx));
9494
+ async function reindexPhases(db, itemId2) {
9495
+ const remaining = await db.select({ idx: planPhases.idx }).from(planPhases).where(eq27(planPhases.itemId, itemId2)).orderBy(asc7(planPhases.idx));
9264
9496
  for (let i = 0; i < remaining.length; i++) {
9265
9497
  const oldIdx = remaining[i].idx;
9266
9498
  if (oldIdx === i) continue;
9267
- await db.update(planTasks).set({ phaseIdx: i }).where(and11(eq27(planTasks.itemId, itemId), eq27(planTasks.phaseIdx, oldIdx)));
9268
- await db.update(planPhases).set({ idx: i }).where(and11(eq27(planPhases.itemId, itemId), eq27(planPhases.idx, oldIdx)));
9499
+ await db.update(planTasks).set({ phaseIdx: i }).where(and11(eq27(planTasks.itemId, itemId2), eq27(planTasks.phaseIdx, oldIdx)));
9500
+ await db.update(planPhases).set({ idx: i }).where(and11(eq27(planPhases.itemId, itemId2), eq27(planPhases.idx, oldIdx)));
9269
9501
  }
9270
9502
  }
9271
9503
  async function adjustCurrentPhase(db, item, removedIdx) {
@@ -9283,18 +9515,18 @@ async function adjustCurrentPhase(db, item, removedIdx) {
9283
9515
  }
9284
9516
 
9285
9517
  // src/commands/backlog/reorderPhaseRows.ts
9286
- async function reorderPhaseRows(orm, itemId, fromIdx, toIdx) {
9518
+ async function reorderPhaseRows(orm, itemId2, fromIdx, toIdx) {
9287
9519
  await orm.transaction(async (tx) => {
9288
- const [phaseRow] = await tx.select({ name: planPhases.name, manualChecks: planPhases.manualChecks }).from(planPhases).where(and12(eq28(planPhases.itemId, itemId), eq28(planPhases.idx, fromIdx)));
9289
- const tasks = await tx.select({ idx: planTasks.idx, task: planTasks.task }).from(planTasks).where(and12(eq28(planTasks.itemId, itemId), eq28(planTasks.phaseIdx, fromIdx))).orderBy(asc8(planTasks.idx));
9520
+ const [phaseRow] = await tx.select({ name: planPhases.name, manualChecks: planPhases.manualChecks }).from(planPhases).where(and12(eq28(planPhases.itemId, itemId2), eq28(planPhases.idx, fromIdx)));
9521
+ const tasks = await tx.select({ idx: planTasks.idx, task: planTasks.task }).from(planTasks).where(and12(eq28(planTasks.itemId, itemId2), eq28(planTasks.phaseIdx, fromIdx))).orderBy(asc8(planTasks.idx));
9290
9522
  await tx.delete(planTasks).where(
9291
- and12(eq28(planTasks.itemId, itemId), eq28(planTasks.phaseIdx, fromIdx))
9523
+ and12(eq28(planTasks.itemId, itemId2), eq28(planTasks.phaseIdx, fromIdx))
9292
9524
  );
9293
- await tx.delete(planPhases).where(and12(eq28(planPhases.itemId, itemId), eq28(planPhases.idx, fromIdx)));
9294
- await reindexPhases(tx, itemId);
9295
- await shiftPhasesUp(tx, itemId, toIdx);
9525
+ await tx.delete(planPhases).where(and12(eq28(planPhases.itemId, itemId2), eq28(planPhases.idx, fromIdx)));
9526
+ await reindexPhases(tx, itemId2);
9527
+ await shiftPhasesUp(tx, itemId2, toIdx);
9296
9528
  await tx.insert(planPhases).values({
9297
- itemId,
9529
+ itemId: itemId2,
9298
9530
  idx: toIdx,
9299
9531
  name: phaseRow.name,
9300
9532
  manualChecks: phaseRow.manualChecks
@@ -9302,7 +9534,7 @@ async function reorderPhaseRows(orm, itemId, fromIdx, toIdx) {
9302
9534
  if (tasks.length) {
9303
9535
  await tx.insert(planTasks).values(
9304
9536
  tasks.map((t) => ({
9305
- itemId,
9537
+ itemId: itemId2,
9306
9538
  phaseIdx: toIdx,
9307
9539
  idx: t.idx,
9308
9540
  task: t.task
@@ -9326,19 +9558,19 @@ function toIndex(value, phaseCount) {
9326
9558
  }
9327
9559
  return pos - 1;
9328
9560
  }
9329
- async function movePhase(id2, from, to) {
9330
- const found = await findOneItem(id2);
9561
+ async function movePhase(id, from, to) {
9562
+ const found = await findOneItem(id);
9331
9563
  if (!found) return;
9332
9564
  const { orm, item } = found;
9333
- const itemId = item.id;
9334
- const [row] = await orm.select({ cnt: count6() }).from(planPhases).where(eq29(planPhases.itemId, itemId));
9565
+ const itemId2 = item.id;
9566
+ const [row] = await orm.select({ cnt: count6() }).from(planPhases).where(eq29(planPhases.itemId, itemId2));
9335
9567
  const phaseCount = row?.cnt ?? 0;
9336
9568
  const fromIdx = toIndex(from, phaseCount);
9337
9569
  if (fromIdx === void 0) return;
9338
9570
  const toIdx = toIndex(to, phaseCount);
9339
9571
  if (toIdx === void 0) return;
9340
9572
  if (fromIdx !== toIdx) {
9341
- await reorderPhaseRows(orm, itemId, fromIdx, toIdx);
9573
+ await reorderPhaseRows(orm, itemId2, fromIdx, toIdx);
9342
9574
  }
9343
9575
  console.log(chalk97.green(`Moved phase ${from} to position ${to}.`));
9344
9576
  }
@@ -9348,26 +9580,26 @@ import chalk99 from "chalk";
9348
9580
 
9349
9581
  // src/commands/backlog/applyPhaseUpdate.ts
9350
9582
  import { and as and13, eq as eq30 } from "drizzle-orm";
9351
- async function applyPhaseUpdate(orm, itemId, phaseIdx, fields) {
9583
+ async function applyPhaseUpdate(orm, itemId2, phaseIdx, fields) {
9352
9584
  await orm.transaction(async (tx) => {
9353
9585
  if (fields.name) {
9354
9586
  await tx.update(planPhases).set({ name: fields.name }).where(
9355
- and13(eq30(planPhases.itemId, itemId), eq30(planPhases.idx, phaseIdx))
9587
+ and13(eq30(planPhases.itemId, itemId2), eq30(planPhases.idx, phaseIdx))
9356
9588
  );
9357
9589
  }
9358
9590
  if (fields.manualCheck) {
9359
9591
  await tx.update(planPhases).set({ manualChecks: JSON.stringify(fields.manualCheck) }).where(
9360
- and13(eq30(planPhases.itemId, itemId), eq30(planPhases.idx, phaseIdx))
9592
+ and13(eq30(planPhases.itemId, itemId2), eq30(planPhases.idx, phaseIdx))
9361
9593
  );
9362
9594
  }
9363
9595
  if (fields.task) {
9364
9596
  await tx.delete(planTasks).where(
9365
- and13(eq30(planTasks.itemId, itemId), eq30(planTasks.phaseIdx, phaseIdx))
9597
+ and13(eq30(planTasks.itemId, itemId2), eq30(planTasks.phaseIdx, phaseIdx))
9366
9598
  );
9367
9599
  if (fields.task.length) {
9368
9600
  await tx.insert(planTasks).values(
9369
9601
  fields.task.map((task, i) => ({
9370
- itemId,
9602
+ itemId: itemId2,
9371
9603
  phaseIdx,
9372
9604
  idx: i,
9373
9605
  task
@@ -9381,21 +9613,23 @@ async function applyPhaseUpdate(orm, itemId, phaseIdx, fields) {
9381
9613
  // src/commands/backlog/findPhase.ts
9382
9614
  import chalk98 from "chalk";
9383
9615
  import { and as and14, count as count7, eq as eq31 } from "drizzle-orm";
9384
- async function findPhase(id2, phase) {
9385
- const found = await findOneItem(id2);
9616
+ async function findPhase(id, phase) {
9617
+ const found = await findOneItem(id);
9386
9618
  if (!found) return void 0;
9387
9619
  const { orm, item } = found;
9388
- const itemId = item.id;
9620
+ const itemId2 = item.id;
9389
9621
  const phaseIdx = Number.parseInt(phase, 10) - 1;
9390
- const [row] = await orm.select({ cnt: count7() }).from(planPhases).where(and14(eq31(planPhases.itemId, itemId), eq31(planPhases.idx, phaseIdx)));
9622
+ const [row] = await orm.select({ cnt: count7() }).from(planPhases).where(and14(eq31(planPhases.itemId, itemId2), eq31(planPhases.idx, phaseIdx)));
9391
9623
  if (!row || row.cnt === 0) {
9392
9624
  console.log(
9393
- chalk98.red(`Phase ${phaseIdx + 1} not found on item #${itemId}.`)
9625
+ chalk98.red(
9626
+ `Phase ${phaseIdx + 1} not found on item ${formatItemId(itemId2)}.`
9627
+ )
9394
9628
  );
9395
9629
  process.exitCode = 1;
9396
9630
  return void 0;
9397
9631
  }
9398
- return { item, orm, itemId, phaseIdx };
9632
+ return { item, orm, itemId: itemId2, phaseIdx };
9399
9633
  }
9400
9634
 
9401
9635
  // src/commands/backlog/update/parseListIndex.ts
@@ -9493,11 +9727,11 @@ function resolveChecks(o, current) {
9493
9727
  CHECK_FLAGS
9494
9728
  );
9495
9729
  }
9496
- function buildFields(name, tasks, checks) {
9730
+ function buildFields(name, tasks, checks2) {
9497
9731
  const fields = {
9498
9732
  name,
9499
9733
  task: tasks.items,
9500
- manualCheck: checks.items
9734
+ manualCheck: checks2.items
9501
9735
  };
9502
9736
  if (!fields.name && !fields.task && !fields.manualCheck) {
9503
9737
  return {
@@ -9510,16 +9744,16 @@ function buildFields(name, tasks, checks) {
9510
9744
  function resolvePhaseFields(options2, current) {
9511
9745
  const tasks = resolveTasks(options2, current);
9512
9746
  if (!tasks.ok) return tasks;
9513
- const checks = resolveChecks(options2, current);
9514
- if (!checks.ok) return checks;
9515
- return buildFields(options2.name, tasks, checks);
9747
+ const checks2 = resolveChecks(options2, current);
9748
+ if (!checks2.ok) return checks2;
9749
+ return buildFields(options2.name, tasks, checks2);
9516
9750
  }
9517
9751
 
9518
9752
  // src/commands/backlog/updatePhase.ts
9519
- async function updatePhase(id2, phase, options2) {
9520
- const found = await findPhase(id2, phase);
9753
+ async function updatePhase(id, phase, options2) {
9754
+ const found = await findPhase(id, phase);
9521
9755
  if (!found) return;
9522
- const { item, orm, itemId, phaseIdx } = found;
9756
+ const { item, orm, itemId: itemId2, phaseIdx } = found;
9523
9757
  const resolved = resolvePhaseFields(options2, item.plan?.[phaseIdx]);
9524
9758
  if (!resolved.ok) {
9525
9759
  console.log(chalk99.red(resolved.error));
@@ -9527,7 +9761,7 @@ async function updatePhase(id2, phase, options2) {
9527
9761
  return;
9528
9762
  }
9529
9763
  const { name, task, manualCheck } = resolved.fields;
9530
- await applyPhaseUpdate(orm, itemId, phaseIdx, { name, task, manualCheck });
9764
+ await applyPhaseUpdate(orm, itemId2, phaseIdx, { name, task, manualCheck });
9531
9765
  const fields = [
9532
9766
  name && "name",
9533
9767
  task && "tasks",
@@ -9535,20 +9769,20 @@ async function updatePhase(id2, phase, options2) {
9535
9769
  ].filter(Boolean).join(", ");
9536
9770
  console.log(
9537
9771
  chalk99.green(
9538
- `Updated ${fields} on phase ${phaseIdx + 1} of item #${itemId}.`
9772
+ `Updated ${fields} on phase ${phaseIdx + 1} of item ${formatItemId(itemId2)}.`
9539
9773
  )
9540
9774
  );
9541
9775
  }
9542
9776
 
9543
9777
  // src/commands/backlog/registerUpdatePhaseCommand.ts
9544
- function collect(value, previous) {
9778
+ function collect2(value, previous) {
9545
9779
  return [...previous, value];
9546
9780
  }
9547
9781
  function registerUpdatePhaseCommand(cmd) {
9548
- cmd.command("update-phase <id> <phase>").description("Modify a plan phase on a backlog item").option("--name <name>", "New phase name").option("--task <task...>", "Replace tasks (repeatable)").option("--manual-check <check...>", "Replace manual checks (repeatable)").option("--add-task <text>", "Append one task (repeatable)", collect, []).option("--edit-task <n> <text...>", "Replace task n (1-based) in place").option("--remove-task <n>", "Remove task n (1-based)").option(
9782
+ cmd.command("update-phase <id> <phase>").description("Modify a plan phase on a backlog item").option("--name <name>", "New phase name").option("--task <task...>", "Replace tasks (repeatable)").option("--manual-check <check...>", "Replace manual checks (repeatable)").option("--add-task <text>", "Append one task (repeatable)", collect2, []).option("--edit-task <n> <text...>", "Replace task n (1-based) in place").option("--remove-task <n>", "Remove task n (1-based)").option(
9549
9783
  "--add-check <text>",
9550
9784
  "Append one manual check (repeatable)",
9551
- collect,
9785
+ collect2,
9552
9786
  []
9553
9787
  ).option(
9554
9788
  "--edit-check <n> <text...>",
@@ -9559,20 +9793,22 @@ function registerUpdatePhaseCommand(cmd) {
9559
9793
  // src/commands/backlog/removePhase.ts
9560
9794
  import chalk100 from "chalk";
9561
9795
  import { and as and15, eq as eq32 } from "drizzle-orm";
9562
- async function removePhase(id2, phase) {
9563
- const found = await findPhase(id2, phase);
9796
+ async function removePhase(id, phase) {
9797
+ const found = await findPhase(id, phase);
9564
9798
  if (!found) return;
9565
- const { item, orm, itemId, phaseIdx } = found;
9799
+ const { item, orm, itemId: itemId2, phaseIdx } = found;
9566
9800
  await orm.transaction(async (tx) => {
9567
9801
  await tx.delete(planTasks).where(
9568
- and15(eq32(planTasks.itemId, itemId), eq32(planTasks.phaseIdx, phaseIdx))
9802
+ and15(eq32(planTasks.itemId, itemId2), eq32(planTasks.phaseIdx, phaseIdx))
9569
9803
  );
9570
- await tx.delete(planPhases).where(and15(eq32(planPhases.itemId, itemId), eq32(planPhases.idx, phaseIdx)));
9571
- await reindexPhases(tx, itemId);
9804
+ await tx.delete(planPhases).where(and15(eq32(planPhases.itemId, itemId2), eq32(planPhases.idx, phaseIdx)));
9805
+ await reindexPhases(tx, itemId2);
9572
9806
  await adjustCurrentPhase(tx, item, phaseIdx);
9573
9807
  });
9574
9808
  console.log(
9575
- chalk100.green(`Removed phase ${phaseIdx + 1} from item #${itemId}.`)
9809
+ chalk100.green(
9810
+ `Removed phase ${phaseIdx + 1} from item ${formatItemId(itemId2)}.`
9811
+ )
9576
9812
  );
9577
9813
  }
9578
9814
 
@@ -9634,8 +9870,8 @@ function buildUpdateValues(options2) {
9634
9870
  }
9635
9871
 
9636
9872
  // src/commands/backlog/update/index.ts
9637
- async function update(id2, options2) {
9638
- const found = await findOneItem(id2);
9873
+ async function update(id, options2) {
9874
+ const found = await findOneItem(id);
9639
9875
  if (!found) return;
9640
9876
  let ac = options2.ac;
9641
9877
  if (hasAcMutations(options2)) {
@@ -9657,13 +9893,15 @@ async function update(id2, options2) {
9657
9893
  const built = buildUpdateValues({ ...options2, ac });
9658
9894
  if (!built) return;
9659
9895
  const { orm } = found;
9660
- const itemId = found.item.id;
9661
- await orm.update(items).set(built.set).where(eq33(items.id, itemId));
9662
- console.log(chalk102.green(`Updated ${built.fields} on item #${itemId}.`));
9896
+ const itemId2 = found.item.id;
9897
+ await orm.update(items).set(built.set).where(eq33(items.id, itemId2));
9898
+ console.log(
9899
+ chalk102.green(`Updated ${built.fields} on item ${formatItemId(itemId2)}.`)
9900
+ );
9663
9901
  }
9664
9902
 
9665
9903
  // src/commands/backlog/registerUpdateCommands.ts
9666
- function collect2(value, previous) {
9904
+ function collect3(value, previous) {
9667
9905
  return [...previous, value];
9668
9906
  }
9669
9907
  function registerUpdateCommands(cmd) {
@@ -9673,7 +9911,7 @@ function registerUpdateCommands(cmd) {
9673
9911
  ).option("--type <type>", "New type (story or bug)").option("--ac <criterion...>", "Replace acceptance criteria (repeatable)").option(
9674
9912
  "--add-ac <text>",
9675
9913
  "Append one acceptance criterion (repeatable)",
9676
- collect2,
9914
+ collect3,
9677
9915
  []
9678
9916
  ).option(
9679
9917
  "--edit-ac <n> <text...>",
@@ -9721,6 +9959,7 @@ function registerBacklog(program2) {
9721
9959
  for (const register of registrars) {
9722
9960
  register(cmd);
9723
9961
  }
9962
+ configHelp(cmd, backlogConfigHelp);
9724
9963
  }
9725
9964
 
9726
9965
  // src/commands/branch/validateSlug.ts
@@ -9769,19 +10008,27 @@ async function branch(slug, options2) {
9769
10008
 
9770
10009
  // src/commands/registerBranch.ts
9771
10010
  function registerBranch(program2) {
9772
- program2.command("branch <slug>").description(
10011
+ const branchCommand = program2.command("branch <slug>").description(
9773
10012
  "Create and switch to a branch off the fresh remote default branch"
9774
- ).option("--jira <key>", "Jira issue key to include in the branch name").addHelpText(
9775
- "after",
9776
- `
9777
- Branch name is assembled as [<prefix>/][<JIRA>-]<slug>, e.g. sw/BAD-671-add-login-form.
9778
-
9779
- Config:
9780
- assist config set branch.prefix sw # optional; prepends "<prefix>/" (omitted when unset)
9781
- assist config set branch.defaultBranch main # optional; overrides the live remote default branch`
9782
- ).action(
10013
+ ).option("--jira <key>", "Jira issue key to include in the branch name").action(
9783
10014
  (slug, options2) => branch(slug, options2)
9784
10015
  );
10016
+ configHelp(
10017
+ branchCommand,
10018
+ [
10019
+ {
10020
+ key: "branch.prefix",
10021
+ setter: "assist config set branch.prefix sw",
10022
+ note: 'optional; prepends "<prefix>/" (omitted when unset)'
10023
+ },
10024
+ {
10025
+ key: "branch.defaultBranch",
10026
+ setter: "assist config set branch.defaultBranch main",
10027
+ note: "optional; overrides the live remote default branch"
10028
+ }
10029
+ ],
10030
+ "Branch name is assembled as [<prefix>/][<JIRA>-]<slug>, e.g. sw/BAD-671-add-login-form."
10031
+ );
9785
10032
  }
9786
10033
 
9787
10034
  // src/commands/cliHook/index.ts
@@ -10834,6 +11081,13 @@ function denyRemove(pattern2, options2) {
10834
11081
  // src/commands/registerDeny.ts
10835
11082
  function registerDeny(parent) {
10836
11083
  const denyCommand = parent.command("deny").description("Manage command deny rules").action(denyList);
11084
+ configHelp(denyCommand, [
11085
+ {
11086
+ key: "deny",
11087
+ setter: "assist deny add <pattern> <message>",
11088
+ note: "command patterns blocked with a correction message"
11089
+ }
11090
+ ]);
10837
11091
  denyCommand.command("add").description("Add a deny rule for a command pattern").argument("<pattern>", "Command prefix to deny").argument("<message>", "Correction message shown to the agent").option("-g, --global", "Write to global ~/.assist.yml").action(denyAdd);
10838
11092
  denyCommand.command("remove").description("Remove a deny rule by pattern").argument("<pattern>", "Command prefix to remove").option("-g, --global", "Remove from global ~/.assist.yml").action(denyRemove);
10839
11093
  denyCommand.command("list").description("List all deny rules").action(denyList);
@@ -10844,6 +11098,13 @@ function registerCliHook(program2) {
10844
11098
  const cmd = program2.command("cli-hook").description("PreToolUse hook for auto-approving read-only CLI commands").action(() => {
10845
11099
  cliHook();
10846
11100
  });
11101
+ configHelp(cmd, [
11102
+ {
11103
+ key: "cliReadVerbs",
11104
+ setter: 'assist config set cliReadVerbs.git "status"',
11105
+ note: "extra per-CLI verbs treated as read-only for auto-approval"
11106
+ }
11107
+ ]);
10847
11108
  cmd.command("check <command>").description("Check whether a command would be auto-approved").option("--tool <tool>", "Tool name to check against", "Bash").action((command, options2) => {
10848
11109
  cliHookCheck(command, options2.tool);
10849
11110
  });
@@ -11589,6 +11850,15 @@ async function analyze(pattern2) {
11589
11850
  await maintainability(searchPattern);
11590
11851
  }
11591
11852
 
11853
+ // src/commands/complexity/complexityConfigHelp.ts
11854
+ var complexityConfigHelp = [
11855
+ {
11856
+ key: "complexity.ignore",
11857
+ setter: 'assist config set complexity.ignore "**/*test.ts*"',
11858
+ note: "globs excluded from maintainability (default: **/*test.ts*)"
11859
+ }
11860
+ ];
11861
+
11592
11862
  // src/commands/registerComplexity.ts
11593
11863
  function registerComplexity(program2) {
11594
11864
  const complexityCommand = program2.command("complexity").description("Analyze TypeScript code complexity metrics").argument("[pattern]").action((pattern2) => {
@@ -11611,6 +11881,7 @@ function registerComplexity(program2) {
11611
11881
  []
11612
11882
  ).action(maintainability);
11613
11883
  complexityCommand.command("sloc [pattern]").description("Count source lines of code per file").option("--threshold <number>", "Max lines threshold", Number.parseInt).action(sloc);
11884
+ configHelp(complexityCommand, complexityConfigHelp);
11614
11885
  }
11615
11886
 
11616
11887
  // src/commands/config/index.ts
@@ -12312,6 +12583,25 @@ function version() {
12312
12583
  console.log(`${chalk127.bold("next:")} ${nextVersion ?? chalk127.dim("none")}`);
12313
12584
  }
12314
12585
 
12586
+ // src/commands/devlog/devlogConfigHelp.ts
12587
+ var devlogConfigHelp = [
12588
+ {
12589
+ key: "devlog.name",
12590
+ setter: "assist config set devlog.name my-repo",
12591
+ note: "override the repo name reported in devlog entries"
12592
+ },
12593
+ {
12594
+ key: "devlog.ignore",
12595
+ setter: 'assist config set devlog.ignore "**/*.lock"',
12596
+ note: "globs excluded when grouping commits"
12597
+ },
12598
+ {
12599
+ key: "devlog.skip",
12600
+ setter: "assist devlog skip 2026-07-10",
12601
+ note: "dates (per repo) omitted from devlog output"
12602
+ }
12603
+ ];
12604
+
12315
12605
  // src/commands/registerDevlog.ts
12316
12606
  function registerDevlog(program2) {
12317
12607
  const devlogCommand = program2.command("devlog").description("Development log utilities");
@@ -12328,6 +12618,7 @@ function registerDevlog(program2) {
12328
12618
  "Only show repos pushed within N days (default: 30)",
12329
12619
  Number.parseInt
12330
12620
  ).option("--all", "Show all non-archived repos regardless of push date").action(repos);
12621
+ configHelp(devlogCommand, devlogConfigHelp);
12331
12622
  }
12332
12623
 
12333
12624
  // src/commands/dotnet/checkBuildLocks.ts
@@ -12953,6 +13244,13 @@ function registerDotnet(program2) {
12953
13244
  cmd.command("check-locks").description("Check if build output files are locked by a debugger").action(checkBuildLocksCommand);
12954
13245
  cmd.command("deps").description("Show .csproj project dependency tree and solution membership").argument("<csproj>", "Path to a .csproj file").option("--json", "Output as JSON").action(deps);
12955
13246
  cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
13247
+ configHelp(cmd, [
13248
+ {
13249
+ key: "dotnet.inspect.suppress",
13250
+ setter: "assist config set dotnet.inspect.suppress CSharpWarnings::CS0168",
13251
+ note: "inspection issue-type IDs suppressed by default"
13252
+ }
13253
+ ]);
12956
13254
  }
12957
13255
 
12958
13256
  // src/commands/editHook/index.ts
@@ -13546,12 +13844,12 @@ async function printPendingHandovers() {
13546
13844
 
13547
13845
  // src/commands/handover/recallHandover.ts
13548
13846
  import { and as and18, desc as desc5, eq as eq36, isNull as isNull3 } from "drizzle-orm";
13549
- async function recallHandover(orm, origin, id2) {
13847
+ async function recallHandover(orm, origin, id) {
13550
13848
  const [row] = await orm.select().from(handovers).where(
13551
13849
  and18(
13552
13850
  eq36(handovers.origin, origin),
13553
13851
  isNull3(handovers.recalledAt),
13554
- ...id2 === void 0 ? [] : [eq36(handovers.id, id2)]
13852
+ ...id === void 0 ? [] : [eq36(handovers.id, id)]
13555
13853
  )
13556
13854
  ).orderBy(desc5(handovers.createdAt), desc5(handovers.id)).limit(1);
13557
13855
  if (!row) return void 0;
@@ -13560,12 +13858,12 @@ async function recallHandover(orm, origin, id2) {
13560
13858
  }
13561
13859
 
13562
13860
  // src/commands/handover/recallAndPrint.ts
13563
- async function recallAndPrint(id2) {
13861
+ async function recallAndPrint(id) {
13564
13862
  const orm = await getDb();
13565
13863
  const content = await recallHandover(
13566
13864
  orm,
13567
13865
  getCurrentOrigin(process.cwd()),
13568
- id2
13866
+ id
13569
13867
  );
13570
13868
  if (content !== void 0) console.log(content);
13571
13869
  }
@@ -13595,7 +13893,7 @@ function registerHandover(program2) {
13595
13893
  cmd.command("recall").argument("[id]", "Id of a specific handover to recall").description(
13596
13894
  "Print an unrecalled handover for this repo and mark it recalled (most recent by default, or the given id)"
13597
13895
  ).action(
13598
- (id2) => recallAndPrint(id2 === void 0 ? void 0 : Number(id2))
13896
+ (id) => recallAndPrint(id === void 0 ? void 0 : Number(id))
13599
13897
  );
13600
13898
  cmd.command("load").description(
13601
13899
  "SessionStart hook: migrate any disk handovers, then advise how many unrecalled handovers exist for this repo"
@@ -13770,6 +14068,13 @@ function registerJira(program2) {
13770
14068
  jiraCommand.command("auth").description("Authenticate with Jira via API token").action(() => jiraAuth());
13771
14069
  jiraCommand.command("ac <issue-key>").description("Print acceptance criteria for a Jira issue").action((issueKey) => acceptanceCriteria(issueKey));
13772
14070
  jiraCommand.command("view <issue-key>").description("Print the title and description of a Jira issue").action((issueKey) => viewIssue(issueKey));
14071
+ configHelp(jiraCommand, [
14072
+ {
14073
+ key: "jira.acField",
14074
+ setter: "assist config set jira.acField customfield_11937",
14075
+ note: "custom field holding acceptance criteria (default: customfield_11937)"
14076
+ }
14077
+ ]);
13773
14078
  }
13774
14079
 
13775
14080
  // src/commands/reviewComments.ts
@@ -13798,7 +14103,7 @@ async function reviewComments(number) {
13798
14103
  var RESUME_SESSION_FLAG = "Resume an interrupted Claude session (used by the sessions daemon on restart)";
13799
14104
  function registerNext(program2) {
13800
14105
  program2.command("next").argument("[id]", "Backlog item ID to run first").description("Alias for backlog next").option("--once", "Exit after the first completed item run").action(
13801
- (id2, opts) => next({ allowEdits: true, once: opts.once }, id2)
14106
+ (id, opts) => next({ allowEdits: true, once: opts.once }, id)
13802
14107
  );
13803
14108
  }
13804
14109
  function registerDescriptionLaunch(program2, name, slashCommand, description, alias) {
@@ -13819,7 +14124,7 @@ function registerReviewComments(program2) {
13819
14124
  }
13820
14125
  function registerRefine(program2) {
13821
14126
  program2.command("refine").argument("[id]", "Backlog item ID").description("Launch Claude in /refine mode to refine a backlog item").option("--once", "Exit when the initial task completes").option("--resume-session <id>", RESUME_SESSION_FLAG).action(
13822
- (id2, opts) => refine(id2, { once: opts.once, resumeSessionId: opts.resumeSession })
14127
+ (id, opts) => refine(id, { once: opts.once, resumeSessionId: opts.resumeSession })
13823
14128
  );
13824
14129
  }
13825
14130
  function registerLaunch(program2) {
@@ -13957,6 +14262,13 @@ function registerMermaid(program2) {
13957
14262
  ).action(
13958
14263
  (file, options2) => mermaidExport(file, options2)
13959
14264
  );
14265
+ configHelp(cmd, [
14266
+ {
14267
+ key: "mermaid.krokiUrl",
14268
+ setter: "assist config set mermaid.krokiUrl https://kroki.io",
14269
+ note: "Kroki server used to render diagrams (default: https://kroki.io)"
14270
+ }
14271
+ ]);
13960
14272
  }
13961
14273
 
13962
14274
  // src/commands/netcap/netcap.ts
@@ -14190,8 +14502,8 @@ function parseRscRows(flight) {
14190
14502
  }
14191
14503
  function makeRscResolver(rows) {
14192
14504
  return (ref) => {
14193
- const [id2, ...path58] = ref.slice(1).replace(/^[L@]/, "").split(":");
14194
- let v = rows[id2];
14505
+ const [id, ...path58] = ref.slice(1).replace(/^[L@]/, "").split(":");
14506
+ let v = rows[id];
14195
14507
  for (const key of path58) {
14196
14508
  if (v == null || typeof v !== "object") return void 0;
14197
14509
  v = v[key];
@@ -14280,9 +14592,9 @@ function activityPermalink(urn) {
14280
14592
  // src/commands/netcap/activityUrnDate.ts
14281
14593
  function activityUrnDate(urn) {
14282
14594
  if (!urn) return void 0;
14283
- const id2 = urn.split(":").pop();
14284
- if (!id2 || !/^\d+$/.test(id2)) return void 0;
14285
- return new Date(Number(BigInt(id2) >> 22n)).toISOString();
14595
+ const id = urn.split(":").pop();
14596
+ if (!id || !/^\d+$/.test(id)) return void 0;
14597
+ return new Date(Number(BigInt(id) >> 22n)).toISOString();
14286
14598
  }
14287
14599
 
14288
14600
  // src/commands/netcap/dedupeLinks.ts
@@ -14379,7 +14691,7 @@ function findAuthorSlug(flight) {
14379
14691
  }
14380
14692
  function findCommentaryRows(rows) {
14381
14693
  return Object.keys(rows).filter(
14382
- (id2) => /"componentkey":"feed-commentary_/.test(JSON.stringify(rows[id2]))
14694
+ (id) => /"componentkey":"feed-commentary_/.test(JSON.stringify(rows[id]))
14383
14695
  );
14384
14696
  }
14385
14697
  function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
@@ -14387,7 +14699,7 @@ function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
14387
14699
  const resolve18 = makeRscResolver(rows);
14388
14700
  const mentionMap = buildMentionMap(rows, resolve18);
14389
14701
  const posts = [];
14390
- for (const id2 of findCommentaryRows(rows)) {
14702
+ for (const id of findCommentaryRows(rows)) {
14391
14703
  const raw = {
14392
14704
  text: [],
14393
14705
  hashtags: [],
@@ -14395,7 +14707,7 @@ function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
14395
14707
  links: [],
14396
14708
  related: []
14397
14709
  };
14398
- walkPostRow(rows[id2], resolve18, raw);
14710
+ walkPostRow(rows[id], resolve18, raw);
14399
14711
  const post = buildPost(raw, mentionMap, author);
14400
14712
  if (post) posts.push(post);
14401
14713
  }
@@ -14827,8 +15139,8 @@ function assertThreadCreated(stdout) {
14827
15139
  } catch {
14828
15140
  throw new Error(`GitHub returned an unparseable response: ${stdout}`);
14829
15141
  }
14830
- const id2 = parsed.data?.addPullRequestReviewThread?.thread?.id;
14831
- if (typeof id2 !== "string" || id2.length === 0) {
15142
+ const id = parsed.data?.addPullRequestReviewThread?.thread?.id;
15143
+ if (typeof id !== "string" || id.length === 0) {
14832
15144
  throw new Error(
14833
15145
  "GitHub did not create a review thread (no thread id returned); the line is likely outside the PR diff."
14834
15146
  );
@@ -14917,9 +15229,9 @@ function parsePrBody(body) {
14917
15229
  return sections;
14918
15230
  }
14919
15231
  function serializePrBody(sections) {
14920
- return sections.map((section2) => `## ${section2.heading}
15232
+ return sections.map((section3) => `## ${section3.heading}
14921
15233
 
14922
- ${section2.content}`).join("\n\n");
15234
+ ${section3.content}`).join("\n\n");
14923
15235
  }
14924
15236
 
14925
15237
  // src/commands/prs/editPrBody.ts
@@ -14967,11 +15279,11 @@ function countSentences(paragraph) {
14967
15279
  }
14968
15280
  function splitParagraphs(body) {
14969
15281
  const paragraphs = [];
14970
- let section2 = "(intro)";
15282
+ let section3 = "(intro)";
14971
15283
  let lines = [];
14972
15284
  const flush = () => {
14973
15285
  if (lines.length > 0) {
14974
- paragraphs.push({ section: section2, lines });
15286
+ paragraphs.push({ section: section3, lines });
14975
15287
  lines = [];
14976
15288
  }
14977
15289
  };
@@ -14979,7 +15291,7 @@ function splitParagraphs(body) {
14979
15291
  const heading = line.match(/^#{1,6}\s+(.*)$/);
14980
15292
  if (heading) {
14981
15293
  flush();
14982
- section2 = heading[1].trim();
15294
+ section3 = heading[1].trim();
14983
15295
  } else if (line.trim() === "") {
14984
15296
  flush();
14985
15297
  } else {
@@ -15639,8 +15951,22 @@ function wontfix(commentId, reason) {
15639
15951
  }
15640
15952
  }
15641
15953
 
15954
+ // src/commands/prs/prsConfigHelp.ts
15955
+ var prsConfigHelp = [
15956
+ {
15957
+ key: "prs.slack",
15958
+ setter: 'assist config set prs.slack "#pull-requests"',
15959
+ note: "Slack channel PRs are announced to (used by /prs-slack)"
15960
+ },
15961
+ {
15962
+ key: "prs.required",
15963
+ setter: "assist config set prs.required true",
15964
+ note: "require a branch when running a backlog item"
15965
+ }
15966
+ ];
15967
+
15642
15968
  // src/commands/registerPrsEdit.ts
15643
- function collect3(value, previous) {
15969
+ function collect4(value, previous) {
15644
15970
  return previous.concat([value]);
15645
15971
  }
15646
15972
  function registerPrsEdit(prsCommand) {
@@ -15649,13 +15975,13 @@ function registerPrsEdit(prsCommand) {
15649
15975
  ).option("-t, --title <title>", "New title for the pull request").option("--what <what>", "Replace the ## What section").option("--why <why>", "Replace the ## Why section").option("--how <how>", "Replace the ## How section").option(
15650
15976
  "--resolves <key>",
15651
15977
  "Jira issue key resolved by this PR, appended to ## Why (repeatable)",
15652
- collect3,
15978
+ collect4,
15653
15979
  []
15654
15980
  ).action(edit);
15655
15981
  }
15656
15982
 
15657
15983
  // src/commands/registerPrsRaise.ts
15658
- function collect4(value, previous) {
15984
+ function collect5(value, previous) {
15659
15985
  return previous.concat([value]);
15660
15986
  }
15661
15987
  function registerPrsRaise(prsCommand) {
@@ -15664,20 +15990,20 @@ function registerPrsRaise(prsCommand) {
15664
15990
  ).option("-t, --title <title>", "Title for the pull request").option("--what <what>", "What the change does (## What section)").option("--why <why>", "Why the change is needed (## Why section)").option("--how <how>", "How the change works (optional ## How section)").option(
15665
15991
  "--resolves <key>",
15666
15992
  "Jira issue key resolved by this PR, appended to ## Why (repeatable)",
15667
- collect4,
15993
+ collect5,
15668
15994
  []
15669
15995
  ).option(
15670
15996
  "--force",
15671
15997
  "Overwrite the title and body of an existing pull request"
15672
- ).option("-B, --base <branch>", "Branch into which the pull request merges").option("-H, --head <branch>", "Branch that contains the commits").option("-d, --draft", "Mark the pull request as a draft").option("-w, --web", "Open the browser to create the pull request").option("-l, --label <label>", "Add a label (repeatable)", collect4, []).option(
15998
+ ).option("-B, --base <branch>", "Branch into which the pull request merges").option("-H, --head <branch>", "Branch that contains the commits").option("-d, --draft", "Mark the pull request as a draft").option("-w, --web", "Open the browser to create the pull request").option("-l, --label <label>", "Add a label (repeatable)", collect5, []).option(
15673
15999
  "-a, --assignee <login>",
15674
16000
  "Assign a person by login (repeatable)",
15675
- collect4,
16001
+ collect5,
15676
16002
  []
15677
16003
  ).option(
15678
16004
  "-r, --reviewer <handle>",
15679
16005
  "Request a review (repeatable)",
15680
- collect4,
16006
+ collect5,
15681
16007
  []
15682
16008
  ).option("-m, --milestone <name>", "Add the pull request to a milestone").action(raise);
15683
16009
  }
@@ -15702,6 +16028,7 @@ function registerPrs(program2) {
15702
16028
  prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path58, line, body) => {
15703
16029
  comment2(path58, Number.parseInt(line, 10), body);
15704
16030
  });
16031
+ configHelp(prsCommand, prsConfigHelp);
15705
16032
  }
15706
16033
 
15707
16034
  // src/commands/ravendb/ravendbAuth.ts
@@ -15797,9 +16124,9 @@ function searchItems(search2) {
15797
16124
  const lower = search2.toLowerCase();
15798
16125
  return items2.filter((i) => i.title.toLowerCase().includes(lower));
15799
16126
  }
15800
- function getItemFields(itemId) {
16127
+ function getItemFields(itemId2) {
15801
16128
  try {
15802
- const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
16129
+ const item = JSON.parse(opExec(`item get "${itemId2}" --format=json`));
15803
16130
  return item.fields.filter((f) => f.reference && f.label);
15804
16131
  } catch {
15805
16132
  console.error(chalk154.red("Failed to get item details from 1Password."));
@@ -15824,11 +16151,11 @@ async function selectOpSecret(searchTerm) {
15824
16151
  console.error(chalk155.red(`No items found matching "${search2}".`));
15825
16152
  process.exit(1);
15826
16153
  }
15827
- const itemId = await selectOne(
16154
+ const itemId2 = await selectOne(
15828
16155
  "Select item:",
15829
16156
  items2.map((i) => ({ name: `${i.title} (${i.vault.name})`, value: i.id }))
15830
16157
  );
15831
- const fields = getItemFields(itemId);
16158
+ const fields = getItemFields(itemId2);
15832
16159
  if (fields.length === 0) {
15833
16160
  console.error(chalk155.red("No fields with references found on this item."));
15834
16161
  process.exit(1);
@@ -16036,6 +16363,20 @@ async function ravendbCollections(connectionName) {
16036
16363
  }
16037
16364
  }
16038
16365
 
16366
+ // src/commands/ravendb/ravendbConfigHelp.ts
16367
+ var ravendbConfigHelp = [
16368
+ {
16369
+ key: "ravendb.connections",
16370
+ setter: "assist ravendb auth add",
16371
+ note: "named RavenDB connections (add/list/remove via ravendb auth)"
16372
+ },
16373
+ {
16374
+ key: "ravendb.defaultConnection",
16375
+ setter: "assist ravendb set-connection <name>",
16376
+ note: "connection used when none is passed"
16377
+ }
16378
+ ];
16379
+
16039
16380
  // src/commands/ravendb/ravendbQuery.ts
16040
16381
  import chalk164 from "chalk";
16041
16382
 
@@ -16124,6 +16465,7 @@ function registerRavendb(program2) {
16124
16465
  (connection, collection, options2) => ravendbQuery(connection, collection, options2)
16125
16466
  );
16126
16467
  cmd.command("collections [connection]").description("List collections in a RavenDB database").action((connection) => ravendbCollections(connection));
16468
+ configHelp(cmd, ravendbConfigHelp);
16127
16469
  }
16128
16470
 
16129
16471
  // src/commands/refactor/check/index.ts
@@ -16369,9 +16711,9 @@ function addImportPreservingSuppressions(sourceFile, structure) {
16369
16711
  import { SyntaxKind as SyntaxKind3 } from "ts-morph";
16370
16712
  function collectReferencedNames(sourceFile) {
16371
16713
  const names = /* @__PURE__ */ new Set();
16372
- for (const id2 of sourceFile.getDescendantsOfKind(SyntaxKind3.Identifier)) {
16373
- if (id2.getFirstAncestorByKind(SyntaxKind3.ImportDeclaration)) continue;
16374
- names.add(id2.getText());
16714
+ for (const id of sourceFile.getDescendantsOfKind(SyntaxKind3.Identifier)) {
16715
+ if (id.getFirstAncestorByKind(SyntaxKind3.ImportDeclaration)) continue;
16716
+ names.add(id.getText());
16375
16717
  }
16376
16718
  return names;
16377
16719
  }
@@ -16422,7 +16764,7 @@ function updateImporters(functionName, sourceFile, importers) {
16422
16764
 
16423
16765
  // src/commands/refactor/extract/applyExtraction.ts
16424
16766
  function isNameReferencedInSource(sourceFile, name) {
16425
- return sourceFile.getDescendantsOfKind(SyntaxKind4.Identifier).some((id2) => id2.getText() === name);
16767
+ return sourceFile.getDescendantsOfKind(SyntaxKind4.Identifier).some((id) => id.getText() === name);
16426
16768
  }
16427
16769
  async function applyExtraction(functionName, sourceFile, destPath, plan2, project) {
16428
16770
  project.createSourceFile(destPath, plan2.destContent, { overwrite: false });
@@ -16506,8 +16848,8 @@ function collectPrivateFunctions(target, fnMap) {
16506
16848
  import { SyntaxKind as SyntaxKind6 } from "ts-morph";
16507
16849
  function getReferencedIdentifiers(fn) {
16508
16850
  const names = /* @__PURE__ */ new Set();
16509
- for (const id2 of fn.getDescendantsOfKind(SyntaxKind6.Identifier)) {
16510
- names.add(id2.getText());
16851
+ for (const id of fn.getDescendantsOfKind(SyntaxKind6.Identifier)) {
16852
+ names.add(id.getText());
16511
16853
  }
16512
16854
  return names;
16513
16855
  }
@@ -16675,8 +17017,8 @@ function matchImport(importDecl, neededNames) {
16675
17017
  function getReferencedNames(nodes) {
16676
17018
  const names = /* @__PURE__ */ new Set();
16677
17019
  for (const node of nodes) {
16678
- for (const id2 of node.getDescendantsOfKind(SyntaxKind12.Identifier)) {
16679
- names.add(id2.getText());
17020
+ for (const id of node.getDescendantsOfKind(SyntaxKind12.Identifier)) {
17021
+ names.add(id.getText());
16680
17022
  }
16681
17023
  }
16682
17024
  return names;
@@ -16866,9 +17208,9 @@ function isInsideExtractedFunction(node, extracted) {
16866
17208
  }
16867
17209
  function sourceReferencesName(sourceFile, functionName, extractedNames) {
16868
17210
  const extracted = new Set(extractedNames);
16869
- for (const id2 of sourceFile.getDescendantsOfKind(SyntaxKind13.Identifier)) {
16870
- if (id2.getText() !== functionName) continue;
16871
- const parent = id2.getParent();
17211
+ for (const id of sourceFile.getDescendantsOfKind(SyntaxKind13.Identifier)) {
17212
+ if (id.getText() !== functionName) continue;
17213
+ const parent = id.getParent();
16872
17214
  if (!parent || DECLARATION_KINDS.has(parent.getKind())) continue;
16873
17215
  if (!isInsideExtractedFunction(parent, extracted)) return true;
16874
17216
  }
@@ -16908,13 +17250,13 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
16908
17250
  // src/commands/refactor/extract/displayPlan.ts
16909
17251
  import path33 from "path";
16910
17252
  import chalk166 from "chalk";
16911
- function section(title) {
17253
+ function section2(title) {
16912
17254
  return `
16913
17255
  ${chalk166.cyan(title)}`;
16914
17256
  }
16915
17257
  function displayImporters(plan2, cwd) {
16916
17258
  if (plan2.importersToUpdate.length === 0) return;
16917
- console.log(section("Update importers:"));
17259
+ console.log(section2("Update importers:"));
16918
17260
  for (const imp of plan2.importersToUpdate) {
16919
17261
  const rel = path33.relative(cwd, imp.file.getFilePath());
16920
17262
  console.log(` ${chalk166.dim(rel)}: \u2192 import from "${imp.relPath}"`);
@@ -16928,18 +17270,18 @@ function displayPlan(functionName, relDest, plan2, cwd) {
16928
17270
  console.log(` ${name}`);
16929
17271
  }
16930
17272
  if (plan2.imports.length > 0) {
16931
- console.log(section("Imports to copy:"));
17273
+ console.log(section2("Imports to copy:"));
16932
17274
  for (const imp of plan2.imports) {
16933
17275
  console.log(` ${formatImportLine(imp)}`);
16934
17276
  }
16935
17277
  }
16936
17278
  if (plan2.exportedDeps.length > 0) {
16937
- console.log(section("New imports from source:"));
17279
+ console.log(section2("New imports from source:"));
16938
17280
  console.log(
16939
17281
  ` import { ${plan2.exportedDeps.join(", ")} } from "${plan2.sourceRelPath}";`
16940
17282
  );
16941
17283
  }
16942
- console.log(section("Source file changes:"));
17284
+ console.log(section2("Source file changes:"));
16943
17285
  console.log(` Remove: ${plan2.extractedNames.join(", ")}`);
16944
17286
  if (plan2.sourceNeedsReimport) {
16945
17287
  console.log(
@@ -16948,7 +17290,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
16948
17290
  }
16949
17291
  displayImporters(plan2, cwd);
16950
17292
  if (plan2.barrel) {
16951
- console.log(section("Barrel export:"));
17293
+ console.log(section2("Barrel export:"));
16952
17294
  console.log(
16953
17295
  ` Add: export { ${functionName} } from "${plan2.barrelRelPath}";`
16954
17296
  );
@@ -17346,8 +17688,8 @@ function isDeclaration(identifier) {
17346
17688
  return parent !== void 0 && declarationKinds.includes(parent.getKind());
17347
17689
  }
17348
17690
  function findSymbol(sourceFile, symbolName) {
17349
- for (const id2 of sourceFile.getDescendantsOfKind(SyntaxKind14.Identifier)) {
17350
- if (id2.getText() === symbolName && isDeclaration(id2)) return id2;
17691
+ for (const id of sourceFile.getDescendantsOfKind(SyntaxKind14.Identifier)) {
17692
+ if (id.getText() === symbolName && isDeclaration(id)) return id;
17351
17693
  }
17352
17694
  return void 0;
17353
17695
  }
@@ -17717,6 +18059,15 @@ async function restructure(pattern2, options2 = {}) {
17717
18059
  }
17718
18060
  }
17719
18061
 
18062
+ // src/commands/refactor/refactorConfigHelp.ts
18063
+ var refactorConfigHelp = [
18064
+ {
18065
+ key: "restructure.ignore",
18066
+ setter: 'assist config set restructure.ignore "src/generated/**"',
18067
+ note: "globs excluded from restructure coupling analysis"
18068
+ }
18069
+ ];
18070
+
17720
18071
  // src/commands/registerRefactor.ts
17721
18072
  function registerCheck(parent) {
17722
18073
  parent.command("check [pattern]").description("Check for files that exceed the maximum line count").option("--modified", "Check only staged and unstaged files").option("--staged", "Check only staged files").option("--unstaged", "Check only unstaged files").option(
@@ -17733,13 +18084,14 @@ function registerRename(parent) {
17733
18084
  ).option("--apply", "Execute the rename (default: dry-run)").action(renameSymbol);
17734
18085
  }
17735
18086
  function registerRestructure(parent) {
17736
- parent.command("restructure [pattern]").description(
18087
+ const restructureCommand = parent.command("restructure [pattern]").description(
17737
18088
  "Analyze import graph and restructure tightly-coupled files into nested directories"
17738
18089
  ).option("--apply", "Execute the restructuring (default: dry-run)").option(
17739
18090
  "--max-depth <number>",
17740
18091
  "Maximum nesting iterations (default: 3)",
17741
18092
  Number.parseInt
17742
18093
  ).action(restructure);
18094
+ configHelp(restructureCommand, refactorConfigHelp);
17743
18095
  }
17744
18096
  function registerRefactor(program2) {
17745
18097
  const refactorCommand = program2.command("refactor").description("Run refactoring checks for code quality");
@@ -19554,6 +19906,20 @@ var seqAuth = createConnectionAuth({
19554
19906
  onFirst: (c) => setDefaultConnection(c.name)
19555
19907
  });
19556
19908
 
19909
+ // src/commands/seq/seqConfigHelp.ts
19910
+ var seqConfigHelp = [
19911
+ {
19912
+ key: "seq.connections",
19913
+ setter: "assist seq auth add",
19914
+ note: "named Seq connections (add/list/remove via seq auth)"
19915
+ },
19916
+ {
19917
+ key: "seq.defaultConnection",
19918
+ setter: "assist seq set-connection <name>",
19919
+ note: "connection used when none is passed"
19920
+ }
19921
+ ];
19922
+
19557
19923
  // src/commands/seq/seqQuery.ts
19558
19924
  import chalk184 from "chalk";
19559
19925
 
@@ -19823,17 +20189,18 @@ function registerSeq(program2) {
19823
20189
  "--to <date>",
19824
20190
  "End of query window (UTC date or relative e.g. 5m, 1h, 2d)"
19825
20191
  ).option("--json", "Output raw JSON").action((filter, options2) => seqQuery(filter, options2));
20192
+ configHelp(cmd, seqConfigHelp);
19826
20193
  }
19827
20194
 
19828
20195
  // src/commands/registerSignal.ts
19829
20196
  function registerSignal(program2) {
19830
20197
  const signalCommand = program2.command("signal").description("Write an assist signal file");
19831
- signalCommand.command("next").argument("[id]", "Backlog item ID to run directly").description("Write a next signal to chain into assist next").action((id2) => {
19832
- writeSignal("next", id2 ? { id: id2 } : void 0);
20198
+ signalCommand.command("next").argument("[id]", "Backlog item ID to run directly").description("Write a next signal to chain into assist next").action((id) => {
20199
+ writeSignal("next", id ? { id } : void 0);
19833
20200
  console.log("Signal written.");
19834
20201
  });
19835
- signalCommand.command("done").argument("[id]", "Backlog item ID created by the session").description("Write a done signal to end a --once launch session").action((id2) => {
19836
- writeSignal("done", id2 ? { id: id2 } : void 0);
20202
+ signalCommand.command("done").argument("[id]", "Backlog item ID created by the session").description("Write a done signal to end a --once launch session").action((id) => {
20203
+ writeSignal("done", id ? { id } : void 0);
19837
20204
  console.log("Signal written.");
19838
20205
  });
19839
20206
  }
@@ -19977,6 +20344,20 @@ async function sqlColumns(table, connectionName) {
19977
20344
  }
19978
20345
  }
19979
20346
 
20347
+ // src/commands/sql/sqlConfigHelp.ts
20348
+ var sqlConfigHelp = [
20349
+ {
20350
+ key: "sql.connections",
20351
+ setter: "assist sql auth add",
20352
+ note: "named MSSQL connections (add/list/remove via sql auth)"
20353
+ },
20354
+ {
20355
+ key: "sql.defaultConnection",
20356
+ setter: "assist sql set-connection <name>",
20357
+ note: "connection used when none is passed"
20358
+ }
20359
+ ];
20360
+
19980
20361
  // src/commands/sql/sqlMutate.ts
19981
20362
  import chalk189 from "chalk";
19982
20363
 
@@ -20105,6 +20486,7 @@ function registerSql(program2) {
20105
20486
  ).action(
20106
20487
  (table, connection) => sqlColumns(table, connection)
20107
20488
  );
20489
+ configHelp(cmd, sqlConfigHelp);
20108
20490
  }
20109
20491
 
20110
20492
  // src/commands/transcript/shared.ts
@@ -20440,9 +20822,29 @@ function move(file, options2) {
20440
20822
  console.log(`Summary target: ${summaryPath}`);
20441
20823
  }
20442
20824
 
20825
+ // src/commands/transcript/transcriptConfigHelp.ts
20826
+ var transcriptConfigHelp = [
20827
+ {
20828
+ key: "transcript.vttDir",
20829
+ setter: "assist transcript configure",
20830
+ note: "pick-up directory scanned for raw .vtt files"
20831
+ },
20832
+ {
20833
+ key: "transcript.transcriptsDir",
20834
+ setter: "assist transcript configure",
20835
+ note: "directory dated markdown transcripts are written to"
20836
+ },
20837
+ {
20838
+ key: "transcript.summaryDir",
20839
+ setter: "assist transcript configure",
20840
+ note: "directory generated transcript summaries are written to"
20841
+ }
20842
+ ];
20843
+
20443
20844
  // src/commands/registerTranscript.ts
20444
20845
  function registerTranscript(program2) {
20445
20846
  const transcriptCommand = program2.command("transcript").description("Meeting transcript utilities");
20847
+ configHelp(transcriptCommand, transcriptConfigHelp);
20446
20848
  transcriptCommand.command("configure").description("Configure transcript directories").action(configure);
20447
20849
  transcriptCommand.command("list").description("List raw .vtt filenames waiting in the pick-up directory").action(list4);
20448
20850
  transcriptCommand.command("move <file>").description(
@@ -20450,6 +20852,59 @@ function registerTranscript(program2) {
20450
20852
  ).requiredOption("--date <YYYY-MM-DD>", "meeting date").requiredOption("--client <name>", "client name").action(move);
20451
20853
  }
20452
20854
 
20855
+ // src/commands/registerVerifyChecks.ts
20856
+ var checks = [
20857
+ {
20858
+ name: "hardcoded-colors",
20859
+ description: "Check for hardcoded hex colors in src/",
20860
+ action: hardcodedColors
20861
+ },
20862
+ {
20863
+ name: "block-comments",
20864
+ description: "Fail on any comment on a changed line, whether added or edited",
20865
+ action: blockComments
20866
+ },
20867
+ {
20868
+ name: "no-venv",
20869
+ description: "Check that no venv folders exist in the repo",
20870
+ action: noVenv
20871
+ },
20872
+ {
20873
+ name: "forbidden-strings",
20874
+ description: "Check configured JSON files for values matching forbiddenStrings rules",
20875
+ action: forbiddenStrings
20876
+ },
20877
+ {
20878
+ name: "config-keys",
20879
+ description: "Check every assistConfigSchema key is surfaced in some command's --help via configHelp",
20880
+ action: configKeys
20881
+ }
20882
+ ];
20883
+ function registerVerifyChecks(verifyCommand) {
20884
+ for (const check2 of checks) {
20885
+ verifyCommand.command(check2.name).description(check2.description).action(check2.action);
20886
+ }
20887
+ }
20888
+
20889
+ // src/commands/verify/verifyConfigHelp.ts
20890
+ var verifyConfigHelp = [
20891
+ {
20892
+ key: "blockComments.ignore",
20893
+ setter: 'assist config set blockComments.ignore "**/*.test.ts"',
20894
+ note: "globs exempt from the block-comments check"
20895
+ },
20896
+ {
20897
+ key: "hardcodedColors.ignore",
20898
+ setter: 'assist config set hardcodedColors.ignore "**/theme.ts"',
20899
+ note: "globs exempt from the hardcoded-colors check"
20900
+ },
20901
+ {
20902
+ key: "forbiddenStrings",
20903
+ setter: 'assist config set forbiddenStrings.0.disallowed "secret"',
20904
+ note: "per-file value rules enforced by the forbidden-strings check"
20905
+ }
20906
+ ];
20907
+
20453
20908
  // src/commands/registerVerify.ts
20454
20909
  function runScope(scope, options2) {
20455
20910
  if (scope && scope !== "all") {
@@ -20471,14 +20926,8 @@ function registerVerify(program2) {
20471
20926
  "--package-json",
20472
20927
  "Write scripts to package.json instead of assist.yml"
20473
20928
  ).action(init3);
20474
- verifyCommand.command("hardcoded-colors").description("Check for hardcoded hex colors in src/").action(hardcodedColors);
20475
- verifyCommand.command("block-comments").description(
20476
- "Fail on any comment on a changed line, whether added or edited"
20477
- ).action(blockComments);
20478
- verifyCommand.command("no-venv").description("Check that no venv folders exist in the repo").action(noVenv);
20479
- verifyCommand.command("forbidden-strings").description(
20480
- "Check configured JSON files for values matching forbiddenStrings rules"
20481
- ).action(forbiddenStrings);
20929
+ registerVerifyChecks(verifyCommand);
20930
+ configHelp(verifyCommand, verifyConfigHelp);
20482
20931
  }
20483
20932
 
20484
20933
  // src/commands/voice/devices.ts
@@ -20732,6 +21181,50 @@ function stop2() {
20732
21181
  console.log("Voice daemon stopped");
20733
21182
  }
20734
21183
 
21184
+ // src/commands/voice/voiceConfigHelp.ts
21185
+ var voiceConfigHelp = [
21186
+ {
21187
+ key: "voice.wakeWords",
21188
+ setter: 'assist config set voice.wakeWords "computer"',
21189
+ note: "wake words that activate the daemon (default: computer)"
21190
+ },
21191
+ {
21192
+ key: "voice.mic",
21193
+ setter: "assist config set voice.mic <device>",
21194
+ note: "audio input device (defaults to the system default)"
21195
+ },
21196
+ {
21197
+ key: "voice.cwd",
21198
+ setter: "assist config set voice.cwd <path>",
21199
+ note: "working directory commands are dispatched from"
21200
+ },
21201
+ {
21202
+ key: "voice.modelsDir",
21203
+ setter: "assist config set voice.modelsDir ~/.assist/voice/models",
21204
+ note: "directory VAD/STT models download to"
21205
+ },
21206
+ {
21207
+ key: "voice.lockDir",
21208
+ setter: "assist config set voice.lockDir <path>",
21209
+ note: "directory holding the daemon lock file"
21210
+ },
21211
+ {
21212
+ key: "voice.submitWindows",
21213
+ setter: 'assist config set voice.submitWindows "Code"',
21214
+ note: "window titles where transcriptions auto-submit"
21215
+ },
21216
+ {
21217
+ key: "voice.models.vad",
21218
+ setter: "assist config set voice.models.vad <path>",
21219
+ note: "override the voice-activity-detection model path"
21220
+ },
21221
+ {
21222
+ key: "voice.models.smartTurn",
21223
+ setter: "assist config set voice.models.smartTurn <path>",
21224
+ note: "override the smart-turn model path"
21225
+ }
21226
+ ];
21227
+
20735
21228
  // src/commands/registerVoice.ts
20736
21229
  function registerVoice(program2) {
20737
21230
  const voiceCommand = program2.command("voice").description("Voice interaction daemon for hands-free Claude commands");
@@ -20741,6 +21234,7 @@ function registerVoice(program2) {
20741
21234
  voiceCommand.command("status").description("Check voice daemon status").action(status);
20742
21235
  voiceCommand.command("devices").description("List available audio input devices").action(devices);
20743
21236
  voiceCommand.command("logs").description("Tail voice daemon logs").option("-n, --lines <count>", "Number of lines to show", "20").action((options2) => logs(options2));
21237
+ configHelp(voiceCommand, voiceConfigHelp);
20744
21238
  }
20745
21239
 
20746
21240
  // src/commands/roam/auth.ts
@@ -20971,8 +21465,82 @@ function registerRoam(program2) {
20971
21465
  roamCommand.command("stop-claude-code-icon").description("Signal Claude Code session stop to Roam local API").action(stopClaudeCodeIcon);
20972
21466
  roamCommand.command("show-codex-icon").description("Forward Codex hook activity to Roam local API").action(showCodexIcon);
20973
21467
  roamCommand.command("stop-codex-icon").description("Signal Codex session stop to Roam local API").action(stopCodexIcon);
21468
+ configHelp(roamCommand, [
21469
+ {
21470
+ key: "roam.clientId",
21471
+ setter: "assist roam auth",
21472
+ note: "OAuth client ID (written by the auth flow)"
21473
+ },
21474
+ {
21475
+ key: "roam.clientSecret",
21476
+ setter: "assist roam auth",
21477
+ note: "OAuth client secret (written by the auth flow)"
21478
+ },
21479
+ {
21480
+ key: "roam.accessToken",
21481
+ setter: "assist roam auth",
21482
+ note: "OAuth access token (managed by the auth flow)"
21483
+ },
21484
+ {
21485
+ key: "roam.refreshToken",
21486
+ setter: "assist roam auth",
21487
+ note: "OAuth refresh token (managed by the auth flow)"
21488
+ },
21489
+ {
21490
+ key: "roam.tokenExpiresAt",
21491
+ setter: "assist roam auth",
21492
+ note: "access-token expiry epoch (managed by the auth flow)"
21493
+ }
21494
+ ]);
20974
21495
  }
20975
21496
 
21497
+ // src/commands/rootConfigHelp.ts
21498
+ var rootConfigHelp = {
21499
+ sync: [
21500
+ {
21501
+ key: "sync.autoConfirm",
21502
+ setter: "assist config set sync.autoConfirm true",
21503
+ note: "skip the settings.json overwrite prompt"
21504
+ }
21505
+ ],
21506
+ commit: [
21507
+ {
21508
+ key: "commit.conventional",
21509
+ setter: "assist config set commit.conventional true",
21510
+ note: "enforce conventional commit message format"
21511
+ },
21512
+ {
21513
+ key: "commit.pull",
21514
+ setter: "assist config set commit.pull true",
21515
+ note: "pull before committing"
21516
+ },
21517
+ {
21518
+ key: "commit.push",
21519
+ setter: "assist config set commit.push true",
21520
+ note: "push after committing"
21521
+ },
21522
+ {
21523
+ key: "commit.expectedBranch",
21524
+ setter: "assist config set commit.expectedBranch main",
21525
+ note: "warn when committing off this branch"
21526
+ }
21527
+ ],
21528
+ notify: [
21529
+ {
21530
+ key: "notify.enabled",
21531
+ setter: "assist config set notify.enabled false",
21532
+ note: "enable or disable desktop notifications (default: enabled)"
21533
+ }
21534
+ ],
21535
+ screenshot: [
21536
+ {
21537
+ key: "screenshot.outputDir",
21538
+ setter: "assist config set screenshot.outputDir ./screenshots",
21539
+ note: "directory screenshots are written to (default: ./screenshots)"
21540
+ }
21541
+ ]
21542
+ };
21543
+
20976
21544
  // src/commands/run/index.ts
20977
21545
  import { resolve as resolve14 } from "path";
20978
21546
 
@@ -21137,30 +21705,32 @@ function execRunConfig(config, args) {
21137
21705
  config.quiet
21138
21706
  );
21139
21707
  }
21140
- function parseBacklogRunOptions(id2, args) {
21708
+ function parseBacklogRunOptions(id, args) {
21141
21709
  let allowEdits = true;
21142
21710
  for (const arg of args) {
21143
21711
  if (arg === "--write" || arg === "-w") allowEdits = true;
21144
21712
  else if (arg === "--no-write") allowEdits = false;
21145
21713
  else {
21146
- console.error(`error: unexpected argument '${arg}' for 'run ${id2}'`);
21714
+ console.error(`error: unexpected argument '${arg}' for 'run ${id}'`);
21147
21715
  process.exit(1);
21148
21716
  }
21149
21717
  }
21150
21718
  return { allowEdits };
21151
21719
  }
21720
+ async function tryBacklogRunAlias(name, args) {
21721
+ if (!/^a?\d+$/.test(name)) return false;
21722
+ if (lookupRunConfig(name).kind !== "not-found") return false;
21723
+ pullIfConfigured();
21724
+ await run2(name, parseBacklogRunOptions(name, args));
21725
+ return true;
21726
+ }
21152
21727
  async function run3(name, args) {
21153
21728
  if (!name) {
21154
21729
  console.error("error: missing required argument 'name'");
21155
21730
  console.error(formatConfiguredCommands());
21156
21731
  process.exit(1);
21157
21732
  }
21158
- if (/^\d+$/.test(name) && lookupRunConfig(name).kind === "not-found") {
21159
- const options2 = parseBacklogRunOptions(name, args);
21160
- pullIfConfigured();
21161
- await run2(name, options2);
21162
- return;
21163
- }
21733
+ if (await tryBacklogRunAlias(name, args)) return;
21164
21734
  execRunConfig(findRunConfig(name), args);
21165
21735
  }
21166
21736
 
@@ -21327,12 +21897,8 @@ function remove() {
21327
21897
  console.log(`Removed run configuration: ${name}`);
21328
21898
  }
21329
21899
 
21330
- // src/commands/run/registerRun.ts
21331
- function registerRun(program2) {
21332
- const runCommand = program2.command("run").description("Run a configured command from assist.yml").argument("[name]", "Name of the configured command").argument("[args...]", "Arguments to pass to the command").allowUnknownOption().addHelpText(
21333
- "after",
21334
- "\nA purely numeric name with no matching command is an alias for\n'assist backlog run <id>' (forwards --write/--no-write/-w)."
21335
- ).addHelpText("after", () => formatConfiguredCommands()).action((name, args) => run3(name, args));
21900
+ // src/commands/run/registerRunSubcommands.ts
21901
+ function registerRunSubcommands(runCommand) {
21336
21902
  runCommand.command("list").description("List configured run commands").option("-v, --verbose", "Show full command details").action((opts) => listRunConfigs(!!opts.verbose));
21337
21903
  runCommand.command("add").description("Add a new run configuration to assist.yml").argument("<name>", "Name for the run configuration").argument("<command>", "Command to execute").argument("[args...]", "Static args to pass to the command").option(
21338
21904
  "--cwd <dir>",
@@ -21345,6 +21911,25 @@ function registerRun(program2) {
21345
21911
  runCommand.command("remove").description("Remove a run configuration from assist.yml").argument("<name>", "Name of the run configuration to remove").action(() => remove());
21346
21912
  }
21347
21913
 
21914
+ // src/commands/run/runConfigHelp.ts
21915
+ var runConfigHelp = [
21916
+ {
21917
+ key: "run",
21918
+ setter: "assist run add <name> <command>",
21919
+ note: "configured commands runnable via assist run <name>"
21920
+ }
21921
+ ];
21922
+
21923
+ // src/commands/run/registerRun.ts
21924
+ function registerRun(program2) {
21925
+ const runCommand = program2.command("run").description("Run a configured command from assist.yml").argument("[name]", "Name of the configured command").argument("[args...]", "Arguments to pass to the command").allowUnknownOption().addHelpText(
21926
+ "after",
21927
+ "\nAn a-prefixed item id (e.g. a555) with no matching command is an alias for\n'assist backlog run <id>' (forwards --write/--no-write/-w)."
21928
+ ).addHelpText("after", () => formatConfiguredCommands()).action((name, args) => run3(name, args));
21929
+ configHelp(runCommand, runConfigHelp);
21930
+ registerRunSubcommands(runCommand);
21931
+ }
21932
+
21348
21933
  // src/commands/screenshot/index.ts
21349
21934
  import { execSync as execSync54 } from "child_process";
21350
21935
  import { existsSync as existsSync51, mkdirSync as mkdirSync22, unlinkSync as unlinkSync19, writeFileSync as writeFileSync39 } from "fs";
@@ -21815,7 +22400,7 @@ function broadcast(clients, msg) {
21815
22400
 
21816
22401
  // src/commands/sessions/daemon/toSessionInfo.ts
21817
22402
  function toSessionInfo({
21818
- id: id2,
22403
+ id,
21819
22404
  name,
21820
22405
  title,
21821
22406
  subtitle,
@@ -21835,7 +22420,7 @@ function toSessionInfo({
21835
22420
  autoAdvance
21836
22421
  }) {
21837
22422
  return {
21838
- id: id2,
22423
+ id,
21839
22424
  name,
21840
22425
  title,
21841
22426
  subtitle,
@@ -21978,10 +22563,10 @@ function shellEscape(s) {
21978
22563
  }
21979
22564
 
21980
22565
  // src/commands/sessions/daemon/createAssistSession.ts
21981
- function createAssistSession(id2, assistArgs, cwd, meta) {
22566
+ function createAssistSession(id, assistArgs, cwd, meta) {
21982
22567
  const startedAt = Date.now();
21983
22568
  return {
21984
- id: id2,
22569
+ id,
21985
22570
  name: `assist ${assistArgs.join(" ")}`,
21986
22571
  title: meta?.title,
21987
22572
  subtitle: meta?.subtitle,
@@ -21990,7 +22575,7 @@ function createAssistSession(id2, assistArgs, cwd, meta) {
21990
22575
  startedAt,
21991
22576
  runningMs: 0,
21992
22577
  runningSince: startedAt,
21993
- pty: spawnPty(["assist", ...assistArgs], cwd, id2),
22578
+ pty: spawnPty(["assist", ...assistArgs], cwd, id),
21994
22579
  scrollback: "",
21995
22580
  assistArgs,
21996
22581
  cwd
@@ -21998,21 +22583,21 @@ function createAssistSession(id2, assistArgs, cwd, meta) {
21998
22583
  }
21999
22584
 
22000
22585
  // src/commands/sessions/daemon/dismissSession.ts
22001
- function dismissSession(sessions, id2) {
22002
- const s = sessions.get(id2);
22586
+ function dismissSession(sessions, id) {
22587
+ const s = sessions.get(id);
22003
22588
  if (!s) return false;
22004
22589
  if (s.status !== "done") s.pty?.kill();
22005
22590
  s.activityWatcher?.close();
22006
22591
  removeActivity(s.id);
22007
22592
  if (s.activity?.itemId != null) releaseLock(s.activity.itemId);
22008
- sessions.delete(id2);
22009
- daemonLog(`session ${id2} dismissed (${s.name})`);
22593
+ sessions.delete(id);
22594
+ daemonLog(`session ${id} dismissed (${s.name})`);
22010
22595
  return true;
22011
22596
  }
22012
22597
  function drainSessions(sessions, onDrained) {
22013
22598
  const names = [...sessions.values()].map((s) => s.name);
22014
22599
  const ids = [...sessions.keys()];
22015
- for (const id2 of ids) dismissSession(sessions, id2);
22600
+ for (const id of ids) dismissSession(sessions, id);
22016
22601
  onDrained();
22017
22602
  daemonLog(
22018
22603
  ids.length > 0 ? `drained ${ids.length} session(s): ${names.join(", ")}` : "drained 0 sessions"
@@ -22043,10 +22628,10 @@ function spawnRun(opts) {
22043
22628
  }
22044
22629
 
22045
22630
  // src/commands/sessions/daemon/createSession.ts
22046
- function sessionBase(id2, status2) {
22631
+ function sessionBase(id, status2) {
22047
22632
  const startedAt = Date.now();
22048
22633
  return {
22049
- id: id2,
22634
+ id,
22050
22635
  status: status2,
22051
22636
  startedAt,
22052
22637
  runningMs: 0,
@@ -22056,21 +22641,21 @@ function sessionBase(id2, status2) {
22056
22641
  scrollback: ""
22057
22642
  };
22058
22643
  }
22059
- function createSession(id2, prompt, cwd) {
22644
+ function createSession(id, prompt, cwd) {
22060
22645
  const claudeSessionId = randomUUID4();
22061
22646
  return {
22062
- ...sessionBase(id2, prompt ? "running" : "waiting"),
22063
- name: prompt?.slice(0, 40) || `Session ${id2}`,
22647
+ ...sessionBase(id, prompt ? "running" : "waiting"),
22648
+ name: prompt?.slice(0, 40) || `Session ${id}`,
22064
22649
  commandType: "claude",
22065
- pty: spawnClaude2({ prompt, cwd, sessionId: id2, claudeSessionId }),
22650
+ pty: spawnClaude2({ prompt, cwd, sessionId: id, claudeSessionId }),
22066
22651
  cwd,
22067
22652
  claudeSessionId,
22068
22653
  initialPrompt: prompt
22069
22654
  };
22070
22655
  }
22071
- function createRunSession(id2, runName, runArgs, cwd) {
22656
+ function createRunSession(id, runName, runArgs, cwd) {
22072
22657
  return {
22073
- ...sessionBase(id2, "running"),
22658
+ ...sessionBase(id, "running"),
22074
22659
  name: `run: ${runName}`,
22075
22660
  commandType: "run",
22076
22661
  pty: spawnRun({ name: runName, args: runArgs, cwd }),
@@ -22118,9 +22703,9 @@ function logSpawnedSession(session) {
22118
22703
 
22119
22704
  // src/shared/db/recordPhaseActiveMs.ts
22120
22705
  import { sql as sql9 } from "drizzle-orm";
22121
- async function recordPhaseActiveMs(db, itemId, phaseIdx, activeMs) {
22706
+ async function recordPhaseActiveMs(db, itemId2, phaseIdx, activeMs) {
22122
22707
  if (activeMs <= 0) return;
22123
- await db.insert(phaseUsage).values({ itemId, phaseIdx, activeMs }).onConflictDoUpdate({
22708
+ await db.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, activeMs }).onConflictDoUpdate({
22124
22709
  target: [phaseUsage.itemId, phaseUsage.phaseIdx],
22125
22710
  set: {
22126
22711
  activeMs: sql9`${phaseUsage.activeMs} + excluded.active_ms`
@@ -22129,10 +22714,10 @@ async function recordPhaseActiveMs(db, itemId, phaseIdx, activeMs) {
22129
22714
  }
22130
22715
 
22131
22716
  // src/commands/sessions/daemon/persistPhaseActiveMs.ts
22132
- async function persistPhaseActiveMs(itemId, phaseIdx, activeMs) {
22717
+ async function persistPhaseActiveMs(itemId2, phaseIdx, activeMs) {
22133
22718
  try {
22134
22719
  if (!process.env.ASSIST_DATABASE_URL && !loadConfig().database.url) return;
22135
- await recordPhaseActiveMs(await getDb(), itemId, phaseIdx, activeMs);
22720
+ await recordPhaseActiveMs(await getDb(), itemId2, phaseIdx, activeMs);
22136
22721
  } catch (error) {
22137
22722
  daemonLog(`phase-active-ms persist failed: ${String(error)}`);
22138
22723
  }
@@ -22189,13 +22774,13 @@ function shouldAutoRun(session) {
22189
22774
  run: false,
22190
22775
  reason: `command "${cmd ?? "(none)"}" is not draft/bug/refine`
22191
22776
  };
22192
- const itemId = session.activity?.itemId;
22193
- if (itemId == null)
22777
+ const itemId2 = session.activity?.itemId;
22778
+ if (itemId2 == null)
22194
22779
  return {
22195
22780
  run: false,
22196
22781
  reason: "no itemId in activity (draft did not create an item)"
22197
22782
  };
22198
- return { run: true, itemId };
22783
+ return { run: true, itemId: itemId2 };
22199
22784
  }
22200
22785
 
22201
22786
  // src/commands/sessions/daemon/watchEscInterrupt.ts
@@ -22267,8 +22852,8 @@ function makeStatusChangeHandler(dismiss, notify2, reuseForRun) {
22267
22852
 
22268
22853
  // src/shared/db/recordPhaseTokens.ts
22269
22854
  import { sql as sql10 } from "drizzle-orm";
22270
- async function recordPhaseTokens(db, itemId, phaseIdx, totalIn, totalOut) {
22271
- await db.insert(phaseUsage).values({ itemId, phaseIdx, lastTotalIn: totalIn, lastTotalOut: totalOut }).onConflictDoUpdate({
22855
+ async function recordPhaseTokens(db, itemId2, phaseIdx, totalIn, totalOut) {
22856
+ await db.insert(phaseUsage).values({ itemId: itemId2, phaseIdx, lastTotalIn: totalIn, lastTotalOut: totalOut }).onConflictDoUpdate({
22272
22857
  target: [phaseUsage.itemId, phaseUsage.phaseIdx],
22273
22858
  set: {
22274
22859
  tokensDown: sql10`${phaseUsage.tokensDown} + CASE WHEN ${phaseUsage.lastTotalIn} IS NULL THEN 0 ELSE GREATEST(excluded.last_total_in - ${phaseUsage.lastTotalIn}, 0) END`,
@@ -22280,10 +22865,10 @@ async function recordPhaseTokens(db, itemId, phaseIdx, totalIn, totalOut) {
22280
22865
  }
22281
22866
 
22282
22867
  // src/commands/sessions/daemon/persistPhaseTokens.ts
22283
- async function persistPhaseTokens(itemId, phaseIdx, totalIn, totalOut) {
22868
+ async function persistPhaseTokens(itemId2, phaseIdx, totalIn, totalOut) {
22284
22869
  try {
22285
22870
  if (!process.env.ASSIST_DATABASE_URL && !loadConfig().database.url) return;
22286
- await recordPhaseTokens(await getDb(), itemId, phaseIdx, totalIn, totalOut);
22871
+ await recordPhaseTokens(await getDb(), itemId2, phaseIdx, totalIn, totalOut);
22287
22872
  } catch (error) {
22288
22873
  daemonLog(`phase-tokens persist failed: ${String(error)}`);
22289
22874
  }
@@ -22317,19 +22902,19 @@ function applyReviewPause(session, activity2) {
22317
22902
 
22318
22903
  // src/shared/db/getPhaseActiveMs.ts
22319
22904
  import { and as and19, eq as eq37 } from "drizzle-orm";
22320
- async function getPhaseActiveMs(db, itemId, phaseIdx) {
22905
+ async function getPhaseActiveMs(db, itemId2, phaseIdx) {
22321
22906
  const [row] = await db.select({ activeMs: phaseUsage.activeMs }).from(phaseUsage).where(
22322
- and19(eq37(phaseUsage.itemId, itemId), eq37(phaseUsage.phaseIdx, phaseIdx))
22907
+ and19(eq37(phaseUsage.itemId, itemId2), eq37(phaseUsage.phaseIdx, phaseIdx))
22323
22908
  );
22324
22909
  return row?.activeMs ?? 0;
22325
22910
  }
22326
22911
 
22327
22912
  // src/commands/sessions/daemon/loadPhaseActiveMs.ts
22328
- async function loadPhaseActiveMs(itemId, phaseIdx) {
22913
+ async function loadPhaseActiveMs(itemId2, phaseIdx) {
22329
22914
  try {
22330
22915
  if (!process.env.ASSIST_DATABASE_URL && !loadConfig().database.url)
22331
22916
  return null;
22332
- return await getPhaseActiveMs(await getDb(), itemId, phaseIdx);
22917
+ return await getPhaseActiveMs(await getDb(), itemId2, phaseIdx);
22333
22918
  } catch (error) {
22334
22919
  daemonLog(`phase-active-ms load failed: ${String(error)}`);
22335
22920
  return null;
@@ -22545,9 +23130,9 @@ function killPtyTree(pty2) {
22545
23130
  }
22546
23131
 
22547
23132
  // src/commands/sessions/daemon/restoreBase.ts
22548
- function restoreBase(id2, persisted) {
23133
+ function restoreBase(id, persisted) {
22549
23134
  return {
22550
- id: id2,
23135
+ id,
22551
23136
  name: persisted.name,
22552
23137
  title: persisted.title,
22553
23138
  subtitle: persisted.subtitle,
@@ -22560,9 +23145,9 @@ function restoreBase(id2, persisted) {
22560
23145
  }
22561
23146
 
22562
23147
  // src/commands/sessions/daemon/errorSession.ts
22563
- function errorSession(id2, persisted, error) {
23148
+ function errorSession(id, persisted, error) {
22564
23149
  return {
22565
- ...restoreBase(id2, persisted),
23150
+ ...restoreBase(id, persisted),
22566
23151
  status: "error",
22567
23152
  startedAt: persisted.startedAt,
22568
23153
  runningMs: persisted.runningMs ?? 0,
@@ -22598,28 +23183,28 @@ function restoredSession(base, persisted, pty2, status2) {
22598
23183
  }
22599
23184
 
22600
23185
  // src/commands/sessions/daemon/restoreInteractiveSession.ts
22601
- function restoreInteractiveSession(id2, persisted, base) {
23186
+ function restoreInteractiveSession(id, persisted, base) {
22602
23187
  if (persisted.commandType !== "run" && persisted.claudeSessionId) {
22603
- return resumeViaClaude(id2, persisted, base);
23188
+ return resumeViaClaude(id, persisted, base);
22604
23189
  }
22605
23190
  if (persisted.commandType === "claude") {
22606
- return unrecoverableClaude(id2, persisted);
23191
+ return unrecoverableClaude(id, persisted);
22607
23192
  }
22608
23193
  return notRestoredStub(base, persisted);
22609
23194
  }
22610
- function resumeViaClaude(id2, persisted, base) {
23195
+ function resumeViaClaude(id, persisted, base) {
22611
23196
  const idle = persisted.status === "waiting";
22612
23197
  const pty2 = spawnClaude2({
22613
23198
  resumeSessionId: persisted.claudeSessionId,
22614
23199
  prompt: idle ? void 0 : buildResumePrompt(),
22615
23200
  cwd: persisted.cwd,
22616
- sessionId: id2
23201
+ sessionId: id
22617
23202
  });
22618
23203
  return idle ? waitingSession(base, persisted, pty2) : runningSession(base, persisted, pty2);
22619
23204
  }
22620
- function unrecoverableClaude(id2, persisted) {
23205
+ function unrecoverableClaude(id, persisted) {
22621
23206
  return errorSession(
22622
- id2,
23207
+ id,
22623
23208
  persisted,
22624
23209
  "no claude session id was recorded before the daemon stopped, so the conversation cannot be resumed"
22625
23210
  );
@@ -22639,9 +23224,9 @@ function notRestoredStub(base, persisted) {
22639
23224
  }
22640
23225
 
22641
23226
  // src/commands/sessions/daemon/updatedSession.ts
22642
- function updatedSession(id2, persisted) {
23227
+ function updatedSession(id, persisted) {
22643
23228
  return {
22644
- ...restoreBase(id2, persisted),
23229
+ ...restoreBase(id, persisted),
22645
23230
  status: "done",
22646
23231
  startedAt: persisted.startedAt,
22647
23232
  runningMs: persisted.runningMs ?? 0,
@@ -22654,20 +23239,20 @@ function isUpdate(persisted) {
22654
23239
  }
22655
23240
 
22656
23241
  // src/commands/sessions/daemon/restoreSession.ts
22657
- function restoreSession(id2, persisted) {
22658
- const base = restoreBase(id2, persisted);
22659
- if (isUpdate(persisted)) return updatedSession(id2, persisted);
23242
+ function restoreSession(id, persisted) {
23243
+ const base = restoreBase(id, persisted);
23244
+ if (isUpdate(persisted)) return updatedSession(id, persisted);
22660
23245
  if (needsWrapperRelaunch(persisted)) {
22661
23246
  const idle = persisted.status === "waiting";
22662
23247
  const pty2 = spawnPty(
22663
23248
  assistResumeArgs(persisted),
22664
23249
  persisted.cwd,
22665
- id2,
23250
+ id,
22666
23251
  idle ? { ASSIST_RESUME_IDLE: "1" } : void 0
22667
23252
  );
22668
23253
  return idle ? waitingSession(base, persisted, pty2) : runningSession(base, persisted, pty2);
22669
23254
  }
22670
- return restoreInteractiveSession(id2, persisted, base);
23255
+ return restoreInteractiveSession(id, persisted, base);
22671
23256
  }
22672
23257
  function needsWrapperRelaunch(persisted) {
22673
23258
  return isBacklogRun(persisted) || isOnceLaunch(persisted) && !!persisted.claudeSessionId;
@@ -22683,20 +23268,20 @@ function isOnceLaunch(persisted) {
22683
23268
  // src/commands/sessions/daemon/restoreOne.ts
22684
23269
  function restoreOne(persisted, spawn12, sessions) {
22685
23270
  try {
22686
- const id2 = spawn12((sid) => restoreSession(sid, persisted));
22687
- logUnresumable(persisted.name, id2, sessions.get(id2));
23271
+ const id = spawn12((sid) => restoreSession(sid, persisted));
23272
+ logUnresumable(persisted.name, id, sessions.get(id));
22688
23273
  } catch (error) {
22689
23274
  const reason = logRestoreError(persisted.name, error);
22690
23275
  try {
22691
- spawn12((id2) => errorSession(id2, persisted, reason));
23276
+ spawn12((id) => errorSession(id, persisted, reason));
22692
23277
  } catch {
22693
23278
  }
22694
23279
  }
22695
23280
  }
22696
- function logUnresumable(name, id2, session) {
23281
+ function logUnresumable(name, id, session) {
22697
23282
  if (session?.status === "error")
22698
23283
  daemonLog(
22699
- `could not resume restored session "${name}" (id ${id2}): ${session.error}`
23284
+ `could not resume restored session "${name}" (id ${id}): ${session.error}`
22700
23285
  );
22701
23286
  }
22702
23287
  function logRestoreError(name, error) {
@@ -22738,17 +23323,17 @@ function restoreAll(spawn12, sessions) {
22738
23323
  }
22739
23324
 
22740
23325
  // src/commands/sessions/daemon/resumeSession.ts
22741
- function resumeSession(id2, sessionId, cwd, name) {
23326
+ function resumeSession(id, sessionId, cwd, name) {
22742
23327
  const startedAt = Date.now();
22743
23328
  return {
22744
- id: id2,
23329
+ id,
22745
23330
  name: name ? `${name.slice(0, 36)} (R)` : `Resume ${sessionId.slice(0, 8)}`,
22746
23331
  commandType: "claude",
22747
23332
  status: "waiting",
22748
23333
  startedAt,
22749
23334
  runningMs: 0,
22750
23335
  runningSince: null,
22751
- pty: spawnClaude2({ resumeSessionId: sessionId, cwd, sessionId: id2 }),
23336
+ pty: spawnClaude2({ resumeSessionId: sessionId, cwd, sessionId: id }),
22752
23337
  scrollback: "",
22753
23338
  cwd,
22754
23339
  /* why: bind the card to the conversation it is resuming so a daemon restart
@@ -22777,8 +23362,8 @@ function respawnThunk(session) {
22777
23362
  }
22778
23363
 
22779
23364
  // src/commands/sessions/daemon/reuseSessionForRun.ts
22780
- function reuseSessionForRun(session, itemId, clients, onStatusChange) {
22781
- const assistArgs = ["backlog", "run", String(itemId)];
23365
+ function reuseSessionForRun(session, itemId2, clients, onStatusChange) {
23366
+ const assistArgs = ["backlog", "run", String(itemId2)];
22782
23367
  session.pty?.kill();
22783
23368
  session.assistArgs = assistArgs;
22784
23369
  session.name = `assist ${assistArgs.join(" ")}`;
@@ -22796,7 +23381,7 @@ function reuseSessionForRun(session, itemId, clients, onStatusChange) {
22796
23381
  broadcast(clients, { type: "clear", sessionId: session.id });
22797
23382
  wirePtyEvents(session, clients, onStatusChange);
22798
23383
  daemonLog(
22799
- `session ${session.id} reused for backlog run ${itemId}: ${session.name}`
23384
+ `session ${session.id} reused for backlog run ${itemId2}: ${session.name}`
22800
23385
  );
22801
23386
  }
22802
23387
 
@@ -22936,14 +23521,14 @@ async function discoverWindowsSessions(conn) {
22936
23521
 
22937
23522
  // src/commands/sessions/daemon/toWindowsSessionId.ts
22938
23523
  var PREFIX = "w-";
22939
- function toWindowsSessionId(id2) {
22940
- return isWindowsSessionId(id2) ? id2 : `${PREFIX}${id2}`;
23524
+ function toWindowsSessionId(id) {
23525
+ return isWindowsSessionId(id) ? id : `${PREFIX}${id}`;
22941
23526
  }
22942
- function isWindowsSessionId(id2) {
22943
- return id2.startsWith(PREFIX);
23527
+ function isWindowsSessionId(id) {
23528
+ return id.startsWith(PREFIX);
22944
23529
  }
22945
- function stripWindowsSessionId(id2) {
22946
- let stripped = id2;
23530
+ function stripWindowsSessionId(id) {
23531
+ let stripped = id;
22947
23532
  while (stripped.startsWith(PREFIX)) stripped = stripped.slice(PREFIX.length);
22948
23533
  return stripped;
22949
23534
  }
@@ -23038,8 +23623,8 @@ function handleSessions(state, msg) {
23038
23623
  id: toWindowsSessionId(s.id)
23039
23624
  }));
23040
23625
  const live = new Set(state.windowsSessions.map((s) => s.id));
23041
- for (const id2 of state.scrollback.keys())
23042
- if (!live.has(id2)) state.scrollback.delete(id2);
23626
+ for (const id of state.scrollback.keys())
23627
+ if (!live.has(id)) state.scrollback.delete(id);
23043
23628
  state.onSessionsChanged();
23044
23629
  }
23045
23630
 
@@ -23442,34 +24027,34 @@ function watchPromptSubmit(session, data, onStatusChange) {
23442
24027
  }
23443
24028
 
23444
24029
  // src/commands/sessions/daemon/writeToSession.ts
23445
- function writeToSession(sessions, id2, data, onStatusChange) {
23446
- const s = sessions.get(id2);
24030
+ function writeToSession(sessions, id, data, onStatusChange) {
24031
+ const s = sessions.get(id);
23447
24032
  if (!s || s.status === "done") return;
23448
24033
  s.pty?.write(data);
23449
24034
  watchEscInterrupt(s, data, onStatusChange);
23450
24035
  watchPromptSubmit(s, data, onStatusChange);
23451
24036
  }
23452
- function resizeSession(sessions, id2, cols, rows) {
23453
- const s = sessions.get(id2);
24037
+ function resizeSession(sessions, id, cols, rows) {
24038
+ const s = sessions.get(id);
23454
24039
  if (s && s.status !== "done") s.pty?.resize(cols, rows);
23455
24040
  }
23456
- function setAutoRun(sessions, id2, enabled) {
23457
- const s = sessions.get(id2);
24041
+ function setAutoRun(sessions, id, enabled) {
24042
+ const s = sessions.get(id);
23458
24043
  if (!s) return false;
23459
24044
  s.autoRun = enabled;
23460
- daemonLog(`session ${id2} autorun ${enabled ? "on" : "off"}`);
24045
+ daemonLog(`session ${id} autorun ${enabled ? "on" : "off"}`);
23461
24046
  return true;
23462
24047
  }
23463
- function setAutoAdvance(sessions, id2, enabled) {
23464
- const s = sessions.get(id2);
24048
+ function setAutoAdvance(sessions, id, enabled) {
24049
+ const s = sessions.get(id);
23465
24050
  if (!s) return false;
23466
24051
  s.autoAdvance = enabled;
23467
- const itemId = s.activity?.itemId;
23468
- if (itemId != null) {
23469
- if (enabled) clearPause(itemId);
23470
- else requestPause(itemId);
24052
+ const itemId2 = s.activity?.itemId;
24053
+ if (itemId2 != null) {
24054
+ if (enabled) clearPause(itemId2);
24055
+ else requestPause(itemId2);
23471
24056
  }
23472
- daemonLog(`session ${id2} autoadvance ${enabled ? "on" : "off"}`);
24057
+ daemonLog(`session ${id} autoadvance ${enabled ? "on" : "off"}`);
23473
24058
  return true;
23474
24059
  }
23475
24060
 
@@ -23513,58 +24098,58 @@ var SessionManager = class {
23513
24098
  }
23514
24099
  spawnWith = (create) => this.add(create(sessionLimits.nextId(this.sessions.size, this.idCounter)));
23515
24100
  spawn(prompt, cwd) {
23516
- return this.spawnWith((id2) => createSession(id2, prompt, cwd));
24101
+ return this.spawnWith((id) => createSession(id, prompt, cwd));
23517
24102
  }
23518
24103
  spawnRun(runName, runArgs, cwd) {
23519
- return this.spawnWith((id2) => createRunSession(id2, runName, runArgs, cwd));
24104
+ return this.spawnWith((id) => createRunSession(id, runName, runArgs, cwd));
23520
24105
  }
23521
24106
  spawnAssist(assistArgs, cwd, meta) {
23522
24107
  return this.spawnWith(
23523
- (id2) => createAssistSession(id2, assistArgs, cwd, meta)
24108
+ (id) => createAssistSession(id, assistArgs, cwd, meta)
23524
24109
  );
23525
24110
  }
23526
24111
  resume(sessionId, cwd, name) {
23527
- return this.spawnWith((id2) => resumeSession(id2, sessionId, cwd, name));
24112
+ return this.spawnWith((id) => resumeSession(id, sessionId, cwd, name));
23528
24113
  }
23529
24114
  onStatusChange = makeStatusChangeHandler(
23530
- (id2) => this.dismissSession(id2),
24115
+ (id) => this.dismissSession(id),
23531
24116
  () => this.notify(),
23532
- (session, itemId) => reuseSessionForRun(session, itemId, this.clients, this.onStatusChange)
24117
+ (session, itemId2) => reuseSessionForRun(session, itemId2, this.clients, this.onStatusChange)
23533
24118
  );
23534
24119
  wire(session) {
23535
24120
  this.sessions.set(session.id, session);
23536
24121
  wirePtyEvents(session, this.clients, this.onStatusChange);
23537
24122
  this.notify();
23538
24123
  }
23539
- writeToSession(id2, data) {
23540
- writeToSession(this.sessions, id2, data, this.onStatusChange);
24124
+ writeToSession(id, data) {
24125
+ writeToSession(this.sessions, id, data, this.onStatusChange);
23541
24126
  }
23542
- resizeSession(id2, cols, rows) {
23543
- resizeSession(this.sessions, id2, cols, rows);
24127
+ resizeSession(id, cols, rows) {
24128
+ resizeSession(this.sessions, id, cols, rows);
23544
24129
  }
23545
- retrySession(id2) {
23546
- const s = this.sessions.get(id2);
24130
+ retrySession(id) {
24131
+ const s = this.sessions.get(id);
23547
24132
  if (s && retrySession(s, this.clients, this.onStatusChange)) this.notify();
23548
24133
  }
23549
- restart(id2) {
23550
- const s = this.sessions.get(id2);
24134
+ restart(id) {
24135
+ const s = this.sessions.get(id);
23551
24136
  if (s && restartSession(s, this.clients, this.onStatusChange))
23552
24137
  this.notify();
23553
24138
  }
23554
- dismissSession = (id2) => {
23555
- if (dismissSession(this.sessions, id2)) this.notify();
24139
+ dismissSession = (id) => {
24140
+ if (dismissSession(this.sessions, id)) this.notify();
23556
24141
  };
23557
- setAutoRun(id2, enabled) {
23558
- if (setAutoRun(this.sessions, id2, enabled)) this.notify();
24142
+ setAutoRun(id, enabled) {
24143
+ if (setAutoRun(this.sessions, id, enabled)) this.notify();
23559
24144
  }
23560
- setAutoAdvance(id2, enabled) {
23561
- if (setAutoAdvance(this.sessions, id2, enabled)) this.notify();
24145
+ setAutoAdvance(id, enabled) {
24146
+ if (setAutoAdvance(this.sessions, id, enabled)) this.notify();
23562
24147
  }
23563
- setStatus(id2, status2) {
23564
- const session = this.sessions.get(id2);
24148
+ setStatus(id, status2) {
24149
+ const session = this.sessions.get(id);
23565
24150
  if (!session) {
23566
24151
  daemonLog(
23567
- `set-status for unknown session id=${id2} status=${status2} (no live session; ignoring)`
24152
+ `set-status for unknown session id=${id} status=${status2} (no live session; ignoring)`
23568
24153
  );
23569
24154
  return;
23570
24155
  }
@@ -23637,7 +24222,7 @@ function deriveSessionType(commandName, name) {
23637
24222
 
23638
24223
  // src/commands/sessions/shared/backlogRunMarkers.ts
23639
24224
  function backlogRunMarkers(text9) {
23640
- const match = text9.match(/backlog item #(\d+):[ \t]*([^\n]*)/);
24225
+ const match = text9.match(/backlog item a(\d+):[ \t]*([^\n]*)/);
23641
24226
  if (!match) return { commandName: "", commandArgs: "" };
23642
24227
  const title = match[2].trim();
23643
24228
  return {
@@ -24057,7 +24642,7 @@ function onListening(manager, checkAutoExit) {
24057
24642
  process.on("exit", cleanupOwnedFiles);
24058
24643
  const restored = manager.restore();
24059
24644
  const liveIds = new Set(manager.listSessions().map((s) => s.id));
24060
- manager.active.restore((id2) => liveIds.has(id2));
24645
+ manager.active.restore((id) => liveIds.has(id));
24061
24646
  daemonLog(
24062
24647
  restored.length > 0 ? `restored ${restored.length} session(s): ${restored.join(", ")}` : "no persisted sessions to restore"
24063
24648
  );
@@ -24253,27 +24838,27 @@ function truncate3(text9, maxChars = 500) {
24253
24838
  function scanSessionBacklogRefs(filePath) {
24254
24839
  const ids = /* @__PURE__ */ new Set();
24255
24840
  for (const text9 of iterateUserMessages(filePath, Number.MAX_SAFE_INTEGER)) {
24256
- for (const id2 of extractBacklogIds(text9)) {
24257
- ids.add(id2);
24841
+ for (const id of extractBacklogIds(text9)) {
24842
+ ids.add(id);
24258
24843
  }
24259
24844
  }
24260
24845
  return [...ids].sort((a, b) => a - b);
24261
24846
  }
24262
24847
  function extractBacklogIds(text9) {
24263
24848
  const ids = [];
24264
- for (const m of text9.matchAll(/backlog\s+run\s+(\d+)/gi)) {
24849
+ for (const m of text9.matchAll(/backlog\s+run\s+a(\d+)/gi)) {
24265
24850
  ids.push(Number.parseInt(m[1], 10));
24266
24851
  }
24267
- for (const m of text9.matchAll(/backlog\s+(?:item\s+)?#(\d+)/gi)) {
24852
+ for (const m of text9.matchAll(/backlog\s+(?:item\s+)?a(\d+)/gi)) {
24268
24853
  ids.push(Number.parseInt(m[1], 10));
24269
24854
  }
24270
- for (const m of text9.matchAll(/backlog\s+phase-done\s+(\d+)/gi)) {
24855
+ for (const m of text9.matchAll(/backlog\s+phase-done\s+a(\d+)/gi)) {
24271
24856
  ids.push(Number.parseInt(m[1], 10));
24272
24857
  }
24273
- for (const m of text9.matchAll(/backlog\s+comment\s+(\d+)/gi)) {
24858
+ for (const m of text9.matchAll(/backlog\s+comment\s+a(\d+)/gi)) {
24274
24859
  ids.push(Number.parseInt(m[1], 10));
24275
24860
  }
24276
- for (const m of text9.matchAll(/(?:^|[\s(])#(\d{1,4})(?=[\s).,;:!?]|$)/gm)) {
24861
+ for (const m of text9.matchAll(/(?:^|[\s(])a(\d{1,4})(?=[\s).,;:!?]|$)/gm)) {
24277
24862
  ids.push(Number.parseInt(m[1], 10));
24278
24863
  }
24279
24864
  return ids;
@@ -24306,7 +24891,7 @@ function buildPrompt2(firstMessage, backlogIds) {
24306
24891
  "Return ONLY the summary, no quotes or explanation."
24307
24892
  ];
24308
24893
  if (backlogIds.length > 0) {
24309
- const refs = backlogIds.map((id2) => `#${id2}`).join(", ");
24894
+ const refs = backlogIds.map((id) => formatItemId(id)).join(", ");
24310
24895
  parts.push(
24311
24896
  `The session references backlog item(s) ${refs}. Start the summary with "Backlog ${refs} \u2014" if relevant.`
24312
24897
  );
@@ -24381,6 +24966,28 @@ function registerSessions(program2) {
24381
24966
  cmd.command("set-status <status>").description(
24382
24967
  "Report the current session's status to the sessions daemon (used by Claude Code hooks)"
24383
24968
  ).action(setSessionStatus);
24969
+ configHelp(cmd, [
24970
+ {
24971
+ key: "sessions.windowsProjectsRoot",
24972
+ setter: "assist config set sessions.windowsProjectsRoot /mnt/c/Users/you/.claude/projects",
24973
+ note: "WSL path to the Windows .claude/projects root to discover"
24974
+ },
24975
+ {
24976
+ key: "sessions.windowsDaemonHost",
24977
+ setter: "assist config set sessions.windowsDaemonHost 127.0.0.1",
24978
+ note: "host the WSL daemon dials to reach the Windows daemon (default: 127.0.0.1)"
24979
+ },
24980
+ {
24981
+ key: "sessions.windowsDaemonPort",
24982
+ setter: "assist config set sessions.windowsDaemonPort 51764",
24983
+ note: "TCP port the Windows daemon listens on (default: 51764)"
24984
+ },
24985
+ {
24986
+ key: "sessions.windowsVersionCheck",
24987
+ setter: "assist config set sessions.windowsVersionCheck block",
24988
+ note: "Windows daemon version mismatch handling: block | warn | off"
24989
+ }
24990
+ ]);
24384
24991
  }
24385
24992
 
24386
24993
  // src/commands/statusLine.ts
@@ -24697,12 +25304,25 @@ async function update2() {
24697
25304
  await restartDaemonAfterUpdate();
24698
25305
  }
24699
25306
 
25307
+ // src/reportCliError.ts
25308
+ import chalk198 from "chalk";
25309
+ function reportCliError(error) {
25310
+ if (error instanceof InvalidItemIdError) {
25311
+ console.error(chalk198.red(error.message));
25312
+ } else {
25313
+ console.error(error);
25314
+ }
25315
+ process.exitCode = 1;
25316
+ }
25317
+
24700
25318
  // src/index.ts
24701
25319
  var program = new Command();
24702
25320
  program.name("assist").description("CLI application").version(package_default.version).option("--no-open", "Do not open a browser on startup").action((options2) => web({ port: "3100", open: options2.open }));
24703
- program.command("sync").description("Copy command files to ~/.claude/commands").option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
25321
+ var syncCommand = program.command("sync").description("Copy command files to ~/.claude/commands").option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
25322
+ configHelp(syncCommand, rootConfigHelp.sync);
24704
25323
  program.command("init").description("Initialize VS Code and verify configurations").action(init5);
24705
- program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <message> [files...]").action(commit);
25324
+ var commitCommand = program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <message> [files...]").action(commit);
25325
+ configHelp(commitCommand, rootConfigHelp.commit);
24706
25326
  registerConfig(program);
24707
25327
  registerRun(program);
24708
25328
  registerNew(program);
@@ -24711,12 +25331,14 @@ lintCommand.command("init").description("Initialize oxlint with baseline linter
24711
25331
  var vscodeCommand = program.command("vscode").description("VS Code configuration utilities");
24712
25332
  vscodeCommand.command("init").description("Add VS Code configuration files").action(init4);
24713
25333
  program.command("status-line").description("Format Claude Code status line from JSON stdin").action(statusLine);
24714
- program.command("notify").description(
25334
+ var notifyCommand = program.command("notify").description(
24715
25335
  "Show notification from Claude Code hook (reads JSON from stdin)"
24716
25336
  ).action(notify);
25337
+ configHelp(notifyCommand, rootConfigHelp.notify);
24717
25338
  program.command("update").description("Update assist to the latest version and sync commands").action(update2);
24718
25339
  program.command("coverage").description("Print global statement coverage percentage").action(coverage);
24719
- program.command("screenshot").description("Capture a screenshot of a running application window").argument("<process>", "Name of the running process (e.g. notepad, code)").action(screenshot);
25340
+ var screenshotCommand = program.command("screenshot").description("Capture a screenshot of a running application window").argument("<process>", "Name of the running process (e.g. notepad, code)").action(screenshot);
25341
+ configHelp(screenshotCommand, rootConfigHelp.screenshot);
24720
25342
  registerActivity(program);
24721
25343
  registerBackup(program);
24722
25344
  registerCliHook(program);
@@ -24751,7 +25373,4 @@ registerPrompts(program);
24751
25373
  registerDeny(program);
24752
25374
  registerLaunch(program);
24753
25375
  registerSignal(program);
24754
- program.parseAsync().catch((error) => {
24755
- console.error(error);
24756
- process.exitCode = 1;
24757
- }).finally(() => closeDb());
25376
+ program.parseAsync().catch(reportCliError).finally(() => closeDb());