@staff0rd/assist 0.21.2 → 0.22.1

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/README.md CHANGED
@@ -35,6 +35,7 @@ After installation, the `assist` command will be available globally.
35
35
  - `assist sync` - Copy command files to `~/.claude/commands`
36
36
  - `assist commit <message>` - Create a git commit with validation
37
37
  - `assist prs` - List pull requests for the current repository
38
+ - `assist prs comments <pr-number>` - List all comments on a pull request
38
39
  - `assist run <name>` - Run a configured command from assist.yml
39
40
  - `assist run add` - Add a new run configuration to assist.yml
40
41
  - `assist update` - Update claude-code to the latest version
@@ -51,6 +52,11 @@ After installation, the `assist` command will be available globally.
51
52
  - `assist devlog version` - Show current repo name and version info
52
53
  - `assist vscode init` - Add VS Code configuration files
53
54
  - `assist deploy init` - Initialize Netlify project and configure deployment
55
+ - `assist deploy redirect` - Add trailing slash redirect script to index.html
54
56
  - `assist notify` - Show desktop notification from JSON stdin (supports macOS, Windows, WSL)
55
57
  - `assist status-line` - Format Claude Code status line from JSON stdin
58
+ - `assist complexity cyclomatic [pattern]` - Calculate cyclomatic complexity per function
59
+ - `assist complexity halstead [pattern]` - Calculate Halstead metrics per function
60
+ - `assist complexity maintainability [pattern]` - Calculate maintainability index per file
61
+ - `assist complexity sloc [pattern]` - Count source lines of code per file
56
62
 
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { execSync as execSync14 } from "child_process";
4
+ import { execSync as execSync16 } from "child_process";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // src/commands/commit.ts
@@ -1004,69 +1004,11 @@ function version() {
1004
1004
  console.log(`${chalk13.bold("next:")} ${nextVersion ?? chalk13.dim("none")}`);
1005
1005
  }
1006
1006
 
1007
- // src/commands/enable-ralph/index.ts
1008
- import * as fs4 from "fs";
1009
- import * as path2 from "path";
1010
- import { fileURLToPath as fileURLToPath2 } from "url";
1011
- import chalk14 from "chalk";
1012
- var __dirname3 = path2.dirname(fileURLToPath2(import.meta.url));
1013
- function deepMerge(target, source) {
1014
- const result = { ...target };
1015
- for (const key of Object.keys(source)) {
1016
- const sourceVal = source[key];
1017
- const targetVal = result[key];
1018
- if (sourceVal && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal && typeof targetVal === "object" && !Array.isArray(targetVal)) {
1019
- result[key] = deepMerge(
1020
- targetVal,
1021
- sourceVal
1022
- );
1023
- } else {
1024
- result[key] = sourceVal;
1025
- }
1026
- }
1027
- return result;
1028
- }
1029
- async function enableRalph() {
1030
- const sourcePath = path2.join(
1031
- __dirname3,
1032
- "commands/enable-ralph/settings.local.json"
1033
- );
1034
- const targetPath = path2.join(process.cwd(), ".claude/settings.local.json");
1035
- const sourceData = JSON.parse(fs4.readFileSync(sourcePath, "utf-8"));
1036
- const targetDir = path2.dirname(targetPath);
1037
- if (!fs4.existsSync(targetDir)) {
1038
- fs4.mkdirSync(targetDir, { recursive: true });
1039
- }
1040
- let targetData = {};
1041
- let targetContent = "{}";
1042
- if (fs4.existsSync(targetPath)) {
1043
- targetContent = fs4.readFileSync(targetPath, "utf-8");
1044
- targetData = JSON.parse(targetContent);
1045
- }
1046
- const merged = deepMerge(targetData, sourceData);
1047
- const mergedContent = `${JSON.stringify(merged, null, " ")}
1048
- `;
1049
- if (mergedContent === targetContent) {
1050
- console.log(chalk14.green("settings.local.json already has ralph enabled"));
1051
- return;
1052
- }
1053
- console.log(chalk14.yellow("\nChanges to settings.local.json:"));
1054
- console.log();
1055
- printDiff(targetContent, mergedContent);
1056
- const confirm = await promptConfirm("Apply these changes?");
1057
- if (!confirm) {
1058
- console.log("Skipped");
1059
- return;
1060
- }
1061
- fs4.writeFileSync(targetPath, mergedContent);
1062
- console.log(`Updated ${targetPath}`);
1063
- }
1064
-
1065
1007
  // src/commands/verify/init.ts
1066
- import chalk25 from "chalk";
1008
+ import chalk24 from "chalk";
1067
1009
 
1068
1010
  // src/shared/promptMultiselect.ts
1069
- import chalk15 from "chalk";
1011
+ import chalk14 from "chalk";
1070
1012
  import enquirer3 from "enquirer";
