@staff0rd/assist 0.315.1 → 0.317.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.315.1",
9
+ version: "0.317.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -300,6 +300,13 @@ var assistConfigSchema = z2.strictObject({
300
300
  message: z2.string()
301
301
  })
302
302
  ).optional(),
303
+ forbiddenStrings: z2.array(
304
+ z2.strictObject({
305
+ file: z2.string(),
306
+ paths: z2.array(z2.string()),
307
+ disallowed: z2.string()
308
+ })
309
+ ).optional(),
303
310
  sync: z2.strictObject({
304
311
  autoConfirm: z2.boolean().default(false)
305
312
  }).default({ autoConfirm: false }),
@@ -771,8 +778,7 @@ import * as path5 from "path";
771
778
  import chalk13 from "chalk";
772
779
 
773
780
  // src/commands/lint/init.ts
774
- import { execSync as execSync6 } from "child_process";
775
- import { existsSync as existsSync7, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync5 } from "fs";
781
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
776
782
  import chalk12 from "chalk";
777
783
 
778
784
  // src/shared/promptConfirm.ts
@@ -927,8 +933,6 @@ var oxlintrc_template_default = {
927
933
  async function init() {
928
934
  removeEslint();
929
935
  await writeOxlintConfig();
930
- removeBiomeConfig();
931
- uninstallBiome();
932
936
  }
933
937
  async function writeOxlintConfig() {
934
938
  const newContent = `${JSON.stringify(oxlintrc_template_default, null, " ")}
@@ -955,29 +959,6 @@ async function writeOxlintConfig() {
955
959
  writeFileSync5(configPath, newContent);
956
960
  console.log("Updated .oxlintrc.json with baseline linter config");
957
961
  }
958
- function removeBiomeConfig() {
959
- for (const file of ["biome.json", "biome.jsonc"]) {
960
- if (existsSync7(file)) {
961
- rmSync(file);
962
- console.log(`Removed ${file}`);
963
- }
964
- }
965
- }
966
- function uninstallBiome() {
967
- const packageJsonPath = "package.json";
968
- if (!existsSync7(packageJsonPath)) {
969
- return;
970
- }
971
- const pkg = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
972
- const hasBiome = Boolean(
973
- pkg.devDependencies?.["@biomejs/biome"] || pkg.dependencies?.["@biomejs/biome"]
974
- );
975
- if (!hasBiome) {
976
- return;
977
- }
978
- console.log("Uninstalling @biomejs/biome...");
979
- execSync6("npm uninstall @biomejs/biome", { stdio: "inherit" });
980
- }
981
962
 
982
963
  // src/commands/verify/setup/setupLint.ts
983
964
  async function setupLint(packageJsonPath, writer) {
@@ -1275,17 +1256,12 @@ function createLaunchJson(type) {
1275
1256
  // src/commands/vscode/init/detectVscodeSetup.ts
1276
1257
  import * as fs3 from "fs";
1277
1258
  import * as path9 from "path";
1278
- function fileContainsBiome(filePath) {
1279
- if (!fs3.existsSync(filePath)) return false;
1280
- return fs3.readFileSync(filePath, "utf8").includes("biome");
1281
- }
1282
1259
  function detectVscodeSetup(pkg) {
1283
1260
  const vscodeDir = path9.join(process.cwd(), ".vscode");
1284
1261
  return {
1285
1262
  hasVscodeFolder: fs3.existsSync(vscodeDir),
1286
1263
  hasLaunchJson: fs3.existsSync(path9.join(vscodeDir, "launch.json")),
1287
1264
  hasSettingsJson: fs3.existsSync(path9.join(vscodeDir, "settings.json")),
1288
- hasBiomeConfig: fileContainsBiome(path9.join(vscodeDir, "settings.json")) || fileContainsBiome(path9.join(vscodeDir, "extensions.json")),
1289
1265
  hasVite: !!pkg.devDependencies?.vite || !!pkg.dependencies?.vite,
1290
1266
  hasTsup: !!pkg.devDependencies?.tsup || !!pkg.dependencies?.tsup
1291
1267
  };
@@ -1307,7 +1283,7 @@ function getAvailableOptions2(setup2) {
1307
1283
  value: "launch",
1308
1284
  description: launchDescription
1309
1285
  });
1310
- if (!setup2.hasSettingsJson || setup2.hasBiomeConfig)
1286
+ if (!setup2.hasSettingsJson)
1311
1287
  options2.push({
1312
1288
  name: "settings",
1313
1289
  value: "settings",
@@ -1341,7 +1317,7 @@ function createSettingsJson() {
1341
1317
  "editor.defaultFormatter": "oxc.oxc-vscode",
1342
1318
  "editor.formatOnSave": true,
1343
1319
  "editor.codeActionsOnSave": {
1344
- ...withoutBiomeCodeActions(existing["editor.codeActionsOnSave"]),
1320
+ ...existingCodeActions(existing["editor.codeActionsOnSave"]),
1345
1321
  "source.fixAll.oxc": "explicit",
1346
1322
  "source.organizeImports.oxc": "explicit"
1347
1323
  }
@@ -1350,13 +1326,9 @@ function createSettingsJson() {
1350
1326
  `);
1351
1327
  console.log(chalk19.green("Created .vscode/settings.json"));
1352
1328
  }
