@staff0rd/assist 0.47.1 → 0.49.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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +513 -393
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { execSync as execSync19 } from "child_process";
4
+ import { execSync as execSync22 } from "child_process";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@staff0rd/assist",
10
- version: "0.47.1",
10
+ version: "0.49.0",
11
11
  type: "module",
12
12
  main: "dist/index.js",
13
13
  bin: {
@@ -316,12 +316,12 @@ import chalk14 from "chalk";
316
316
  // src/shared/promptMultiselect.ts
317
317
  import chalk3 from "chalk";
318
318
  import enquirer from "enquirer";
319
- async function promptMultiselect(message, options) {
319
+ async function promptMultiselect(message, options2) {
320
320
  const { selected } = await enquirer.prompt({
321
321
  type: "multiselect",
322
322
  name: "selected",
323
323
  message,
324
- choices: options.map((opt) => ({
324
+ choices: options2.map((opt) => ({
325
325
  name: opt.value,
326
326
  message: `${opt.name} - ${chalk3.dim(opt.description)}`
327
327
  })),
@@ -460,12 +460,22 @@ async function setupBuild(packageJsonPath, hasVite, hasTypescript) {
460
460
  } else if (hasVite) {
461
461
  command = "vite build --logLevel error";
462
462
  } else {
463
- command = "tsc --noEmit";
463
+ command = "npm run build";
464
464
  }
465
465
  console.log(chalk6.dim(`Using: ${command}`));
466
466
  const pkg = readPackageJson(packageJsonPath);
467
467
  writePackageJson(packageJsonPath, addScript(pkg, "verify:build", command));
468
468
  }
469
+ async function setupTypecheck(packageJsonPath) {
470
+ console.log(chalk6.blue("\nSetting up typecheck verification..."));
471
+ const command = "tsc --noEmit";
472
+ console.log(chalk6.dim(`Using: ${command}`));
473
+ const pkg = readPackageJson(packageJsonPath);
474
+ writePackageJson(
475
+ packageJsonPath,
476
+ addScript(pkg, "verify:typecheck", command)
477
+ );
478
+ }
469
479
 
470
480
  // src/commands/verify/setup/setupDuplicateCode.ts
471
481
  import * as path3 from "path";
@@ -578,8 +588,8 @@ function removeEslintConfigFiles() {
578
588
  }
579
589
 
580
590
  // src/shared/removeEslint/index.ts
581
- function removeEslint(options = {}) {
582
- const removedFromPackageJson = removeEslintFromPackageJson(options);
591
+ function removeEslint(options2 = {}) {
592
+ const removedFromPackageJson = removeEslintFromPackageJson(options2);
583
593
  const removedConfigFiles = removeEslintConfigFiles();
584
594
  if (removedFromPackageJson || removedConfigFiles) {
585
595
  console.log("Running npm install...");
@@ -588,7 +598,7 @@ function removeEslint(options = {}) {
588
598
  }
589
599
  return false;
590
600
  }
591
- function removeEslintFromPackageJson(options) {
601
+ function removeEslintFromPackageJson(options2) {
592
602
  const packageJsonPath = "package.json";
593
603
  if (!existsSync5(packageJsonPath)) {
594
604
  return false;
@@ -597,7 +607,7 @@ function removeEslintFromPackageJson(options) {
597
607
  let modified = false;
598
608
  modified = removeEslintDeps(packageJson.dependencies) || modified;
599
609
  modified = removeEslintDeps(packageJson.devDependencies) || modified;
600
- modified = removeEslintScripts(packageJson.scripts, options) || modified;
610
+ modified = removeEslintScripts(packageJson.scripts, options2) || modified;
601
611
  if (modified) {
602
612
  writeFileSync3(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
603
613
  `);
@@ -616,11 +626,11 @@ function removeEslintDeps(deps) {
616
626
  }
617
627
  return modified;
618
628
  }
619
- function removeEslintScripts(scripts, options) {
629
+ function removeEslintScripts(scripts, options2) {
620
630
  if (!scripts) return false;
621
631
  let modified = false;
622
632
  for (const key of Object.keys(scripts)) {
623
- const isEslintScript = key.includes("eslint") || scripts[key].includes("eslint") || options.removeLintScripts && key.includes("lint");
633
+ const isEslintScript = key.includes("eslint") || scripts[key].includes("eslint") || options2.removeLintScripts && key.includes("lint");
624
634
  if (isEslintScript) {
625
635
  delete scripts[key];
626
636
  modified = true;
@@ -770,34 +780,21 @@ function detectExistingSetup(pkg) {
770
780
  test: toolStatus(pkg, "verify:test", !!pkg.devDependencies?.vitest),
771
781
  hasVite: !!pkg.devDependencies?.vite || !!pkg.dependencies?.vite,
772
782
  hasTypescript: !!pkg.devDependencies?.typescript,
773
- build: {
774
- hasPackage: true,
775
- hasScript: !!pkg.scripts?.["verify:build"],
776
- isOutdated: false
777
- },
783
+ build: toolStatus(pkg, "verify:build", true),
784
+ typecheck: toolStatus(pkg, "verify:typecheck", true),
778
785
  hardcodedColors: toolStatus(pkg, "verify:hardcoded-colors", true),
779
786
  hasOpenColor: !!pkg.dependencies?.["open-color"] || !!pkg.devDependencies?.["open-color"]
780
787
  };
781
788
  }
782
789
 
783
- // src/commands/verify/init/getAvailableOptions.ts
790
+ // src/commands/verify/init/options.ts
784
791
  function getBuildDescription(setup) {
785
792
  if (setup.hasVite && setup.hasTypescript)
786
793
  return "TypeScript + Vite build verification";
787
794
  if (setup.hasVite) return "Vite build verification";
788
- return "TypeScript type checking";
789
- }
790
- function shouldInclude(setup, def) {
791
- return needsSetup(setup[def.toolKey]) && (def.extraCondition ?? true);
795
+ return "Build verification";
792
796
  }
793
- function toVerifyOption(setup, def) {
794
- return {
795
- name: `${def.label}${getStatusLabel(setup[def.toolKey])}`,
796
- value: def.value,
797
- description: def.description
798
- };
799
- }
800
- var STATIC_OPTIONS = [
797
+ var options = [
801
798
  {
802
799
  toolKey: "knip",
803
800
  value: "knip",
@@ -821,31 +818,45 @@ var STATIC_OPTIONS = [
821
818
  value: "hardcoded-colors",
822
819
  label: "hardcoded-colors",
823
820
  description: "Detect hardcoded hex colors (use open-color instead)"
821
+ },
822
+ {
823
+ toolKey: "test",
824
+ value: "test",
825
+ label: "test",
826
+ description: "Run tests with vitest",
827
+ extraCondition: (s) => s.test.hasPackage
828
+ },
829
+ {
830
+ toolKey: "build",
831
+ value: "build",
832
+ label: "build",
833
+ description: getBuildDescription,
834
+ extraCondition: (s) => s.hasTypescript || s.hasVite
835
+ },
836
+ {
837
+ toolKey: "typecheck",
838
+ value: "typecheck",
839
+ label: "typecheck",
840
+ description: "TypeScript type checking",
841
+ extraCondition: (s) => s.hasTypescript && !s.hasVite
824
842
  }
825
843
  ];
826
- function getConditionalOptions(setup) {
827
- return [
828
- {
829
- toolKey: "test",
830
- value: "test",
831
- label: "test",
832
- description: "Run tests with vitest",
833
- extraCondition: setup.test.hasPackage
834
- },
835
- {
836
- toolKey: "build",
837
- value: "build",
838
- label: "build",
839
- description: getBuildDescription(setup),
840
- extraCondition: setup.hasTypescript || setup.hasVite
841
- }
842
- ];
844
+
845
+ // src/commands/verify/init/getAvailableOptions.ts
846
+ function resolveDescription(desc, setup) {
847
+ return typeof desc === "function" ? desc(setup) : desc;
843
848
  }
844
- function getAllOptionDefs(setup) {
845
- return [...STATIC_OPTIONS, ...getConditionalOptions(setup)];
849
+ function toVerifyOption(def, setup) {
850
+ return {
851
+ name: `${def.label}${getStatusLabel(setup[def.toolKey])}`,
852
+ value: def.value,
853
+ description: resolveDescription(def.description, setup)
854
+ };
846
855
  }
847
856
  function getAvailableOptions(setup) {
848
- return getAllOptionDefs(setup).filter((def) => shouldInclude(setup, def)).map((def) => toVerifyOption(setup, def));
857
+ return options.filter(
858
+ (def) => needsSetup(setup[def.toolKey]) && (def.extraCondition?.(setup) ?? true)
859
+ ).map((def) => toVerifyOption(def, setup));
849
860
  }
850
861
 
851
862
  // src/commands/verify/init/index.ts
@@ -856,6 +867,7 @@ function getSetupHandlers(hasVite, hasTypescript, hasOpenColor) {
856
867
  "duplicate-code": (p) => setupDuplicateCode(p),
857
868
  test: (p) => setupTest(p),
858
869
  build: (p) => setupBuild(p, hasVite, hasTypescript),
870
+ typecheck: (p) => setupTypecheck(p),
859
871
  "hardcoded-colors": (p) => setupHardcodedColors(p, hasOpenColor)
860
872
  };
861
873
  }
@@ -989,20 +1001,20 @@ var SETUP_HANDLERS = {
989
1001
  }
990
1002
  };
991
1003
  function getAvailableOptions2(setup) {
992
- const options = [];
1004
+ const options2 = [];
993
1005
  if (!setup.hasLaunchJson && setup.hasVite)
994
- options.push({
1006
+ options2.push({
995
1007
  name: "launch",
996
1008
  value: "launch",
997
1009
  description: "Debug configuration for Vite dev server"
998
1010
  });
999
1011
  if (!setup.hasSettingsJson)
1000
- options.push({
1012
+ options2.push({
1001
1013
  name: "settings",
1002
1014
  value: "settings",
1003
1015
  description: "Biome formatter configuration"
1004
1016
  });
1005
- return options;
1017
+ return options2;
1006
1018
  }
1007
1019
  async function init3() {
1008
1020
  const { pkg } = requirePackageJson();
@@ -1045,8 +1057,8 @@ import chalk17 from "chalk";
1045
1057
  import fs5 from "fs";
1046
1058
  import path10 from "path";
1047
1059
  var EXTENSIONS = [".ts", ".tsx"];
1048
- function findSourceFiles(dir, options = {}) {
1049
- const { includeTests = true } = options;
1060
+ function findSourceFiles(dir, options2 = {}) {
1061
+ const { includeTests = true } = options2;
1050
1062
  const results = [];
1051
1063
  if (!fs5.existsSync(dir)) {
1052
1064
  return results;
@@ -1055,7 +1067,7 @@ function findSourceFiles(dir, options = {}) {
1055
1067
  for (const entry of entries) {
1056
1068
  const fullPath = path10.join(dir, entry.name);
1057
1069
  if (entry.isDirectory() && entry.name !== "node_modules") {
1058
- results.push(...findSourceFiles(fullPath, options));
1070
+ results.push(...findSourceFiles(fullPath, options2));
1059
1071
  } else if (entry.isFile() && EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
1060
1072
  if (!includeTests && entry.name.includes(".test.")) {
1061
1073
  continue;
@@ -1223,22 +1235,261 @@ function lint() {
1223
1235
  }
1224
1236
  }
1225
1237
 
1226
- // src/commands/new/newProject.ts
1238
+ // src/commands/new/newCli.ts
1239
+ import { execSync as execSync7 } from "child_process";
1240
+ import { basename as basename2, resolve } from "path";
1241
+
1242
+ // src/commands/verify/hardcodedColors.ts
1243
+ import { execSync as execSync5 } from "child_process";
1244
+ var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
1245
+ function hardcodedColors() {
1246
+ try {
1247
+ const output = execSync5(`grep -rEnH '${pattern}' src/`, {
1248
+ encoding: "utf-8"
1249
+ });
1250
+ const lines = output.trim().split("\n");
1251
+ console.log("Hardcoded colors found:\n");
1252
+ for (const line of lines) {
1253
+ const match = line.match(/^(.+):(\d+):(.+)$/);
1254
+ if (match) {
1255
+ const [, file, lineNum, content] = match;
1256
+ const colorMatch = content.match(/0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}/);
1257
+ const color = colorMatch?.[0] ?? "unknown";
1258
+ console.log(`${file}:${lineNum} \u2192 ${color}`);
1259
+ }
1260
+ }
1261
+ console.log(`
1262
+ Total: ${lines.length} hardcoded color(s)`);
1263
+ console.log("\nUse colors from the 'open-color' (oc) library instead.");
1264
+ console.log("\nExample fix:");
1265
+ console.log(" Before: color: '#228be6'");
1266
+ console.log(" After: color: oc.blue[6]");
1267
+ console.log("\nImport open-color with: import oc from 'open-color'");
1268
+ process.exit(1);
1269
+ } catch {
1270
+ console.log("No hardcoded colors found.");
1271
+ process.exit(0);
1272
+ }
1273
+ }
1274
+
1275
+ // src/commands/verify/run/index.ts
1276
+ import { spawn } from "child_process";
1277
+ import * as path12 from "path";
1278
+
1279
+ // src/commands/verify/run/createTimerCallback/printTaskStatuses.ts
1280
+ function formatDuration(ms) {
1281
+ if (ms < 1e3) {
1282
+ return `${ms}ms`;
1283
+ }
1284
+ const seconds = (ms / 1e3).toFixed(1);
1285
+ return `${seconds}s`;
1286
+ }
1287
+ function printTaskStatuses(tasks) {
1288
+ console.log("\n--- Task Status ---");
1289
+ for (const task of tasks) {
1290
+ if (task.endTime !== void 0) {
1291
+ const duration = formatDuration(task.endTime - task.startTime);
1292
+ const status = task.code === 0 ? "\u2713" : "\u2717";
1293
+ console.log(` ${status} ${task.script}: ${duration}`);
1294
+ } else {
1295
+ const elapsed = formatDuration(Date.now() - task.startTime);
1296
+ console.log(` \u22EF ${task.script}: running (${elapsed})`);
1297
+ }
1298
+ }
1299
+ console.log("-------------------\n");
1300
+ }
1301
+
1302
+ // src/commands/verify/run/createTimerCallback/index.ts
1303
+ function logFailedScripts(failed) {
1304
+ console.error(`
1305
+ ${failed.length} script(s) failed:`);
1306
+ for (const f of failed) {
1307
+ console.error(` - ${f.script} (exit code ${f.code})`);
1308
+ }
1309
+ }
1310
+ function createTimerCallback(taskStatuses, index) {
1311
+ return (exitCode) => {
1312
+ taskStatuses[index].endTime = Date.now();
1313
+ taskStatuses[index].code = exitCode;
1314
+ printTaskStatuses(taskStatuses);
1315
+ };
1316
+ }
1317
+ function initTaskStatuses(scripts) {
1318
+ return scripts.map((script) => ({ script, startTime: Date.now() }));
1319
+ }
1320
+
1321
+ // src/commands/verify/run/index.ts
1322
+ function spawnScript(script, cwd) {
1323
+ return spawn("npm", ["run", script], { stdio: "inherit", shell: true, cwd });
1324
+ }
1325
+ function onScriptClose(script, onComplete, resolve2) {
1326
+ return (code) => {
1327
+ const exitCode = code ?? 1;
1328
+ onComplete?.(exitCode);
1329
+ resolve2({ script, code: exitCode });
1330
+ };
1331
+ }
1332
+ function runScript(script, cwd, onComplete) {
1333
+ return new Promise((resolve2) => {
1334
+ spawnScript(script, cwd).on(
1335
+ "close",
1336
+ onScriptClose(script, onComplete, resolve2)
1337
+ );
1338
+ });
1339
+ }
1340
+ function runAllScripts(verifyScripts, packageDir, timer) {
1341
+ const taskStatuses = initTaskStatuses(verifyScripts);
1342
+ return Promise.all(
1343
+ verifyScripts.map(
1344
+ (script, index) => runScript(
1345
+ script,
1346
+ packageDir,
1347
+ timer ? createTimerCallback(taskStatuses, index) : void 0
1348
+ )
1349
+ )
1350
+ );
1351
+ }
1352
+ function printScriptList(scripts) {
1353
+ console.log(`Running ${scripts.length} verify script(s) in parallel:`);
1354
+ for (const script of scripts) {
1355
+ console.log(` - ${script}`);
1356
+ }
1357
+ }
1358
+ function exitIfFailed(failed) {
1359
+ if (failed.length === 0) return;
1360
+ logFailedScripts(failed);
1361
+ process.exit(1);
1362
+ }
1363
+ function handleResults(results, totalCount) {
1364
+ exitIfFailed(results.filter((r) => r.code !== 0));
1365
+ console.log(`
1366
+ All ${totalCount} verify script(s) passed`);
1367
+ }
1368
+ function resolveVerifyScripts() {
1369
+ const result = findPackageJsonWithVerifyScripts(process.cwd());
1370
+ if (!result) {
1371
+ console.log("No package.json with verify:* scripts found");
1372
+ return null;
1373
+ }
1374
+ return result;
1375
+ }
1376
+ function getPackageDir(found) {
1377
+ return path12.dirname(found.packageJsonPath);
1378
+ }
1379
+ async function executeVerifyScripts(found, timer) {
1380
+ printScriptList(found.verifyScripts);
1381
+ const results = await runAllScripts(
1382
+ found.verifyScripts,
1383
+ getPackageDir(found),
1384
+ timer
1385
+ );
1386
+ handleResults(results, found.verifyScripts.length);
1387
+ }
1388
+ async function run(options2 = {}) {
1389
+ const found = resolveVerifyScripts();
1390
+ if (!found) return;
1391
+ await executeVerifyScripts(found, options2.timer ?? false);
1392
+ }
1393
+
1394
+ // src/commands/new/initPackageJson.ts
1227
1395
  import { execSync as execSync6 } from "child_process";
1228
- import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
1396
+ function initPackageJson(name) {
1397
+ console.log("Initializing package.json...");
1398
+ execSync6("npm init -y", { stdio: "inherit" });
1399
+ console.log("Configuring package.json...");
1400
+ execSync6("npm pkg delete main", { stdio: "inherit" });
1401
+ execSync6("npm pkg set type=module", { stdio: "inherit" });
1402
+ execSync6(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
1403
+ execSync6("npm pkg set scripts.build=tsup", { stdio: "inherit" });
1404
+ execSync6('npm pkg set scripts.start="node dist/index.js"', {
1405
+ stdio: "inherit"
1406
+ });
1407
+ }
1408
+
1409
+ // src/commands/new/writeCliTemplate.ts
1410
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync6 } from "fs";
1411
+ function writeCliTemplate(name) {
1412
+ console.log("Writing tsconfig.json...");
1413
+ writeFileSync6(
1414
+ "tsconfig.json",
1415
+ JSON.stringify(
1416
+ {
1417
+ compilerOptions: {
1418
+ target: "ES2022",
1419
+ module: "ESNext",
1420
+ moduleResolution: "bundler",
1421
+ outDir: "./dist",
1422
+ rootDir: "./src",
1423
+ strict: true,
1424
+ esModuleInterop: true,
1425
+ resolveJsonModule: true,
1426
+ skipLibCheck: true,
1427
+ forceConsistentCasingInFileNames: true
1428
+ },
1429
+ include: ["src/**/*"],
1430
+ exclude: ["node_modules"]
1431
+ },
1432
+ null,
1433
+ " "
1434
+ )
1435
+ );
1436
+ console.log("Writing tsup.config.ts...");
1437
+ writeFileSync6(
1438
+ "tsup.config.ts",
1439
+ `import { defineConfig } from "tsup";
1440
+ export default defineConfig({
1441
+ entry: ["src/index.ts"],
1442
+ format: ["esm"],
1443
+ target: "node22",
1444
+ outDir: "dist",
1445
+ clean: true,
1446
+ shims: true,
1447
+ });
1448
+ `
1449
+ );
1450
+ console.log("Writing src/index.ts...");
1451
+ mkdirSync2("src", { recursive: true });
1452
+ writeFileSync6(
1453
+ "src/index.ts",
1454
+ `#!/usr/bin/env node
1455
+ import { Command } from "commander";
1456
+ const program = new Command();
1457
+ program.name("${name}").description("").version("0.0.0");
1458
+ program.parse();
1459
+ `
1460
+ );
1461
+ }
1462
+
1463
+ // src/commands/new/newCli.ts
1464
+ async function newCli() {
1465
+ const name = basename2(resolve("."));
1466
+ initPackageJson(name);
1467
+ console.log("Installing dependencies...");
1468
+ execSync7("npm install commander", { stdio: "inherit" });
1469
+ execSync7("npm install -D tsup typescript @types/node", {
1470
+ stdio: "inherit"
1471
+ });
1472
+ writeCliTemplate(name);
1473
+ await init4();
1474
+ await run();
1475
+ }
1476
+
1477
+ // src/commands/new/newProject.ts
1478
+ import { execSync as execSync9 } from "child_process";
1479
+ import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
1229
1480
 
1230
1481
  // src/commands/deploy/init/index.ts
1231
- import { execSync as execSync5 } from "child_process";
1482
+ import { execSync as execSync8 } from "child_process";
1232
1483
  import chalk20 from "chalk";
1233
1484
  import enquirer3 from "enquirer";
1234
1485
 
1235
1486
  // src/commands/deploy/init/updateWorkflow.ts
1236
- import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
1237
- import { dirname as dirname8, join as join7 } from "path";
1487
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
1488
+ import { dirname as dirname9, join as join7 } from "path";
1238
1489
  import { fileURLToPath as fileURLToPath2 } from "url";
1239
1490
  import chalk19 from "chalk";
1240
1491
  var WORKFLOW_PATH = ".github/workflows/build.yml";
1241
- var __dirname3 = dirname8(fileURLToPath2(import.meta.url));
1492
+ var __dirname3 = dirname9(fileURLToPath2(import.meta.url));
1242
1493
  function getExistingSiteId() {
1243
1494
  if (!existsSync9(WORKFLOW_PATH)) {
1244
1495
  return null;
@@ -1256,7 +1507,7 @@ async function updateWorkflow(siteId) {
1256
1507
  const newContent = getTemplateContent(siteId);
1257
1508
  const workflowDir = ".github/workflows";
1258
1509
  if (!existsSync9(workflowDir)) {
1259
- mkdirSync2(workflowDir, { recursive: true });
1510
+ mkdirSync3(workflowDir, { recursive: true });
1260
1511
  }
1261
1512
  if (existsSync9(WORKFLOW_PATH)) {
1262
1513
  const oldContent = readFileSync7(WORKFLOW_PATH, "utf-8");
@@ -1273,7 +1524,7 @@ async function updateWorkflow(siteId) {
1273
1524
  return;
1274
1525
  }
1275
1526
  }
1276
- writeFileSync6(WORKFLOW_PATH, newContent);
1527
+ writeFileSync7(WORKFLOW_PATH, newContent);
1277
1528
  console.log(chalk19.green(`
1278
1529
  Created ${WORKFLOW_PATH}`));
1279
1530
  }
@@ -1281,7 +1532,7 @@ Created ${WORKFLOW_PATH}`));
1281
1532
  // src/commands/deploy/init/index.ts
1282
1533
  async function ensureNetlifyCli() {
1283
1534
  try {
1284
- execSync5("netlify sites:create --disable-linking", { stdio: "inherit" });
1535
+ execSync8("netlify sites:create --disable-linking", { stdio: "inherit" });
1285
1536
  } catch (error) {
1286
1537
  if (!(error instanceof Error) || !error.message.includes("command not found"))
1287
1538
  throw error;
@@ -1296,9 +1547,9 @@ async function ensureNetlifyCli() {
1296
1547
  process.exit(1);
1297
1548
  }
1298
1549
  console.log(chalk20.dim("\nInstalling netlify-cli...\n"));
1299
- execSync5("npm install -g netlify-cli", { stdio: "inherit" });
1550
+ execSync8("npm install -g netlify-cli", { stdio: "inherit" });
1300
1551
  console.log();
1301
- execSync5("netlify sites:create --disable-linking", { stdio: "inherit" });
1552
+ execSync8("netlify sites:create --disable-linking", { stdio: "inherit" });
1302
1553
  }
1303
1554
  }
1304
1555
  function printSetupInstructions() {
@@ -1341,7 +1592,7 @@ async function init5() {
1341
1592
  // src/commands/new/newProject.ts
1342
1593
  async function newProject() {
1343
1594
  console.log("Initializing Vite with react-ts template...");
1344
- execSync6("npm create vite@latest . -- --template react-ts", {
1595
+ execSync9("npm create vite@latest . -- --template react-ts", {
1345
1596
  stdio: "inherit"
1346
1597
  });
1347
1598
  removeEslint({ removeLintScripts: true });
@@ -1365,11 +1616,18 @@ function addViteBaseConfig() {
1365
1616
  'defineConfig({\n base: "./",'
1366
1617
  );
1367
1618
  if (updated !== content) {
1368
- writeFileSync7(viteConfigPath, updated);
1619
+ writeFileSync8(viteConfigPath, updated);
1369
1620
  console.log('Added base: "./" to vite.config.ts');
1370
1621
  }
1371
1622
  }
1372
1623
 
1624
+ // src/commands/new/registerNew.ts
1625
+ function registerNew(program2) {
1626
+ const newCommand = program2.command("new").description("Scaffold a new project");
1627
+ newCommand.command("vite").description("Initialize a new Vite React TypeScript project").action(newProject);
1628
+ newCommand.command("cli").description("Initialize a new tsup CLI project").action(newCli);
1629
+ }
1630
+
1373
1631
  // src/lib/readStdin.ts
1374
1632
  import * as readline from "readline";
1375
1633
  async function readStdin() {
@@ -1405,17 +1663,17 @@ function detectPlatform() {
1405
1663
  }
1406
1664
 
1407
1665
  // src/commands/notify/showNotification/showWindowsNotificationFromWsl.ts
1408
- import { spawn } from "child_process";
1666
+ import { spawn as spawn2 } from "child_process";
1409
1667
  import fs9 from "fs";
1410
1668
  import { createRequire } from "module";
1411
- import path12 from "path";
1669
+ import path13 from "path";
1412
1670
  var require2 = createRequire(import.meta.url);
1413
1671
  function getSnoreToastPath() {
1414
- const notifierPath = path12.dirname(require2.resolve("node-notifier"));
1415
- return path12.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
1672
+ const notifierPath = path13.dirname(require2.resolve("node-notifier"));
1673
+ return path13.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
1416
1674
  }
1417
- function showWindowsNotificationFromWsl(options) {
1418
- const { title, message, sound } = options;
1675
+ function showWindowsNotificationFromWsl(options2) {
1676
+ const { title, message, sound } = options2;
1419
1677
  const snoreToastPath = getSnoreToastPath();
1420
1678
  try {
1421
1679
  fs9.chmodSync(snoreToastPath, 493);
@@ -1427,7 +1685,7 @@ function showWindowsNotificationFromWsl(options) {
1427
1685
  } else if (sound === "Reminder") {
1428
1686
  args.push("-s", "ms-winsoundevent:Notification.Reminder");
1429
1687
  }
1430
- const child = spawn(snoreToastPath, args, {
1688
+ const child = spawn2(snoreToastPath, args, {
1431
1689
  detached: true,
1432
1690
  stdio: "ignore"
1433
1691
  });
@@ -1436,8 +1694,8 @@ function showWindowsNotificationFromWsl(options) {
1436
1694
  }
1437
1695
 
1438
1696
  // src/commands/notify/showNotification/index.ts
1439
- function showNotification(options) {
1440
- const { title, message, sound } = options;
1697
+ function showNotification(options2) {
1698
+ const { title, message, sound } = options2;
1441
1699
  const platform = detectPlatform();
1442
1700
  if (platform === "wsl") {
1443
1701
  return showWindowsNotificationFromWsl({ title, message, sound });
@@ -1500,13 +1758,13 @@ import chalk22 from "chalk";
1500
1758
 
1501
1759
  // src/commands/complexity/shared/index.ts
1502
1760
  import fs11 from "fs";
1503
- import path14 from "path";
1761
+ import path15 from "path";
1504
1762
  import chalk21 from "chalk";
1505
1763
  import ts5 from "typescript";
1506
1764
 
1507
1765
  // src/commands/complexity/findSourceFiles.ts
1508
1766
  import fs10 from "fs";
1509
- import path13 from "path";
1767
+ import path14 from "path";
1510
1768
  import { minimatch } from "minimatch";
1511
1769
  function applyIgnoreGlobs(files) {
1512
1770
  const { complexity } = loadConfig();
@@ -1521,7 +1779,7 @@ function walk(dir, results) {
1521
1779
  const extensions = [".ts", ".tsx"];
1522
1780
  const entries = fs10.readdirSync(dir, { withFileTypes: true });
1523
1781
  for (const entry of entries) {
1524
- const fullPath = path13.join(dir, entry.name);
1782
+ const fullPath = path14.join(dir, entry.name);
1525
1783
  if (entry.isDirectory()) {
1526
1784
  if (entry.name !== "node_modules" && entry.name !== ".git") {
1527
1785
  walk(fullPath, results);
@@ -1737,7 +1995,7 @@ function countSloc(content) {
1737
1995
  function createSourceFromFile(filePath) {
1738
1996
  const content = fs11.readFileSync(filePath, "utf-8");
1739
1997
  return ts5.createSourceFile(
1740
- path14.basename(filePath),
1998
+ path15.basename(filePath),
1741
1999
  content,
1742
2000
  ts5.ScriptTarget.Latest,
1743
2001
  true,
@@ -1766,20 +2024,20 @@ function forEachFunction(files, callback) {
1766
2024
  }
1767
2025
 
1768
2026
  // src/commands/complexity/cyclomatic.ts
1769
- async function cyclomatic(pattern2 = "**/*.ts", options = {}) {
2027
+ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
1770
2028
  withSourceFiles(pattern2, (files) => {
1771
2029
  const results = [];
1772
2030
  let hasViolation = false;
1773
2031
  forEachFunction(files, (file, name, node) => {
1774
2032
  const complexity = calculateCyclomaticComplexity(node);
1775
2033
  results.push({ file, name, complexity });
1776
- if (options.threshold !== void 0 && complexity > options.threshold) {
2034
+ if (options2.threshold !== void 0 && complexity > options2.threshold) {
1777
2035
  hasViolation = true;
1778
2036
  }
1779
2037
  });
1780
2038
  results.sort((a, b) => b.complexity - a.complexity);
1781
2039
  for (const { file, name, complexity } of results) {
1782
- const exceedsThreshold = options.threshold !== void 0 && complexity > options.threshold;
2040
+ const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
1783
2041
  const color = exceedsThreshold ? chalk22.red : chalk22.white;
1784
2042
  console.log(`${color(`${file}:${name}`)} \u2192 ${chalk22.cyan(complexity)}`);
1785
2043
  }
@@ -1797,20 +2055,20 @@ Analyzed ${results.length} functions across ${files.length} files`
1797
2055
 
1798
2056
  // src/commands/complexity/halstead.ts
1799
2057
  import chalk23 from "chalk";
1800
- async function halstead(pattern2 = "**/*.ts", options = {}) {
2058
+ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
1801
2059
  withSourceFiles(pattern2, (files) => {
1802
2060
  const results = [];
1803
2061
  let hasViolation = false;
1804
2062
  forEachFunction(files, (file, name, node) => {
1805
2063
  const metrics = calculateHalstead(node);
1806
2064
  results.push({ file, name, metrics });
1807
- if (options.threshold !== void 0 && metrics.volume > options.threshold) {
2065
+ if (options2.threshold !== void 0 && metrics.volume > options2.threshold) {
1808
2066
  hasViolation = true;
1809
2067
  }
1810
2068
  });
1811
2069
  results.sort((a, b) => b.metrics.effort - a.metrics.effort);
1812
2070
  for (const { file, name, metrics } of results) {
1813
- const exceedsThreshold = options.threshold !== void 0 && metrics.volume > options.threshold;
2071
+ const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
1814
2072
  const color = exceedsThreshold ? chalk23.red : chalk23.white;
1815
2073
  console.log(
1816
2074
  `${color(`${file}:${name}`)} \u2192 volume: ${chalk23.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk23.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk23.magenta(metrics.effort.toFixed(1))}`
@@ -1898,18 +2156,18 @@ function aggregateResults(fileMetrics) {
1898
2156
  results.sort((a, b) => a.minMaintainability - b.minMaintainability);
1899
2157
  return results;
1900
2158
  }
1901
- async function maintainability(pattern2 = "**/*.ts", options = {}) {
2159
+ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
1902
2160
  withSourceFiles(pattern2, (files) => {
1903
2161
  const fileMetrics = collectFileMetrics(files);
1904
2162
  const results = aggregateResults(fileMetrics);
1905
- displayMaintainabilityResults(results, options.threshold);
2163
+ displayMaintainabilityResults(results, options2.threshold);
1906
2164
  });
1907
2165
  }
1908
2166
 
1909
2167
  // src/commands/complexity/sloc.ts
1910
2168
  import fs13 from "fs";
1911
2169
  import chalk25 from "chalk";
1912
- async function sloc(pattern2 = "**/*.ts", options = {}) {
2170
+ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
1913
2171
  withSourceFiles(pattern2, (files) => {
1914
2172
  const results = [];
1915
2173
  let hasViolation = false;
@@ -1917,13 +2175,13 @@ async function sloc(pattern2 = "**/*.ts", options = {}) {
1917
2175
  const content = fs13.readFileSync(file, "utf-8");
1918
2176
  const lines = countSloc(content);
1919
2177
  results.push({ file, lines });
1920
- if (options.threshold !== void 0 && lines > options.threshold) {
2178
+ if (options2.threshold !== void 0 && lines > options2.threshold) {
1921
2179
  hasViolation = true;
1922
2180
  }
1923
2181
  }
1924
2182
  results.sort((a, b) => b.lines - a.lines);
1925
2183
  for (const { file, lines } of results) {
1926
- const exceedsThreshold = options.threshold !== void 0 && lines > options.threshold;
2184
+ const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
1927
2185
  const color = exceedsThreshold ? chalk25.red : chalk25.white;
1928
2186
  console.log(`${color(file)} \u2192 ${chalk25.cyan(lines)} lines`);
1929
2187
  }
@@ -1984,7 +2242,7 @@ function registerComplexity(program2) {
1984
2242
  }
1985
2243
 
1986
2244
  // src/commands/deploy/redirect.ts
1987
- import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
2245
+ import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
1988
2246
  import chalk27 from "chalk";
1989
2247
  var TRAILING_SLASH_SCRIPT = ` <script>
1990
2248
  if (!window.location.pathname.endsWith('/')) {
@@ -2008,7 +2266,7 @@ function redirect() {
2008
2266
  return;
2009
2267
  }
2010
2268
  const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
2011
- writeFileSync8(indexPath, newContent);
2269
+ writeFileSync9(indexPath, newContent);
2012
2270
  console.log(chalk27.green("Added trailing slash redirect to index.html"));
2013
2271
  }
2014
2272
 
@@ -2020,11 +2278,11 @@ function registerDeploy(program2) {
2020
2278
  }
2021
2279
 
2022
2280
  // src/commands/devlog/list/index.ts
2023
- import { execSync as execSync8 } from "child_process";
2024
- import { basename as basename2 } from "path";
2281
+ import { execSync as execSync11 } from "child_process";
2282
+ import { basename as basename3 } from "path";
2025
2283
 
2026
2284
  // src/commands/devlog/shared.ts
2027
- import { execSync as execSync7 } from "child_process";
2285
+ import { execSync as execSync10 } from "child_process";
2028
2286
  import chalk28 from "chalk";
2029
2287
 
2030
2288
  // src/commands/devlog/loadDevlogEntries.ts
@@ -2068,7 +2326,7 @@ function loadDevlogEntries(repoName) {
2068
2326
  // src/commands/devlog/shared.ts
2069
2327
  function getCommitFiles(hash) {
2070
2328
  try {
2071
- const output = execSync7(`git show --name-only --format="" ${hash}`, {
2329
+ const output = execSync10(`git show --name-only --format="" ${hash}`, {
2072
2330
  encoding: "utf-8"
2073
2331
  });
2074
2332
  return output.trim().split("\n").filter(Boolean);
@@ -2130,16 +2388,16 @@ function printDateHeader(date, isSkipped, entries) {
2130
2388
  }
2131
2389
 
2132
2390
  // src/commands/devlog/list/index.ts
2133
- function list(options) {
2391
+ function list(options2) {
2134
2392
  const config = loadConfig();
2135
- const days = options.days ?? 30;
2136
- const ignore2 = options.ignore ?? config.devlog?.ignore ?? [];
2393
+ const days = options2.days ?? 30;
2394
+ const ignore2 = options2.ignore ?? config.devlog?.ignore ?? [];
2137
2395
  const skipDays = new Set(config.devlog?.skip?.days ?? []);
2138
- const repoName = basename2(process.cwd());
2396
+ const repoName = basename3(process.cwd());
2139
2397
  const devlogEntries = loadDevlogEntries(repoName);
2140
- const reverseFlag = options.reverse ? "--reverse " : "";
2141
- const limitFlag = options.reverse ? "" : "-n 500 ";
2142
- const output = execSync8(
2398
+ const reverseFlag = options2.reverse ? "--reverse " : "";
2399
+ const limitFlag = options2.reverse ? "" : "-n 500 ";
2400
+ const output = execSync11(
2143
2401
  `git log ${reverseFlag}${limitFlag}--pretty=format:'%ad|%h|%s' --date=short`,
2144
2402
  { encoding: "utf-8" }
2145
2403
  );
@@ -2147,8 +2405,8 @@ function list(options) {
2147
2405
  let dateCount = 0;
2148
2406
  let isFirst = true;
2149
2407
  for (const [date, dateCommits] of commitsByDate) {
2150
- if (options.since) {
2151
- if (date < options.since) {
2408
+ if (options2.since) {
2409
+ if (date < options2.since) {
2152
2410
  break;
2153
2411
  }
2154
2412
  } else if (dateCount >= days) {
@@ -2160,16 +2418,16 @@ function list(options) {
2160
2418
  }
2161
2419
  isFirst = false;
2162
2420
  printDateHeader(date, skipDays.has(date), devlogEntries.get(date));
2163
- printCommitsWithFiles(dateCommits, ignore2, options.verbose ?? false);
2421
+ printCommitsWithFiles(dateCommits, ignore2, options2.verbose ?? false);
2164
2422
  }
2165
2423
  }
2166
2424
 
2167
2425
  // src/commands/devlog/getLastVersionInfo.ts
2168
- import { execSync as execSync9 } from "child_process";
2426
+ import { execSync as execSync12 } from "child_process";
2169
2427
  import semver from "semver";
2170
2428
  function getVersionAtCommit(hash) {
2171
2429
  try {
2172
- const content = execSync9(`git show ${hash}:package.json`, {
2430
+ const content = execSync12(`git show ${hash}:package.json`, {
2173
2431
  encoding: "utf-8"
2174
2432
  });
2175
2433
  const pkg = JSON.parse(content);
@@ -2184,7 +2442,7 @@ function stripToMinor(version2) {
2184
2442
  }
2185
2443
  function getLastVersionInfoFromGit() {
2186
2444
  try {
2187
- const output = execSync9(
2445
+ const output = execSync12(
2188
2446
  "git log -1 --pretty=format:'%ad|%h' --date=short",
2189
2447
  {
2190
2448
  encoding: "utf-8"
@@ -2227,7 +2485,7 @@ function bumpVersion(version2, type) {
2227
2485
  }
2228
2486
 
2229
2487
  // src/commands/devlog/next/displayNextEntry/index.ts
2230
- import { execSync as execSync10 } from "child_process";
2488
+ import { execSync as execSync13 } from "child_process";
2231
2489
  import chalk31 from "chalk";
2232
2490
 
2233
2491
  // src/commands/devlog/next/displayNextEntry/displayVersion.ts
@@ -2261,7 +2519,7 @@ function findTargetDate(commitsByDate, skipDays) {
2261
2519
  return Array.from(commitsByDate.keys()).filter((d) => !skipDays.has(d)).sort()[0];
2262
2520
  }
2263
2521
  function fetchCommitsByDate(ignore2, lastDate) {
2264
- const output = execSync10(
2522
+ const output = execSync13(
2265
2523
  "git log --pretty=format:'%ad|%h|%s' --date=short -n 500",
2266
2524
  { encoding: "utf-8" }
2267
2525
  );
@@ -2276,8 +2534,8 @@ function printVersionInfo(config, lastInfo, firstHash) {
2276
2534
  versions.minor
2277
2535
  );
2278
2536
  }
2279
- function resolveIgnoreList(options, config) {
2280
- return options.ignore ?? config.devlog?.ignore ?? [];
2537
+ function resolveIgnoreList(options2, config) {
2538
+ return options2.ignore ?? config.devlog?.ignore ?? [];
2281
2539
  }
2282
2540
  function resolveSkipDays(config) {
2283
2541
  return new Set(config.devlog?.skip?.days ?? []);
@@ -2305,15 +2563,15 @@ function logNoCommits(lastInfo) {
2305
2563
  }
2306
2564
 
2307
2565
  // src/commands/devlog/next/index.ts
2308
- function resolveContextData(config, options) {
2566
+ function resolveContextData(config, options2) {
2309
2567
  const repoName = getRepoName();
2310
2568
  const lastInfo = getLastVersionInfo(repoName, config);
2311
- return { repoName, lastInfo, ignore: resolveIgnoreList(options, config) };
2569
+ return { repoName, lastInfo, ignore: resolveIgnoreList(options2, config) };
2312
2570
  }
2313
- function buildContext(options) {
2571
+ function buildContext(options2) {
2314
2572
  const config = loadConfig();
2315
- const data = resolveContextData(config, options);
2316
- return { config, ...data, verbose: options.verbose ?? false };
2573
+ const data = resolveContextData(config, options2);
2574
+ return { config, ...data, verbose: options2.verbose ?? false };
2317
2575
  }
2318
2576
  function fetchNextCommits(ctx) {
2319
2577
  const commitsByDate = fetchCommitsByDate(
@@ -2330,8 +2588,8 @@ function showResult(ctx, found) {
2330
2588
  }
2331
2589
  displayNextEntry(ctx, found.targetDate, found.commits);
2332
2590
  }
2333
- function next(options) {
2334
- const ctx = buildContext(options);
2591
+ function next(options2) {
2592
+ const ctx = buildContext(options2);
2335
2593
  showResult(ctx, fetchNextCommits(ctx));
2336
2594
  }
2337
2595
 
@@ -2387,9 +2645,12 @@ function registerDevlog(program2) {
2387
2645
  devlogCommand.command("skip <date>").description("Add a date (YYYY-MM-DD) to the skip list").action(skip);
2388
2646
  }
2389
2647
 
2648
+ // src/commands/prs/fixed.ts
2649
+ import { execSync as execSync16 } from "child_process";
2650
+
2390
2651
  // src/commands/prs/resolveCommentWithReply.ts
2391
- import { execSync as execSync12 } from "child_process";
2392
- import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "fs";
2652
+ import { execSync as execSync15 } from "child_process";
2653
+ import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "fs";
2393
2654
  import { tmpdir } from "os";
2394
2655
  import { join as join10 } from "path";
2395
2656
 
@@ -2417,7 +2678,7 @@ function deleteCommentsCache(prNumber) {
2417
2678
  }
2418
2679
 
2419
2680
  // src/commands/prs/shared.ts
2420
- import { execSync as execSync11 } from "child_process";
2681
+ import { execSync as execSync14 } from "child_process";
2421
2682
  function isGhNotInstalled(error) {
2422
2683
  if (error instanceof Error) {
2423
2684
  const msg = error.message.toLowerCase();
@@ -2433,14 +2694,14 @@ function isNotFound(error) {
2433
2694
  }
2434
2695
  function getRepoInfo() {
2435
2696
  const repoInfo = JSON.parse(
2436
- execSync11("gh repo view --json owner,name", { encoding: "utf-8" })
2697
+ execSync14("gh repo view --json owner,name", { encoding: "utf-8" })
2437
2698
  );
2438
2699
  return { org: repoInfo.owner.login, repo: repoInfo.name };
2439
2700
  }
2440
2701
  function getCurrentPrNumber() {
2441
2702
  try {
2442
2703
  const prInfo = JSON.parse(
2443
- execSync11("gh pr view --json number", { encoding: "utf-8" })
2704
+ execSync14("gh pr view --json number", { encoding: "utf-8" })
2444
2705
  );
2445
2706
  return prInfo.number;
2446
2707
  } catch (error) {
@@ -2454,7 +2715,7 @@ function getCurrentPrNumber() {
2454
2715
 
2455
2716
  // src/commands/prs/resolveCommentWithReply.ts
2456
2717
  function replyToComment(org, repo, prNumber, commentId, message) {
2457
- execSync12(
2718
+ execSync15(
2458
2719
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
2459
2720
  { stdio: "inherit" }
2460
2721
  );
@@ -2462,9 +2723,9 @@ function replyToComment(org, repo, prNumber, commentId, message) {
2462
2723
  function resolveThread(threadId) {
2463
2724
  const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
2464
2725
  const queryFile = join10(tmpdir(), `gh-mutation-${Date.now()}.graphql`);
2465
- writeFileSync9(queryFile, mutation);
2726
+ writeFileSync10(queryFile, mutation);
2466
2727
  try {
2467
- execSync12(
2728
+ execSync15(
2468
2729
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
2469
2730
  { stdio: "inherit" }
2470
2731
  );
@@ -2514,11 +2775,22 @@ function resolveCommentWithReply(commentId, message) {
2514
2775
  }
2515
2776
 
2516
2777
  // src/commands/prs/fixed.ts
2778
+ function verifySha(sha) {
2779
+ try {
2780
+ return execSync16(`git rev-parse --verify ${sha}`, {
2781
+ encoding: "utf-8"
2782
+ }).trim();
2783
+ } catch {
2784
+ console.error(`Error: '${sha}' is not a valid commit in this repository.`);
2785
+ process.exit(1);
2786
+ }
2787
+ }
2517
2788
  function fixed(commentId, sha) {
2518
2789
  try {
2790
+ const fullSha = verifySha(sha);
2519
2791
  const { org, repo } = getRepoInfo();
2520
2792
  const repoUrl = `https://github.com/${org}/${repo}`;
2521
- const message = `Fixed in [${sha}](${repoUrl}/commit/${sha})`;
2793
+ const message = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
2522
2794
  resolveCommentWithReply(commentId, message);
2523
2795
  } catch (error) {
2524
2796
  if (isGhNotInstalled(error)) {
@@ -2531,7 +2803,7 @@ function fixed(commentId, sha) {
2531
2803
  }
2532
2804
 
2533
2805
  // src/commands/prs/listComments/index.ts
2534
- import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync11 } from "fs";
2806
+ import { existsSync as existsSync13, mkdirSync as mkdirSync4, writeFileSync as writeFileSync12 } from "fs";
2535
2807
  import { join as join12 } from "path";
2536
2808
  import { stringify } from "yaml";
2537
2809
 
@@ -2541,16 +2813,16 @@ function isClaudeCode() {
2541
2813
  }
2542
2814
 
2543
2815
  // src/commands/prs/fetchThreadIds.ts
2544
- import { execSync as execSync13 } from "child_process";
2545
- import { unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
2816
+ import { execSync as execSync17 } from "child_process";
2817
+ import { unlinkSync as unlinkSync4, writeFileSync as writeFileSync11 } from "fs";
2546
2818
  import { tmpdir as tmpdir2 } from "os";
2547
2819
  import { join as join11 } from "path";
2548
2820
  var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
2549
2821
  function fetchThreadIds(org, repo, prNumber) {
2550
2822
  const queryFile = join11(tmpdir2(), `gh-query-${Date.now()}.graphql`);
2551
- writeFileSync10(queryFile, THREAD_QUERY);
2823
+ writeFileSync11(queryFile, THREAD_QUERY);
2552
2824
  try {
2553
- const result = execSync13(
2825
+ const result = execSync17(
2554
2826
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
2555
2827
  { encoding: "utf-8" }
2556
2828
  );
@@ -2572,9 +2844,9 @@ function fetchThreadIds(org, repo, prNumber) {
2572
2844
  }
2573
2845
 
2574
2846
  // src/commands/prs/listComments/fetchReviewComments.ts
2575
- import { execSync as execSync14 } from "child_process";
2847
+ import { execSync as execSync18 } from "child_process";
2576
2848
  function fetchJson(endpoint) {
2577
- const result = execSync14(`gh api ${endpoint}`, { encoding: "utf-8" });
2849
+ const result = execSync18(`gh api ${endpoint}`, { encoding: "utf-8" });
2578
2850
  if (!result.trim()) return [];
2579
2851
  return JSON.parse(result);
2580
2852
  }
@@ -2652,7 +2924,7 @@ function printComments(comments) {
2652
2924
  function writeCommentsCache(prNumber, comments) {
2653
2925
  const assistDir = join12(process.cwd(), ".assist");
2654
2926
  if (!existsSync13(assistDir)) {
2655
- mkdirSync3(assistDir, { recursive: true });
2927
+ mkdirSync4(assistDir, { recursive: true });
2656
2928
  }
2657
2929
  const cacheData = {
2658
2930
  prNumber,
@@ -2660,7 +2932,7 @@ function writeCommentsCache(prNumber, comments) {
2660
2932
  comments
2661
2933
  };
2662
2934
  const cachePath = join12(assistDir, `pr-${prNumber}-comments.yaml`);
2663
- writeFileSync11(cachePath, stringify(cacheData));
2935
+ writeFileSync12(cachePath, stringify(cacheData));
2664
2936
  }
2665
2937
  function handleKnownErrors(error) {
2666
2938
  if (isGhNotInstalled(error)) {
@@ -2700,7 +2972,7 @@ async function listComments() {
2700
2972
  }
2701
2973
 
2702
2974
  // src/commands/prs/prs/index.ts
2703
- import { execSync as execSync15 } from "child_process";
2975
+ import { execSync as execSync19 } from "child_process";
2704
2976
 
2705
2977
  // src/commands/prs/prs/displayPaginated/index.ts
2706
2978
  import enquirer4 from "enquirer";
@@ -2803,10 +3075,10 @@ async function displayPaginated(pullRequests) {
2803
3075
  }
2804
3076
 
2805
3077
  // src/commands/prs/prs/index.ts
2806
- async function prs(options) {
2807
- const state = options.open ? "open" : options.closed ? "closed" : "all";
3078
+ async function prs(options2) {
3079
+ const state = options2.open ? "open" : options2.closed ? "closed" : "all";
2808
3080
  try {
2809
- const result = execSync15(
3081
+ const result = execSync19(
2810
3082
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
2811
3083
  { encoding: "utf-8" }
2812
3084
  );
@@ -2829,7 +3101,7 @@ async function prs(options) {
2829
3101
  }
2830
3102
 
2831
3103
  // src/commands/prs/wontfix.ts
2832
- import { execSync as execSync16 } from "child_process";
3104
+ import { execSync as execSync20 } from "child_process";
2833
3105
  function validateReason(reason) {
2834
3106
  const lowerReason = reason.toLowerCase();
2835
3107
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -2846,7 +3118,7 @@ function validateShaReferences(reason) {
2846
3118
  const invalidShas = [];
2847
3119
  for (const sha of shas) {
2848
3120
  try {
2849
- execSync16(`git cat-file -t ${sha}`, { stdio: "pipe" });
3121
+ execSync20(`git cat-file -t ${sha}`, { stdio: "pipe" });
2850
3122
  } catch {
2851
3123
  invalidShas.push(sha);
2852
3124
  }
@@ -2888,8 +3160,8 @@ function registerPrs(program2) {
2888
3160
  }
2889
3161
 
2890
3162
  // src/commands/refactor/check/index.ts
2891
- import { spawn as spawn2 } from "child_process";
2892
- import * as path15 from "path";
3163
+ import { spawn as spawn3 } from "child_process";
3164
+ import * as path16 from "path";
2893
3165
 
2894
3166
  // src/commands/refactor/logViolations.ts
2895
3167
  import chalk36 from "chalk";
@@ -2947,7 +3219,7 @@ Refactor check failed:
2947
3219
  }
2948
3220
 
2949
3221
  // src/commands/refactor/check/getViolations/index.ts
2950
- import { execSync as execSync17 } from "child_process";
3222
+ import { execSync as execSync21 } from "child_process";
2951
3223
  import fs15 from "fs";
2952
3224
  import { minimatch as minimatch2 } from "minimatch";
2953
3225
 
@@ -2991,31 +3263,31 @@ function countLines(filePath) {
2991
3263
  const content = fs15.readFileSync(filePath, "utf-8");
2992
3264
  return content.split("\n").length;
2993
3265
  }
2994
- function getGitFiles(options) {
2995
- if (!options.modified && !options.staged && !options.unstaged) {
3266
+ function getGitFiles(options2) {
3267
+ if (!options2.modified && !options2.staged && !options2.unstaged) {
2996
3268
  return null;
2997
3269
  }
2998
3270
  const files = /* @__PURE__ */ new Set();
2999
- if (options.staged || options.modified) {
3000
- const staged = execSync17("git diff --cached --name-only", {
3271
+ if (options2.staged || options2.modified) {
3272
+ const staged = execSync21("git diff --cached --name-only", {
3001
3273
  encoding: "utf-8"
3002
3274
  });
3003
3275
  for (const file of staged.trim().split("\n").filter(Boolean)) {
3004
3276
  files.add(file);
3005
3277
  }
3006
3278
  }
3007
- if (options.unstaged || options.modified) {
3008
- const unstaged = execSync17("git diff --name-only", { encoding: "utf-8" });
3279
+ if (options2.unstaged || options2.modified) {
3280
+ const unstaged = execSync21("git diff --name-only", { encoding: "utf-8" });
3009
3281
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
3010
3282
  files.add(file);
3011
3283
  }
3012
3284
  }
3013
3285
  return files;
3014
3286
  }
3015
- function getViolations(pattern2, options = {}, maxLines = DEFAULT_MAX_LINES) {
3287
+ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
3016
3288
  let sourceFiles = findSourceFiles("src", { includeTests: false });
3017
3289
  const ignoredFiles = getIgnoredFiles();
3018
- const gitFiles = getGitFiles(options);
3290
+ const gitFiles = getGitFiles(options2);
3019
3291
  if (pattern2) {
3020
3292
  sourceFiles = sourceFiles.filter((f) => minimatch2(f, pattern2));
3021
3293
  }
@@ -3034,9 +3306,9 @@ function getViolations(pattern2, options = {}, maxLines = DEFAULT_MAX_LINES) {
3034
3306
  }
3035
3307
 
3036
3308
  // src/commands/refactor/check/index.ts
3037
- function runScript(script, cwd) {
3038
- return new Promise((resolve) => {
3039
- const child = spawn2("npm", ["run", script], {
3309
+ function runScript2(script, cwd) {
3310
+ return new Promise((resolve2) => {
3311
+ const child = spawn3("npm", ["run", script], {
3040
3312
  stdio: "pipe",
3041
3313
  shell: true,
3042
3314
  cwd
@@ -3049,7 +3321,7 @@ function runScript(script, cwd) {
3049
3321
  output += data.toString();
3050
3322
  });
3051
3323
  child.on("close", (code) => {
3052
- resolve({ script, code: code ?? 1, output });
3324
+ resolve2({ script, code: code ?? 1, output });
3053
3325
  });
3054
3326
  });
3055
3327
  }
@@ -3066,9 +3338,9 @@ ${failed.length} verify script(s) failed:`);
3066
3338
  async function runVerifyQuietly() {
3067
3339
  const result = findPackageJsonWithVerifyScripts(process.cwd());
3068
3340
  if (!result) return true;
3069
- const packageDir = path15.dirname(result.packageJsonPath);
3341
+ const packageDir = path16.dirname(result.packageJsonPath);
3070
3342
  const results = await Promise.all(
3071
- result.verifyScripts.map((script) => runScript(script, packageDir))
3343
+ result.verifyScripts.map((script) => runScript2(script, packageDir))
3072
3344
  );
3073
3345
  const failed = results.filter((r) => r.code !== 0);
3074
3346
  if (failed.length > 0) {
@@ -3077,13 +3349,13 @@ async function runVerifyQuietly() {
3077
3349
  }
3078
3350
  return true;
3079
3351
  }
3080
- async function check(pattern2, options) {
3352
+ async function check(pattern2, options2) {
3081
3353
  const verifyPassed = await runVerifyQuietly();
3082
3354
  if (!verifyPassed) {
3083
3355
  process.exit(1);
3084
3356
  }
3085
- const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
3086
- const violations = getViolations(pattern2, options, maxLines);
3357
+ const maxLines = options2.maxLines ?? DEFAULT_MAX_LINES;
3358
+ const violations = getViolations(pattern2, options2, maxLines);
3087
3359
  violations.sort((a, b) => b.lines - a.lines);
3088
3360
  logViolations(violations, maxLines);
3089
3361
  if (violations.length > 0) {
@@ -3120,11 +3392,11 @@ function ignore(file) {
3120
3392
  }
3121
3393
 
3122
3394
  // src/commands/refactor/restructure/index.ts
3123
- import path24 from "path";
3395
+ import path25 from "path";
3124
3396
  import chalk40 from "chalk";
3125
3397
 
3126
3398
  // src/commands/refactor/restructure/buildImportGraph/index.ts
3127
- import path16 from "path";
3399
+ import path17 from "path";
3128
3400
  import ts7 from "typescript";
3129
3401
 
3130
3402
  // src/commands/refactor/restructure/buildImportGraph/getImportSpecifiers.ts
@@ -3151,7 +3423,7 @@ function loadParsedConfig(tsConfigPath) {
3151
3423
  return ts7.parseJsonConfigFileContent(
3152
3424
  configFile.config,
3153
3425
  ts7.sys,
3154
- path16.dirname(tsConfigPath)
3426
+ path17.dirname(tsConfigPath)
3155
3427
  );
3156
3428
  }
3157
3429
  function addToSetMap(map, key, value) {
@@ -3162,12 +3434,12 @@ function addToSetMap(map, key, value) {
3162
3434
  }
3163
3435
  set.add(value);
3164
3436
  }
3165
- function resolveImport(specifier, filePath, options) {
3437
+ function resolveImport(specifier, filePath, options2) {
3166
3438
  if (!specifier.startsWith(".")) return null;
3167
- const resolved = ts7.resolveModuleName(specifier, filePath, options, ts7.sys);
3439
+ const resolved = ts7.resolveModuleName(specifier, filePath, options2, ts7.sys);
3168
3440
  const resolvedPath = resolved.resolvedModule?.resolvedFileName;
3169
3441
  if (!resolvedPath || resolvedPath.includes("node_modules")) return null;
3170
- return path16.resolve(resolvedPath);
3442
+ return path17.resolve(resolvedPath);
3171
3443
  }
3172
3444
  function buildImportGraph(candidateFiles, tsConfigPath) {
3173
3445
  const parsed = loadParsedConfig(tsConfigPath);
@@ -3176,7 +3448,7 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
3176
3448
  const importedBy = /* @__PURE__ */ new Map();
3177
3449
  const imports = /* @__PURE__ */ new Map();
3178
3450
  for (const sourceFile of program2.getSourceFiles()) {
3179
- const filePath = path16.resolve(sourceFile.fileName);
3451
+ const filePath = path17.resolve(sourceFile.fileName);
3180
3452
  if (filePath.includes("node_modules")) continue;
3181
3453
  for (const specifier of getImportSpecifiers(sourceFile)) {
3182
3454
  const absTarget = resolveImport(specifier, filePath, parsed.options);
@@ -3190,12 +3462,12 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
3190
3462
  }
3191
3463
 
3192
3464
  // src/commands/refactor/restructure/clusterDirectories.ts
3193
- import path17 from "path";
3465
+ import path18 from "path";
3194
3466
  function clusterDirectories(graph) {
3195
3467
  const dirImportedBy = /* @__PURE__ */ new Map();
3196
3468
  for (const edge of graph.edges) {
3197
- const sourceDir = path17.dirname(edge.source);
3198
- const targetDir = path17.dirname(edge.target);
3469
+ const sourceDir = path18.dirname(edge.source);
3470
+ const targetDir = path18.dirname(edge.target);
3199
3471
  if (sourceDir === targetDir) continue;
3200
3472
  if (!graph.files.has(edge.target)) continue;
3201
3473
  const existing = dirImportedBy.get(targetDir) ?? /* @__PURE__ */ new Set();
@@ -3223,20 +3495,20 @@ function clusterDirectories(graph) {
3223
3495
  return clusters;
3224
3496
  }
3225
3497
  function isAncestor(ancestor, descendant) {
3226
- const rel = path17.relative(ancestor, descendant);
3498
+ const rel = path18.relative(ancestor, descendant);
3227
3499
  return !rel.startsWith("..") && rel !== "";
3228
3500
  }
3229
3501
 
3230
3502
  // src/commands/refactor/restructure/clusterFiles.ts
3231
- import path18 from "path";
3503
+ import path19 from "path";
3232
3504
  function findRootParent(file, importedBy, visited) {
3233
3505
  const importers = importedBy.get(file);
3234
3506
  if (!importers || importers.size !== 1) return file;
3235
3507
  const parent = [...importers][0];
3236
- const parentDir = path18.dirname(parent);
3237
- const fileDir = path18.dirname(file);
3508
+ const parentDir = path19.dirname(parent);
3509
+ const fileDir = path19.dirname(file);
3238
3510
  if (parentDir !== fileDir) return file;
3239
- if (path18.basename(parent, path18.extname(parent)) === "index") return file;
3511
+ if (path19.basename(parent, path19.extname(parent)) === "index") return file;
3240
3512
  if (visited.has(parent)) return file;
3241
3513
  visited.add(parent);
3242
3514
  return findRootParent(parent, importedBy, visited);
@@ -3244,16 +3516,16 @@ function findRootParent(file, importedBy, visited) {
3244
3516
  function clusterFiles(graph) {
3245
3517
  const clusters = /* @__PURE__ */ new Map();
3246
3518
  for (const file of graph.files) {
3247
- const basename6 = path18.basename(file, path18.extname(file));
3248
- if (basename6 === "index") continue;
3519
+ const basename7 = path19.basename(file, path19.extname(file));
3520
+ if (basename7 === "index") continue;
3249
3521
  const importers = graph.importedBy.get(file);
3250
3522
  if (!importers || importers.size !== 1) continue;
3251
3523
  const parent = [...importers][0];
3252
3524
  if (!graph.files.has(parent)) continue;
3253
- const parentDir = path18.dirname(parent);
3254
- const fileDir = path18.dirname(file);
3525
+ const parentDir = path19.dirname(parent);
3526
+ const fileDir = path19.dirname(file);
3255
3527
  if (parentDir !== fileDir) continue;
3256
- const parentBasename = path18.basename(parent, path18.extname(parent));
3528
+ const parentBasename = path19.basename(parent, path19.extname(parent));
3257
3529
  if (parentBasename === "index") continue;
3258
3530
  const root = findRootParent(parent, graph.importedBy, /* @__PURE__ */ new Set([file]));
3259
3531
  if (!root || root === file) continue;
@@ -3265,7 +3537,7 @@ function clusterFiles(graph) {
3265
3537
  }
3266
3538
 
3267
3539
  // src/commands/refactor/restructure/computeRewrites/index.ts
3268
- import path19 from "path";
3540
+ import path20 from "path";
3269
3541
 
3270
3542
  // src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
3271
3543
  import fs17 from "fs";
@@ -3319,7 +3591,7 @@ function normalizeSpecifier(rel) {
3319
3591
  );
3320
3592
  }
3321
3593
  function computeSpecifier(fromFile, toFile) {
3322
- return normalizeSpecifier(path19.relative(path19.dirname(fromFile), toFile));
3594
+ return normalizeSpecifier(path20.relative(path20.dirname(fromFile), toFile));
3323
3595
  }
3324
3596
  function isAffected(edge, moveMap) {
3325
3597
  return moveMap.has(edge.target) || moveMap.has(edge.source);
@@ -3363,10 +3635,10 @@ function computeRewrites(moves, edges, allProjectFiles) {
3363
3635
  }
3364
3636
 
3365
3637
  // src/commands/refactor/restructure/displayPlan.ts
3366
- import path20 from "path";
3638
+ import path21 from "path";
3367
3639
  import chalk38 from "chalk";
3368
3640
  function relPath(filePath) {
3369
- return path20.relative(process.cwd(), filePath);
3641
+ return path21.relative(process.cwd(), filePath);
3370
3642
  }
3371
3643
  function displayMoves(plan) {
3372
3644
  if (plan.moves.length === 0) return;
@@ -3416,33 +3688,33 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
3416
3688
 
3417
3689
  // src/commands/refactor/restructure/executePlan.ts
3418
3690
  import fs18 from "fs";
3419
- import path21 from "path";
3691
+ import path22 from "path";
3420
3692
  import chalk39 from "chalk";
3421
3693
  function executePlan(plan) {
3422
3694
  const updatedContents = applyRewrites(plan.rewrites);
3423
3695
  for (const [file, content] of updatedContents) {
3424
3696
  fs18.writeFileSync(file, content, "utf-8");
3425
3697
  console.log(
3426
- chalk39.cyan(` Rewrote imports in ${path21.relative(process.cwd(), file)}`)
3698
+ chalk39.cyan(` Rewrote imports in ${path22.relative(process.cwd(), file)}`)
3427
3699
  );
3428
3700
  }
3429
3701
  for (const dir of plan.newDirectories) {
3430
3702
  fs18.mkdirSync(dir, { recursive: true });
3431
- console.log(chalk39.green(` Created ${path21.relative(process.cwd(), dir)}/`));
3703
+ console.log(chalk39.green(` Created ${path22.relative(process.cwd(), dir)}/`));
3432
3704
  }
3433
3705
  for (const move of plan.moves) {
3434
- const targetDir = path21.dirname(move.to);
3706
+ const targetDir = path22.dirname(move.to);
3435
3707
  if (!fs18.existsSync(targetDir)) {
3436
3708
  fs18.mkdirSync(targetDir, { recursive: true });
3437
3709
  }
3438
3710
  fs18.renameSync(move.from, move.to);
3439
3711
  console.log(
3440
3712
  chalk39.white(
3441
- ` Moved ${path21.relative(process.cwd(), move.from)} \u2192 ${path21.relative(process.cwd(), move.to)}`
3713
+ ` Moved ${path22.relative(process.cwd(), move.from)} \u2192 ${path22.relative(process.cwd(), move.to)}`
3442
3714
  )
3443
3715
  );
3444
3716
  }
3445
- removeEmptyDirectories(plan.moves.map((m) => path21.dirname(m.from)));
3717
+ removeEmptyDirectories(plan.moves.map((m) => path22.dirname(m.from)));
3446
3718
  }
3447
3719
  function removeEmptyDirectories(dirs) {
3448
3720
  const unique = [...new Set(dirs)];
@@ -3453,7 +3725,7 @@ function removeEmptyDirectories(dirs) {
3453
3725
  fs18.rmdirSync(dir);
3454
3726
  console.log(
3455
3727
  chalk39.dim(
3456
- ` Removed empty directory ${path21.relative(process.cwd(), dir)}`
3728
+ ` Removed empty directory ${path22.relative(process.cwd(), dir)}`
3457
3729
  )
3458
3730
  );
3459
3731
  }
@@ -3462,13 +3734,13 @@ function removeEmptyDirectories(dirs) {
3462
3734
 
3463
3735
  // src/commands/refactor/restructure/planFileMoves/index.ts
3464
3736
  import fs20 from "fs";
3465
- import path23 from "path";
3737
+ import path24 from "path";
3466
3738
 
3467
3739
  // src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
3468
3740
  import fs19 from "fs";
3469
- import path22 from "path";
3741
+ import path23 from "path";
3470
3742
  function collectEntry(results, dir, entry) {
3471
- const full = path22.join(dir, entry.name);
3743
+ const full = path23.join(dir, entry.name);
3472
3744
  const items = entry.isDirectory() ? listFilesRecursive(full) : [full];
3473
3745
  results.push(...items);
3474
3746
  }
@@ -3482,15 +3754,15 @@ function listFilesRecursive(dir) {
3482
3754
  }
3483
3755
  function addDirectoryFileMoves(moves, childDir, newLocation, reason) {
3484
3756
  for (const file of listFilesRecursive(childDir)) {
3485
- const rel = path22.relative(childDir, file);
3486
- moves.push({ from: file, to: path22.join(newLocation, rel), reason });
3757
+ const rel = path23.relative(childDir, file);
3758
+ moves.push({ from: file, to: path23.join(newLocation, rel), reason });
3487
3759
  }
3488
3760
  }
3489
3761
  function resolveChildDest(parentDir, childDir) {
3490
- return path22.join(parentDir, path22.basename(childDir));
3762
+ return path23.join(parentDir, path23.basename(childDir));
3491
3763
  }
3492
3764
  function childMoveReason(parentDir) {
3493
- return `Directory only imported from ${path22.basename(parentDir)}/`;
3765
+ return `Directory only imported from ${path23.basename(parentDir)}/`;
3494
3766
  }
3495
3767
  function registerDirectoryMove(result, childDir, dest, parentDir) {
3496
3768
  result.directories.push(dest);
@@ -3518,7 +3790,7 @@ function emptyResult() {
3518
3790
  return { moves: [], directories: [], warnings: [] };
3519
3791
  }
3520
3792
  function childMoveData(child, newDir, parentBase) {
3521
- const to = path23.join(newDir, path23.basename(child));
3793
+ const to = path24.join(newDir, path24.basename(child));
3522
3794
  return { from: child, to, reason: `Only imported by ${parentBase}` };
3523
3795
  }
3524
3796
  function addChildMoves(moves, children, newDir, parentBase) {
@@ -3531,15 +3803,15 @@ function checkDirConflict(result, label, dir) {
3531
3803
  return true;
3532
3804
  }
3533
3805
  function getBaseName(filePath) {
3534
- return path23.basename(filePath, path23.extname(filePath));
3806
+ return path24.basename(filePath, path24.extname(filePath));
3535
3807
  }
3536
3808
  function resolveClusterDir(parent) {
3537
- return path23.join(path23.dirname(parent), getBaseName(parent));
3809
+ return path24.join(path24.dirname(parent), getBaseName(parent));
3538
3810
  }
3539
3811
  function createParentMove(parent, newDir) {
3540
3812
  return {
3541
3813
  from: parent,
3542
- to: path23.join(newDir, `index${path23.extname(parent)}`),
3814
+ to: path24.join(newDir, `index${path24.extname(parent)}`),
3543
3815
  reason: `Main module of new ${getBaseName(parent)}/ directory`
3544
3816
  };
3545
3817
  }
@@ -3563,7 +3835,7 @@ function planFileMoves(clusters) {
3563
3835
 
3564
3836
  // src/commands/refactor/restructure/index.ts
3565
3837
  function buildPlan(candidateFiles, tsConfigPath) {
3566
- const candidates = new Set(candidateFiles.map((f) => path24.resolve(f)));
3838
+ const candidates = new Set(candidateFiles.map((f) => path25.resolve(f)));
3567
3839
  const graph = buildImportGraph(candidates, tsConfigPath);
3568
3840
  const allProjectFiles = /* @__PURE__ */ new Set([
3569
3841
  ...graph.importedBy.keys(),
@@ -3579,21 +3851,21 @@ function buildPlan(candidateFiles, tsConfigPath) {
3579
3851
  const rewrites = computeRewrites(moves, graph.edges, allProjectFiles);
3580
3852
  return { moves, rewrites, newDirectories: directories, warnings };
3581
3853
  }
3582
- async function restructure(pattern2, options = {}) {
3854
+ async function restructure(pattern2, options2 = {}) {
3583
3855
  const targetPattern = pattern2 ?? "src";
3584
3856
  const files = findSourceFiles2(targetPattern);
3585
3857
  if (files.length === 0) {
3586
3858
  console.log(chalk40.yellow("No files found matching pattern"));
3587
3859
  return;
3588
3860
  }
3589
- const tsConfigPath = path24.resolve("tsconfig.json");
3861
+ const tsConfigPath = path25.resolve("tsconfig.json");
3590
3862
  const plan = buildPlan(files, tsConfigPath);
3591
3863
  if (plan.moves.length === 0) {
3592
3864
  console.log(chalk40.green("No restructuring needed"));
3593
3865
  return;
3594
3866
  }
3595
3867
  displayPlan(plan);
3596
- if (options.apply) {
3868
+ if (options2.apply) {
3597
3869
  console.log(chalk40.bold("\nApplying changes..."));
3598
3870
  executePlan(plan);
3599
3871
  console.log(chalk40.green("\nRestructuring complete"));
@@ -3622,7 +3894,7 @@ function registerRefactor(program2) {
3622
3894
 
3623
3895
  // src/commands/transcript/shared.ts
3624
3896
  import { existsSync as existsSync14, readdirSync as readdirSync2, statSync } from "fs";
3625
- import { basename as basename3, join as join13, relative } from "path";
3897
+ import { basename as basename4, join as join13, relative } from "path";
3626
3898
  import * as readline2 from "readline";
3627
3899
  var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
3628
3900
  function getDatePrefix(daysOffset = 0) {
@@ -3653,7 +3925,7 @@ function toFileInfo(baseDir, fullPath) {
3653
3925
  return {
3654
3926
  absolutePath: fullPath,
3655
3927
  relativePath: relative(baseDir, fullPath),
3656
- filename: basename3(fullPath)
3928
+ filename: basename4(fullPath)
3657
3929
  };
3658
3930
  }
3659
3931
  function findVttFilesRecursive(dir, baseDir = dir) {
@@ -3663,7 +3935,7 @@ function findMdFilesRecursive(dir, baseDir = dir) {
3663
3935
  return collectFiles(dir, ".md").map((f) => toFileInfo(baseDir, f));
3664
3936
  }
3665
3937
  function getTranscriptBaseName(transcriptFile) {
3666
- return basename3(transcriptFile, ".md").replace(/ Transcription$/, "");
3938
+ return basename4(transcriptFile, ".md").replace(/ Transcription$/, "");
3667
3939
  }
3668
3940
  function createReadlineInterface() {
3669
3941
  return readline2.createInterface({
@@ -3672,9 +3944,9 @@ function createReadlineInterface() {
3672
3944
  });
3673
3945
  }
3674
3946
  function askQuestion(rl, question) {
3675
- return new Promise((resolve) => {
3947
+ return new Promise((resolve2) => {
3676
3948
  rl.question(question, (answer) => {
3677
- resolve(answer.trim());
3949
+ resolve2(answer.trim());
3678
3950
  });
3679
3951
  });
3680
3952
  }
@@ -3737,7 +4009,7 @@ async function configure() {
3737
4009
  import { existsSync as existsSync16 } from "fs";
3738
4010
 
3739
4011
  // src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
3740
- import { dirname as dirname10, join as join15 } from "path";
4012
+ import { dirname as dirname11, join as join15 } from "path";
3741
4013
 
3742
4014
  // src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
3743
4015
  import { renameSync } from "fs";
@@ -3787,11 +4059,11 @@ async function fixInvalidDatePrefixes(vttFiles) {
3787
4059
  for (let i = 0; i < vttFiles.length; i++) {
3788
4060
  const vttFile = vttFiles[i];
3789
4061
  if (!isValidDatePrefix(vttFile.filename)) {
3790
- const vttFileDir = dirname10(vttFile.absolutePath);
4062
+ const vttFileDir = dirname11(vttFile.absolutePath);
3791
4063
  const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
3792
4064
  if (newFilename) {
3793
4065
  const newRelativePath = join15(
3794
- dirname10(vttFile.relativePath),
4066
+ dirname11(vttFile.relativePath),
3795
4067
  newFilename
3796
4068
  );
3797
4069
  vttFiles[i] = {
@@ -3808,8 +4080,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
3808
4080
  }
3809
4081
 
3810
4082
  // src/commands/transcript/format/processVttFile/index.ts
3811
- import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "fs";
3812
- import { basename as basename4, dirname as dirname11, join as join16 } from "path";
4083
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync13 } from "fs";
4084
+ import { basename as basename5, dirname as dirname12, join as join16 } from "path";
3813
4085
 
3814
4086
  // src/commands/transcript/cleanText.ts
3815
4087
  function cleanText(text) {
@@ -3832,7 +4104,7 @@ function cleanText(text) {
3832
4104
  return cleaned.join(" ").replace(/\s+/g, " ").trim();
3833
4105
  }
3834
4106
 
3835
- // src/commands/transcript/format/parseVtt/deduplicateCues/removeSubstringDuplicates.ts
4107
+ // src/commands/transcript/format/processVttFile/parseVtt/deduplicateCues/removeSubstringDuplicates.ts
3836
4108
  function normalizeText(text) {
3837
4109
  return text.toLowerCase().trim();
3838
4110
  }
@@ -3875,7 +4147,7 @@ function removeSubstringDuplicates(cues) {
3875
4147
  return cues.filter((_, i) => !toRemove.has(i));
3876
4148
  }
3877
4149
 
3878
- // src/commands/transcript/format/parseVtt/deduplicateCues/index.ts
4150
+ // src/commands/transcript/format/processVttFile/parseVtt/deduplicateCues/index.ts
3879
4151
  function findWordOverlap(currentWords, nextWords) {
3880
4152
  for (let j = Math.min(5, currentWords.length); j >= 1; j--) {
3881
4153
  const suffix = currentWords.slice(-j).join(" ");
@@ -3923,7 +4195,7 @@ function deduplicateCues(cues) {
3923
4195
  }));
3924
4196
  }
3925
4197
 
3926
- // src/commands/transcript/format/parseVtt/index.ts
4198
+ // src/commands/transcript/format/processVttFile/parseVtt/index.ts
3927
4199
  function parseHMS(h, m, s) {
3928
4200
  return Number.parseInt(h, 10) * 3600 + Number.parseInt(m, 10) * 60 + Number.parseFloat(s);
3929
4201
  }
@@ -4016,14 +4288,14 @@ function formatChatLog(messages) {
4016
4288
 
4017
4289
  // src/commands/transcript/format/processVttFile/index.ts
4018
4290
  function toMdFilename(vttFilename) {
4019
- return `${basename4(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
4291
+ return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
4020
4292
  }
4021
4293
  function resolveOutputDir(relativeDir, transcriptsDir) {
4022
4294
  return relativeDir === "." ? transcriptsDir : join16(transcriptsDir, relativeDir);
4023
4295
  }
4024
4296
  function buildOutputPaths(vttFile, transcriptsDir) {
4025
4297
  const mdFile = toMdFilename(vttFile.filename);
4026
- const relativeDir = dirname11(vttFile.relativePath);
4298
+ const relativeDir = dirname12(vttFile.relativePath);
4027
4299
  const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
4028
4300
  const outputPath = join16(outputDir, mdFile);
4029
4301
  return { outputDir, outputPath, mdFile, relativeDir };
@@ -4034,7 +4306,7 @@ function logSkipped(relativeDir, mdFile) {
4034
4306
  }
4035
4307
  function ensureDirectory(dir, label) {
4036
4308
  if (!existsSync15(dir)) {
4037
- mkdirSync4(dir, { recursive: true });
4309
+ mkdirSync5(dir, { recursive: true });
4038
4310
  console.log(`Created ${label}: ${dir}`);
4039
4311
  }
4040
4312
  }
@@ -4059,7 +4331,7 @@ function readAndParseCues(inputPath) {
4059
4331
  return processCues(readFileSync12(inputPath, "utf-8"));
4060
4332
  }
4061
4333
  function writeFormatted(outputPath, content) {
4062
- writeFileSync12(outputPath, content, "utf-8");
4334
+ writeFileSync13(outputPath, content, "utf-8");
4063
4335
  console.log(`Written: ${outputPath}`);
4064
4336
  }
4065
4337
  function convertVttToMarkdown(inputPath, outputPath) {
@@ -4128,17 +4400,17 @@ async function format() {
4128
4400
 
4129
4401
  // src/commands/transcript/summarise/index.ts
4130
4402
  import { existsSync as existsSync18 } from "fs";
4131
- import { basename as basename5, dirname as dirname13, join as join18, relative as relative2 } from "path";
4403
+ import { basename as basename6, dirname as dirname14, join as join18, relative as relative2 } from "path";
4132
4404
 
4133
4405
  // src/commands/transcript/summarise/processStagedFile/index.ts
4134
4406
  import {
4135
4407
  existsSync as existsSync17,
4136
- mkdirSync as mkdirSync5,
4408
+ mkdirSync as mkdirSync6,
4137
4409
  readFileSync as readFileSync13,
4138
4410
  renameSync as renameSync2,
4139
4411
  rmSync
4140
4412
  } from "fs";
4141
- import { dirname as dirname12, join as join17 } from "path";
4413
+ import { dirname as dirname13, join as join17 } from "path";
4142
4414
 
4143
4415
  // src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
4144
4416
  import chalk41 from "chalk";
@@ -4192,9 +4464,9 @@ function processStagedFile() {
4192
4464
  process.exit(1);
4193
4465
  }
4194
4466
  const destPath = join17(summaryDir, matchingTranscript.relativePath);
4195
- const destDir = dirname12(destPath);
4467
+ const destDir = dirname13(destPath);
4196
4468
  if (!existsSync17(destDir)) {
4197
- mkdirSync5(destDir, { recursive: true });
4469
+ mkdirSync6(destDir, { recursive: true });
4198
4470
  }
4199
4471
  renameSync2(stagedFile.absolutePath, destPath);
4200
4472
  const remaining = findMdFilesRecursive(STAGING_DIR);
@@ -4206,14 +4478,14 @@ function processStagedFile() {
4206
4478
 
4207
4479
  // src/commands/transcript/summarise/index.ts
4208
4480
  function buildRelativeKey(relativePath, baseName) {
4209
- const relDir = dirname13(relativePath);
4481
+ const relDir = dirname14(relativePath);
4210
4482
  return relDir === "." ? baseName : join18(relDir, baseName);
4211
4483
  }
4212
4484
  function buildSummaryIndex(summaryDir) {
4213
4485
  const summaryFiles = findMdFilesRecursive(summaryDir);
4214
4486
  return new Set(
4215
4487
  summaryFiles.map(
4216
- (f) => buildRelativeKey(f.relativePath, basename5(f.filename, ".md"))
4488
+ (f) => buildRelativeKey(f.relativePath, basename6(f.filename, ".md"))
4217
4489
  )
4218
4490
  );
4219
4491
  }
@@ -4242,7 +4514,7 @@ function summarise() {
4242
4514
  const next2 = missing[0];
4243
4515
  const outputFilename = `${getTranscriptBaseName(next2.filename)}.md`;
4244
4516
  const outputPath = join18(STAGING_DIR, outputFilename);
4245
- const summaryFileDir = join18(summaryDir, dirname13(next2.relativePath));
4517
+ const summaryFileDir = join18(summaryDir, dirname14(next2.relativePath));
4246
4518
  const relativeTranscriptPath = encodeURI(
4247
4519
  relative2(summaryFileDir, next2.absolutePath).replace(/\\/g, "/")
4248
4520
  );
@@ -4266,161 +4538,9 @@ function registerTranscript(program2) {
4266
4538
  transcriptCommand.command("summarise").description("List transcripts that do not have summaries").action(summarise);
4267
4539
  }
4268
4540
 
4269
- // src/commands/verify/hardcodedColors.ts
4270
- import { execSync as execSync18 } from "child_process";
4271
- var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
4272
- function hardcodedColors() {
4273
- try {
4274
- const output = execSync18(`grep -rEnH '${pattern}' src/`, {
4275
- encoding: "utf-8"
4276
- });
4277
- const lines = output.trim().split("\n");
4278
- console.log("Hardcoded colors found:\n");
4279
- for (const line of lines) {
4280
- const match = line.match(/^(.+):(\d+):(.+)$/);
4281
- if (match) {
4282
- const [, file, lineNum, content] = match;
4283
- const colorMatch = content.match(/0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}/);
4284
- const color = colorMatch?.[0] ?? "unknown";
4285
- console.log(`${file}:${lineNum} \u2192 ${color}`);
4286
- }
4287
- }
4288
- console.log(`
4289
- Total: ${lines.length} hardcoded color(s)`);
4290
- console.log("\nUse colors from the 'open-color' (oc) library instead.");
4291
- console.log("\nExample fix:");
4292
- console.log(" Before: color: '#228be6'");
4293
- console.log(" After: color: oc.blue[6]");
4294
- console.log("\nImport open-color with: import oc from 'open-color'");
4295
- process.exit(1);
4296
- } catch {
4297
- console.log("No hardcoded colors found.");
4298
- process.exit(0);
4299
- }
4300
- }
4301
-
4302
- // src/commands/verify/run/index.ts
4303
- import { spawn as spawn3 } from "child_process";
4304
- import * as path25 from "path";
4305
-
4306
- // src/commands/verify/run/createTimerCallback/printTaskStatuses.ts
4307
- function formatDuration(ms) {
4308
- if (ms < 1e3) {
4309
- return `${ms}ms`;
4310
- }
4311
- const seconds = (ms / 1e3).toFixed(1);
4312
- return `${seconds}s`;
4313
- }
4314
- function printTaskStatuses(tasks) {
4315
- console.log("\n--- Task Status ---");
4316
- for (const task of tasks) {
4317
- if (task.endTime !== void 0) {
4318
- const duration = formatDuration(task.endTime - task.startTime);
4319
- const status = task.code === 0 ? "\u2713" : "\u2717";
4320
- console.log(` ${status} ${task.script}: ${duration}`);
4321
- } else {
4322
- const elapsed = formatDuration(Date.now() - task.startTime);
4323
- console.log(` \u22EF ${task.script}: running (${elapsed})`);
4324
- }
4325
- }
4326
- console.log("-------------------\n");
4327
- }
4328
-
4329
- // src/commands/verify/run/createTimerCallback/index.ts
4330
- function logFailedScripts(failed) {
4331
- console.error(`
4332
- ${failed.length} script(s) failed:`);
4333
- for (const f of failed) {
4334
- console.error(` - ${f.script} (exit code ${f.code})`);
4335
- }
4336
- }
4337
- function createTimerCallback(taskStatuses, index) {
4338
- return (exitCode) => {
4339
- taskStatuses[index].endTime = Date.now();
4340
- taskStatuses[index].code = exitCode;
4341
- printTaskStatuses(taskStatuses);
4342
- };
4343
- }
4344
- function initTaskStatuses(scripts) {
4345
- return scripts.map((script) => ({ script, startTime: Date.now() }));
4346
- }
4347
-
4348
- // src/commands/verify/run/index.ts
4349
- function spawnScript(script, cwd) {
4350
- return spawn3("npm", ["run", script], { stdio: "inherit", shell: true, cwd });
4351
- }
4352
- function onScriptClose(script, onComplete, resolve) {
4353
- return (code) => {
4354
- const exitCode = code ?? 1;
4355
- onComplete?.(exitCode);
4356
- resolve({ script, code: exitCode });
4357
- };
4358
- }
4359
- function runScript2(script, cwd, onComplete) {
4360
- return new Promise((resolve) => {
4361
- spawnScript(script, cwd).on(
4362
- "close",
4363
- onScriptClose(script, onComplete, resolve)
4364
- );
4365
- });
4366
- }
4367
- function runAllScripts(verifyScripts, packageDir, timer) {
4368
- const taskStatuses = initTaskStatuses(verifyScripts);
4369
- return Promise.all(
4370
- verifyScripts.map(
4371
- (script, index) => runScript2(
4372
- script,
4373
- packageDir,
4374
- timer ? createTimerCallback(taskStatuses, index) : void 0
4375
- )
4376
- )
4377
- );
4378
- }
4379
- function printScriptList(scripts) {
4380
- console.log(`Running ${scripts.length} verify script(s) in parallel:`);
4381
- for (const script of scripts) {
4382
- console.log(` - ${script}`);
4383
- }
4384
- }
4385
- function exitIfFailed(failed) {
4386
- if (failed.length === 0) return;
4387
- logFailedScripts(failed);
4388
- process.exit(1);
4389
- }
4390
- function handleResults(results, totalCount) {
4391
- exitIfFailed(results.filter((r) => r.code !== 0));
4392
- console.log(`
4393
- All ${totalCount} verify script(s) passed`);
4394
- }
4395
- function resolveVerifyScripts() {
4396
- const result = findPackageJsonWithVerifyScripts(process.cwd());
4397
- if (!result) {
4398
- console.log("No package.json with verify:* scripts found");
4399
- return null;
4400
- }
4401
- return result;
4402
- }
4403
- function getPackageDir(found) {
4404
- return path25.dirname(found.packageJsonPath);
4405
- }
4406
- async function executeVerifyScripts(found, timer) {
4407
- printScriptList(found.verifyScripts);
4408
- const results = await runAllScripts(
4409
- found.verifyScripts,
4410
- getPackageDir(found),
4411
- timer
4412
- );
4413
- handleResults(results, found.verifyScripts.length);
4414
- }
4415
- async function run(options = {}) {
4416
- const found = resolveVerifyScripts();
4417
- if (!found) return;
4418
- await executeVerifyScripts(found, options.timer ?? false);
4419
- }
4420
-
4421
4541
  // src/commands/registerVerify.ts
4422
4542
  function registerVerify(program2) {
4423
- const verifyCommand = program2.command("verify").description("Run all verify:* scripts from package.json in parallel").option("--timer", "Show timing information for each task as they complete").action((options) => run(options));
4543
+ const verifyCommand = program2.command("verify").description("Run all verify:* scripts from package.json in parallel").option("--timer", "Show timing information for each task as they complete").action((options2) => run(options2));
4424
4544
  verifyCommand.command("init").description("Add verify scripts to a project").action(init2);
4425
4545
  verifyCommand.command("hardcoded-colors").description("Check for hardcoded hex colors in src/").action(hardcodedColors);
4426
4546
  }
@@ -4651,7 +4771,7 @@ program.command("init").description("Initialize VS Code and verify configuration
4651
4771
  program.command("commit <message>").description("Create a git commit with validation").action(commit);
4652
4772
  program.command("update").description("Update claude-code to the latest version").action(() => {
4653
4773
  console.log("Updating claude-code...");
4654
- execSync19("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
4774
+ execSync22("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
4655
4775
  });
4656
4776
  var configCommand = program.command("config").description("View and modify assist.yml configuration");
4657
4777
  configCommand.command("set <key> <value>").description("Set a config value (e.g. commit.push true)").action(configSet);
@@ -4661,7 +4781,7 @@ var runCommand = program.command("run").description("Run a configured command fr
4661
4781
  run2(name, args);
4662
4782
  });
4663
4783
  runCommand.command("add").description("Add a new run configuration to assist.yml").allowUnknownOption().allowExcessArguments().action(() => add());
4664
- program.command("new").description("Initialize a new Vite React TypeScript project").action(newProject);
4784
+ registerNew(program);
4665
4785
  var lintCommand = program.command("lint").description("Run lint checks for conventions not enforced by biomejs").action(lint);
4666
4786
  lintCommand.command("init").description("Initialize Biome with standard linter config").action(init);
4667
4787
  var vscodeCommand = program.command("vscode").description("VS Code configuration utilities");