1071
1013
  async function promptMultiselect(message, options) {
1072
1014
  const { selected } = await enquirer3.prompt({
@@ -1075,7 +1017,7 @@ async function promptMultiselect(message, options) {
1075
1017
  message,
1076
1018
  choices: options.map((opt) => ({
1077
1019
  name: opt.value,
1078
- message: `${opt.name} - ${chalk15.dim(opt.description)}`
1020
+ message: `${opt.name} - ${chalk14.dim(opt.description)}`
1079
1021
  })),
1080
1022
  // @ts-expect-error - enquirer types don't include symbols but it's supported
1081
1023
  symbols: {
@@ -1089,23 +1031,23 @@ async function promptMultiselect(message, options) {
1089
1031
  }
1090
1032
 
1091
1033
  // src/shared/readPackageJson.ts
1092
- import * as fs5 from "fs";
1093
- import * as path3 from "path";
1094
- import chalk16 from "chalk";
1034
+ import * as fs4 from "fs";
1035
+ import * as path2 from "path";
1036
+ import chalk15 from "chalk";
1095
1037
  function findPackageJson() {
1096
- const packageJsonPath = path3.join(process.cwd(), "package.json");
1097
- if (fs5.existsSync(packageJsonPath)) {
1038
+ const packageJsonPath = path2.join(process.cwd(), "package.json");
1039
+ if (fs4.existsSync(packageJsonPath)) {
1098
1040
  return packageJsonPath;
1099
1041
  }
1100
1042
  return null;
1101
1043
  }
1102
1044
  function readPackageJson(filePath) {
1103
- return JSON.parse(fs5.readFileSync(filePath, "utf-8"));
1045
+ return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
1104
1046
  }
1105
1047
  function requirePackageJson() {
1106
1048
  const packageJsonPath = findPackageJson();
1107
1049
  if (!packageJsonPath) {
1108
- console.error(chalk16.red("No package.json found in current directory"));
1050
+ console.error(chalk15.red("No package.json found in current directory"));
1109
1051
  process.exit(1);
1110
1052
  }
1111
1053
  const pkg = readPackageJson(packageJsonPath);
@@ -1114,9 +1056,9 @@ function requirePackageJson() {
1114
1056
  function findPackageJsonWithVerifyScripts(startDir) {
1115
1057
  let currentDir = startDir;
1116
1058
  while (true) {
1117
- const packageJsonPath = path3.join(currentDir, "package.json");
1118
- if (fs5.existsSync(packageJsonPath)) {
1119
- const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
1059
+ const packageJsonPath = path2.join(currentDir, "package.json");
1060
+ if (fs4.existsSync(packageJsonPath)) {
1061
+ const packageJson = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
1120
1062
  const scripts = packageJson.scripts || {};
1121
1063
  const verifyScripts = Object.keys(scripts).filter(
1122
1064
  (name) => name.startsWith("verify:")
@@ -1125,7 +1067,7 @@ function findPackageJsonWithVerifyScripts(startDir) {
1125
1067
  return { packageJsonPath, verifyScripts };
1126
1068
  }
1127
1069
  }
1128
- const parentDir = path3.dirname(currentDir);
1070
+ const parentDir = path2.dirname(currentDir);
1129
1071
  if (parentDir === currentDir) {
1130
1072
  return null;
1131
1073
  }
@@ -1143,15 +1085,15 @@ var expectedScripts = {
1143
1085
  };
1144
1086
 
1145
1087
  // src/commands/verify/setup/setupBuild.ts
1146
- import chalk18 from "chalk";
1088
+ import chalk17 from "chalk";
1147
1089
 
1148
1090
  // src/commands/verify/installPackage.ts
1149
1091
  import { execSync as execSync7 } from "child_process";
1150
- import * as fs6 from "fs";
1151
- import * as path4 from "path";
1152
- import chalk17 from "chalk";
1092
+ import * as fs5 from "fs";
1093
+ import * as path3 from "path";
1094
+ import chalk16 from "chalk";
1153
1095
  function writePackageJson(filePath, pkg) {
1154
- fs6.writeFileSync(filePath, `${JSON.stringify(pkg, null, 2)}
1096
+ fs5.writeFileSync(filePath, `${JSON.stringify(pkg, null, 2)}
1155
1097
  `);
1156
1098
  }
1157
1099
  function addScript(pkg, name, command) {
@@ -1164,36 +1106,36 @@ function addScript(pkg, name, command) {
1164
1106
  };
1165
1107
  }
1166
1108
  function installPackage(name, cwd) {
1167
- console.log(chalk17.dim(`Installing ${name}...`));
1109
+ console.log(chalk16.dim(`Installing ${name}...`));
1168
1110
  try {
1169
1111
  execSync7(`npm install -D ${name}`, { stdio: "inherit", cwd });
1170
1112
  return true;
1171
1113
  } catch {
1172
- console.error(chalk17.red(`Failed to install ${name}`));
1114
+ console.error(chalk16.red(`Failed to install ${name}`));
1173
1115
  return false;
1174
1116
  }
1175
1117
  }
1176
1118
  function addToKnipIgnoreBinaries(cwd, binary) {
1177
- const knipJsonPath = path4.join(cwd, "knip.json");
1119
+ const knipJsonPath = path3.join(cwd, "knip.json");
1178
1120
  try {
1179
1121
  let knipConfig;
1180
- if (fs6.existsSync(knipJsonPath)) {
1181
- knipConfig = JSON.parse(fs6.readFileSync(knipJsonPath, "utf-8"));
1122
+ if (fs5.existsSync(knipJsonPath)) {
1123
+ knipConfig = JSON.parse(fs5.readFileSync(knipJsonPath, "utf-8"));
1182
1124
  } else {
1183
1125
  knipConfig = { $schema: "https://unpkg.com/knip@5/schema.json" };
1184
1126
  }
1185
1127
  const ignoreBinaries = knipConfig.ignoreBinaries ?? [];
1186
1128
  if (!ignoreBinaries.includes(binary)) {
1187
1129
  knipConfig.ignoreBinaries = [...ignoreBinaries, binary];
1188
- fs6.writeFileSync(
1130
+ fs5.writeFileSync(
1189
1131
  knipJsonPath,
1190
1132
  `${JSON.stringify(knipConfig, null, " ")}
1191
1133
  `
1192
1134
  );
1193
- console.log(chalk17.dim(`Added '${binary}' to knip.json ignoreBinaries`));
1135
+ console.log(chalk16.dim(`Added '${binary}' to knip.json ignoreBinaries`));
1194
1136
  }
1195
1137
  } catch {
1196
- console.log(chalk17.yellow("Warning: Could not update knip.json"));
1138
+ console.log(chalk16.yellow("Warning: Could not update knip.json"));
1197
1139
  }
1198
1140
  }
1199
1141
  function setupVerifyScript(packageJsonPath, scriptName, command) {
@@ -1205,7 +1147,7 @@ function setupVerifyScript(packageJsonPath, scriptName, command) {
1205
1147
 
1206
1148
  // src/commands/verify/setup/setupBuild.ts
1207
1149
  async function setupBuild(packageJsonPath, hasVite, hasTypescript) {
1208
- console.log(chalk18.blue("\nSetting up build verification..."));
1150
+ console.log(chalk17.blue("\nSetting up build verification..."));
1209
1151
  let command;
1210
1152
  if (hasVite && hasTypescript) {
1211
1153
  command = "tsc -b && vite build --logLevel error";
@@ -1214,17 +1156,17 @@ async function setupBuild(packageJsonPath, hasVite, hasTypescript) {
1214
1156
  } else {
1215
1157
  command = "tsc --noEmit";
1216
1158
  }
1217
- console.log(chalk18.dim(`Using: ${command}`));
1159
+ console.log(chalk17.dim(`Using: ${command}`));
1218
1160
  const pkg = readPackageJson(packageJsonPath);
1219
1161
  writePackageJson(packageJsonPath, addScript(pkg, "verify:build", command));
1220
1162
  }
1221
1163
 
1222
1164
  // src/commands/verify/setup/setupDuplicateCode.ts
1223
- import * as path5 from "path";
1224
- import chalk19 from "chalk";
1165
+ import * as path4 from "path";
1166
+ import chalk18 from "chalk";
1225
1167
  async function setupDuplicateCode(packageJsonPath) {
1226
- console.log(chalk19.blue("\nSetting up jscpd..."));
1227
- const cwd = path5.dirname(packageJsonPath);
1168
+ console.log(chalk18.blue("\nSetting up jscpd..."));
1169
+ const cwd = path4.dirname(packageJsonPath);
1228
1170
  const pkg = readPackageJson(packageJsonPath);
1229
1171
  const hasJscpd = !!pkg.dependencies?.jscpd || !!pkg.devDependencies?.jscpd;
1230
1172
  if (!hasJscpd && !installPackage("jscpd", cwd)) {
@@ -1238,11 +1180,11 @@ async function setupDuplicateCode(packageJsonPath) {
1238
1180
  }
1239
1181
 
1240
1182
  // src/commands/verify/setup/setupHardcodedColors.ts
1241
- import * as path6 from "path";
1242
- import chalk20 from "chalk";
1183
+ import * as path5 from "path";
1184
+ import chalk19 from "chalk";
1243
1185
  async function setupHardcodedColors(packageJsonPath, hasOpenColor) {
1244
- console.log(chalk20.blue("\nSetting up hardcoded colors check..."));
1245
- const cwd = path6.dirname(packageJsonPath);
1186
+ console.log(chalk19.blue("\nSetting up hardcoded colors check..."));
1187
+ const cwd = path5.dirname(packageJsonPath);
1246
1188
  if (!hasOpenColor) {
1247
1189
  installPackage("open-color", cwd);
1248
1190
  }
@@ -1255,11 +1197,11 @@ async function setupHardcodedColors(packageJsonPath, hasOpenColor) {
1255
1197
  }
1256
1198
 
1257
1199
  // src/commands/verify/setup/setupKnip.ts
1258
- import * as path7 from "path";
1259
- import chalk21 from "chalk";
1200
+ import * as path6 from "path";
1201
+ import chalk20 from "chalk";
1260
1202
  async function setupKnip(packageJsonPath) {
1261
- console.log(chalk21.blue("\nSetting up knip..."));
1262
- const cwd = path7.dirname(packageJsonPath);
1203
+ console.log(chalk20.blue("\nSetting up knip..."));
1204
+ const cwd = path6.dirname(packageJsonPath);
1263
1205
  const pkg = readPackageJson(packageJsonPath);
1264
1206
  if (!pkg.devDependencies?.knip && !installPackage("knip", cwd)) {
1265
1207
  return;
@@ -1272,19 +1214,19 @@ async function setupKnip(packageJsonPath) {
1272
1214
  }
1273
1215
 
1274
1216
  // src/commands/verify/setup/setupLint.ts
1275
- import * as path8 from "path";
1276
- import chalk23 from "chalk";
1217
+ import * as path7 from "path";
1218
+ import chalk22 from "chalk";
1277
1219
 
1278
1220
  // src/commands/lint/init.ts
1279
1221
  import { execSync as execSync9 } from "child_process";
1280
- import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
1281
- import { dirname as dirname7, join as join7 } from "path";
1282
- import { fileURLToPath as fileURLToPath3 } from "url";
1283
- import chalk22 from "chalk";
1222
+ import { existsSync as existsSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
1223
+ import { dirname as dirname6, join as join6 } from "path";
1224
+ import { fileURLToPath as fileURLToPath2 } from "url";
1225
+ import chalk21 from "chalk";
1284
1226
 
1285
1227
  // src/shared/removeEslint.ts
1286
1228
  import { execSync as execSync8 } from "child_process";
1287
- import { existsSync as existsSync7, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
1229
+ import { existsSync as existsSync6, readFileSync as readFileSync7, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
1288
1230
  function removeEslint(options = {}) {
1289
1231
  const removedFromPackageJson = removeEslintFromPackageJson(options);
1290
1232
  const removedConfigFiles = removeEslintConfigFiles();
@@ -1297,10 +1239,10 @@ function removeEslint(options = {}) {
1297
1239
  }
1298
1240
  function removeEslintFromPackageJson(options) {
1299
1241
  const packageJsonPath = "package.json";
1300
- if (!existsSync7(packageJsonPath)) {
1242
+ if (!existsSync6(packageJsonPath)) {
1301
1243
  return false;
1302
1244
  }
1303
- const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
1245
+ const packageJson = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
1304
1246
  let modified = false;
1305
1247
  if (packageJson.dependencies) {
1306
1248
  for (const key of Object.keys(packageJson.dependencies)) {
@@ -1328,7 +1270,7 @@ function removeEslintFromPackageJson(options) {
1328
1270
  }
1329
1271
  }
1330
1272
  if (modified) {
1331
- writeFileSync6(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
1273
+ writeFileSync5(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
1332
1274
  `);
1333
1275
  console.log("Removed eslint references from package.json");
1334
1276
  }
@@ -1349,7 +1291,7 @@ function removeEslintConfigFiles() {
1349
1291
  ];
1350
1292
  let removed = false;
1351
1293
  for (const configFile of eslintConfigFiles) {
1352
- if (existsSync7(configFile)) {
1294
+ if (existsSync6(configFile)) {
1353
1295
  unlinkSync(configFile);
1354
1296
  console.log(`Removed ${configFile}`);
1355
1297
  removed = true;
@@ -1359,21 +1301,21 @@ function removeEslintConfigFiles() {
1359
1301
  }
1360
1302
 
1361
1303
  // src/commands/lint/init.ts
1362
- var __dirname4 = dirname7(fileURLToPath3(import.meta.url));
1304
+ var __dirname3 = dirname6(fileURLToPath2(import.meta.url));
1363
1305
  async function init2() {
1364
1306
  removeEslint();
1365
1307
  const biomeConfigPath = "biome.json";
1366
- if (!existsSync8(biomeConfigPath)) {
1308
+ if (!existsSync7(biomeConfigPath)) {
1367
1309
  console.log("Initializing Biome...");
1368
1310
  execSync9("npx @biomejs/biome init", { stdio: "inherit" });
1369
1311
  }
1370
- if (!existsSync8(biomeConfigPath)) {
1312
+ if (!existsSync7(biomeConfigPath)) {
1371
1313
  console.log("No biome.json found, skipping linter config");
1372
1314
  return;
1373
1315
  }
1374
- const linterConfigPath = join7(__dirname4, "commands/lint/biome.linter.json");
1375
- const linterConfig = JSON.parse(readFileSync9(linterConfigPath, "utf-8"));
1376
- const biomeConfig = JSON.parse(readFileSync9(biomeConfigPath, "utf-8"));
1316
+ const linterConfigPath = join6(__dirname3, "commands/lint/biome.linter.json");
1317
+ const linterConfig = JSON.parse(readFileSync8(linterConfigPath, "utf-8"));
1318
+ const biomeConfig = JSON.parse(readFileSync8(biomeConfigPath, "utf-8"));
1377
1319
  const oldContent = `${JSON.stringify(biomeConfig, null, 2)}
1378
1320
  `;
1379
1321
  biomeConfig.linter = linterConfig.linter;
@@ -1386,22 +1328,22 @@ async function init2() {
1386
1328
  console.log("biome.json already has the correct linter config");
1387
1329
  return;
1388
1330
  }
1389
- console.log(chalk22.yellow("\n\u26A0\uFE0F biome.json will be updated:"));
1331
+ console.log(chalk21.yellow("\n\u26A0\uFE0F biome.json will be updated:"));
1390
1332
  console.log();
1391
1333
  printDiff(oldContent, newContent);
1392
- const confirm = await promptConfirm(chalk22.red("Update biome.json?"));
1334
+ const confirm = await promptConfirm(chalk21.red("Update biome.json?"));
1393
1335
  if (!confirm) {
1394
1336
  console.log("Skipped biome.json update");
1395
1337
  return;
1396
1338
  }
1397
- writeFileSync7(biomeConfigPath, newContent);
1339
+ writeFileSync6(biomeConfigPath, newContent);
1398
1340
  console.log("Updated biome.json with linter config");
1399
1341
  }
1400
1342
 
1401
1343
  // src/commands/verify/setup/setupLint.ts
1402
1344
  async function setupLint(packageJsonPath) {
1403
- console.log(chalk23.blue("\nSetting up biome..."));
1404
- const cwd = path8.dirname(packageJsonPath);
1345
+ console.log(chalk22.blue("\nSetting up biome..."));
1346
+ const cwd = path7.dirname(packageJsonPath);
1405
1347
  const pkg = readPackageJson(packageJsonPath);
1406
1348
  if (!pkg.devDependencies?.["@biomejs/biome"]) {
1407
1349
  if (!installPackage("@biomejs/biome", cwd)) {
@@ -1417,11 +1359,11 @@ async function setupLint(packageJsonPath) {
1417
1359
  }
1418
1360
 
1419
1361
  // src/commands/verify/setup/setupTest.ts
1420
- import * as path9 from "path";
1421
- import chalk24 from "chalk";
1362
+ import * as path8 from "path";
1363
+ import chalk23 from "chalk";
1422
1364
  async function setupTest(packageJsonPath) {
1423
- console.log(chalk24.blue("\nSetting up vitest..."));
1424
- const cwd = path9.dirname(packageJsonPath);
1365
+ console.log(chalk23.blue("\nSetting up vitest..."));
1366
+ const cwd = path8.dirname(packageJsonPath);
1425
1367
  const pkg = readPackageJson(packageJsonPath);
1426
1368
  if (!pkg.devDependencies?.vitest && !installPackage("vitest", cwd)) {
1427
1369
  return;
@@ -1563,16 +1505,16 @@ async function init3() {
1563
1505
  const setup = detectExistingSetup(pkg);
1564
1506
  const availableOptions = getAvailableOptions(setup);
1565
1507
  if (availableOptions.length === 0) {
1566
- console.log(chalk25.green("All verify scripts are already configured!"));
1508
+ console.log(chalk24.green("All verify scripts are already configured!"));
1567
1509
  return;
1568
1510
  }
1569
- console.log(chalk25.bold("Available verify scripts to add:\n"));
1511
+ console.log(chalk24.bold("Available verify scripts to add:\n"));
1570
1512
  const selected = await promptMultiselect(
1571
1513
  "Select verify scripts to add:",
1572
1514
  availableOptions
1573
1515
  );
1574
1516
  if (selected.length === 0) {
1575
- console.log(chalk25.yellow("No scripts selected"));
1517
+ console.log(chalk24.yellow("No scripts selected"));
1576
1518
  return;
1577
1519
  }
1578
1520
  for (const choice of selected) {
@@ -1597,43 +1539,43 @@ async function init3() {
1597
1539
  break;
1598
1540
  }
1599
1541
  }
1600
- console.log(chalk25.green(`
1542
+ console.log(chalk24.green(`
1601
1543
  Added ${selected.length} verify script(s):`));
1602
1544
  for (const choice of selected) {
1603
- console.log(chalk25.green(` - verify:${choice}`));
1545
+ console.log(chalk24.green(` - verify:${choice}`));
1604
1546
  }
1605
- console.log(chalk25.dim("\nRun 'assist verify' to run all verify scripts"));
1547
+ console.log(chalk24.dim("\nRun 'assist verify' to run all verify scripts"));
1606
1548
  }
1607
1549
 
1608
1550
  // src/commands/vscode/init.ts
1609
- import * as fs8 from "fs";
1610
- import * as path11 from "path";
1611
- import chalk27 from "chalk";
1612
-
1613
- // src/commands/vscode/createLaunchJson.ts
1614
1551
  import * as fs7 from "fs";
1615
1552
  import * as path10 from "path";
1616
1553
  import chalk26 from "chalk";
1554
+
1555
+ // src/commands/vscode/createLaunchJson.ts
1556
+ import * as fs6 from "fs";
1557
+ import * as path9 from "path";
1558
+ import chalk25 from "chalk";
1617
1559
  function ensureVscodeFolder() {
1618
- const vscodeDir = path10.join(process.cwd(), ".vscode");
1619
- if (!fs7.existsSync(vscodeDir)) {
1620
- fs7.mkdirSync(vscodeDir);
1621
- console.log(chalk26.dim("Created .vscode folder"));
1560
+ const vscodeDir = path9.join(process.cwd(), ".vscode");
1561
+ if (!fs6.existsSync(vscodeDir)) {
1562
+ fs6.mkdirSync(vscodeDir);
1563
+ console.log(chalk25.dim("Created .vscode folder"));
1622
1564
  }
1623
1565
  }
1624
1566
  function removeVscodeFromGitignore() {
1625
- const gitignorePath = path10.join(process.cwd(), ".gitignore");
1626
- if (!fs7.existsSync(gitignorePath)) {
1567
+ const gitignorePath = path9.join(process.cwd(), ".gitignore");
1568
+ if (!fs6.existsSync(gitignorePath)) {
1627
1569
  return;
1628
1570
  }
1629
- const content = fs7.readFileSync(gitignorePath, "utf-8");
1571
+ const content = fs6.readFileSync(gitignorePath, "utf-8");
1630
1572
  const lines = content.split("\n");
1631
1573
  const filteredLines = lines.filter(
1632
1574
  (line) => !line.trim().toLowerCase().includes(".vscode")
1633
1575
  );
1634
1576
  if (filteredLines.length !== lines.length) {
1635
- fs7.writeFileSync(gitignorePath, filteredLines.join("\n"));
1636
- console.log(chalk26.dim("Removed .vscode references from .gitignore"));
1577
+ fs6.writeFileSync(gitignorePath, filteredLines.join("\n"));
1578
+ console.log(chalk25.dim("Removed .vscode references from .gitignore"));
1637
1579
  }
1638
1580
  }
1639
1581
  function createLaunchJson() {
@@ -1648,10 +1590,10 @@ function createLaunchJson() {
1648
1590
  }
1649
1591
  ]
1650
1592
  };
1651
- const launchPath = path10.join(process.cwd(), ".vscode", "launch.json");
1652
- fs7.writeFileSync(launchPath, `${JSON.stringify(launchConfig, null, " ")}
1593
+ const launchPath = path9.join(process.cwd(), ".vscode", "launch.json");
1594
+ fs6.writeFileSync(launchPath, `${JSON.stringify(launchConfig, null, " ")}
1653
1595
  `);
1654
- console.log(chalk26.green("Created .vscode/launch.json"));
1596
+ console.log(chalk25.green("Created .vscode/launch.json"));
1655
1597
  }
1656
1598
  function createSettingsJson() {
1657
1599
  const settings = {
@@ -1661,31 +1603,31 @@ function createSettingsJson() {
1661
1603
  "source.organizeImports.biome": "explicit"
1662
1604
  }
1663
1605
  };
1664
- const settingsPath = path10.join(process.cwd(), ".vscode", "settings.json");
1665
- fs7.writeFileSync(settingsPath, `${JSON.stringify(settings, null, " ")}
1606
+ const settingsPath = path9.join(process.cwd(), ".vscode", "settings.json");
1607
+ fs6.writeFileSync(settingsPath, `${JSON.stringify(settings, null, " ")}
1666
1608
  `);
1667
- console.log(chalk26.green("Created .vscode/settings.json"));
1609
+ console.log(chalk25.green("Created .vscode/settings.json"));
1668
1610
  }
1669
1611
  function createExtensionsJson() {
1670
1612
  const extensions = {
1671
1613
  recommendations: ["biomejs.biome"]
1672
1614
  };
1673
- const extensionsPath = path10.join(process.cwd(), ".vscode", "extensions.json");
1674
- fs7.writeFileSync(
1615
+ const extensionsPath = path9.join(process.cwd(), ".vscode", "extensions.json");
1616
+ fs6.writeFileSync(
1675
1617
  extensionsPath,
1676
1618
  `${JSON.stringify(extensions, null, " ")}
1677
1619
  `
1678
1620
  );
1679
- console.log(chalk26.green("Created .vscode/extensions.json"));
1621
+ console.log(chalk25.green("Created .vscode/extensions.json"));
1680
1622
  }
1681
1623
 
1682
1624
  // src/commands/vscode/init.ts
1683
1625
  function detectExistingSetup2(pkg) {
1684
- const vscodeDir = path11.join(process.cwd(), ".vscode");
1626
+ const vscodeDir = path10.join(process.cwd(), ".vscode");
1685
1627
  return {
1686
- hasVscodeFolder: fs8.existsSync(vscodeDir),
1687
- hasLaunchJson: fs8.existsSync(path11.join(vscodeDir, "launch.json")),
1688
- hasSettingsJson: fs8.existsSync(path11.join(vscodeDir, "settings.json")),
1628
+ hasVscodeFolder: fs7.existsSync(vscodeDir),
1629
+ hasLaunchJson: fs7.existsSync(path10.join(vscodeDir, "launch.json")),
1630
+ hasSettingsJson: fs7.existsSync(path10.join(vscodeDir, "settings.json")),
1689
1631
  hasVite: !!pkg.devDependencies?.vite || !!pkg.dependencies?.vite
1690
1632
  };
1691
1633
  }
@@ -1708,16 +1650,16 @@ async function init4() {
1708
1650
  });
1709
1651
  }
1710
1652
  if (availableOptions.length === 0) {
1711
- console.log(chalk27.green("VS Code configuration already exists!"));
1653
+ console.log(chalk26.green("VS Code configuration already exists!"));
1712
1654
  return;
1713
1655
  }
1714
- console.log(chalk27.bold("Available VS Code configurations to add:\n"));
1656
+ console.log(chalk26.bold("Available VS Code configurations to add:\n"));
1715
1657
  const selected = await promptMultiselect(
1716
1658
  "Select configurations to add:",
1717
1659
  availableOptions
1718
1660
  );
1719
1661
  if (selected.length === 0) {
1720
- console.log(chalk27.yellow("No configurations selected"));
1662
+ console.log(chalk26.yellow("No configurations selected"));
1721
1663
  return;
1722
1664
  }
1723
1665
  removeVscodeFromGitignore();
@@ -1734,7 +1676,7 @@ async function init4() {
1734
1676
  }
1735
1677
  }
1736
1678
  console.log(
1737
- chalk27.green(`
1679
+ chalk26.green(`
1738
1680
  Added ${selected.length} VS Code configuration(s)`)
1739
1681
  );
1740
1682
  }
@@ -1746,23 +1688,23 @@ async function init5() {
1746
1688
  }
1747
1689
 
1748
1690
  // src/commands/lint/runFileNameCheck.ts
1749
- import fs10 from "fs";
1750
- import path13 from "path";
1751
- import chalk28 from "chalk";
1752
-
1753
- // src/shared/findSourceFiles.ts
1754
1691
  import fs9 from "fs";
1755
1692
  import path12 from "path";
1693
+ import chalk27 from "chalk";
1694
+
1695
+ // src/shared/findSourceFiles.ts
1696
+ import fs8 from "fs";
1697
+ import path11 from "path";
1756
1698
  var EXTENSIONS = [".ts", ".tsx"];
1757
1699
  function findSourceFiles(dir, options = {}) {
1758
1700
  const { includeTests = true } = options;
1759
1701
  const results = [];
1760
- if (!fs9.existsSync(dir)) {
1702
+ if (!fs8.existsSync(dir)) {
1761
1703
  return results;
1762
1704
  }
1763
- const entries = fs9.readdirSync(dir, { withFileTypes: true });
1705
+ const entries = fs8.readdirSync(dir, { withFileTypes: true });
1764
1706
  for (const entry of entries) {
1765
- const fullPath = path12.join(dir, entry.name);
1707
+ const fullPath = path11.join(dir, entry.name);
1766
1708
  if (entry.isDirectory() && entry.name !== "node_modules") {
1767
1709
  results.push(...findSourceFiles(fullPath, options));
1768
1710
  } else if (entry.isFile() && EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
@@ -1786,10 +1728,10 @@ function checkFileNames() {
1786
1728
  const sourceFiles = findSourceFiles("src");
1787
1729
  const violations = [];
1788
1730
  for (const filePath of sourceFiles) {
1789
- const fileName = path13.basename(filePath);
1731
+ const fileName = path12.basename(filePath);
1790
1732
  const nameWithoutExt = fileName.replace(/\.(ts|tsx)$/, "");
1791
1733
  if (/^[A-Z]/.test(nameWithoutExt)) {
1792
- const content = fs10.readFileSync(filePath, "utf-8");
1734
+ const content = fs9.readFileSync(filePath, "utf-8");
1793
1735
  if (!hasClassOrComponent(content)) {
1794
1736
  violations.push({ filePath, fileName });
1795
1737
  }
@@ -1800,16 +1742,16 @@ function checkFileNames() {
1800
1742
  function runFileNameCheck() {
1801
1743
  const violations = checkFileNames();
1802
1744
  if (violations.length > 0) {
1803
- console.error(chalk28.red("\nFile name check failed:\n"));
1745
+ console.error(chalk27.red("\nFile name check failed:\n"));
1804
1746
  console.error(
1805
- chalk28.red(
1747
+ chalk27.red(
1806
1748
  " Files without classes or React components should not start with a capital letter.\n"
1807
1749
  )
1808
1750
  );
1809
1751
  for (const violation of violations) {
1810
- console.error(chalk28.red(` ${violation.filePath}`));
1752
+ console.error(chalk27.red(` ${violation.filePath}`));
1811
1753
  console.error(
1812
- chalk28.gray(
1754
+ chalk27.gray(
1813
1755
  ` Rename to: ${violation.fileName.charAt(0).toLowerCase()}${violation.fileName.slice(1)}
1814
1756
  `
1815
1757
  )
@@ -1826,20 +1768,20 @@ function runFileNameCheck() {
1826
1768
  }
1827
1769
 
1828
1770
  // src/commands/lint/runImportExtensionCheck.ts
1829
- import fs11 from "fs";
1771
+ import fs10 from "fs";
1830
1772
 
1831
1773
  // src/commands/lint/shared.ts
1832
- import chalk29 from "chalk";
1774
+ import chalk28 from "chalk";
1833
1775
  function reportViolations(violations, checkName, errorMessage, successMessage) {
1834
1776
  if (violations.length > 0) {
1835
- console.error(chalk29.red(`
1777
+ console.error(chalk28.red(`
1836
1778
  ${checkName} failed:
1837
1779
  `));
1838
- console.error(chalk29.red(` ${errorMessage}
1780
+ console.error(chalk28.red(` ${errorMessage}
1839
1781
  `));
1840
1782
  for (const violation of violations) {
1841
- console.error(chalk29.red(` ${violation.filePath}:${violation.line}`));
1842
- console.error(chalk29.gray(` ${violation.content}
1783
+ console.error(chalk28.red(` ${violation.filePath}:${violation.line}`));
1784
+ console.error(chalk28.gray(` ${violation.content}
1843
1785
  `));
1844
1786
  }
1845
1787
  return false;
@@ -1852,7 +1794,7 @@ ${checkName} failed:
1852
1794
 
1853
1795
  // src/commands/lint/runImportExtensionCheck.ts
1854
1796
  function checkForImportExtensions(filePath) {
1855
- const content = fs11.readFileSync(filePath, "utf-8");
1797
+ const content = fs10.readFileSync(filePath, "utf-8");
1856
1798
  const lines = content.split("\n");
1857
1799
  const violations = [];
1858
1800
  const importExtensionPattern = /from\s+["']\..*\.(js|ts)["']/;
@@ -1886,9 +1828,9 @@ function runImportExtensionCheck() {
1886
1828
  }
1887
1829
 
1888
1830
  // src/commands/lint/runStaticImportCheck.ts
1889
- import fs12 from "fs";
1831
+ import fs11 from "fs";
1890
1832
  function checkForDynamicImports(filePath) {
1891
- const content = fs12.readFileSync(filePath, "utf-8");
1833
+ const content = fs11.readFileSync(filePath, "utf-8");
1892
1834
  const lines = content.split("\n");
1893
1835
  const violations = [];
1894
1836
  const requirePattern = /\brequire\s*\(/;
@@ -1934,7 +1876,7 @@ function lint() {
1934
1876
 
1935
1877
  // src/commands/new/newProject.ts
1936
1878
  import { execSync as execSync10 } from "child_process";
1937
- import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
1879
+ import { existsSync as existsSync10, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
1938
1880
  async function newProject() {
1939
1881
  console.log("Initializing Vite with react-ts template...");
1940
1882
  execSync10("npm create vite@latest . -- --template react-ts", {
@@ -1947,11 +1889,11 @@ async function newProject() {
1947
1889
  }
1948
1890
  function addViteBaseConfig() {
1949
1891
  const viteConfigPath = "vite.config.ts";
1950
- if (!existsSync11(viteConfigPath)) {
1892
+ if (!existsSync10(viteConfigPath)) {
1951
1893
  console.log("No vite.config.ts found, skipping base config");
1952
1894
  return;
1953
1895
  }
1954
- const content = readFileSync11(viteConfigPath, "utf-8");
1896
+ const content = readFileSync10(viteConfigPath, "utf-8");
1955
1897
  if (content.includes("base:")) {
1956
1898
  console.log("vite.config.ts already has base config");
1957
1899
  return;
@@ -1961,7 +1903,7 @@ function addViteBaseConfig() {
1961
1903
  'defineConfig({\n base: "./",'
1962
1904
  );
1963
1905
  if (updated !== content) {
1964
- writeFileSync9(viteConfigPath, updated);
1906
+ writeFileSync8(viteConfigPath, updated);
1965
1907
  console.log('Added base: "./" to vite.config.ts');
1966
1908
  }
1967
1909
  }
@@ -2002,19 +1944,19 @@ function detectPlatform() {
2002
1944
 
2003
1945
  // src/commands/notify/showWindowsNotificationFromWsl.ts
2004
1946
  import { spawn } from "child_process";
2005
- import fs13 from "fs";
1947
+ import fs12 from "fs";
2006
1948
  import { createRequire } from "module";
2007
- import path14 from "path";
1949
+ import path13 from "path";
2008
1950
  var require2 = createRequire(import.meta.url);
2009
1951
  function getSnoreToastPath() {
2010
- const notifierPath = path14.dirname(require2.resolve("node-notifier"));
2011
- return path14.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
1952
+ const notifierPath = path13.dirname(require2.resolve("node-notifier"));
1953
+ return path13.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
2012
1954
  }
2013
1955
  function showWindowsNotificationFromWsl(options) {
2014
1956
  const { title, message, sound } = options;
2015
1957
  const snoreToastPath = getSnoreToastPath();
2016
1958
  try {
2017
- fs13.chmodSync(snoreToastPath, 493);
1959
+ fs12.chmodSync(snoreToastPath, 493);
2018
1960
  } catch {
2019
1961
  }
2020
1962
  const args = ["-t", title, "-m", message];
@@ -2084,11 +2026,17 @@ async function notify() {
2084
2026
  console.log(`Notification sent: ${notification_type} for ${projectName}`);
2085
2027
  }
2086
2028
 
2087
- // src/commands/prs.ts
2029
+ // src/commands/prs/comments.ts
2030
+ import { execSync as execSync12 } from "child_process";
2031
+ import chalk29 from "chalk";
2032
+
2033
+ // src/lib/isClaudeCode.ts
2034
+ function isClaudeCode() {
2035
+ return process.env.CLAUDECODE !== void 0;
2036
+ }
2037
+
2038
+ // src/commands/prs/shared.ts
2088
2039
  import { execSync as execSync11 } from "child_process";
2089
- import chalk30 from "chalk";
2090
- import enquirer4 from "enquirer";
2091
- var PAGE_SIZE = 10;
2092
2040
  function isGhNotInstalled(error) {
2093
2041
  if (error instanceof Error) {
2094
2042
  const msg = error.message.toLowerCase();
@@ -2108,10 +2056,104 @@ function getRepoInfo() {
2108
2056
  );
2109
2057
  return { org: repoInfo.owner.login, repo: repoInfo.name };
2110
2058
  }
2059
+
2060
+ // src/commands/prs/comments.ts
2061
+ function formatForHuman(comment) {
2062
+ if (comment.type === "review") {
2063
+ const stateColor = comment.state === "APPROVED" ? chalk29.green : comment.state === "CHANGES_REQUESTED" ? chalk29.red : chalk29.yellow;
2064
+ return [
2065
+ `${chalk29.cyan("Review")} by ${chalk29.bold(comment.user)} ${stateColor(`[${comment.state}]`)}`,
2066
+ comment.body,
2067
+ ""
2068
+ ].join("\n");
2069
+ }
2070
+ const location = comment.line ? `:${comment.line}` : "";
2071
+ return [
2072
+ `${chalk29.cyan("Line comment")} by ${chalk29.bold(comment.user)} on ${chalk29.dim(`${comment.path}${location}`)}`,
2073
+ chalk29.dim(comment.diff_hunk.split("\n").slice(-3).join("\n")),
2074
+ comment.body,
2075
+ ""
2076
+ ].join("\n");
2077
+ }
2078
+ function printComments(comments2) {
2079
+ if (comments2.length === 0) {
2080
+ console.log("No comments found.");
2081
+ return;
2082
+ }
2083
+ if (isClaudeCode()) {
2084
+ for (const comment of comments2) {
2085
+ console.log(JSON.stringify(comment));
2086
+ }
2087
+ } else {
2088
+ for (const comment of comments2) {
2089
+ console.log(formatForHuman(comment));
2090
+ }
2091
+ }
2092
+ }
2093
+ async function comments(prNumber) {
2094
+ try {
2095
+ const { org, repo } = getRepoInfo();
2096
+ const allComments = [];
2097
+ const reviewResult = execSync12(
2098
+ `gh api repos/${org}/${repo}/pulls/${prNumber}/reviews`,
2099
+ { encoding: "utf-8" }
2100
+ );
2101
+ if (reviewResult.trim()) {
2102
+ const reviews = JSON.parse(reviewResult);
2103
+ for (const review of reviews) {
2104
+ if (review.body) {
2105
+ allComments.push({
2106
+ type: "review",
2107
+ id: review.id,
2108
+ user: review.user.login,
2109
+ state: review.state,
2110
+ body: review.body
2111
+ });
2112
+ }
2113
+ }
2114
+ }
2115
+ const lineResult = execSync12(
2116
+ `gh api repos/${org}/${repo}/pulls/${prNumber}/comments`,
2117
+ { encoding: "utf-8" }
2118
+ );
2119
+ if (lineResult.trim()) {
2120
+ const lineComments = JSON.parse(lineResult);
2121
+ for (const comment of lineComments) {
2122
+ allComments.push({
2123
+ type: "line",
2124
+ id: comment.id,
2125
+ user: comment.user.login,
2126
+ path: comment.path,
2127
+ line: comment.line,
2128
+ body: comment.body,
2129
+ diff_hunk: comment.diff_hunk
2130
+ });
2131
+ }
2132
+ }
2133
+ return allComments;
2134
+ } catch (error) {
2135
+ if (isGhNotInstalled(error)) {
2136
+ console.error("Error: GitHub CLI (gh) is not installed.");
2137
+ console.error("Install it from https://cli.github.com/");
2138
+ return [];
2139
+ }
2140
+ if (isNotFound(error)) {
2141
+ console.error("Error: Pull request not found.");
2142
+ return [];
2143
+ }
2144
+ throw error;
2145
+ }
2146
+ }
2147
+
2148
+ // src/commands/prs/prs.ts
2149
+ import { execSync as execSync13 } from "child_process";
2150
+ import chalk30 from "chalk";
2151
+ import enquirer4 from "enquirer";
2152
+ var PAGE_SIZE = 10;
2111
2153
  async function prs(options) {
2112
2154
  const state = options.open ? "open" : options.closed ? "closed" : "all";
2113
2155
  try {
2114
- const result = execSync11(
2156
+ const result = execSync13(
2115
2157
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
2116
2158
  { encoding: "utf-8" }
2117
2159
  );
@@ -2192,78 +2234,24 @@ Page ${page + 1} of ${totalPages} (${pullRequests.length} total)
2192
2234
  }
2193
2235
  }
2194
2236
  }
2195
- async function comments(prNumber) {
2196
- try {
2197
- const { org, repo } = getRepoInfo();
2198
- const allComments = [];
2199
- const reviewResult = execSync11(
2200
- `gh api repos/${org}/${repo}/pulls/${prNumber}/reviews`,
2201
- { encoding: "utf-8" }
2202
- );
2203
- if (reviewResult.trim()) {
2204
- const reviews = JSON.parse(reviewResult);
2205
- for (const review of reviews) {
2206
- if (review.body) {
2207
- allComments.push({
2208
- type: "review",
2209
- id: review.id,
2210
- user: review.user.login,
2211
- state: review.state,
2212
- body: review.body
2213
- });
2214
- }
2215
- }
2216
- }
2217
- const lineResult = execSync11(
2218
- `gh api repos/${org}/${repo}/pulls/${prNumber}/comments`,
2219
- { encoding: "utf-8" }
2220
- );
2221
- if (lineResult.trim()) {
2222
- const lineComments = JSON.parse(lineResult);
2223
- for (const comment of lineComments) {
2224
- allComments.push({
2225
- type: "line",
2226
- id: comment.id,
2227
- user: comment.user.login,
2228
- path: comment.path,
2229
- line: comment.line,
2230
- body: comment.body,
2231
- diff_hunk: comment.diff_hunk
2232
- });
2233
- }
2234
- }
2235
- return allComments;
2236
- } catch (error) {
2237
- if (isGhNotInstalled(error)) {
2238
- console.error("Error: GitHub CLI (gh) is not installed.");
2239
- console.error("Install it from https://cli.github.com/");
2240
- return [];
2241
- }
2242
- if (isNotFound(error)) {
2243
- console.error("Error: Pull request not found.");
2244
- return [];
2245
- }
2246
- throw error;
2247
- }
2248
- }
2249
2237
 
2250
2238
  // src/commands/refactor/check.ts
2251
2239
  import { spawn as spawn2 } from "child_process";
2252
- import * as path15 from "path";
2240
+ import * as path14 from "path";
2253
2241
 
2254
2242
  // src/commands/refactor/getViolations.ts
2255
- import { execSync as execSync12 } from "child_process";
2256
- import fs15 from "fs";
2243
+ import { execSync as execSync14 } from "child_process";
2244
+ import fs14 from "fs";
2257
2245
  import { minimatch as minimatch2 } from "minimatch";
2258
2246
 
2259
2247
  // src/commands/refactor/getIgnoredFiles.ts
2260
- import fs14 from "fs";
2248
+ import fs13 from "fs";
2261
2249
  var REFACTOR_YML_PATH = "refactor.yml";
2262
2250
  function parseRefactorYml() {
2263
- if (!fs14.existsSync(REFACTOR_YML_PATH)) {
2251
+ if (!fs13.existsSync(REFACTOR_YML_PATH)) {
2264
2252
  return [];
2265
2253
  }
2266
- const content = fs14.readFileSync(REFACTOR_YML_PATH, "utf-8");
2254
+ const content = fs13.readFileSync(REFACTOR_YML_PATH, "utf-8");
2267
2255
  const entries = [];
2268
2256
  const lines = content.split("\n");
2269
2257
  let currentEntry = {};
@@ -2348,7 +2336,7 @@ Refactor check failed:
2348
2336
 
2349
2337
  // src/commands/refactor/getViolations.ts
2350
2338
  function countLines(filePath) {
2351
- const content = fs15.readFileSync(filePath, "utf-8");
2339
+ const content = fs14.readFileSync(filePath, "utf-8");
2352
2340
  return content.split("\n").length;
2353
2341
  }
2354
2342
  function getGitFiles(options) {
@@ -2357,7 +2345,7 @@ function getGitFiles(options) {
2357
2345
  }
2358
2346
  const files = /* @__PURE__ */ new Set();
2359
2347
  if (options.staged || options.modified) {
2360
- const staged = execSync12("git diff --cached --name-only", {
2348
+ const staged = execSync14("git diff --cached --name-only", {
2361
2349
  encoding: "utf-8"
2362
2350
  });
2363
2351
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -2365,7 +2353,7 @@ function getGitFiles(options) {
2365
2353
  }
2366
2354
  }
2367
2355
  if (options.unstaged || options.modified) {
2368
- const unstaged = execSync12("git diff --name-only", { encoding: "utf-8" });
2356
+ const unstaged = execSync14("git diff --name-only", { encoding: "utf-8" });
2369
2357
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
2370
2358
  files.add(file);
2371
2359
  }
@@ -2400,7 +2388,7 @@ async function runVerifyQuietly() {
2400
2388
  return true;
2401
2389
  }
2402
2390
  const { packageJsonPath, verifyScripts } = result;
2403
- const packageDir = path15.dirname(packageJsonPath);
2391
+ const packageDir = path14.dirname(packageJsonPath);
2404
2392
  const results = await Promise.all(
2405
2393
  verifyScripts.map(
2406
2394
  (script) => new Promise(
@@ -2453,25 +2441,25 @@ async function check(pattern2, options) {
2453
2441
  }
2454
2442
 
2455
2443
  // src/commands/refactor/ignore.ts
2456
- import fs16 from "fs";
2444
+ import fs15 from "fs";
2457
2445
  import chalk32 from "chalk";
2458
2446
  var REFACTOR_YML_PATH2 = "refactor.yml";
2459
2447
  function ignore(file) {
2460
- if (!fs16.existsSync(file)) {
2448
+ if (!fs15.existsSync(file)) {
2461
2449
  console.error(chalk32.red(`Error: File does not exist: ${file}`));
2462
2450
  process.exit(1);
2463
2451
  }
2464
- const content = fs16.readFileSync(file, "utf-8");
2452
+ const content = fs15.readFileSync(file, "utf-8");
2465
2453
  const lineCount = content.split("\n").length;
2466
2454
  const maxLines = lineCount + 10;
2467
2455
  const entry = `- file: ${file}
2468
2456
  maxLines: ${maxLines}
2469
2457
  `;
2470
- if (fs16.existsSync(REFACTOR_YML_PATH2)) {
2471
- const existing = fs16.readFileSync(REFACTOR_YML_PATH2, "utf-8");
2472
- fs16.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
2458
+ if (fs15.existsSync(REFACTOR_YML_PATH2)) {
2459
+ const existing = fs15.readFileSync(REFACTOR_YML_PATH2, "utf-8");
2460
+ fs15.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
2473
2461
  } else {
2474
- fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
2462
+ fs15.writeFileSync(REFACTOR_YML_PATH2, entry);
2475
2463
  }
2476
2464
  console.log(
2477
2465
  chalk32.green(
@@ -2565,22 +2553,22 @@ async function statusLine() {
2565
2553
  }
2566
2554
 
2567
2555
  // src/commands/sync.ts
2568
- import * as fs18 from "fs";
2556
+ import * as fs17 from "fs";
2569
2557
  import * as os from "os";
2570
- import * as path17 from "path";
2571
- import { fileURLToPath as fileURLToPath4 } from "url";
2558
+ import * as path16 from "path";
2559
+ import { fileURLToPath as fileURLToPath3 } from "url";
2572
2560
 
2573
2561
  // src/commands/sync/syncSettings.ts
2574
- import * as fs17 from "fs";
2575
- import * as path16 from "path";
2562
+ import * as fs16 from "fs";
2563
+ import * as path15 from "path";
2576
2564
  import chalk33 from "chalk";
2577
2565
  async function syncSettings(claudeDir, targetBase) {
2578
- const source = path16.join(claudeDir, "settings.json");
2579
- const target = path16.join(targetBase, "settings.json");
2580
- const sourceContent = fs17.readFileSync(source, "utf-8");
2566
+ const source = path15.join(claudeDir, "settings.json");
2567
+ const target = path15.join(targetBase, "settings.json");
2568
+ const sourceContent = fs16.readFileSync(source, "utf-8");
2581
2569
  const normalizedSource = JSON.stringify(JSON.parse(sourceContent), null, 2);
2582
- if (fs17.existsSync(target)) {
2583
- const targetContent = fs17.readFileSync(target, "utf-8");
2570
+ if (fs16.existsSync(target)) {
2571
+ const targetContent = fs16.readFileSync(target, "utf-8");
2584
2572
  const normalizedTarget = JSON.stringify(JSON.parse(targetContent), null, 2);
2585
2573
  if (normalizedSource !== normalizedTarget) {
2586
2574
  console.log(
@@ -2598,37 +2586,37 @@ async function syncSettings(claudeDir, targetBase) {
2598
2586
  }
2599
2587
  }
2600
2588
  }
2601
- fs17.copyFileSync(source, target);
2589
+ fs16.copyFileSync(source, target);
2602
2590
  console.log("Copied settings.json to ~/.claude/settings.json");
2603
2591
  }
2604
2592
 
2605
2593
  // src/commands/sync.ts
2606
- var __filename2 = fileURLToPath4(import.meta.url);
2607
- var __dirname5 = path17.dirname(__filename2);
2594
+ var __filename2 = fileURLToPath3(import.meta.url);
2595
+ var __dirname4 = path16.dirname(__filename2);
2608
2596
  async function sync() {
2609
- const claudeDir = path17.join(__dirname5, "..", "claude");
2610
- const targetBase = path17.join(os.homedir(), ".claude");
2597
+ const claudeDir = path16.join(__dirname4, "..", "claude");
2598
+ const targetBase = path16.join(os.homedir(), ".claude");
2611
2599
  syncCommands(claudeDir, targetBase);
2612
2600
  await syncSettings(claudeDir, targetBase);
2613
2601
  }
2614
2602
  function syncCommands(claudeDir, targetBase) {
2615
- const sourceDir = path17.join(claudeDir, "commands");
2616
- const targetDir = path17.join(targetBase, "commands");
2617
- fs18.mkdirSync(targetDir, { recursive: true });
2618
- const files = fs18.readdirSync(sourceDir);
2603
+ const sourceDir = path16.join(claudeDir, "commands");
2604
+ const targetDir = path16.join(targetBase, "commands");
2605
+ fs17.mkdirSync(targetDir, { recursive: true });
2606
+ const files = fs17.readdirSync(sourceDir);
2619
2607
  for (const file of files) {
2620
- fs18.copyFileSync(path17.join(sourceDir, file), path17.join(targetDir, file));
2608
+ fs17.copyFileSync(path16.join(sourceDir, file), path16.join(targetDir, file));
2621
2609
  console.log(`Copied ${file} to ${targetDir}`);
2622
2610
  }
2623
2611
  console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
2624
2612
  }
2625
2613
 
2626
2614
  // src/commands/verify/hardcodedColors.ts
2627
- import { execSync as execSync13 } from "child_process";
2615
+ import { execSync as execSync15 } from "child_process";
2628
2616
  var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
2629
2617
  function hardcodedColors() {
2630
2618
  try {
2631
- const output = execSync13(`grep -rEnH '${pattern}' src/`, {
2619
+ const output = execSync15(`grep -rEnH '${pattern}' src/`, {
2632
2620
  encoding: "utf-8"
2633
2621
  });
2634
2622
  const lines = output.trim().split("\n");
@@ -2658,7 +2646,7 @@ Total: ${lines.length} hardcoded color(s)`);
2658
2646
 
2659
2647
  // src/commands/verify/run.ts
2660
2648
  import { spawn as spawn4 } from "child_process";
2661
- import * as path18 from "path";
2649
+ import * as path17 from "path";
2662
2650
  function formatDuration(ms) {
2663
2651
  if (ms < 1e3) {
2664
2652
  return `${ms}ms`;
@@ -2688,7 +2676,7 @@ async function run2(options = {}) {
2688
2676
  return;
2689
2677
  }
2690
2678
  const { packageJsonPath, verifyScripts } = result;
2691
- const packageDir = path18.dirname(packageJsonPath);
2679
+ const packageDir = path17.dirname(packageJsonPath);
2692
2680
  console.log(`Running ${verifyScripts.length} verify script(s) in parallel:`);
2693
2681
  for (const script of verifyScripts) {
2694
2682
  console.log(` - ${script}`);
@@ -2738,15 +2726,11 @@ program.command("init").description("Initialize VS Code and verify configuration
2738
2726
  program.command("commit <message>").description("Create a git commit with validation").action(commit);
2739
2727
  program.command("update").description("Update claude-code to the latest version").action(() => {
2740
2728
  console.log("Updating claude-code...");
2741
- execSync14("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
2729
+ execSync16("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
2742
2730
  });
2743
2731
  var prsCommand = program.command("prs").description("Pull request utilities").option("--open", "List only open pull requests").option("--closed", "List only closed pull requests").action(prs);
2744
2732
  prsCommand.command("comments <pr-number>").description("List all comments on a pull request").action((prNumber) => {
2745
- comments(Number.parseInt(prNumber, 10)).then((comments2) => {
2746
- for (const comment of comments2) {
2747
- console.log(JSON.stringify(comment));
2748
- }
2749
- });
2733
+ comments(Number.parseInt(prNumber, 10)).then(printComments);
2750
2734
  });
2751
2735
  var runCommand = program.command("run").description("Run a configured command from assist.yml").argument("<name>", "Name of the configured command").argument("[args...]", "Arguments to pass to the command").allowUnknownOption().action((name, args) => {
2752
2736
  run(name, args);
@@ -2779,7 +2763,6 @@ vscodeCommand.command("init").description("Add VS Code configuration files").act
2779
2763
  var deployCommand = program.command("deploy").description("Netlify deployment utilities");
2780
2764
  deployCommand.command("init").description("Initialize Netlify project and configure deployment").action(init);
2781
2765
  deployCommand.command("redirect").description("Add trailing slash redirect script to index.html").action(redirect);
2782
- program.command("enable-ralph").description("Enable ralph-wiggum plugin for spacetraders").action(enableRalph);
2783
2766
  program.command("status-line").description("Format Claude Code status line from JSON stdin").action(statusLine);
2784
2767
  program.command("notify").description(
2785
2768
  "Show notification from Claude Code hook (reads JSON from stdin)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.21.2",
3
+ "version": "0.22.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,78 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import chalk from "chalk";
5
- import { promptConfirm } from "../../shared/promptConfirm";
6
- import { printDiff } from "../../utils/printDiff";
7
-
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
-
10
- function deepMerge(
11
- target: Record<string, unknown>,
12
- source: Record<string, unknown>,
13
- ): Record<string, unknown> {
14
- const result = { ...target };
15
- for (const key of Object.keys(source)) {
16
- const sourceVal = source[key];
17
- const targetVal = result[key];
18
- if (
19
- sourceVal &&
20
- typeof sourceVal === "object" &&
21
- !Array.isArray(sourceVal) &&
22
- targetVal &&
23
- typeof targetVal === "object" &&
24
- !Array.isArray(targetVal)
25
- ) {
26
- result[key] = deepMerge(
27
- targetVal as Record<string, unknown>,
28
- sourceVal as Record<string, unknown>,
29
- );
30
- } else {
31
- result[key] = sourceVal;
32
- }
33
- }
34
- return result;
35
- }
36
-
37
- export async function enableRalph(): Promise<void> {
38
- const sourcePath = path.join(
39
- __dirname,
40
- "commands/enable-ralph/settings.local.json",
41
- );
42
- const targetPath = path.join(process.cwd(), ".claude/settings.local.json");
43
- const sourceData = JSON.parse(fs.readFileSync(sourcePath, "utf-8"));
44
-
45
- const targetDir = path.dirname(targetPath);
46
- if (!fs.existsSync(targetDir)) {
47
- fs.mkdirSync(targetDir, { recursive: true });
48
- }
49
-
50
- let targetData: Record<string, unknown> = {};
51
- let targetContent = "{}";
52
- if (fs.existsSync(targetPath)) {
53
- targetContent = fs.readFileSync(targetPath, "utf-8");
54
- targetData = JSON.parse(targetContent);
55
- }
56
-
57
- const merged = deepMerge(targetData, sourceData);
58
- const mergedContent = `${JSON.stringify(merged, null, "\t")}\n`;
59
-
60
- if (mergedContent === targetContent) {
61
- console.log(chalk.green("settings.local.json already has ralph enabled"));
62
- return;
63
- }
64
-
65
- console.log(chalk.yellow("\nChanges to settings.local.json:"));
66
- console.log();
67
- printDiff(targetContent, mergedContent);
68
-
69
- const confirm = await promptConfirm("Apply these changes?");
70
-
71
- if (!confirm) {
72
- console.log("Skipped");
73
- return;
74
- }
75
-
76
- fs.writeFileSync(targetPath, mergedContent);
77
- console.log(`Updated ${targetPath}`);
78
- }
@@ -1,8 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": ["Bash"]
4
- },
5
- "enabledPlugins": {
6
- "ralph-wiggum@claude-plugins-official": true
7
- }
8
- }