1353
- function withoutBiomeCodeActions(actions) {
1329
+ function existingCodeActions(actions) {
1354
1330
  if (!actions || typeof actions !== "object") return {};
1355
- return Object.fromEntries(
1356
- Object.entries(actions).filter(
1357
- ([key]) => !key.includes("biome")
1358
- )
1359
- );
1331
+ return actions;
1360
1332
  }
1361
1333
 
1362
1334
  // src/commands/vscode/init/createExtensionsJson.ts
@@ -1366,9 +1338,7 @@ import chalk20 from "chalk";
1366
1338
  function createExtensionsJson() {
1367
1339
  const extensionsPath = path11.join(process.cwd(), ".vscode", "extensions.json");
1368
1340
  const existing = readVscodeJson(extensionsPath);
1369
- const previous = Array.isArray(existing.recommendations) ? existing.recommendations.filter(
1370
- (r) => r !== "biomejs.biome"
1371
- ) : [];
1341
+ const previous = Array.isArray(existing.recommendations) ? existing.recommendations : [];
1372
1342
  const recommendations = previous.includes("oxc.oxc-vscode") ? previous : [...previous, "oxc.oxc-vscode"];
1373
1343
  const extensions = { ...existing, recommendations };
1374
1344
  fs6.writeFileSync(
@@ -1741,11 +1711,11 @@ function lint(options2 = {}) {
1741
1711
  }
1742
1712
 
1743
1713
  // src/commands/new/registerNew/newCli/index.ts
1744
- import { execSync as execSync13 } from "child_process";
1714
+ import { execSync as execSync12 } from "child_process";
1745
1715
  import { basename, resolve as resolve5 } from "path";
1746
1716
 
1747
1717
  // src/commands/verify/commentPolicy/findAddedComments.ts
1748
- import { execSync as execSync7 } from "child_process";
1718
+ import { execSync as execSync6 } from "child_process";
1749
1719
  import fs13 from "fs";
1750
1720
  import { minimatch } from "minimatch";
1751
1721
  import { Project as Project2 } from "ts-morph";
@@ -1772,7 +1742,6 @@ function collectComments(sourceFile) {
1772
1742
 
1773
1743
  // src/commands/verify/commentPolicy/isCommentExempt.ts
1774
1744
  var MACHINE_DIRECTIVES = [
1775
- "biome-ignore",
1776
1745
  "oxlint-disable",
1777
1746
  "oxlint-enable",
1778
1747
  "@ts-expect-error",
@@ -1839,7 +1808,7 @@ function shouldScan(file, ignoreGlobs) {
1839
1808
  return fs13.existsSync(file);
1840
1809
  }
1841
1810
  function findAddedComments(options2) {
1842
- const diff2 = execSync7("git diff HEAD", {
1811
+ const diff2 = execSync6("git diff HEAD", {
1843
1812
  encoding: "utf8",
1844
1813
  maxBuffer: 64 * 1024 * 1024
1845
1814
  });
@@ -1890,21 +1859,94 @@ Total: ${findings.length} comment(s)`);
1890
1859
  process.exit(1);
1891
1860
  }
1892
1861
 
1893
- // src/commands/verify/hardcodedColors.ts
1894
- import { execSync as execSync8 } from "child_process";
1862
+ // src/commands/verify/forbiddenStrings/index.ts
1863
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
1864
+
1865
+ // src/commands/verify/forbiddenStrings/findForbiddenStrings.ts
1895
1866
  import { minimatch as minimatch2 } from "minimatch";
1867
+ function resolveStringsAtPath(data, path57) {
1868
+ let current = data;
1869
+ for (const segment of path57.split(".")) {
1870
+ if (current === null || typeof current !== "object") return [];
1871
+ current = current[segment];
1872
+ }
1873
+ if (typeof current === "string") return [current];
1874
+ if (Array.isArray(current))
1875
+ return current.filter(
1876
+ (value) => typeof value === "string"
1877
+ );
1878
+ return [];
1879
+ }
1880
+ function findRuleViolations(data, rule) {
1881
+ const violations = [];
1882
+ for (const path57 of rule.paths) {
1883
+ for (const value of resolveStringsAtPath(data, path57)) {
1884
+ if (minimatch2(value, rule.disallowed))
1885
+ violations.push({ file: rule.file, path: path57, value });
1886
+ }
1887
+ }
1888
+ return violations;
1889
+ }
1890
+ function findForbiddenStrings(rules, readJson) {
1891
+ return rules.flatMap((rule) => findRuleViolations(readJson(rule.file), rule));
1892
+ }
1893
+
1894
+ // src/commands/verify/forbiddenStrings/index.ts
1895
+ function forbiddenStrings() {
1896
+ const rules = loadConfig().forbiddenStrings ?? [];
1897
+ if (rules.length === 0) {
1898
+ console.log("No forbidden-strings rules configured.");
1899
+ process.exit(0);
1900
+ }
1901
+ const cache = /* @__PURE__ */ new Map();
1902
+ const readJson = (file) => {
1903
+ if (cache.has(file)) return cache.get(file);
1904
+ if (!existsSync11(file)) {
1905
+ console.log(`Forbidden-strings file not found: ${file}`);
1906
+ process.exit(1);
1907
+ }
1908
+ let parsed;
1909
+ try {
1910
+ parsed = JSON.parse(readFileSync8(file, "utf8"));
1911
+ } catch (error) {
1912
+ console.log(`Could not parse ${file}: ${error.message}`);
1913
+ process.exit(1);
1914
+ }
1915
+ cache.set(file, parsed);
1916
+ return parsed;
1917
+ };
1918
+ const violations = findForbiddenStrings(rules, readJson);
1919
+ if (violations.length === 0) {
1920
+ console.log("No forbidden strings found.");
1921
+ process.exit(0);
1922
+ }
1923
+ console.log("Forbidden strings found:\n");
1924
+ for (const { file, path: path57, value } of violations) {
1925
+ console.log(` ${file} ${path57}: ${value}`);
1926
+ }
1927
+ console.log(`
1928
+ Total: ${violations.length} forbidden string(s).`);
1929
+ console.log(
1930
+ "\nRemove each flagged value, or adjust the matching forbiddenStrings rule in assist.yml."
1931
+ );
1932
+ process.exit(1);
1933
+ }
1934
+
1935
+ // src/commands/verify/hardcodedColors.ts
1936
+ import { execSync as execSync7 } from "child_process";
1937
+ import { minimatch as minimatch3 } from "minimatch";
1896
1938
  var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
1897
1939
  function hardcodedColors() {
1898
1940
  const ignoreGlobs = loadConfig().hardcodedColors?.ignore ?? [];
1899
1941
  try {
1900
- const output = execSync8(`grep -rEnH '${pattern}' src/`, {
1942
+ const output = execSync7(`grep -rEnH '${pattern}' src/`, {
1901
1943
  encoding: "utf8"
1902
1944
  });
1903
1945
  const lines = output.trim().split("\n").filter((line) => {
1904
1946
  const match = line.match(/^(.+?):\d+:/);
1905
1947
  if (!match) return true;
1906
1948
  const file = match[1];
1907
- return !ignoreGlobs.some((glob) => minimatch2(file, glob));
1949
+ return !ignoreGlobs.some((glob) => minimatch3(file, glob));
1908
1950
  });
1909
1951
  if (lines.length === 0) {
1910
1952
  console.log("No hardcoded colors found.");
@@ -1960,14 +2002,14 @@ function assertNoDuplicateRunNames(configs) {
1960
2002
  }
1961
2003
 
1962
2004
  // src/shared/findLinkedConfigPath.ts
1963
- import { existsSync as existsSync11 } from "fs";
2005
+ import { existsSync as existsSync12 } from "fs";
1964
2006
  import { join as join8, resolve } from "path";
1965
2007
  function findLinkedConfigPath(linkPath, fromDir) {
1966
2008
  const resolved = resolve(fromDir, linkPath);
1967
2009
  const claudePath = join8(resolved, ".claude", "assist.yml");
1968
- if (existsSync11(claudePath)) return claudePath;
2010
+ if (existsSync12(claudePath)) return claudePath;
1969
2011
  const rootPath = join8(resolved, "assist.yml");
1970
- if (existsSync11(rootPath)) return rootPath;
2012
+ if (existsSync12(rootPath)) return rootPath;
1971
2013
  throw new Error(`No assist.yml found in linked project: ${resolved}`);
1972
2014
  }
1973
2015
 
@@ -2078,10 +2120,10 @@ function list() {
2078
2120
  }
2079
2121
 
2080
2122
  // src/commands/verify/noVenv.ts
2081
- import { execSync as execSync9 } from "child_process";
2123
+ import { execSync as execSync8 } from "child_process";
2082
2124
  function noVenv() {
2083
2125
  try {
2084
- const output = execSync9(
2126
+ const output = execSync8(
2085
2127
  "find . -type d -name venv -not -path '*/node_modules/*'",
2086
2128
  {
2087
2129
  encoding: "utf8"
@@ -2110,12 +2152,12 @@ Total: ${folders.length} venv folder(s)`);
2110
2152
  }
2111
2153
 
2112
2154
  // src/commands/verify/run/filterByChangedFiles.ts
2113
- import { minimatch as minimatch3 } from "minimatch";
2155
+ import { minimatch as minimatch4 } from "minimatch";
2114
2156
 
2115
2157
  // src/commands/verify/run/getChangedFiles.ts
2116
- import { execSync as execSync10 } from "child_process";
2158
+ import { execSync as execSync9 } from "child_process";
2117
2159
  function getChangedFiles() {
2118
- const output = execSync10("git diff --name-only HEAD", {
2160
+ const output = execSync9("git diff --name-only HEAD", {
2119
2161
  encoding: "utf8"
2120
2162
  }).trim();
2121
2163
  if (output === "") return [];
@@ -2131,7 +2173,7 @@ function filterByChangedFiles(entries) {
2131
2173
  const { filter } = entry;
2132
2174
  if (!filter) return true;
2133
2175
  if (changedFiles.length === 0) return false;
2134
- return changedFiles.some((file) => minimatch3(file, filter));
2176
+ return changedFiles.some((file) => minimatch4(file, filter));
2135
2177
  });
2136
2178
  }
2137
2179
 
@@ -2286,81 +2328,26 @@ async function run(options2 = {}) {
2286
2328
  handleResults(results, entries.length);
2287
2329
  }
2288
2330
 
2289
- // src/commands/verify/settingsGuard.ts
2290
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
2291
-
2292
- // src/commands/verify/findAssistReferences.ts
2293
- function offendingEntries(list4) {
2294
- if (!Array.isArray(list4)) return [];
2295
- return list4.filter(
2296
- (entry) => typeof entry === "string" && /\bassist\b/.test(entry)
2297
- );
2298
- }
2299
- function findAssistReferences(settings) {
2300
- const permissions = settings?.permissions ?? {};
2301
- return [
2302
- ...offendingEntries(permissions.allow).map(
2303
- (entry) => ({ list: "allow", entry })
2304
- ),
2305
- ...offendingEntries(permissions.deny).map(
2306
- (entry) => ({ list: "deny", entry })
2307
- )
2308
- ];
2309
- }
2310
-
2311
- // src/commands/verify/settingsGuard.ts
2312
- var SETTINGS_PATH = "claude/settings.json";
2313
- function settingsGuard() {
2314
- if (!existsSync12(SETTINGS_PATH)) {
2315
- console.log(`No ${SETTINGS_PATH}; nothing to guard.`);
2316
- process.exit(0);
2317
- }
2318
- let settings;
2319
- try {
2320
- settings = JSON.parse(readFileSync9(SETTINGS_PATH, "utf8"));
2321
- } catch (error) {
2322
- console.log(
2323
- `Could not parse ${SETTINGS_PATH}: ${error.message}`
2324
- );
2325
- process.exit(1);
2326
- }
2327
- const offenders = findAssistReferences(settings);
2328
- if (offenders.length === 0) {
2329
- console.log(`No assist references in ${SETTINGS_PATH} permissions.`);
2330
- process.exit(0);
2331
- }
2332
- console.log(`assist references found in ${SETTINGS_PATH} permissions:
2333
- `);
2334
- for (const { list: list4, entry } of offenders) {
2335
- console.log(` permissions.${list4}: ${entry}`);
2336
- }
2337
- console.log(
2338
- `
2339
- Total: ${offenders.length} entry(ies). Remove every assist reference from the permission lists.`
2340
- );
2341
- process.exit(1);
2342
- }
2343
-
2344
2331
  // src/commands/new/registerNew/initGit.ts
2345
- import { execSync as execSync11 } from "child_process";
2332
+ import { execSync as execSync10 } from "child_process";
2346
2333
  import { writeFileSync as writeFileSync9 } from "fs";
2347
2334
  function initGit() {
2348
2335
  console.log("Initializing git repository...");
2349
- execSync11("git init", { stdio: "inherit" });
2336
+ execSync10("git init", { stdio: "inherit" });
2350
2337
  writeFileSync9(".gitignore", "dist\nnode_modules\n");
2351
2338
  }
2352
2339
 
2353
2340
  // src/commands/new/registerNew/newCli/initPackageJson.ts
2354
- import { execSync as execSync12 } from "child_process";
2341
+ import { execSync as execSync11 } from "child_process";
2355
2342
  function initPackageJson(name) {
2356
2343
  console.log("Initializing package.json...");
2357
- execSync12("npm init -y", { stdio: "inherit" });
2344
+ execSync11("npm init -y", { stdio: "inherit" });
2358
2345
  console.log("Configuring package.json...");
2359
- execSync12("npm pkg delete main", { stdio: "inherit" });
2360
- execSync12("npm pkg set type=module", { stdio: "inherit" });
2361
- execSync12(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
2362
- execSync12("npm pkg set scripts.build=tsup", { stdio: "inherit" });
2363
- execSync12('npm pkg set scripts.start="node dist/index.js"', {
2346
+ execSync11("npm pkg delete main", { stdio: "inherit" });
2347
+ execSync11("npm pkg set type=module", { stdio: "inherit" });
2348
+ execSync11(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
2349
+ execSync11("npm pkg set scripts.build=tsup", { stdio: "inherit" });
2350
+ execSync11('npm pkg set scripts.start="node dist/index.js"', {
2364
2351
  stdio: "inherit"
2365
2352
  });
2366
2353
  }
@@ -2425,8 +2412,8 @@ async function newCli() {
2425
2412
  initGit();
2426
2413
  initPackageJson(name);
2427
2414
  console.log("Installing dependencies...");
2428
- execSync13("npm install commander", { stdio: "inherit" });
2429
- execSync13("npm install -D tsup typescript @types/node", {
2415
+ execSync12("npm install commander", { stdio: "inherit" });
2416
+ execSync12("npm install -D tsup typescript @types/node", {
2430
2417
  stdio: "inherit"
2431
2418
  });
2432
2419
  writeCliTemplate(name);
@@ -2435,16 +2422,16 @@ async function newCli() {
2435
2422
  }
2436
2423
 
2437
2424
  // src/commands/new/registerNew/newProject.ts
2438
- import { execSync as execSync15 } from "child_process";
2439
- import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync12 } from "fs";
2425
+ import { execSync as execSync14 } from "child_process";
2426
+ import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync12 } from "fs";
2440
2427
 
2441
2428
  // src/commands/deploy/init/index.ts
2442
- import { execSync as execSync14 } from "child_process";
2429
+ import { execSync as execSync13 } from "child_process";
2443
2430
  import chalk26 from "chalk";
2444
2431
  import enquirer3 from "enquirer";
2445
2432
 
2446
2433
  // src/commands/deploy/init/updateWorkflow.ts
2447
- import { existsSync as existsSync13, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
2434
+ import { existsSync as existsSync13, mkdirSync as mkdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync11 } from "fs";
2448
2435
  import { dirname as dirname11, join as join9 } from "path";
2449
2436
  import { fileURLToPath } from "url";
2450
2437
  import chalk25 from "chalk";
@@ -2454,13 +2441,13 @@ function getExistingSiteId() {
2454
2441
  if (!existsSync13(WORKFLOW_PATH)) {
2455
2442
  return null;
2456
2443
  }
2457
- const content = readFileSync10(WORKFLOW_PATH, "utf8");
2444
+ const content = readFileSync9(WORKFLOW_PATH, "utf8");
2458
2445
  const match = content.match(/-s\s+([a-f0-9-]{36})/);
2459
2446
  return match ? match[1] : null;
2460
2447
  }
2461
2448
  function getTemplateContent(siteId) {
2462
2449
  const templatePath = join9(__dirname2, "commands/deploy/build.yml");
2463
- const template = readFileSync10(templatePath, "utf8");
2450
+ const template = readFileSync9(templatePath, "utf8");
2464
2451
  return template.replace("{{NETLIFY_SITE_ID}}", siteId);
2465
2452
  }
2466
2453
  async function updateWorkflow(siteId) {
@@ -2470,7 +2457,7 @@ async function updateWorkflow(siteId) {
2470
2457
  mkdirSync3(workflowDir, { recursive: true });
2471
2458
  }
2472
2459
  if (existsSync13(WORKFLOW_PATH)) {
2473
- const oldContent = readFileSync10(WORKFLOW_PATH, "utf8");
2460
+ const oldContent = readFileSync9(WORKFLOW_PATH, "utf8");
2474
2461
  if (oldContent === newContent) {
2475
2462
  console.log(chalk25.green("build.yml is already up to date"));
2476
2463
  return;
@@ -2492,7 +2479,7 @@ Created ${WORKFLOW_PATH}`));
2492
2479
  // src/commands/deploy/init/index.ts
2493
2480
  async function ensureNetlifyCli() {
2494
2481
  try {
2495
- execSync14("netlify sites:create --disable-linking", { stdio: "inherit" });
2482
+ execSync13("netlify sites:create --disable-linking", { stdio: "inherit" });
2496
2483
  } catch (error) {
2497
2484
  if (!(error instanceof Error) || !error.message.includes("command not found"))
2498
2485
  throw error;
@@ -2507,9 +2494,9 @@ async function ensureNetlifyCli() {
2507
2494
  process.exit(1);
2508
2495
  }
2509
2496
  console.log(chalk26.dim("\nInstalling netlify-cli...\n"));
2510
- execSync14("npm install -g netlify-cli", { stdio: "inherit" });
2497
+ execSync13("npm install -g netlify-cli", { stdio: "inherit" });
2511
2498
  console.log();
2512
- execSync14("netlify sites:create --disable-linking", { stdio: "inherit" });
2499
+ execSync13("netlify sites:create --disable-linking", { stdio: "inherit" });
2513
2500
  }
2514
2501
  }
2515
2502
  function printSetupInstructions() {
@@ -2552,7 +2539,7 @@ async function init5() {
2552
2539
  // src/commands/new/registerNew/newProject.ts
2553
2540
  async function newProject() {
2554
2541
  console.log("Initializing Vite with react-ts template...");
2555
- execSync15("npm create vite@latest . -- --template react-ts", {
2542
+ execSync14("npm create vite@latest . -- --template react-ts", {
2556
2543
  stdio: "inherit"
2557
2544
  });
2558
2545
  initGit();
@@ -2568,7 +2555,7 @@ function addViteBaseConfig() {
2568
2555
  console.log("No vite.config.ts found, skipping base config");
2569
2556
  return;
2570
2557
  }
2571
- const content = readFileSync11(viteConfigPath, "utf8");
2558
+ const content = readFileSync10(viteConfigPath, "utf8");
2572
2559
  if (content.includes("base:")) {
2573
2560
  console.log("vite.config.ts already has base config");
2574
2561
  return;
@@ -2744,11 +2731,11 @@ function activityChart(data, range) {
2744
2731
  }
2745
2732
 
2746
2733
  // src/commands/activity/fetchCommitsPerDay.ts
2747
- import { execSync as execSync16 } from "child_process";
2734
+ import { execSync as execSync15 } from "child_process";
2748
2735
  function fetchContributions(from, to) {
2749
2736
  const query = `{ viewer { contributionsCollection(from: "${from}T00:00:00Z", to: "${to}T23:59:59Z") { contributionCalendar { weeks { contributionDays { date contributionCount } } } } } }`;
2750
2737
  const jq = ".data.viewer.contributionsCollection.contributionCalendar.weeks[].contributionDays[]";
2751
- const raw = execSync16(`gh api graphql -f query='${query}' --jq '${jq}'`, {
2738
+ const raw = execSync15(`gh api graphql -f query='${query}' --jq '${jq}'`, {
2752
2739
  encoding: "utf8"
2753
2740
  }).trim();
2754
2741
  if (!raw) return [];
@@ -3210,10 +3197,10 @@ import { join as join10 } from "path";
3210
3197
  import chalk28 from "chalk";
3211
3198
 
3212
3199
  // src/commands/backup/readCrontab.ts
3213
- import { execSync as execSync17 } from "child_process";
3200
+ import { execSync as execSync16 } from "child_process";
3214
3201
  function readCrontab() {
3215
3202
  try {
3216
- return execSync17("crontab -l", {
3203
+ return execSync16("crontab -l", {
3217
3204
  encoding: "utf8",
3218
3205
  stdio: ["ignore", "pipe", "ignore"]
3219
3206
  });
@@ -3223,7 +3210,7 @@ function readCrontab() {
3223
3210
  }
3224
3211
  function writeCrontab(content) {
3225
3212
  try {
3226
- execSync17("crontab -", {
3213
+ execSync16("crontab -", {
3227
3214
  input: content,
3228
3215
  stdio: ["pipe", "ignore", "pipe"]
3229
3216
  });
@@ -3391,40 +3378,17 @@ import chalk29 from "chalk";
3391
3378
  // src/commands/backlog/dump/DumpTable.ts
3392
3379
  var DUMP_FORMAT = "assist-backlog-dump";
3393
3380
  var DUMP_VERSION = 1;
3394
- var DUMP_TABLES = [
3395
- {
3396
- name: "items",
3397
- columns: [
3398
- "id",
3399
- "origin",
3400
- "type",
3401
- "name",
3402
- "description",
3403
- "acceptance_criteria",
3404
- "status",
3405
- "current_phase"
3406
- ]
3407
- },
3408
- {
3409
- name: "comments",
3410
- columns: ["id", "item_id", "idx", "text", "phase", "timestamp", "type"]
3411
- },
3412
- { name: "links", columns: ["item_id", "type", "target_id"] },
3413
- { name: "plan_phases", columns: ["item_id", "idx", "name", "manual_checks"] },
3414
- { name: "plan_tasks", columns: ["item_id", "phase_idx", "idx", "task"] },
3415
- { name: "metadata", columns: ["key", "value"] }
3416
- ];
3417
3381
 
3418
3382
  // src/commands/backlog/dump/buildDump.ts
3419
- async function buildDump(copyOut) {
3383
+ async function buildDump(tables, copyOut) {
3420
3384
  const header = JSON.stringify({
3421
3385
  format: DUMP_FORMAT,
3422
3386
  version: DUMP_VERSION,
3423
- tables: DUMP_TABLES.map(({ name, columns }) => ({ name, columns }))
3387
+ tables: tables.map(({ name, columns }) => ({ name, columns }))
3424
3388
  });
3425
3389
  const parts = [Buffer.from(`${header}
3426
3390
  `, "utf8")];
3427
- for (const table of DUMP_TABLES) {
3391
+ for (const table of tables) {
3428
3392
  const data = await copyOut(table);
3429
3393
  parts.push(Buffer.from(`@table ${table.name} ${data.length}
3430
3394
  `, "utf8"));
@@ -3445,11 +3409,95 @@ async function copyTableOut(client, table) {
3445
3409
  return Buffer.concat(chunks);
3446
3410
  }
3447
3411
 
3412
+ // src/commands/backlog/dump/groupColumns.ts
3413
+ function groupColumns(rows) {
3414
+ const byName = /* @__PURE__ */ new Map();
3415
+ for (const { table_name, quoted_table, quoted_column } of rows) {
3416
+ let entry = byName.get(table_name);
3417
+ if (!entry) {
3418
+ entry = { raw: table_name, table: { name: quoted_table, columns: [] } };
3419
+ byName.set(table_name, entry);
3420
+ }
3421
+ entry.table.columns.push(quoted_column);
3422
+ }
3423
+ return [...byName.values()];
3424
+ }
3425
+
3426
+ // src/commands/backlog/dump/orderDumpTables.ts
3427
+ function buildGraph(names, edges) {
3428
+ const present = new Set(names);
3429
+ const indegree = new Map(names.map((n) => [n, 0]));
3430
+ const children = /* @__PURE__ */ new Map();
3431
+ for (const { child, parent } of edges) {
3432
+ if (!present.has(child) || !present.has(parent)) continue;
3433
+ indegree.set(child, (indegree.get(child) ?? 0) + 1);
3434
+ children.set(parent, [...children.get(parent) ?? [], child]);
3435
+ }
3436
+ return { indegree, children };
3437
+ }
3438
+ function nextReady(names, emitted, indegree) {
3439
+ return names.find((n) => !emitted.has(n) && (indegree.get(n) ?? 0) === 0);
3440
+ }
3441
+ function topoSort(entries, edges) {
3442
+ const names = entries.map((e) => e.raw);
3443
+ const { indegree, children } = buildGraph(names, edges);
3444
+ const byRaw = new Map(entries.map((e) => [e.raw, e.table]));
3445
+ const ordered = [];
3446
+ const emitted = /* @__PURE__ */ new Set();
3447
+ while (ordered.length < entries.length) {
3448
+ const next3 = nextReady(names, emitted, indegree);
3449
+ if (!next3)
3450
+ throw new Error("Cannot dump: foreign-key cycle between tables.");
3451
+ emitted.add(next3);
3452
+ ordered.push(byRaw.get(next3));
3453
+ for (const child of children.get(next3) ?? []) {
3454
+ indegree.set(child, (indegree.get(child) ?? 0) - 1);
3455
+ }
3456
+ }
3457
+ return ordered;
3458
+ }
3459
+ function orderDumpTables(columnRows, fkRows) {
3460
+ return topoSort(groupColumns(columnRows), fkRows);
3461
+ }
3462
+
3463
+ // src/commands/backlog/dump/introspectDumpTables.ts
3464
+ var COLUMNS_SQL = `
3465
+ SELECT
3466
+ c.table_name AS table_name,
3467
+ quote_ident(c.table_name) AS quoted_table,
3468
+ quote_ident(c.column_name) AS quoted_column
3469
+ FROM information_schema.columns c
3470
+ JOIN information_schema.tables t
3471
+ ON t.table_schema = c.table_schema
3472
+ AND t.table_name = c.table_name
3473
+ WHERE c.table_schema = 'public'
3474
+ AND t.table_type = 'BASE TABLE'
3475
+ ORDER BY c.table_name, c.ordinal_position
3476
+ `;
3477
+ var FK_SQL = `
3478
+ SELECT child.relname AS child, parent.relname AS parent
3479
+ FROM pg_constraint con
3480
+ JOIN pg_class child ON child.oid = con.conrelid
3481
+ JOIN pg_class parent ON parent.oid = con.confrelid
3482
+ JOIN pg_namespace n ON n.oid = con.connamespace
3483
+ WHERE con.contype = 'f'
3484
+ AND n.nspname = 'public'
3485
+ AND con.conrelid <> con.confrelid
3486
+ `;
3487
+ async function introspectDumpTables(client) {
3488
+ const [{ rows: columnRows }, { rows: fkRows }] = await Promise.all([
3489
+ client.query(COLUMNS_SQL),
3490
+ client.query(FK_SQL)
3491
+ ]);
3492
+ return orderDumpTables(columnRows, fkRows);
3493
+ }
3494
+
3448
3495
  // src/commands/backlog/export/index.ts
3449
3496
  async function exportBacklog(file) {
3450
- const dump = await withDbClient(
3451
- (client) => buildDump((table) => copyTableOut(client, table))
3452
- );
3497
+ const dump = await withDbClient(async (client) => {
3498
+ const tables = await introspectDumpTables(client);
3499
+ return buildDump(tables, (table) => copyTableOut(client, table));
3500
+ });
3453
3501
  if (file) {
3454
3502
  await writeFile(file, dump);
3455
3503
  console.error(
@@ -3496,7 +3544,7 @@ import chalk42 from "chalk";
3496
3544
  import enquirer5 from "enquirer";
3497
3545
 
3498
3546
  // src/shared/pullIfConfigured.ts
3499
- import { execSync as execSync18 } from "child_process";
3547
+ import { execSync as execSync17 } from "child_process";
3500
3548
  import chalk31 from "chalk";
3501
3549
  function pullIfConfigured() {
3502
3550
  const config = loadConfig();
@@ -3510,7 +3558,7 @@ function pullIfConfigured() {
3510
3558
  return;
3511
3559
  }
3512
3560
  try {
3513
- execSync18("git pull --ff-only", { stdio: "inherit" });
3561
+ execSync17("git pull --ff-only", { stdio: "inherit" });
3514
3562
  } catch {
3515
3563
  console.error(chalk31.red("git pull --ff-only failed; aborting."));
3516
3564
  process.exit(1);
@@ -3518,7 +3566,7 @@ function pullIfConfigured() {
3518
3566
  }
3519
3567
  function hasLocalChanges() {
3520
3568
  try {
3521
- const status2 = execSync18("git status --porcelain", {
3569
+ const status2 = execSync17("git status --porcelain", {
3522
3570
  encoding: "utf8"
3523
3571
  });
3524
3572
  return status2.trim().length > 0;
@@ -3531,7 +3579,7 @@ function hasLocalChanges() {
3531
3579
  import {
3532
3580
  existsSync as existsSync15,
3533
3581
  mkdirSync as mkdirSync4,
3534
- readFileSync as readFileSync12,
3582
+ readFileSync as readFileSync11,
3535
3583
  unlinkSync as unlinkSync2,
3536
3584
  writeFileSync as writeFileSync13
3537
3585
  } from "fs";
@@ -3555,7 +3603,7 @@ function isLockedByOther(itemId) {
3555
3603
  const lockPath = getLockPath(itemId);
3556
3604
  if (!existsSync15(lockPath)) return false;
3557
3605
  try {
3558
- const lock = JSON.parse(readFileSync12(lockPath, "utf8"));
3606
+ const lock = JSON.parse(readFileSync11(lockPath, "utf8"));
3559
3607
  if (lock.pid === process.pid) return false;
3560
3608
  return isProcessAlive(lock.pid);
3561
3609
  } catch {
@@ -3767,11 +3815,11 @@ function backupLocalBacklogFiles(dir) {
3767
3815
  }
3768
3816
 
3769
3817
  // src/commands/backlog/gitPullBacklog.ts
3770
- import { execSync as execSync19 } from "child_process";
3818
+ import { execSync as execSync18 } from "child_process";
3771
3819
  import chalk34 from "chalk";
3772
3820
  function gitPullBacklog(dir) {
3773
3821
  try {
3774
- execSync19("git pull --ff-only", {
3822
+ execSync18("git pull --ff-only", {
3775
3823
  cwd: dir,
3776
3824
  stdio: ["pipe", "pipe", "pipe"]
3777
3825
  });
@@ -4008,7 +4056,7 @@ async function loadAllItems(orm, origin) {
4008
4056
  }
4009
4057
 
4010
4058
  // src/commands/backlog/parseBacklogJsonl.ts
4011
- import { readFileSync as readFileSync13 } from "fs";
4059
+ import { readFileSync as readFileSync12 } from "fs";
4012
4060
 
4013
4061
  // src/commands/backlog/types.ts
4014
4062
  import { z as z3 } from "zod";
@@ -4053,7 +4101,7 @@ var backlogFileSchema = z3.array(backlogItemSchema);
4053
4101
 
4054
4102
  // src/commands/backlog/parseBacklogJsonl.ts
4055
4103
  function parseBacklogJsonl(path57) {
4056
- const content = readFileSync13(path57, "utf8").trim();
4104
+ const content = readFileSync12(path57, "utf8").trim();
4057
4105
  if (content.length === 0) return [];
4058
4106
  return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
4059
4107
  }
@@ -4399,7 +4447,7 @@ Failed to launch Claude for ${context}: ${message}`)
4399
4447
  }
4400
4448
 
4401
4449
  // src/shared/emitActivity.ts
4402
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync14, rmSync as rmSync2, writeFileSync as writeFileSync16 } from "fs";
4450
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync13, rmSync, writeFileSync as writeFileSync16 } from "fs";
4403
4451
  import { homedir as homedir7 } from "os";
4404
4452
  import { dirname as dirname14, join as join18 } from "path";
4405
4453
  import { z as z4 } from "zod";
@@ -4425,7 +4473,7 @@ function emitActivity(activity2) {
4425
4473
  }
4426
4474
  function readActivity(path57) {
4427
4475
  try {
4428
- return JSON.parse(readFileSync14(path57, "utf8"));
4476
+ return JSON.parse(readFileSync13(path57, "utf8"));
4429
4477
  } catch {
4430
4478
  return void 0;
4431
4479
  }
@@ -4441,7 +4489,7 @@ function reconcileActivity(sessionId, activity2) {
4441
4489
  }
4442
4490
  function removeActivity(sessionId) {
4443
4491
  try {
4444
- rmSync2(activityPath(sessionId));
4492
+ rmSync(activityPath(sessionId));
4445
4493
  } catch {
4446
4494
  }
4447
4495
  }
@@ -4576,7 +4624,7 @@ async function handleIncompletePhase() {
4576
4624
  }
4577
4625
 
4578
4626
  // src/commands/backlog/readSignal.ts
4579
- import { existsSync as existsSync20, readFileSync as readFileSync15 } from "fs";
4627
+ import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
4580
4628
 
4581
4629
  // src/commands/backlog/writeSignal.ts
4582
4630
  import { writeFileSync as writeFileSync17 } from "fs";
@@ -4597,7 +4645,7 @@ function readSignal() {
4597
4645
  const path57 = getSignalPath();
4598
4646
  if (!existsSync20(path57)) return void 0;
4599
4647
  try {
4600
- return JSON.parse(readFileSync15(path57, "utf8"));
4648
+ return JSON.parse(readFileSync14(path57, "utf8"));
4601
4649
  } catch {
4602
4650
  return void 0;
4603
4651
  }
@@ -5056,7 +5104,7 @@ function printComments(item) {
5056
5104
  import { WebSocketServer } from "ws";
5057
5105
 
5058
5106
  // src/shared/getInstallDir.ts
5059
- import { execSync as execSync20 } from "child_process";
5107
+ import { execSync as execSync19 } from "child_process";
5060
5108
  import { dirname as dirname15, resolve as resolve7 } from "path";
5061
5109
  import { fileURLToPath as fileURLToPath2 } from "url";
5062
5110
  var __filename2 = fileURLToPath2(import.meta.url);
@@ -5066,7 +5114,7 @@ function getInstallDir() {
5066
5114
  }
5067
5115
  function isGitRepo(dir) {
5068
5116
  try {
5069
- const result = execSync20("git rev-parse --show-toplevel", {
5117
+ const result = execSync19("git rev-parse --show-toplevel", {
5070
5118
  cwd: dir,
5071
5119
  stdio: "pipe"
5072
5120
  }).toString().trim();
@@ -5083,11 +5131,11 @@ import {
5083
5131
  import chalk49 from "chalk";
5084
5132
 
5085
5133
  // src/lib/openBrowser.ts
5086
- import { execSync as execSync21 } from "child_process";
5134
+ import { execSync as execSync20 } from "child_process";
5087
5135
  function tryExec(commands) {
5088
5136
  for (const cmd of commands) {
5089
5137
  try {
5090
- execSync21(cmd, { stdio: "ignore" });
5138
+ execSync20(cmd, { stdio: "ignore" });
5091
5139
  return true;
5092
5140
  } catch {
5093
5141
  }
@@ -5300,12 +5348,12 @@ function delay(ms) {
5300
5348
 
5301
5349
  // src/commands/sessions/web/handleRequest.ts
5302
5350
  import { createHash as createHash2 } from "crypto";
5303
- import { readFileSync as readFileSync17 } from "fs";
5351
+ import { readFileSync as readFileSync16 } from "fs";
5304
5352
  import { createRequire as createRequire2 } from "module";
5305
5353
 
5306
5354
  // src/shared/createBundleHandler.ts
5307
5355
  import { createHash } from "crypto";
5308
- import { readFileSync as readFileSync16 } from "fs";
5356
+ import { readFileSync as readFileSync15 } from "fs";
5309
5357
  import { dirname as dirname16, join as join20 } from "path";
5310
5358
  import { fileURLToPath as fileURLToPath3 } from "url";
5311
5359
  function createBundleHandler(importMetaUrl, bundlePath) {
@@ -5313,7 +5361,7 @@ function createBundleHandler(importMetaUrl, bundlePath) {
5313
5361
  let cache;
5314
5362
  return (req, res) => {
5315
5363
  if (!cache) {
5316
- const body = readFileSync16(join20(dir, bundlePath), "utf8");
5364
+ const body = readFileSync15(join20(dir, bundlePath), "utf8");
5317
5365
  const etag = `"${createHash("sha256").update(body).digest("hex").slice(0, 16)}"`;
5318
5366
  cache = { body, etag };
5319
5367
  }
@@ -5662,7 +5710,7 @@ function getHtml() {
5662
5710
  }
5663
5711
 
5664
5712
  // src/commands/prs/getPreferredRemoteRepo.ts
5665
- import { execSync as execSync22 } from "child_process";
5713
+ import { execSync as execSync21 } from "child_process";
5666
5714
  var GITHUB_URL_PATTERN = /(?:git@github\.com:|https:\/\/github\.com\/)([^/]+)\/([^/]+?)(?:\.git)?\/?$/;
5667
5715
  function parseGitHubUrl(url) {
5668
5716
  const match = url.match(GITHUB_URL_PATTERN);
@@ -5671,7 +5719,7 @@ function parseGitHubUrl(url) {
5671
5719
  }
5672
5720
  function tryGetRemoteUrl(remote, cwd) {
5673
5721
  try {
5674
- return execSync22(`git remote get-url ${remote}`, {
5722
+ return execSync21(`git remote get-url ${remote}`, {
5675
5723
  encoding: "utf8",
5676
5724
  stdio: ["pipe", "pipe", "pipe"],
5677
5725
  cwd
@@ -5682,7 +5730,7 @@ function tryGetRemoteUrl(remote, cwd) {
5682
5730
  }
5683
5731
  function getCurrentBranchRemote(cwd) {
5684
5732
  try {
5685
- const ref = execSync22(
5733
+ const ref = execSync21(
5686
5734
  "git rev-parse --abbrev-ref --symbolic-full-name @{u}",
5687
5735
  { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], cwd }
5688
5736
  ).trim();
@@ -5694,7 +5742,7 @@ function getCurrentBranchRemote(cwd) {
5694
5742
  }
5695
5743
  function listRemotes(cwd) {
5696
5744
  try {
5697
- return execSync22("git remote", {
5745
+ return execSync21("git remote", {
5698
5746
  encoding: "utf8",
5699
5747
  stdio: ["pipe", "pipe", "pipe"],
5700
5748
  cwd
@@ -6060,7 +6108,7 @@ function createCssHandler(packageEntry) {
6060
6108
  return (req, res) => {
6061
6109
  if (!cache) {
6062
6110
  const resolved = require3.resolve(packageEntry);
6063
- const body = readFileSync17(resolved, "utf8");
6111
+ const body = readFileSync16(resolved, "utf8");
6064
6112
  const etag = `"${createHash2("sha256").update(body).digest("hex").slice(0, 16)}"`;
6065
6113
  cache = { body, etag };
6066
6114
  }
@@ -6573,7 +6621,7 @@ function registerCommentCommands(cmd) {
6573
6621
  // src/commands/backlog/registerExportCommand.ts
6574
6622
  function registerExportCommand(cmd) {
6575
6623
  cmd.command("export [file]").description(
6576
- "Export the entire backlog database to a file, or stdout if omitted"
6624
+ "Export every table in the backlog database (discovered by introspection) to a file, or stdout if omitted"
6577
6625
  ).action(exportBacklog);
6578
6626
  }
6579
6627
 
@@ -6631,11 +6679,9 @@ function parseDump(dump) {
6631
6679
  }
6632
6680
 
6633
6681
  // src/commands/backlog/dump/validateDump.ts
6634
- function tableShape(tables) {
6635
- return JSON.stringify(tables.map(({ name, columns }) => ({ name, columns })));
6636
- }
6637
6682
  function validateDump({ header, sections }) {
6638
- const missing = DUMP_TABLES.find(({ name }) => !sections.has(name))?.name;
6683
+ const tables = header.tables ?? [];
6684
+ const missing = tables.find(({ name }) => !sections.has(name))?.name;
6639
6685
  const checks = [
6640
6686
  [
6641
6687
  header.format === DUMP_FORMAT,
@@ -6645,10 +6691,7 @@ function validateDump({ header, sections }) {
6645
6691
  header.version === DUMP_VERSION,
6646
6692
  `Unsupported dump version ${header.version} (this build restores version ${DUMP_VERSION}).`
6647
6693
  ],
6648
- [
6649
- tableShape(header.tables ?? []) === tableShape(DUMP_TABLES),
6650
- "Dump table set does not match this build's backlog schema; cannot restore."
6651
- ],
6694
+ [tables.length > 0, "Dump header lists no tables; cannot restore."],
6652
6695
  [!missing, `Invalid dump: missing data section for "${missing}".`]
6653
6696
  ];
6654
6697
  const failure = checks.find(([ok]) => !ok);
@@ -6663,24 +6706,24 @@ async function countRows(client, table) {
6663
6706
  );
6664
6707
  return rows[0].n;
6665
6708
  }
6666
- function printSummary(current, incoming) {
6667
- const lines = DUMP_TABLES.map(
6709
+ function printSummary(tables, current, incoming) {
6710
+ const lines = tables.map(
6668
6711
  (t, i) => ` ${t.name}: ${current[i]} \u2192 ${incoming[i]} rows`
6669
6712
  );
6670
6713
  console.error(chalk57.bold("\nThis will REPLACE all backlog data:"));
6671
6714
  console.error(`${lines.join("\n")}
6672
6715
  `);
6673
6716
  }
6674
- async function confirmReplace(client, incoming, fromStdin) {
6717
+ async function confirmReplace(client, tables, incoming, fromStdin) {
6675
6718
  if (fromStdin) {
6676
6719
  throw new Error(
6677
6720
  "Reading a dump from stdin requires --yes (stdin is consumed by the dump)."
6678
6721
  );
6679
6722
  }
6680
6723
  const current = await Promise.all(
6681
- DUMP_TABLES.map((t) => countRows(client, t.name))
6724
+ tables.map((t) => countRows(client, t.name))
6682
6725
  );
6683
- printSummary(current, incoming);
6726
+ printSummary(tables, current, incoming);
6684
6727
  return promptConfirm("Replace all backlog data with this dump?", false);
6685
6728
  }
6686
6729
 
@@ -6703,23 +6746,48 @@ async function copyTableIn(client, table, data) {
6703
6746
  await finished(stream);
6704
6747
  }
6705
6748
 
6706
- // src/commands/backlog/import/restore.ts
6707
- var IDENTITY_TABLES = ["items", "comments"];
6708
- function resyncIdentitySql(table) {
6709
- return `SELECT setval(pg_get_serial_sequence('${table}', 'id'),
6710
- GREATEST(COALESCE((SELECT max(id) FROM ${table}), 0), 1),
6711
- (SELECT count(*) FROM ${table}) > 0)`;
6749
+ // src/commands/backlog/dump/introspectIdentityColumns.ts
6750
+ var IDENTITY_SQL = `
6751
+ SELECT
6752
+ quote_ident(table_name) AS table,
6753
+ quote_ident(column_name) AS column,
6754
+ column_name AS raw_column
6755
+ FROM information_schema.columns
6756
+ WHERE table_schema = 'public'
6757
+ AND is_identity = 'YES'
6758
+ ORDER BY table_name, ordinal_position
6759
+ `;
6760
+ async function introspectIdentityColumns(client) {
6761
+ const { rows } = await client.query(IDENTITY_SQL);
6762
+ return rows.map((row) => ({
6763
+ table: row.table,
6764
+ column: row.column,
6765
+ rawColumn: row.raw_column
6766
+ }));
6712
6767
  }
6768
+ function resyncIdentitySql(col) {
6769
+ return {
6770
+ text: `SELECT setval(
6771
+ pg_get_serial_sequence($1, $2),
6772
+ GREATEST(COALESCE((SELECT max(${col.column}) FROM ${col.table}), 0), 1),
6773
+ (SELECT count(*) FROM ${col.table}) > 0)`,
6774
+ values: [col.table, col.rawColumn]
6775
+ };
6776
+ }
6777
+
6778
+ // src/commands/backlog/import/restore.ts
6713
6779
  async function replaceData(client, parsed) {
6714
- const tables = DUMP_TABLES.map((t) => t.name).join(", ");
6780
+ const { tables } = parsed.header;
6781
+ const tableList = tables.map((t) => t.name).join(", ");
6715
6782
  await client.query(SCHEMA);
6716
- await client.query(`TRUNCATE ${tables} RESTART IDENTITY CASCADE`);
6717
- for (const table of DUMP_TABLES) {
6783
+ await client.query(`TRUNCATE ${tableList} RESTART IDENTITY CASCADE`);
6784
+ for (const table of tables) {
6718
6785
  const data = parsed.sections.get(table.name) ?? Buffer.alloc(0);
6719
6786
  await copyTableIn(client, table, data);
6720
6787
  }
6721
- for (const table of IDENTITY_TABLES) {
6722
- await client.query(resyncIdentitySql(table));
6788
+ for (const col of await introspectIdentityColumns(client)) {
6789
+ const { text: text6, values } = resyncIdentitySql(col);
6790
+ await client.query(text6, values);
6723
6791
  }
6724
6792
  }
6725
6793
  async function restore(client, parsed) {
@@ -6738,11 +6806,12 @@ async function importBacklog(file, options2 = {}) {
6738
6806
  const raw = file ? await readFile(file) : await readStdinBuffer();
6739
6807
  const parsed = parseDump(raw);
6740
6808
  validateDump(parsed);
6741
- const incoming = DUMP_TABLES.map(
6809
+ const { tables } = parsed.header;
6810
+ const incoming = tables.map(
6742
6811
  (t) => countCopyRows(parsed.sections.get(t.name) ?? Buffer.alloc(0))
6743
6812
  );
6744
6813
  await withDbClient(async (client) => {
6745
- if (!options2.yes && !await confirmReplace(client, incoming, !file)) {
6814
+ if (!options2.yes && !await confirmReplace(client, tables, incoming, !file)) {
6746
6815
  console.error(chalk58.yellow("Import cancelled; no changes made."));
6747
6816
  return;
6748
6817
  }
@@ -6750,7 +6819,7 @@ async function importBacklog(file, options2 = {}) {
6750
6819
  const total = incoming.reduce((sum, n) => sum + n, 0);
6751
6820
  console.error(
6752
6821
  chalk58.green(
6753
- `Imported backlog: ${total} rows restored across ${DUMP_TABLES.length} tables.`
6822
+ `Imported backlog: ${total} rows restored across ${tables.length} tables.`
6754
6823
  )
6755
6824
  );
6756
6825
  });
@@ -6759,7 +6828,7 @@ async function importBacklog(file, options2 = {}) {
6759
6828
  // src/commands/backlog/registerImportCommand.ts
6760
6829
  function registerImportCommand(cmd) {
6761
6830
  cmd.command("import [file]").description(
6762
- "Restore the entire backlog database from a dump file, or stdin if omitted (destructive)"
6831
+ "Restore every table in a dump back into the backlog database, in foreign-key-safe order, from a file or stdin if omitted (destructive)"
6763
6832
  ).option("-y, --yes", "Skip the confirmation prompt").action(
6764
6833
  (file, options2) => importBacklog(file, options2)
6765
6834
  );
@@ -6770,7 +6839,7 @@ import chalk59 from "chalk";
6770
6839
 
6771
6840
  // src/commands/backlog/add/shared.ts
6772
6841
  import { spawnSync as spawnSync2 } from "child_process";
6773
- import { mkdtempSync, readFileSync as readFileSync18, unlinkSync as unlinkSync6, writeFileSync as writeFileSync18 } from "fs";
6842
+ import { mkdtempSync, readFileSync as readFileSync17, unlinkSync as unlinkSync6, writeFileSync as writeFileSync18 } from "fs";
6774
6843
  import { tmpdir } from "os";
6775
6844
  import { join as join21 } from "path";
6776
6845
  import enquirer6 from "enquirer";
@@ -6820,7 +6889,7 @@ function openEditor() {
6820
6889
  unlinkSync6(filePath);
6821
6890
  return void 0;
6822
6891
  }
6823
- const content = readFileSync18(filePath, "utf8").trim();
6892
+ const content = readFileSync17(filePath, "utf8").trim();
6824
6893
  unlinkSync6(filePath);
6825
6894
  return content || void 0;
6826
6895
  }
@@ -8291,7 +8360,7 @@ function extractGraphqlQuery(args) {
8291
8360
  }
8292
8361
 
8293
8362
  // src/shared/loadCliReads.ts
8294
- import { existsSync as existsSync23, readFileSync as readFileSync19, writeFileSync as writeFileSync19 } from "fs";
8363
+ import { existsSync as existsSync23, readFileSync as readFileSync18, writeFileSync as writeFileSync19 } from "fs";
8295
8364
  import { dirname as dirname17, resolve as resolve8 } from "path";
8296
8365
  import { fileURLToPath as fileURLToPath4 } from "url";
8297
8366
  var __filename3 = fileURLToPath4(import.meta.url);
@@ -8301,7 +8370,7 @@ function packageRoot() {
8301
8370
  }
8302
8371
  function readLines(path57) {
8303
8372
  if (!existsSync23(path57)) return [];
8304
- return readFileSync19(path57, "utf8").split("\n").filter((line) => line.trim() !== "");
8373
+ return readFileSync18(path57, "utf8").split("\n").filter((line) => line.trim() !== "");
8305
8374
  }
8306
8375
  var cachedReads;
8307
8376
  var cachedWrites;
@@ -8347,7 +8416,7 @@ function findCliWrite(command) {
8347
8416
  }
8348
8417
 
8349
8418
  // src/shared/readSettingsPerms.ts
8350
- import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
8419
+ import { existsSync as existsSync24, readFileSync as readFileSync19 } from "fs";
8351
8420
  import { homedir as homedir9 } from "os";
8352
8421
  import { join as join23 } from "path";
8353
8422
  function readSettingsPerms(key) {
@@ -8365,7 +8434,7 @@ function readSettingsPerms(key) {
8365
8434
  function readPermissionArray(filePath, key) {
8366
8435
  if (!existsSync24(filePath)) return [];
8367
8436
  try {
8368
- const data = JSON.parse(readFileSync20(filePath, "utf8"));
8437
+ const data = JSON.parse(readFileSync19(filePath, "utf8"));
8369
8438
  const arr = data?.permissions?.[key];
8370
8439
  return Array.isArray(arr) ? arr.filter((e) => typeof e === "string") : [];
8371
8440
  } catch {
@@ -8627,12 +8696,12 @@ ${reasons.join("\n")}`);
8627
8696
  }
8628
8697
 
8629
8698
  // src/commands/permitCliReads/index.ts
8630
- import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync21, writeFileSync as writeFileSync20 } from "fs";
8699
+ import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync20, writeFileSync as writeFileSync20 } from "fs";
8631
8700
  import { homedir as homedir10 } from "os";
8632
8701
  import { join as join24 } from "path";
8633
8702
 
8634
8703
  // src/shared/checkCliAvailable.ts
8635
- import { execSync as execSync23 } from "child_process";
8704
+ import { execSync as execSync22 } from "child_process";
8636
8705
  function checkCliAvailable(cli) {
8637
8706
  const binary = cli.split(/\s+/)[0];
8638
8707
  const opts = {
@@ -8640,11 +8709,11 @@ function checkCliAvailable(cli) {
8640
8709
  stdio: ["ignore", "pipe", "pipe"]
8641
8710
  };
8642
8711
  try {
8643
- execSync23(`command -v ${binary}`, opts);
8712
+ execSync22(`command -v ${binary}`, opts);
8644
8713
  return true;
8645
8714
  } catch {
8646
8715
  try {
8647
- execSync23(`where ${binary}`, opts);
8716
+ execSync22(`where ${binary}`, opts);
8648
8717
  return true;
8649
8718
  } catch {
8650
8719
  return false;
@@ -8923,7 +8992,7 @@ function logPath(cli) {
8923
8992
  function readCache(cli) {
8924
8993
  const path57 = logPath(cli);
8925
8994
  if (!existsSync25(path57)) return void 0;
8926
- return readFileSync21(path57, "utf8");
8995
+ return readFileSync20(path57, "utf8");
8927
8996
  }
8928
8997
  function writeCache(cli, output) {
8929
8998
  const dir = join24(homedir10(), ".assist");
@@ -9069,11 +9138,11 @@ import ts5 from "typescript";
9069
9138
  // src/commands/complexity/findSourceFiles.ts
9070
9139
  import fs15 from "fs";
9071
9140
  import path20 from "path";
9072
- import { minimatch as minimatch4 } from "minimatch";
9141
+ import { minimatch as minimatch5 } from "minimatch";
9073
9142
  function applyIgnoreGlobs(files, extraIgnore = []) {
9074
9143
  const { complexity } = loadConfig();
9075
9144
  const ignore2 = [...complexity.ignore, ...extraIgnore];
9076
- return files.filter((f) => !ignore2.some((glob) => minimatch4(f, glob)));
9145
+ return files.filter((f) => !ignore2.some((glob) => minimatch5(f, glob)));
9077
9146
  }
9078
9147
  function walk(dir, results) {
9079
9148
  if (!fs15.existsSync(dir)) {
@@ -9097,7 +9166,7 @@ function findSourceFiles2(pattern2, baseDir = ".", extraIgnore = []) {
9097
9166
  if (pattern2.includes("*")) {
9098
9167
  walk(baseDir, results);
9099
9168
  return applyIgnoreGlobs(
9100
- results.filter((f) => minimatch4(f, pattern2)),
9169
+ results.filter((f) => minimatch5(f, pattern2)),
9101
9170
  extraIgnore
9102
9171
  );
9103
9172
  }
@@ -9110,7 +9179,7 @@ function findSourceFiles2(pattern2, baseDir = ".", extraIgnore = []) {
9110
9179
  }
9111
9180
  walk(baseDir, results);
9112
9181
  return applyIgnoreGlobs(
9113
- results.filter((f) => minimatch4(f, pattern2)),
9182
+ results.filter((f) => minimatch5(f, pattern2)),
9114
9183
  extraIgnore
9115
9184
  );
9116
9185
  }
@@ -9735,7 +9804,7 @@ function registerConfig(program2) {
9735
9804
  }
9736
9805
 
9737
9806
  // src/commands/deploy/redirect.ts
9738
- import { existsSync as existsSync26, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "fs";
9807
+ import { existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync21 } from "fs";
9739
9808
  import chalk99 from "chalk";
9740
9809
  var TRAILING_SLASH_SCRIPT = ` <script>
9741
9810
  if (!window.location.pathname.endsWith('/')) {
@@ -9748,7 +9817,7 @@ function redirect() {
9748
9817
  console.log(chalk99.yellow("No index.html found"));
9749
9818
  return;
9750
9819
  }
9751
- const content = readFileSync22(indexPath, "utf8");
9820
+ const content = readFileSync21(indexPath, "utf8");
9752
9821
  if (content.includes("window.location.pathname.endsWith('/')")) {
9753
9822
  console.log(chalk99.dim("Trailing slash script already present"));
9754
9823
  return;
@@ -9787,11 +9856,11 @@ function loadBlogSkipDays(repoName) {
9787
9856
  }
9788
9857
 
9789
9858
  // src/commands/devlog/shared.ts
9790
- import { execSync as execSync24 } from "child_process";
9859
+ import { execSync as execSync23 } from "child_process";
9791
9860
  import chalk100 from "chalk";
9792
9861
 
9793
9862
  // src/shared/getRepoName.ts
9794
- import { existsSync as existsSync27, readFileSync as readFileSync23 } from "fs";
9863
+ import { existsSync as existsSync27, readFileSync as readFileSync22 } from "fs";
9795
9864
  import { basename as basename3, join as join26 } from "path";
9796
9865
  function getRepoName() {
9797
9866
  const config = loadConfig();
@@ -9801,7 +9870,7 @@ function getRepoName() {
9801
9870
  const packageJsonPath = join26(process.cwd(), "package.json");
9802
9871
  if (existsSync27(packageJsonPath)) {
9803
9872
  try {
9804
- const content = readFileSync23(packageJsonPath, "utf8");
9873
+ const content = readFileSync22(packageJsonPath, "utf8");
9805
9874
  const pkg = JSON.parse(content);
9806
9875
  if (pkg.name) {
9807
9876
  return pkg.name;
@@ -9813,7 +9882,7 @@ function getRepoName() {
9813
9882
  }
9814
9883
 
9815
9884
  // src/commands/devlog/loadDevlogEntries.ts
9816
- import { readdirSync, readFileSync as readFileSync24 } from "fs";
9885
+ import { readdirSync, readFileSync as readFileSync23 } from "fs";
9817
9886
  import { join as join27 } from "path";
9818
9887
  var DEVLOG_DIR = join27(BLOG_REPO_ROOT, "src/content/devlog");
9819
9888
  function extractFrontmatter(content) {
@@ -9843,7 +9912,7 @@ function readDevlogFiles(callback) {
9843
9912
  try {
9844
9913
  const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
9845
9914
  for (const file of files) {
9846
- const content = readFileSync24(join27(DEVLOG_DIR, file), "utf8");
9915
+ const content = readFileSync23(join27(DEVLOG_DIR, file), "utf8");
9847
9916
  const parsed = parseFrontmatter(content, file);
9848
9917
  if (parsed) callback(parsed);
9849
9918
  }
@@ -9879,7 +9948,7 @@ function loadAllDevlogLatestDates() {
9879
9948
  // src/commands/devlog/shared.ts
9880
9949
  function getCommitFiles(hash) {
9881
9950
  try {
9882
- const output = execSync24(`git show --name-only --format="" ${hash}`, {
9951
+ const output = execSync23(`git show --name-only --format="" ${hash}`, {
9883
9952
  encoding: "utf8"
9884
9953
  });
9885
9954
  return output.trim().split("\n").filter(Boolean);
@@ -9975,11 +10044,11 @@ function list3(options2) {
9975
10044
  }
9976
10045
 
9977
10046
  // src/commands/devlog/getLastVersionInfo.ts
9978
- import { execFileSync as execFileSync3, execSync as execSync25 } from "child_process";
10047
+ import { execFileSync as execFileSync3, execSync as execSync24 } from "child_process";
9979
10048
  import semver from "semver";
9980
10049
  function getVersionAtCommit(hash) {
9981
10050
  try {
9982
- const content = execSync25(`git show ${hash}:package.json`, {
10051
+ const content = execSync24(`git show ${hash}:package.json`, {
9983
10052
  encoding: "utf8"
9984
10053
  });
9985
10054
  const pkg = JSON.parse(content);
@@ -10152,7 +10221,7 @@ function next2(options2) {
10152
10221
  }
10153
10222
 
10154
10223
  // src/commands/devlog/repos/index.ts
10155
- import { execSync as execSync26 } from "child_process";
10224
+ import { execSync as execSync25 } from "child_process";
10156
10225
 
10157
10226
  // src/commands/devlog/repos/printReposTable.ts
10158
10227
  import chalk104 from "chalk";
@@ -10187,7 +10256,7 @@ function getStatus(lastPush, lastDevlog) {
10187
10256
  return lastDevlog < lastPush ? "outdated" : "ok";
10188
10257
  }
10189
10258
  function fetchRepos(days, all) {
10190
- const json = execSync26(
10259
+ const json = execSync25(
10191
10260
  "gh repo list staff0rd --json name,pushedAt,isArchived --limit 200",
10192
10261
  { encoding: "utf8" }
10193
10262
  );
@@ -10371,11 +10440,11 @@ async function checkBuildLocksCommand() {
10371
10440
  }
10372
10441
 
10373
10442
  // src/commands/dotnet/buildTree.ts
10374
- import { readFileSync as readFileSync25 } from "fs";
10443
+ import { readFileSync as readFileSync24 } from "fs";
10375
10444
  import path23 from "path";
10376
10445
  var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
10377
10446
  function getProjectRefs(csprojPath) {
10378
- const content = readFileSync25(csprojPath, "utf8");
10447
+ const content = readFileSync24(csprojPath, "utf8");
10379
10448
  const refs = [];
10380
10449
  for (const match of content.matchAll(PROJECT_REF_RE)) {
10381
10450
  refs.push(match[1].replace(/\\/g, "/"));
@@ -10392,7 +10461,7 @@ function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
10392
10461
  for (const ref of getProjectRefs(abs)) {
10393
10462
  const childAbs = path23.resolve(dir, ref);
10394
10463
  try {
10395
- readFileSync25(childAbs);
10464
+ readFileSync24(childAbs);
10396
10465
  node.children.push(buildTree(childAbs, repoRoot, visited));
10397
10466
  } catch {
10398
10467
  node.children.push({
@@ -10417,7 +10486,7 @@ function collectAllDeps(node) {
10417
10486
  }
10418
10487
 
10419
10488
  // src/commands/dotnet/findContainingSolutions.ts
10420
- import { readdirSync as readdirSync3, readFileSync as readFileSync26, statSync as statSync2 } from "fs";
10489
+ import { readdirSync as readdirSync3, readFileSync as readFileSync25, statSync as statSync2 } from "fs";
10421
10490
  import path24 from "path";
10422
10491
  function findSlnFiles(dir, maxDepth, depth = 0) {
10423
10492
  if (depth > maxDepth) return [];
@@ -10452,7 +10521,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
10452
10521
  const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
10453
10522
  for (const sln of slnFiles) {
10454
10523
  try {
10455
- const content = readFileSync26(sln, "utf8");
10524
+ const content = readFileSync25(sln, "utf8");
10456
10525
  if (pattern2.test(content)) {
10457
10526
  matches.push(path24.relative(repoRoot, sln));
10458
10527
  }
@@ -10547,7 +10616,7 @@ async function deps(csprojPath, options2) {
10547
10616
  }
10548
10617
 
10549
10618
  // src/commands/dotnet/getChangedCsFiles.ts
10550
- import { execSync as execSync27 } from "child_process";
10619
+ import { execSync as execSync26 } from "child_process";
10551
10620
  var SCOPE_ALL = "all";
10552
10621
  var SCOPE_BASE = "base:";
10553
10622
  var SCOPE_COMMIT = "commit:";
@@ -10571,7 +10640,7 @@ function getChangedCsFiles(scope) {
10571
10640
  } else {
10572
10641
  cmd = "git diff --name-only HEAD";
10573
10642
  }
10574
- const output = execSync27(cmd, { encoding: "utf8" }).trim();
10643
+ const output = execSync26(cmd, { encoding: "utf8" }).trim();
10575
10644
  if (output === "") return [];
10576
10645
  return output.split("\n").filter((f) => f.toLowerCase().endsWith(".cs"));
10577
10646
  }
@@ -10769,14 +10838,14 @@ function parseInspectReport(json) {
10769
10838
  }
10770
10839
 
10771
10840
  // src/commands/dotnet/runInspectCode.ts
10772
- import { execSync as execSync28 } from "child_process";
10773
- import { existsSync as existsSync31, readFileSync as readFileSync27, unlinkSync as unlinkSync7 } from "fs";
10841
+ import { execSync as execSync27 } from "child_process";
10842
+ import { existsSync as existsSync31, readFileSync as readFileSync26, unlinkSync as unlinkSync7 } from "fs";
10774
10843
  import { tmpdir as tmpdir3 } from "os";
10775
10844
  import path27 from "path";
10776
10845
  import chalk114 from "chalk";
10777
10846
  function assertJbInstalled() {
10778
10847
  try {
10779
- execSync28("jb inspectcode --version", { stdio: "pipe" });
10848
+ execSync27("jb inspectcode --version", { stdio: "pipe" });
10780
10849
  } catch {
10781
10850
  console.error(chalk114.red("jb is not installed. Install with:"));
10782
10851
  console.error(
@@ -10790,7 +10859,7 @@ function runInspectCode(slnPath, include, swea) {
10790
10859
  const includeFlag = include ? ` --include="${include}"` : "";
10791
10860
  const sweaFlag = swea ? " --swea" : "";
10792
10861
  try {
10793
- execSync28(
10862
+ execSync27(
10794
10863
  `jb inspectcode "${slnPath}" -o="${reportPath}"${includeFlag}${sweaFlag} --verbosity=OFF`,
10795
10864
  { stdio: "pipe" }
10796
10865
  );
@@ -10805,13 +10874,13 @@ function runInspectCode(slnPath, include, swea) {
10805
10874
  console.error(chalk114.red("Report file not generated"));
10806
10875
  process.exit(1);
10807
10876
  }
10808
- const xml = readFileSync27(reportPath, "utf8");
10877
+ const xml = readFileSync26(reportPath, "utf8");
10809
10878
  unlinkSync7(reportPath);
10810
10879
  return xml;
10811
10880
  }
10812
10881
 
10813
10882
  // src/commands/dotnet/runRoslynInspect.ts
10814
- import { execSync as execSync29 } from "child_process";
10883
+ import { execSync as execSync28 } from "child_process";
10815
10884
  import chalk115 from "chalk";
10816
10885
  function resolveMsbuildPath() {
10817
10886
  const { run: run4 } = loadConfig();
@@ -10822,7 +10891,7 @@ function resolveMsbuildPath() {
10822
10891
  function assertMsbuildInstalled() {
10823
10892
  const msbuild = resolveMsbuildPath();
10824
10893
  try {
10825
- execSync29(`"${msbuild}" -version`, { stdio: "pipe" });
10894
+ execSync28(`"${msbuild}" -version`, { stdio: "pipe" });
10826
10895
  } catch {
10827
10896
  console.error(chalk115.red(`msbuild not found at: ${msbuild}`));
10828
10897
  console.error(
@@ -10848,7 +10917,7 @@ function runRoslynInspect(slnPath) {
10848
10917
  const msbuild = resolveMsbuildPath();
10849
10918
  let output;
10850
10919
  try {
10851
- output = execSync29(
10920
+ output = execSync28(
10852
10921
  `"${msbuild}" "${slnPath}" -t:Build -v:minimal -maxcpucount -p:EnforceCodeStyleInBuild=true -p:RunAnalyzersDuringBuild=true 2>&1`,
10853
10922
  { encoding: "utf8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
10854
10923
  );
@@ -11148,8 +11217,8 @@ async function countPendingHandovers(orm, origin) {
11148
11217
  import {
11149
11218
  existsSync as existsSync32,
11150
11219
  readdirSync as readdirSync5,
11151
- readFileSync as readFileSync28,
11152
- rmSync as rmSync3,
11220
+ readFileSync as readFileSync27,
11221
+ rmSync as rmSync2,
11153
11222
  statSync as statSync3
11154
11223
  } from "fs";
11155
11224
  import { basename as basename5, join as join34 } from "path";
@@ -11211,14 +11280,14 @@ function collectMarkdown(dir) {
11211
11280
  return out;
11212
11281
  }
11213
11282
  async function migrateFile(orm, origin, file, createdAt) {
11214
- const content = readFileSync28(file, "utf8");
11283
+ const content = readFileSync27(file, "utf8");
11215
11284
  await saveHandover(orm, {
11216
11285
  origin,
11217
11286
  summary: summariseHandoverContent(content),
11218
11287
  content,
11219
11288
  createdAt
11220
11289
  });
11221
- rmSync3(file);
11290
+ rmSync2(file);
11222
11291
  }
11223
11292
  async function migrateDiskHandovers(orm, origin, cwd = process.cwd()) {
11224
11293
  let migrated = 0;
@@ -11419,12 +11488,12 @@ function adfToText(doc) {
11419
11488
  }
11420
11489
 
11421
11490
  // src/commands/jira/fetchIssue.ts
11422
- import { execSync as execSync30 } from "child_process";
11491
+ import { execSync as execSync29 } from "child_process";
11423
11492
  import chalk119 from "chalk";
11424
11493
  function fetchIssue(issueKey, fields) {
11425
11494
  let result;
11426
11495
  try {
11427
- result = execSync30(
11496
+ result = execSync29(
11428
11497
  `acli jira workitem view ${issueKey} -f ${fields} --json`,
11429
11498
  { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }
11430
11499
  );
@@ -11470,10 +11539,10 @@ function acceptanceCriteria(issueKey) {
11470
11539
  }
11471
11540
 
11472
11541
  // src/commands/jira/jiraAuth.ts
11473
- import { execSync as execSync31 } from "child_process";
11542
+ import { execSync as execSync30 } from "child_process";
11474
11543
 
11475
11544
  // src/shared/loadJson.ts
11476
- import { existsSync as existsSync33, mkdirSync as mkdirSync11, readFileSync as readFileSync29, writeFileSync as writeFileSync24 } from "fs";
11545
+ import { existsSync as existsSync33, mkdirSync as mkdirSync11, readFileSync as readFileSync28, writeFileSync as writeFileSync24 } from "fs";
11477
11546
  import { homedir as homedir12 } from "os";
11478
11547
  import { join as join35 } from "path";
11479
11548
  function getStoreDir() {
@@ -11486,7 +11555,7 @@ function loadJson(filename) {
11486
11555
  const path57 = getStorePath(filename);
11487
11556
  if (existsSync33(path57)) {
11488
11557
  try {
11489
- return JSON.parse(readFileSync29(path57, "utf8"));
11558
+ return JSON.parse(readFileSync28(path57, "utf8"));
11490
11559
  } catch {
11491
11560
  return {};
11492
11561
  }
@@ -11534,7 +11603,7 @@ async function jiraAuth() {
11534
11603
  console.error("All fields are required.");
11535
11604
  process.exit(1);
11536
11605
  }
11537
- execSync31(`acli jira auth login --site ${site} --email "${email}" --token`, {
11606
+ execSync30(`acli jira auth login --site ${site} --email "${email}" --token`, {
11538
11607
  encoding: "utf8",
11539
11608
  input: token,
11540
11609
  stdio: ["pipe", "inherit", "inherit"]
@@ -11642,7 +11711,7 @@ import { resolve as resolve11 } from "path";
11642
11711
  import chalk125 from "chalk";
11643
11712
 
11644
11713
  // src/commands/mermaid/exportFile.ts
11645
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync25 } from "fs";
11714
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync25 } from "fs";
11646
11715
  import { basename as basename6, extname, resolve as resolve10 } from "path";
11647
11716
  import chalk124 from "chalk";
11648
11717
 
@@ -11668,7 +11737,7 @@ async function renderBlock(krokiUrl, source) {
11668
11737
 
11669
11738
  // src/commands/mermaid/exportFile.ts
11670
11739
  async function exportFile(file, outDir, krokiUrl, onlyIndex) {
11671
- const content = readFileSync30(file, "utf8");
11740
+ const content = readFileSync29(file, "utf8");
11672
11741
  const blocks = extractMermaidBlocks(content);
11673
11742
  const stem = basename6(file, extname(file));
11674
11743
  if (onlyIndex !== void 0) {
@@ -11952,7 +12021,7 @@ import { join as join40 } from "path";
11952
12021
  import chalk128 from "chalk";
11953
12022
 
11954
12023
  // src/commands/netcap/extractPostsFromCapture.ts
11955
- import { readFileSync as readFileSync31 } from "fs";
12024
+ import { readFileSync as readFileSync30 } from "fs";
11956
12025
 
11957
12026
  // src/commands/netcap/parseRscRows.ts
11958
12027
  var isRscRef = (v) => typeof v === "string" && /^\$[0-9a-fL@]/.test(v);
@@ -12348,7 +12417,7 @@ function extractVoyagerPosts(body) {
12348
12417
 
12349
12418
  // src/commands/netcap/extractPostsFromCapture.ts
12350
12419
  function captureEntries(captureFile) {
12351
- const lines = readFileSync31(captureFile, "utf8").split("\n").filter(Boolean);
12420
+ const lines = readFileSync30(captureFile, "utf8").split("\n").filter(Boolean);
12352
12421
  const entries = [];
12353
12422
  for (const line of lines) {
12354
12423
  let entry;
@@ -12508,7 +12577,7 @@ function registerPrompts(program2) {
12508
12577
  }
12509
12578
 
12510
12579
  // src/commands/prs/shared.ts
12511
- import { execSync as execSync32 } from "child_process";
12580
+ import { execSync as execSync31 } from "child_process";
12512
12581
  function isGhNotInstalled(error) {
12513
12582
  if (error instanceof Error) {
12514
12583
  const msg = error.message.toLowerCase();
@@ -12526,12 +12595,12 @@ function getRepoInfo() {
12526
12595
  const preferred = getPreferredRemoteRepo();
12527
12596
  if (preferred) return preferred;
12528
12597
  const repoInfo = JSON.parse(
12529
- execSync32("gh repo view --json owner,name", { encoding: "utf8" })
12598
+ execSync31("gh repo view --json owner,name", { encoding: "utf8" })
12530
12599
  );
12531
12600
  return { org: repoInfo.owner.login, repo: repoInfo.name };
12532
12601
  }
12533
12602
  function getCurrentBranch() {
12534
- return execSync32("git rev-parse --abbrev-ref HEAD", {
12603
+ return execSync31("git rev-parse --abbrev-ref HEAD", {
12535
12604
  encoding: "utf8"
12536
12605
  }).trim();
12537
12606
  }
@@ -12539,7 +12608,7 @@ function viewCurrentPr(fields) {
12539
12608
  const { org, repo } = getRepoInfo();
12540
12609
  const branch = getCurrentBranch();
12541
12610
  return JSON.parse(
12542
- execSync32(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
12611
+ execSync31(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
12543
12612
  encoding: "utf8"
12544
12613
  })
12545
12614
  );
@@ -12643,7 +12712,7 @@ function comment2(path57, line, body, startLine) {
12643
12712
  }
12644
12713
 
12645
12714
  // src/commands/prs/edit.ts
12646
- import { execSync as execSync33 } from "child_process";
12715
+ import { execSync as execSync32 } from "child_process";
12647
12716
 
12648
12717
  // src/commands/prs/buildPrBody.ts
12649
12718
  function jiraBrowseUrl(key) {
@@ -12816,23 +12885,23 @@ function edit(options2) {
12816
12885
  if (options2.title) args.push(`--title ${shellQuote(options2.title)}`);
12817
12886
  args.push(`--body ${shellQuote(newBody)}`);
12818
12887
  try {
12819
- execSync33(args.join(" "), { stdio: "inherit" });
12888
+ execSync32(args.join(" "), { stdio: "inherit" });
12820
12889
  } catch {
12821
12890
  process.exit(1);
12822
12891
  }
12823
12892
  }
12824
12893
 
12825
12894
  // src/commands/prs/fixed.ts
12826
- import { execSync as execSync36 } from "child_process";
12895
+ import { execSync as execSync35 } from "child_process";
12827
12896
 
12828
12897
  // src/commands/prs/resolveCommentWithReply.ts
12829
- import { execSync as execSync35 } from "child_process";
12898
+ import { execSync as execSync34 } from "child_process";
12830
12899
  import { unlinkSync as unlinkSync10, writeFileSync as writeFileSync27 } from "fs";
12831
12900
  import { tmpdir as tmpdir5 } from "os";
12832
12901
  import { join as join42 } from "path";
12833
12902
 
12834
12903
  // src/commands/prs/loadCommentsCache.ts
12835
- import { existsSync as existsSync34, readFileSync as readFileSync32, unlinkSync as unlinkSync9 } from "fs";
12904
+ import { existsSync as existsSync34, readFileSync as readFileSync31, unlinkSync as unlinkSync9 } from "fs";
12836
12905
  import { join as join41 } from "path";
12837
12906
  import { parse as parse2 } from "yaml";
12838
12907
  function getCachePath(prNumber) {
@@ -12843,7 +12912,7 @@ function loadCommentsCache(prNumber) {
12843
12912
  if (!existsSync34(cachePath)) {
12844
12913
  return null;
12845
12914
  }
12846
- const content = readFileSync32(cachePath, "utf8");
12915
+ const content = readFileSync31(cachePath, "utf8");
12847
12916
  return parse2(content);
12848
12917
  }
12849
12918
  function deleteCommentsCache(prNumber) {
@@ -12855,9 +12924,9 @@ function deleteCommentsCache(prNumber) {
12855
12924
  }
12856
12925
 
12857
12926
  // src/commands/prs/replyToComment.ts
12858
- import { execSync as execSync34 } from "child_process";
12927
+ import { execSync as execSync33 } from "child_process";
12859
12928
  function replyToComment(org, repo, prNumber, commentId, message) {
12860
- execSync34(
12929
+ execSync33(
12861
12930
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, String.raw`\"`)}" -F in_reply_to=${commentId}`,
12862
12931
  { stdio: ["inherit", "pipe", "inherit"] }
12863
12932
  );
@@ -12869,7 +12938,7 @@ function resolveThread(threadId) {
12869
12938
  const queryFile = join42(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
12870
12939
  writeFileSync27(queryFile, mutation);
12871
12940
  try {
12872
- execSync35(
12941
+ execSync34(
12873
12942
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
12874
12943
  { stdio: ["inherit", "pipe", "inherit"] }
12875
12944
  );
@@ -12921,7 +12990,7 @@ function resolveCommentWithReply(commentId, message) {
12921
12990
  // src/commands/prs/fixed.ts
12922
12991
  function verifySha(sha) {
12923
12992
  try {
12924
- return execSync36(`git rev-parse --verify ${sha}`, {
12993
+ return execSync35(`git rev-parse --verify ${sha}`, {
12925
12994
  encoding: "utf8"
12926
12995
  }).trim();
12927
12996
  } catch {
@@ -12935,7 +13004,7 @@ function fixed(commentId, sha) {
12935
13004
  const { org, repo } = getRepoInfo();
12936
13005
  const repoUrl = `https://github.com/${org}/${repo}`;
12937
13006
  const message = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
12938
- execSync36("git push", { stdio: "inherit" });
13007
+ execSync35("git push", { stdio: "inherit" });
12939
13008
  resolveCommentWithReply(commentId, message);
12940
13009
  } catch (error) {
12941
13010
  if (isGhNotInstalled(error)) {
@@ -12953,7 +13022,7 @@ import { join as join44 } from "path";
12953
13022
  import { stringify } from "yaml";
12954
13023
 
12955
13024
  // src/commands/prs/fetchThreadIds.ts
12956
- import { execSync as execSync37 } from "child_process";
13025
+ import { execSync as execSync36 } from "child_process";
12957
13026
  import { unlinkSync as unlinkSync11, writeFileSync as writeFileSync28 } from "fs";
12958
13027
  import { tmpdir as tmpdir6 } from "os";
12959
13028
  import { join as join43 } from "path";
@@ -12962,7 +13031,7 @@ function fetchThreadIds(org, repo, prNumber) {
12962
13031
  const queryFile = join43(tmpdir6(), `gh-query-${Date.now()}.graphql`);
12963
13032
  writeFileSync28(queryFile, THREAD_QUERY);
12964
13033
  try {
12965
- const result = execSync37(
13034
+ const result = execSync36(
12966
13035
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
12967
13036
  { encoding: "utf8" }
12968
13037
  );
@@ -12984,9 +13053,9 @@ function fetchThreadIds(org, repo, prNumber) {
12984
13053
  }
12985
13054
 
12986
13055
  // src/commands/prs/listComments/fetchReviewComments.ts
12987
- import { execSync as execSync38 } from "child_process";
13056
+ import { execSync as execSync37 } from "child_process";
12988
13057
  function fetchJson(endpoint) {
12989
- const result = execSync38(`gh api --paginate ${endpoint}`, {
13058
+ const result = execSync37(`gh api --paginate ${endpoint}`, {
12990
13059
  encoding: "utf8"
12991
13060
  });
12992
13061
  if (!result.trim()) return [];
@@ -13125,7 +13194,7 @@ async function listComments() {
13125
13194
  }
13126
13195
 
13127
13196
  // src/commands/prs/prs/index.ts
13128
- import { execSync as execSync39 } from "child_process";
13197
+ import { execSync as execSync38 } from "child_process";
13129
13198
 
13130
13199
  // src/commands/prs/prs/displayPaginated/index.ts
13131
13200
  import enquirer9 from "enquirer";
@@ -13232,7 +13301,7 @@ async function prs(options2) {
13232
13301
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
13233
13302
  try {
13234
13303
  const { org, repo } = getRepoInfo();
13235
- const result = execSync39(
13304
+ const result = execSync38(
13236
13305
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100 -R ${org}/${repo}`,
13237
13306
  { encoding: "utf8" }
13238
13307
  );
@@ -13255,7 +13324,7 @@ async function prs(options2) {
13255
13324
  }
13256
13325
 
13257
13326
  // src/commands/prs/raise.ts
13258
- import { execSync as execSync40 } from "child_process";
13327
+ import { execSync as execSync39 } from "child_process";
13259
13328
 
13260
13329
  // src/commands/prs/buildCreateArgs.ts
13261
13330
  function buildCreateArgs(title, body, options2) {
@@ -13315,7 +13384,7 @@ function raise(options2) {
13315
13384
  `--body ${shellQuote(body)}`
13316
13385
  ] : buildCreateArgs(options2.title, body, options2);
13317
13386
  try {
13318
- execSync40(args.join(" "), { stdio: "inherit" });
13387
+ execSync39(args.join(" "), { stdio: "inherit" });
13319
13388
  } catch {
13320
13389
  process.exit(1);
13321
13390
  }
@@ -13347,7 +13416,7 @@ function reply(commentId, body) {
13347
13416
  }
13348
13417
 
13349
13418
  // src/commands/prs/wontfix.ts
13350
- import { execSync as execSync41 } from "child_process";
13419
+ import { execSync as execSync40 } from "child_process";
13351
13420
  function validateReason(reason) {
13352
13421
  const lowerReason = reason.toLowerCase();
13353
13422
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -13364,7 +13433,7 @@ function validateShaReferences(reason) {
13364
13433
  const invalidShas = [];
13365
13434
  for (const sha of shas) {
13366
13435
  try {
13367
- execSync41(`git cat-file -t ${sha}`, { stdio: "pipe" });
13436
+ execSync40(`git cat-file -t ${sha}`, { stdio: "pipe" });
13368
13437
  } catch {
13369
13438
  invalidShas.push(sha);
13370
13439
  }
@@ -13526,10 +13595,10 @@ import chalk135 from "chalk";
13526
13595
  import Enquirer2 from "enquirer";
13527
13596
 
13528
13597
  // src/commands/ravendb/searchItems.ts
13529
- import { execSync as execSync42 } from "child_process";
13598
+ import { execSync as execSync41 } from "child_process";
13530
13599
  import chalk134 from "chalk";
13531
13600
  function opExec(args) {
13532
- return execSync42(`op ${args}`, {
13601
+ return execSync41(`op ${args}`, {
13533
13602
  encoding: "utf8",
13534
13603
  stdio: ["pipe", "pipe", "pipe"]
13535
13604
  }).trim();
@@ -13681,7 +13750,7 @@ ${errorText}`
13681
13750
  }
13682
13751
 
13683
13752
  // src/commands/ravendb/resolveOpSecret.ts
13684
- import { execSync as execSync43 } from "child_process";
13753
+ import { execSync as execSync42 } from "child_process";
13685
13754
  import chalk139 from "chalk";
13686
13755
  function resolveOpSecret(reference) {
13687
13756
  if (!reference.startsWith("op://")) {
@@ -13689,7 +13758,7 @@ function resolveOpSecret(reference) {
13689
13758
  process.exit(1);
13690
13759
  }
13691
13760
  try {
13692
- return execSync43(`op read "${reference}"`, {
13761
+ return execSync42(`op read "${reference}"`, {
13693
13762
  encoding: "utf8",
13694
13763
  stdio: ["pipe", "pipe", "pipe"]
13695
13764
  }).trim();
@@ -13938,9 +14007,9 @@ Refactor check failed:
13938
14007
  }
13939
14008
 
13940
14009
  // src/commands/refactor/check/getViolations/index.ts
13941
- import { execSync as execSync44 } from "child_process";
14010
+ import { execSync as execSync43 } from "child_process";
13942
14011
  import fs20 from "fs";
13943
- import { minimatch as minimatch5 } from "minimatch";
14012
+ import { minimatch as minimatch6 } from "minimatch";
13944
14013
 
13945
14014
  // src/commands/refactor/check/getViolations/getIgnoredFiles.ts
13946
14015
  import fs19 from "fs";
@@ -13988,7 +14057,7 @@ function getGitFiles(options2) {
13988
14057
  }
13989
14058
  const files = /* @__PURE__ */ new Set();
13990
14059
  if (options2.staged || options2.modified) {
13991
- const staged = execSync44("git diff --cached --name-only", {
14060
+ const staged = execSync43("git diff --cached --name-only", {
13992
14061
  encoding: "utf8"
13993
14062
  });
13994
14063
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -13996,7 +14065,7 @@ function getGitFiles(options2) {
13996
14065
  }
13997
14066
  }
13998
14067
  if (options2.unstaged || options2.modified) {
13999
- const unstaged = execSync44("git diff --name-only", { encoding: "utf8" });
14068
+ const unstaged = execSync43("git diff --name-only", { encoding: "utf8" });
14000
14069
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
14001
14070
  files.add(file);
14002
14071
  }
@@ -14008,7 +14077,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
14008
14077
  const ignoredFiles = getIgnoredFiles();
14009
14078
  const gitFiles = getGitFiles(options2);
14010
14079
  if (pattern2) {
14011
- sourceFiles = sourceFiles.filter((f) => minimatch5(f, pattern2));
14080
+ sourceFiles = sourceFiles.filter((f) => minimatch6(f, pattern2));
14012
14081
  }
14013
14082
  if (gitFiles) {
14014
14083
  sourceFiles = sourceFiles.filter((f) => gitFiles.has(f));
@@ -14093,7 +14162,7 @@ import { SyntaxKind as SyntaxKind4 } from "ts-morph";
14093
14162
  import {
14094
14163
  SyntaxKind as SyntaxKind2
14095
14164
  } from "ts-morph";
14096
- var suppressionPattern = /^\s*(\/\/|\/\*)\s*(biome-ignore(-all)?|oxlint-disable)\b/;
14165
+ var suppressionPattern = /^\s*(\/\/|\/\*)\s*oxlint-disable\b/;
14097
14166
  function countLeadingSuppressions(sourceFile) {
14098
14167
  let count6 = 0;
14099
14168
  for (const stmt of sourceFile.getStatementsWithComments()) {
@@ -15640,9 +15709,9 @@ function buildReviewPaths(repoRoot, key) {
15640
15709
  }
15641
15710
 
15642
15711
  // src/commands/review/fetchExistingComments.ts
15643
- import { execSync as execSync45 } from "child_process";
15712
+ import { execSync as execSync44 } from "child_process";
15644
15713
  function fetchRawComments(org, repo, prNumber) {
15645
- const out = execSync45(
15714
+ const out = execSync44(
15646
15715
  `gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
15647
15716
  { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }
15648
15717
  );
@@ -15673,14 +15742,14 @@ function fetchExistingComments() {
15673
15742
  }
15674
15743
 
15675
15744
  // src/commands/review/gatherContext.ts
15676
- import { execSync as execSync48 } from "child_process";
15745
+ import { execSync as execSync47 } from "child_process";
15677
15746
 
15678
15747
  // src/commands/review/fetchPrDiff.ts
15679
- import { execSync as execSync46 } from "child_process";
15748
+ import { execSync as execSync45 } from "child_process";
15680
15749
  function fetchPrDiff(prNumber, baseSha, headSha) {
15681
15750
  const { org, repo } = getRepoInfo();
15682
15751
  try {
15683
- return execSync46(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
15752
+ return execSync45(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
15684
15753
  encoding: "utf8",
15685
15754
  maxBuffer: 256 * 1024 * 1024,
15686
15755
  stdio: ["ignore", "pipe", "pipe"]
@@ -15695,19 +15764,19 @@ function isDiffTooLarge(error) {
15695
15764
  }
15696
15765
  function fetchDiffViaGit(baseSha, headSha) {
15697
15766
  try {
15698
- execSync46(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
15767
+ execSync45(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
15699
15768
  } catch {
15700
15769
  }
15701
- return execSync46(`git diff ${baseSha}...${headSha}`, {
15770
+ return execSync45(`git diff ${baseSha}...${headSha}`, {
15702
15771
  encoding: "utf8",
15703
15772
  maxBuffer: 256 * 1024 * 1024
15704
15773
  });
15705
15774
  }
15706
15775
 
15707
15776
  // src/commands/review/fetchPrDiffInfo.ts
15708
- import { execSync as execSync47 } from "child_process";
15777
+ import { execSync as execSync46 } from "child_process";
15709
15778
  function getCurrentBranch2() {
15710
- return execSync47("git rev-parse --abbrev-ref HEAD", {
15779
+ return execSync46("git rev-parse --abbrev-ref HEAD", {
15711
15780
  encoding: "utf8"
15712
15781
  }).trim();
15713
15782
  }
@@ -15717,7 +15786,7 @@ function fetchPrDiffInfo() {
15717
15786
  const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
15718
15787
  let raw;
15719
15788
  try {
15720
- raw = execSync47(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
15789
+ raw = execSync46(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
15721
15790
  encoding: "utf8",
15722
15791
  stdio: ["ignore", "pipe", "pipe"]
15723
15792
  });
@@ -15741,7 +15810,7 @@ function fetchPrDiffInfo() {
15741
15810
  }
15742
15811
  function fetchPrChangedFiles(prNumber) {
15743
15812
  const { org, repo } = getRepoInfo();
15744
- const out = execSync47(
15813
+ const out = execSync46(
15745
15814
  `gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
15746
15815
  {
15747
15816
  encoding: "utf8",
@@ -15753,11 +15822,11 @@ function fetchPrChangedFiles(prNumber) {
15753
15822
 
15754
15823
  // src/commands/review/gatherContext.ts
15755
15824
  function gatherContext() {
15756
- const branch = execSync48("git rev-parse --abbrev-ref HEAD", {
15825
+ const branch = execSync47("git rev-parse --abbrev-ref HEAD", {
15757
15826
  encoding: "utf8"
15758
15827
  }).trim();
15759
- const sha = execSync48("git rev-parse HEAD", { encoding: "utf8" }).trim();
15760
- const shortSha = execSync48("git rev-parse --short=7 HEAD", {
15828
+ const sha = execSync47("git rev-parse HEAD", { encoding: "utf8" }).trim();
15829
+ const shortSha = execSync47("git rev-parse --short=7 HEAD", {
15761
15830
  encoding: "utf8"
15762
15831
  }).trim();
15763
15832
  const prInfo = fetchPrDiffInfo();
@@ -15778,7 +15847,7 @@ function gatherContext() {
15778
15847
  }
15779
15848
 
15780
15849
  // src/commands/review/postReviewToPr.ts
15781
- import { readFileSync as readFileSync33 } from "fs";
15850
+ import { readFileSync as readFileSync32 } from "fs";
15782
15851
 
15783
15852
  // src/commands/review/parseFindings.ts
15784
15853
  var SEVERITIES = ["blocker", "major", "minor", "nit"];
@@ -16088,7 +16157,7 @@ async function confirmPost(prNumber, count6, options2) {
16088
16157
  async function postReviewToPr(synthesisPath, options2) {
16089
16158
  const prInfo = fetchPrDiffInfo();
16090
16159
  const prNumber = prInfo.prNumber;
16091
- const markdown = readFileSync33(synthesisPath, "utf8");
16160
+ const markdown = readFileSync32(synthesisPath, "utf8");
16092
16161
  const findings = parseFindings(markdown);
16093
16162
  if (findings.length === 0) {
16094
16163
  console.log("Synthesis contains no findings; nothing to post.");
@@ -16972,7 +17041,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
16972
17041
  }
16973
17042
 
16974
17043
  // src/commands/review/synthesise.ts
16975
- import { readFileSync as readFileSync34 } from "fs";
17044
+ import { readFileSync as readFileSync33 } from "fs";
16976
17045
 
16977
17046
  // src/commands/review/buildSynthesisStdin.ts
16978
17047
  var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
@@ -17028,7 +17097,7 @@ Files:
17028
17097
 
17029
17098
  // src/commands/review/synthesise.ts
17030
17099
  function printSummary2(synthesisPath) {
17031
- const markdown = readFileSync34(synthesisPath, "utf8");
17100
+ const markdown = readFileSync33(synthesisPath, "utf8");
17032
17101
  console.log("");
17033
17102
  console.log(buildReviewSummary(markdown));
17034
17103
  console.log("");
@@ -18042,7 +18111,7 @@ async function fixInvalidDatePrefixes(vttFiles) {
18042
18111
  }
18043
18112
 
18044
18113
  // src/commands/transcript/format/processVttFile/index.ts
18045
- import { existsSync as existsSync40, mkdirSync as mkdirSync15, readFileSync as readFileSync35, writeFileSync as writeFileSync32 } from "fs";
18114
+ import { existsSync as existsSync40, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync32 } from "fs";
18046
18115
  import { basename as basename9, dirname as dirname23, join as join49 } from "path";
18047
18116
 
18048
18117
  // src/commands/transcript/cleanText.ts
@@ -18290,7 +18359,7 @@ function logReduction(cueCount, messageCount) {
18290
18359
  }
18291
18360
  function readAndParseCues(inputPath) {
18292
18361
  console.log(`Reading: ${inputPath}`);
18293
- return processCues(readFileSync35(inputPath, "utf8"));
18362
+ return processCues(readFileSync34(inputPath, "utf8"));
18294
18363
  }
18295
18364
  function writeFormatted(outputPath, content) {
18296
18365
  writeFileSync32(outputPath, content, "utf8");
@@ -18368,9 +18437,9 @@ import { basename as basename10, dirname as dirname25, join as join51, relative
18368
18437
  import {
18369
18438
  existsSync as existsSync42,
18370
18439
  mkdirSync as mkdirSync16,
18371
- readFileSync as readFileSync36,
18440
+ readFileSync as readFileSync35,
18372
18441
  renameSync as renameSync3,
18373
- rmSync as rmSync4
18442
+ rmSync as rmSync3
18374
18443
  } from "fs";
18375
18444
  import { dirname as dirname24, join as join50 } from "path";
18376
18445
 
@@ -18412,7 +18481,7 @@ function processStagedFile() {
18412
18481
  }
18413
18482
  const { transcriptsDir, summaryDir } = getTranscriptConfig();
18414
18483
  const stagedFile = stagedFiles[0];
18415
- const content = readFileSync36(stagedFile.absolutePath, "utf8");
18484
+ const content = readFileSync35(stagedFile.absolutePath, "utf8");
18416
18485
  validateStagedContent(stagedFile.filename, content);
18417
18486
  const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
18418
18487
  const transcriptFiles = findMdFilesRecursive(transcriptsDir);
@@ -18433,7 +18502,7 @@ function processStagedFile() {
18433
18502
  renameSync3(stagedFile.absolutePath, destPath);
18434
18503
  const remaining = findMdFilesRecursive(STAGING_DIR);
18435
18504
  if (remaining.length === 0) {
18436
- rmSync4(STAGING_DIR, { recursive: true });
18505
+ rmSync3(STAGING_DIR, { recursive: true });
18437
18506
  }
18438
18507
  return true;
18439
18508
  }
@@ -18524,9 +18593,9 @@ function registerVerify(program2) {
18524
18593
  verifyCommand.command("hardcoded-colors").description("Check for hardcoded hex colors in src/").action(hardcodedColors);
18525
18594
  verifyCommand.command("comment-policy").description("Check for undocumented comments added on changed lines").action(commentPolicy);
18526
18595
  verifyCommand.command("no-venv").description("Check that no venv folders exist in the repo").action(noVenv);
18527
- verifyCommand.command("settings-guard").description(
18528
- "Check that claude/settings.json permission lists contain no assist references"
18529
- ).action(settingsGuard);
18596
+ verifyCommand.command("forbidden-strings").description(
18597
+ "Check configured JSON files for values matching forbiddenStrings rules"
18598
+ ).action(forbiddenStrings);
18530
18599
  }
18531
18600
 
18532
18601
  // src/commands/voice/devices.ts
@@ -18567,14 +18636,14 @@ function devices() {
18567
18636
  }
18568
18637
 
18569
18638
  // src/commands/voice/logs.ts
18570
- import { existsSync as existsSync44, readFileSync as readFileSync37 } from "fs";
18639
+ import { existsSync as existsSync44, readFileSync as readFileSync36 } from "fs";
18571
18640
  function logs(options2) {
18572
18641
  if (!existsSync44(voicePaths.log)) {
18573
18642
  console.log("No voice log file found");
18574
18643
  return;
18575
18644
  }
18576
18645
  const count6 = Number.parseInt(options2.lines ?? "150", 10);
18577
- const content = readFileSync37(voicePaths.log, "utf8").trim();
18646
+ const content = readFileSync36(voicePaths.log, "utf8").trim();
18578
18647
  if (!content) {
18579
18648
  console.log("Voice log is empty");
18580
18649
  return;
@@ -18600,8 +18669,8 @@ import { mkdirSync as mkdirSync18 } from "fs";
18600
18669
  import { join as join55 } from "path";
18601
18670
 
18602
18671
  // src/commands/voice/checkLockFile.ts
18603
- import { execSync as execSync49 } from "child_process";
18604
- import { existsSync as existsSync45, mkdirSync as mkdirSync17, readFileSync as readFileSync38, writeFileSync as writeFileSync33 } from "fs";
18672
+ import { execSync as execSync48 } from "child_process";
18673
+ import { existsSync as existsSync45, mkdirSync as mkdirSync17, readFileSync as readFileSync37, writeFileSync as writeFileSync33 } from "fs";
18605
18674
  import { join as join54 } from "path";
18606
18675
  function isProcessAlive2(pid) {
18607
18676
  try {
@@ -18615,7 +18684,7 @@ function checkLockFile() {
18615
18684
  const lockFile = getLockFile();
18616
18685
  if (!existsSync45(lockFile)) return;
18617
18686
  try {
18618
- const lock = JSON.parse(readFileSync38(lockFile, "utf8"));
18687
+ const lock = JSON.parse(readFileSync37(lockFile, "utf8"));
18619
18688
  if (lock.pid && isProcessAlive2(lock.pid)) {
18620
18689
  console.error(
18621
18690
  `Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
@@ -18629,7 +18698,7 @@ function bootstrapVenv() {
18629
18698
  if (existsSync45(getVenvPython())) return;
18630
18699
  console.log("Setting up Python environment...");
18631
18700
  const pythonDir = getPythonDir();
18632
- execSync49(
18701
+ execSync48(
18633
18702
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
18634
18703
  {
18635
18704
  stdio: "inherit",
@@ -18717,7 +18786,7 @@ function start2(options2) {
18717
18786
  }
18718
18787
 
18719
18788
  // src/commands/voice/status.ts
18720
- import { existsSync as existsSync46, readFileSync as readFileSync39 } from "fs";
18789
+ import { existsSync as existsSync46, readFileSync as readFileSync38 } from "fs";
18721
18790
  function isProcessAlive3(pid) {
18722
18791
  try {
18723
18792
  process.kill(pid, 0);
@@ -18728,7 +18797,7 @@ function isProcessAlive3(pid) {
18728
18797
  }
18729
18798
  function readRecentLogs(count6) {
18730
18799
  if (!existsSync46(voicePaths.log)) return [];
18731
- const lines = readFileSync39(voicePaths.log, "utf8").trim().split("\n");
18800
+ const lines = readFileSync38(voicePaths.log, "utf8").trim().split("\n");
18732
18801
  return lines.slice(-count6);
18733
18802
  }
18734
18803
  function status() {
@@ -18736,7 +18805,7 @@ function status() {
18736
18805
  console.log("Voice daemon: not running (no PID file)");
18737
18806
  return;
18738
18807
  }
18739
- const pid = Number.parseInt(readFileSync39(voicePaths.pid, "utf8").trim(), 10);
18808
+ const pid = Number.parseInt(readFileSync38(voicePaths.pid, "utf8").trim(), 10);
18740
18809
  const alive = isProcessAlive3(pid);
18741
18810
  console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
18742
18811
  const recent = readRecentLogs(5);
@@ -18755,13 +18824,13 @@ function status() {
18755
18824
  }
18756
18825
 
18757
18826
  // src/commands/voice/stop.ts
18758
- import { existsSync as existsSync47, readFileSync as readFileSync40, unlinkSync as unlinkSync15 } from "fs";
18827
+ import { existsSync as existsSync47, readFileSync as readFileSync39, unlinkSync as unlinkSync15 } from "fs";
18759
18828
  function stop2() {
18760
18829
  if (!existsSync47(voicePaths.pid)) {
18761
18830
  console.log("Voice daemon is not running (no PID file)");
18762
18831
  return;
18763
18832
  }
18764
- const pid = Number.parseInt(readFileSync40(voicePaths.pid, "utf8").trim(), 10);
18833
+ const pid = Number.parseInt(readFileSync39(voicePaths.pid, "utf8").trim(), 10);
18765
18834
  try {
18766
18835
  process.kill(pid, "SIGTERM");
18767
18836
  console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
@@ -18952,7 +19021,7 @@ async function auth() {
18952
19021
 
18953
19022
  // src/commands/roam/postRoamActivity.ts
18954
19023
  import { execFileSync as execFileSync7 } from "child_process";
18955
- import { readdirSync as readdirSync8, readFileSync as readFileSync41, statSync as statSync6 } from "fs";
19024
+ import { readdirSync as readdirSync8, readFileSync as readFileSync40, statSync as statSync6 } from "fs";
18956
19025
  import { join as join57 } from "path";
18957
19026
  function findPortFile(roamDir) {
18958
19027
  let entries;
@@ -18978,7 +19047,7 @@ function postRoamActivity(app, event) {
18978
19047
  if (!portFile) return;
18979
19048
  let port;
18980
19049
  try {
18981
- port = readFileSync41(portFile, "utf8").trim();
19050
+ port = readFileSync40(portFile, "utf8").trim();
18982
19051
  } catch {
18983
19052
  return;
18984
19053
  }
@@ -19106,11 +19175,11 @@ function resolveParams(params, cliArgs) {
19106
19175
  }
19107
19176
 
19108
19177
  // src/commands/run/runPreCommands.ts
19109
- import { execSync as execSync50 } from "child_process";
19178
+ import { execSync as execSync49 } from "child_process";
19110
19179
  function runPreCommands(pre, cwd) {
19111
19180
  for (const cmd of pre) {
19112
19181
  try {
19113
- execSync50(cmd, { stdio: "inherit", cwd });
19182
+ execSync49(cmd, { stdio: "inherit", cwd });
19114
19183
  } catch (error) {
19115
19184
  const code = error && typeof error === "object" && "status" in error ? error.status : 1;
19116
19185
  process.exit(code);
@@ -19394,7 +19463,7 @@ function registerRun(program2) {
19394
19463
  }
19395
19464
 
19396
19465
  // src/commands/screenshot/index.ts
19397
- import { execSync as execSync51 } from "child_process";
19466
+ import { execSync as execSync50 } from "child_process";
19398
19467
  import { existsSync as existsSync50, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync36 } from "fs";
19399
19468
  import { tmpdir as tmpdir7 } from "os";
19400
19469
  import { join as join61, resolve as resolve15 } from "path";
@@ -19537,7 +19606,7 @@ function runPowerShellScript(processName, outputPath) {
19537
19606
  const scriptPath = join61(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
19538
19607
  writeFileSync36(scriptPath, captureWindowPs1, "utf8");
19539
19608
  try {
19540
- execSync51(
19609
+ execSync50(
19541
19610
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
19542
19611
  { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }
19543
19612
  );
@@ -19611,7 +19680,7 @@ function applyLine(result, pending, line) {
19611
19680
  }
19612
19681
 
19613
19682
  // src/commands/sessions/daemon/reportStolenSocket.ts
19614
- import { readFileSync as readFileSync42 } from "fs";
19683
+ import { readFileSync as readFileSync41 } from "fs";
19615
19684
  function reportStolenSocket(socketPid) {
19616
19685
  if (!socketPid) return;
19617
19686
  const filePid = readPidFile();
@@ -19623,7 +19692,7 @@ function reportStolenSocket(socketPid) {
19623
19692
  function readPidFile() {
19624
19693
  try {
19625
19694
  const pid = Number.parseInt(
19626
- readFileSync42(daemonPaths.pid, "utf8").trim(),
19695
+ readFileSync41(daemonPaths.pid, "utf8").trim(),
19627
19696
  10
19628
19697
  );
19629
19698
  return Number.isInteger(pid) ? pid : void 0;
@@ -21484,7 +21553,7 @@ function handleConnection(socket, manager) {
21484
21553
  import { unlinkSync as unlinkSync18, writeFileSync as writeFileSync37 } from "fs";
21485
21554
 
21486
21555
  // src/commands/sessions/daemon/startPidFileWatchdog.ts
21487
- import { readFileSync as readFileSync43 } from "fs";
21556
+ import { readFileSync as readFileSync42 } from "fs";
21488
21557
  var WATCHDOG_INTERVAL_MS = 5e3;
21489
21558
  function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
21490
21559
  const timer = setInterval(() => {
@@ -21495,7 +21564,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
21495
21564
  }
21496
21565
  function ownsPidFile() {
21497
21566
  try {
21498
- return readFileSync43(daemonPaths.pid, "utf8").trim() === String(process.pid);
21567
+ return readFileSync42(daemonPaths.pid, "utf8").trim() === String(process.pid);
21499
21568
  } catch {
21500
21569
  return false;
21501
21570
  }
@@ -22052,7 +22121,7 @@ function syncCommands(claudeDir, targetBase) {
22052
22121
  }
22053
22122
 
22054
22123
  // src/commands/update.ts
22055
- import { execSync as execSync52 } from "child_process";
22124
+ import { execSync as execSync51 } from "child_process";
22056
22125
  import * as path56 from "path";
22057
22126
 
22058
22127
  // src/commands/restartDaemonAfterUpdate.ts
@@ -22076,7 +22145,7 @@ function isGlobalNpmInstall(dir) {
22076
22145
  if (resolved.split(path56.sep).includes("node_modules")) {
22077
22146
  return true;
22078
22147
  }
22079
- const globalPrefix = execSync52("npm prefix -g", { stdio: "pipe" }).toString().trim();
22148
+ const globalPrefix = execSync51("npm prefix -g", { stdio: "pipe" }).toString().trim();
22080
22149
  return resolved.toLowerCase().startsWith(path56.resolve(globalPrefix).toLowerCase());
22081
22150
  } catch {
22082
22151
  return false;
@@ -22087,18 +22156,18 @@ async function update2() {
22087
22156
  console.log(`Assist is installed at: ${installDir}`);
22088
22157
  if (isGitRepo(installDir)) {
22089
22158
  console.log("Detected git repo installation, pulling latest...");
22090
- execSync52("git pull", { cwd: installDir, stdio: "inherit" });
22159
+ execSync51("git pull", { cwd: installDir, stdio: "inherit" });
22091
22160
  console.log("Installing dependencies...");
22092
- execSync52("npm i", { cwd: installDir, stdio: "inherit" });
22161
+ execSync51("npm i", { cwd: installDir, stdio: "inherit" });
22093
22162
  console.log("Building...");
22094
- execSync52("npm run build", { cwd: installDir, stdio: "inherit" });
22163
+ execSync51("npm run build", { cwd: installDir, stdio: "inherit" });
22095
22164
  console.log("Syncing commands...");
22096
- execSync52("assist sync", { stdio: "inherit" });
22165
+ execSync51("assist sync", { stdio: "inherit" });
22097
22166
  } else if (isGlobalNpmInstall(installDir)) {
22098
22167
  console.log("Detected global npm installation, updating...");
22099
- execSync52("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
22168
+ execSync51("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
22100
22169
  console.log("Syncing commands...");
22101
- execSync52("assist sync", { stdio: "inherit" });
22170
+ execSync51("assist sync", { stdio: "inherit" });
22102
22171
  } else {
22103
22172
  console.error(
22104
22173
  "Could not determine installation method. Expected a git repo or global npm install."