@staff0rd/assist 0.22.0 → 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 +6 -0
- package/dist/index.js +199 -258
- package/package.json +1 -1
- package/dist/commands/enable-ralph/index.ts +0 -78
- package/dist/commands/enable-ralph/settings.local.json +0 -8
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
|
@@ -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
|
|
1008
|
+
import chalk24 from "chalk";
|
|
1067
1009
|
|
|
1068
1010
|
// src/shared/promptMultiselect.ts
|
|
1069
|
-
import
|
|
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} - ${
|
|
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
|
|
1093
|
-
import * as
|
|
1094
|
-
import
|
|
1034
|
+
import * as fs4 from "fs";
|
|
1035
|
+
import * as path2 from "path";
|
|
1036
|
+
import chalk15 from "chalk";
|
|
1095
1037
|
function findPackageJson() {
|
|
1096
|
-
const packageJsonPath =
|
|
1097
|
-
if (
|
|
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(
|
|
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(
|
|
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 =
|
|
1118
|
-
if (
|
|
1119
|
-
const packageJson = JSON.parse(
|
|
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 =
|
|
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
|
|
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
|
|
1151
|
-
import * as
|
|
1152
|
-
import
|
|
1092
|
+
import * as fs5 from "fs";
|
|
1093
|
+
import * as path3 from "path";
|
|
1094
|
+
import chalk16 from "chalk";
|
|
1153
1095
|
function writePackageJson(filePath, pkg) {
|
|
1154
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
1119
|
+
const knipJsonPath = path3.join(cwd, "knip.json");
|
|
1178
1120
|
try {
|
|
1179
1121
|
let knipConfig;
|
|
1180
|
-
if (
|
|
1181
|
-
knipConfig = JSON.parse(
|
|
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
|
-
|
|
1130
|
+
fs5.writeFileSync(
|
|
1189
1131
|
knipJsonPath,
|
|
1190
1132
|
`${JSON.stringify(knipConfig, null, " ")}
|
|
1191
1133
|
`
|
|
1192
1134
|
);
|
|
1193
|
-
console.log(
|
|
1135
|
+
console.log(chalk16.dim(`Added '${binary}' to knip.json ignoreBinaries`));
|
|
1194
1136
|
}
|
|
1195
1137
|
} catch {
|
|
1196
|
-
console.log(
|
|
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(
|
|
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(
|
|
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
|
|
1224
|
-
import
|
|
1165
|
+
import * as path4 from "path";
|
|
1166
|
+
import chalk18 from "chalk";
|
|
1225
1167
|
async function setupDuplicateCode(packageJsonPath) {
|
|
1226
|
-
console.log(
|
|
1227
|
-
const cwd =
|
|
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
|
|
1242
|
-
import
|
|
1183
|
+
import * as path5 from "path";
|
|
1184
|
+
import chalk19 from "chalk";
|
|
1243
1185
|
async function setupHardcodedColors(packageJsonPath, hasOpenColor) {
|
|
1244
|
-
console.log(
|
|
1245
|
-
const cwd =
|
|
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
|
|
1259
|
-
import
|
|
1200
|
+
import * as path6 from "path";
|
|
1201
|
+
import chalk20 from "chalk";
|
|
1260
1202
|
async function setupKnip(packageJsonPath) {
|
|
1261
|
-
console.log(
|
|
1262
|
-
const cwd =
|
|
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
|
|
1276
|
-
import
|
|
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
|
|
1281
|
-
import { dirname as
|
|
1282
|
-
import { fileURLToPath as
|
|
1283
|
-
import
|
|
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
|
|
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 (!
|
|
1242
|
+
if (!existsSync6(packageJsonPath)) {
|
|
1301
1243
|
return false;
|
|
1302
1244
|
}
|
|
1303
|
-
const packageJson = JSON.parse(
|
|
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
|
-
|
|
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 (
|
|
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
|
|
1304
|
+
var __dirname3 = dirname6(fileURLToPath2(import.meta.url));
|
|
1363
1305
|
async function init2() {
|
|
1364
1306
|
removeEslint();
|
|
1365
1307
|
const biomeConfigPath = "biome.json";
|
|
1366
|
-
if (!
|
|
1308
|
+
if (!existsSync7(biomeConfigPath)) {
|
|
1367
1309
|
console.log("Initializing Biome...");
|
|
1368
1310
|
execSync9("npx @biomejs/biome init", { stdio: "inherit" });
|
|
1369
1311
|
}
|
|
1370
|
-
if (!
|
|
1312
|
+
if (!existsSync7(biomeConfigPath)) {
|
|
1371
1313
|
console.log("No biome.json found, skipping linter config");
|
|
1372
1314
|
return;
|
|
1373
1315
|
}
|
|
1374
|
-
const linterConfigPath =
|
|
1375
|
-
const linterConfig = JSON.parse(
|
|
1376
|
-
const biomeConfig = JSON.parse(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
1404
|
-
const cwd =
|
|
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
|
|
1421
|
-
import
|
|
1362
|
+
import * as path8 from "path";
|
|
1363
|
+
import chalk23 from "chalk";
|
|
1422
1364
|
async function setupTest(packageJsonPath) {
|
|
1423
|
-
console.log(
|
|
1424
|
-
const cwd =
|
|
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(
|
|
1508
|
+
console.log(chalk24.green("All verify scripts are already configured!"));
|
|
1567
1509
|
return;
|
|
1568
1510
|
}
|
|
1569
|
-
console.log(
|
|
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(
|
|
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(
|
|
1542
|
+
console.log(chalk24.green(`
|
|
1601
1543
|
Added ${selected.length} verify script(s):`));
|
|
1602
1544
|
for (const choice of selected) {
|
|
1603
|
-
console.log(
|
|
1545
|
+
console.log(chalk24.green(` - verify:${choice}`));
|
|
1604
1546
|
}
|
|
1605
|
-
console.log(
|
|
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 =
|
|
1619
|
-
if (!
|
|
1620
|
-
|
|
1621
|
-
console.log(
|
|
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 =
|
|
1626
|
-
if (!
|
|
1567
|
+
const gitignorePath = path9.join(process.cwd(), ".gitignore");
|
|
1568
|
+
if (!fs6.existsSync(gitignorePath)) {
|
|
1627
1569
|
return;
|
|
1628
1570
|
}
|
|
1629
|
-
const content =
|
|
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
|
-
|
|
1636
|
-
console.log(
|
|
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 =
|
|
1652
|
-
|
|
1593
|
+
const launchPath = path9.join(process.cwd(), ".vscode", "launch.json");
|
|
1594
|
+
fs6.writeFileSync(launchPath, `${JSON.stringify(launchConfig, null, " ")}
|
|
1653
1595
|
`);
|
|
1654
|
-
console.log(
|
|
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 =
|
|
1665
|
-
|
|
1606
|
+
const settingsPath = path9.join(process.cwd(), ".vscode", "settings.json");
|
|
1607
|
+
fs6.writeFileSync(settingsPath, `${JSON.stringify(settings, null, " ")}
|
|
1666
1608
|
`);
|
|
1667
|
-
console.log(
|
|
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 =
|
|
1674
|
-
|
|
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(
|
|
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 =
|
|
1626
|
+
const vscodeDir = path10.join(process.cwd(), ".vscode");
|
|
1685
1627
|
return {
|
|
1686
|
-
hasVscodeFolder:
|
|
1687
|
-
hasLaunchJson:
|
|
1688
|
-
hasSettingsJson:
|
|
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(
|
|
1653
|
+
console.log(chalk26.green("VS Code configuration already exists!"));
|
|
1712
1654
|
return;
|
|
1713
1655
|
}
|
|
1714
|
-
console.log(
|
|
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(
|
|
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
|
-
|
|
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 (!
|
|
1702
|
+
if (!fs8.existsSync(dir)) {
|
|
1761
1703
|
return results;
|
|
1762
1704
|
}
|
|
1763
|
-
const entries =
|
|
1705
|
+
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
1764
1706
|
for (const entry of entries) {
|
|
1765
|
-
const fullPath =
|
|
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 =
|
|
1731
|
+
const fileName = path12.basename(filePath);
|
|
1790
1732
|
const nameWithoutExt = fileName.replace(/\.(ts|tsx)$/, "");
|
|
1791
1733
|
if (/^[A-Z]/.test(nameWithoutExt)) {
|
|
1792
|
-
const content =
|
|
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(
|
|
1745
|
+
console.error(chalk27.red("\nFile name check failed:\n"));
|
|
1804
1746
|
console.error(
|
|
1805
|
-
|
|
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(
|
|
1752
|
+
console.error(chalk27.red(` ${violation.filePath}`));
|
|
1811
1753
|
console.error(
|
|
1812
|
-
|
|
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
|
|
1771
|
+
import fs10 from "fs";
|
|
1830
1772
|
|
|
1831
1773
|
// src/commands/lint/shared.ts
|
|
1832
|
-
import
|
|
1774
|
+
import chalk28 from "chalk";
|
|
1833
1775
|
function reportViolations(violations, checkName, errorMessage, successMessage) {
|
|
1834
1776
|
if (violations.length > 0) {
|
|
1835
|
-
console.error(
|
|
1777
|
+
console.error(chalk28.red(`
|
|
1836
1778
|
${checkName} failed:
|
|
1837
1779
|
`));
|
|
1838
|
-
console.error(
|
|
1780
|
+
console.error(chalk28.red(` ${errorMessage}
|
|
1839
1781
|
`));
|
|
1840
1782
|
for (const violation of violations) {
|
|
1841
|
-
console.error(
|
|
1842
|
-
console.error(
|
|
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 =
|
|
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
|
|
1831
|
+
import fs11 from "fs";
|
|
1890
1832
|
function checkForDynamicImports(filePath) {
|
|
1891
|
-
const content =
|
|
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
|
|
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 (!
|
|
1892
|
+
if (!existsSync10(viteConfigPath)) {
|
|
1951
1893
|
console.log("No vite.config.ts found, skipping base config");
|
|
1952
1894
|
return;
|
|
1953
1895
|
}
|
|
1954
|
-
const content =
|
|
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
|
-
|
|
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
|
|
1947
|
+
import fs12 from "fs";
|
|
2006
1948
|
import { createRequire } from "module";
|
|
2007
|
-
import
|
|
1949
|
+
import path13 from "path";
|
|
2008
1950
|
var require2 = createRequire(import.meta.url);
|
|
2009
1951
|
function getSnoreToastPath() {
|
|
2010
|
-
const notifierPath =
|
|
2011
|
-
return
|
|
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
|
-
|
|
1959
|
+
fs12.chmodSync(snoreToastPath, 493);
|
|
2018
1960
|
} catch {
|
|
2019
1961
|
}
|
|
2020
1962
|
const args = ["-t", title, "-m", message];
|
|
@@ -2086,7 +2028,7 @@ async function notify() {
|
|
|
2086
2028
|
|
|
2087
2029
|
// src/commands/prs/comments.ts
|
|
2088
2030
|
import { execSync as execSync12 } from "child_process";
|
|
2089
|
-
import
|
|
2031
|
+
import chalk29 from "chalk";
|
|
2090
2032
|
|
|
2091
2033
|
// src/lib/isClaudeCode.ts
|
|
2092
2034
|
function isClaudeCode() {
|
|
@@ -2118,17 +2060,17 @@ function getRepoInfo() {
|
|
|
2118
2060
|
// src/commands/prs/comments.ts
|
|
2119
2061
|
function formatForHuman(comment) {
|
|
2120
2062
|
if (comment.type === "review") {
|
|
2121
|
-
const stateColor = comment.state === "APPROVED" ?
|
|
2063
|
+
const stateColor = comment.state === "APPROVED" ? chalk29.green : comment.state === "CHANGES_REQUESTED" ? chalk29.red : chalk29.yellow;
|
|
2122
2064
|
return [
|
|
2123
|
-
`${
|
|
2065
|
+
`${chalk29.cyan("Review")} by ${chalk29.bold(comment.user)} ${stateColor(`[${comment.state}]`)}`,
|
|
2124
2066
|
comment.body,
|
|
2125
2067
|
""
|
|
2126
2068
|
].join("\n");
|
|
2127
2069
|
}
|
|
2128
2070
|
const location = comment.line ? `:${comment.line}` : "";
|
|
2129
2071
|
return [
|
|
2130
|
-
`${
|
|
2131
|
-
|
|
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")),
|
|
2132
2074
|
comment.body,
|
|
2133
2075
|
""
|
|
2134
2076
|
].join("\n");
|
|
@@ -2205,7 +2147,7 @@ async function comments(prNumber) {
|
|
|
2205
2147
|
|
|
2206
2148
|
// src/commands/prs/prs.ts
|
|
2207
2149
|
import { execSync as execSync13 } from "child_process";
|
|
2208
|
-
import
|
|
2150
|
+
import chalk30 from "chalk";
|
|
2209
2151
|
import enquirer4 from "enquirer";
|
|
2210
2152
|
var PAGE_SIZE = 10;
|
|
2211
2153
|
async function prs(options) {
|
|
@@ -2237,12 +2179,12 @@ async function displayPaginated(pullRequests) {
|
|
|
2237
2179
|
let currentPage = 0;
|
|
2238
2180
|
const getStatus = (pr) => {
|
|
2239
2181
|
if (pr.state === "MERGED" && pr.mergedAt) {
|
|
2240
|
-
return { label:
|
|
2182
|
+
return { label: chalk30.magenta("merged"), date: pr.mergedAt };
|
|
2241
2183
|
}
|
|
2242
2184
|
if (pr.state === "CLOSED" && pr.closedAt) {
|
|
2243
|
-
return { label:
|
|
2185
|
+
return { label: chalk30.red("closed"), date: pr.closedAt };
|
|
2244
2186
|
}
|
|
2245
|
-
return { label:
|
|
2187
|
+
return { label: chalk30.green("opened"), date: pr.createdAt };
|
|
2246
2188
|
};
|
|
2247
2189
|
const displayPage = (page) => {
|
|
2248
2190
|
const start = page * PAGE_SIZE;
|
|
@@ -2258,9 +2200,9 @@ Page ${page + 1} of ${totalPages} (${pullRequests.length} total)
|
|
|
2258
2200
|
const formattedDate = new Date(status.date).toISOString().split("T")[0];
|
|
2259
2201
|
const fileCount = pr.changedFiles.toLocaleString();
|
|
2260
2202
|
console.log(
|
|
2261
|
-
`${
|
|
2203
|
+
`${chalk30.cyan(`#${pr.number}`)} ${pr.title} ${chalk30.dim(`(${pr.author.login},`)} ${status.label} ${chalk30.dim(`${formattedDate})`)}`
|
|
2262
2204
|
);
|
|
2263
|
-
console.log(
|
|
2205
|
+
console.log(chalk30.dim(` ${fileCount} files | ${pr.url}`));
|
|
2264
2206
|
console.log();
|
|
2265
2207
|
}
|
|
2266
2208
|
};
|
|
@@ -2295,21 +2237,21 @@ Page ${page + 1} of ${totalPages} (${pullRequests.length} total)
|
|
|
2295
2237
|
|
|
2296
2238
|
// src/commands/refactor/check.ts
|
|
2297
2239
|
import { spawn as spawn2 } from "child_process";
|
|
2298
|
-
import * as
|
|
2240
|
+
import * as path14 from "path";
|
|
2299
2241
|
|
|
2300
2242
|
// src/commands/refactor/getViolations.ts
|
|
2301
2243
|
import { execSync as execSync14 } from "child_process";
|
|
2302
|
-
import
|
|
2244
|
+
import fs14 from "fs";
|
|
2303
2245
|
import { minimatch as minimatch2 } from "minimatch";
|
|
2304
2246
|
|
|
2305
2247
|
// src/commands/refactor/getIgnoredFiles.ts
|
|
2306
|
-
import
|
|
2248
|
+
import fs13 from "fs";
|
|
2307
2249
|
var REFACTOR_YML_PATH = "refactor.yml";
|
|
2308
2250
|
function parseRefactorYml() {
|
|
2309
|
-
if (!
|
|
2251
|
+
if (!fs13.existsSync(REFACTOR_YML_PATH)) {
|
|
2310
2252
|
return [];
|
|
2311
2253
|
}
|
|
2312
|
-
const content =
|
|
2254
|
+
const content = fs13.readFileSync(REFACTOR_YML_PATH, "utf-8");
|
|
2313
2255
|
const entries = [];
|
|
2314
2256
|
const lines = content.split("\n");
|
|
2315
2257
|
let currentEntry = {};
|
|
@@ -2338,7 +2280,7 @@ function getIgnoredFiles() {
|
|
|
2338
2280
|
}
|
|
2339
2281
|
|
|
2340
2282
|
// src/commands/refactor/logViolations.ts
|
|
2341
|
-
import
|
|
2283
|
+
import chalk31 from "chalk";
|
|
2342
2284
|
var DEFAULT_MAX_LINES = 100;
|
|
2343
2285
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
2344
2286
|
if (violations.length === 0) {
|
|
@@ -2347,43 +2289,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
2347
2289
|
}
|
|
2348
2290
|
return;
|
|
2349
2291
|
}
|
|
2350
|
-
console.error(
|
|
2292
|
+
console.error(chalk31.red(`
|
|
2351
2293
|
Refactor check failed:
|
|
2352
2294
|
`));
|
|
2353
|
-
console.error(
|
|
2295
|
+
console.error(chalk31.red(` The following files exceed ${maxLines} lines:
|
|
2354
2296
|
`));
|
|
2355
2297
|
for (const violation of violations) {
|
|
2356
|
-
console.error(
|
|
2298
|
+
console.error(chalk31.red(` ${violation.file} (${violation.lines} lines)`));
|
|
2357
2299
|
}
|
|
2358
2300
|
console.error(
|
|
2359
|
-
|
|
2301
|
+
chalk31.yellow(
|
|
2360
2302
|
`
|
|
2361
2303
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
2362
2304
|
way to refactor it, ignore it with:
|
|
2363
2305
|
`
|
|
2364
2306
|
)
|
|
2365
2307
|
);
|
|
2366
|
-
console.error(
|
|
2308
|
+
console.error(chalk31.gray(` assist refactor ignore <file>
|
|
2367
2309
|
`));
|
|
2368
2310
|
if (process.env.CLAUDECODE) {
|
|
2369
|
-
console.error(
|
|
2311
|
+
console.error(chalk31.cyan(`
|
|
2370
2312
|
## Extracting Code to New Files
|
|
2371
2313
|
`));
|
|
2372
2314
|
console.error(
|
|
2373
|
-
|
|
2315
|
+
chalk31.cyan(
|
|
2374
2316
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
2375
2317
|
`
|
|
2376
2318
|
)
|
|
2377
2319
|
);
|
|
2378
2320
|
console.error(
|
|
2379
|
-
|
|
2321
|
+
chalk31.cyan(
|
|
2380
2322
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
2381
2323
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
2382
2324
|
`
|
|
2383
2325
|
)
|
|
2384
2326
|
);
|
|
2385
2327
|
console.error(
|
|
2386
|
-
|
|
2328
|
+
chalk31.cyan(
|
|
2387
2329
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
2388
2330
|
domains, move it to a common/shared folder.
|
|
2389
2331
|
`
|
|
@@ -2394,7 +2336,7 @@ Refactor check failed:
|
|
|
2394
2336
|
|
|
2395
2337
|
// src/commands/refactor/getViolations.ts
|
|
2396
2338
|
function countLines(filePath) {
|
|
2397
|
-
const content =
|
|
2339
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
2398
2340
|
return content.split("\n").length;
|
|
2399
2341
|
}
|
|
2400
2342
|
function getGitFiles(options) {
|
|
@@ -2446,7 +2388,7 @@ async function runVerifyQuietly() {
|
|
|
2446
2388
|
return true;
|
|
2447
2389
|
}
|
|
2448
2390
|
const { packageJsonPath, verifyScripts } = result;
|
|
2449
|
-
const packageDir =
|
|
2391
|
+
const packageDir = path14.dirname(packageJsonPath);
|
|
2450
2392
|
const results = await Promise.all(
|
|
2451
2393
|
verifyScripts.map(
|
|
2452
2394
|
(script) => new Promise(
|
|
@@ -2499,28 +2441,28 @@ async function check(pattern2, options) {
|
|
|
2499
2441
|
}
|
|
2500
2442
|
|
|
2501
2443
|
// src/commands/refactor/ignore.ts
|
|
2502
|
-
import
|
|
2503
|
-
import
|
|
2444
|
+
import fs15 from "fs";
|
|
2445
|
+
import chalk32 from "chalk";
|
|
2504
2446
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
2505
2447
|
function ignore(file) {
|
|
2506
|
-
if (!
|
|
2507
|
-
console.error(
|
|
2448
|
+
if (!fs15.existsSync(file)) {
|
|
2449
|
+
console.error(chalk32.red(`Error: File does not exist: ${file}`));
|
|
2508
2450
|
process.exit(1);
|
|
2509
2451
|
}
|
|
2510
|
-
const content =
|
|
2452
|
+
const content = fs15.readFileSync(file, "utf-8");
|
|
2511
2453
|
const lineCount = content.split("\n").length;
|
|
2512
2454
|
const maxLines = lineCount + 10;
|
|
2513
2455
|
const entry = `- file: ${file}
|
|
2514
2456
|
maxLines: ${maxLines}
|
|
2515
2457
|
`;
|
|
2516
|
-
if (
|
|
2517
|
-
const existing =
|
|
2518
|
-
|
|
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);
|
|
2519
2461
|
} else {
|
|
2520
|
-
|
|
2462
|
+
fs15.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
2521
2463
|
}
|
|
2522
2464
|
console.log(
|
|
2523
|
-
|
|
2465
|
+
chalk32.green(
|
|
2524
2466
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
2525
2467
|
)
|
|
2526
2468
|
);
|
|
@@ -2611,31 +2553,31 @@ async function statusLine() {
|
|
|
2611
2553
|
}
|
|
2612
2554
|
|
|
2613
2555
|
// src/commands/sync.ts
|
|
2614
|
-
import * as
|
|
2556
|
+
import * as fs17 from "fs";
|
|
2615
2557
|
import * as os from "os";
|
|
2616
|
-
import * as
|
|
2617
|
-
import { fileURLToPath as
|
|
2558
|
+
import * as path16 from "path";
|
|
2559
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2618
2560
|
|
|
2619
2561
|
// src/commands/sync/syncSettings.ts
|
|
2620
|
-
import * as
|
|
2621
|
-
import * as
|
|
2622
|
-
import
|
|
2562
|
+
import * as fs16 from "fs";
|
|
2563
|
+
import * as path15 from "path";
|
|
2564
|
+
import chalk33 from "chalk";
|
|
2623
2565
|
async function syncSettings(claudeDir, targetBase) {
|
|
2624
|
-
const source =
|
|
2625
|
-
const target =
|
|
2626
|
-
const sourceContent =
|
|
2566
|
+
const source = path15.join(claudeDir, "settings.json");
|
|
2567
|
+
const target = path15.join(targetBase, "settings.json");
|
|
2568
|
+
const sourceContent = fs16.readFileSync(source, "utf-8");
|
|
2627
2569
|
const normalizedSource = JSON.stringify(JSON.parse(sourceContent), null, 2);
|
|
2628
|
-
if (
|
|
2629
|
-
const targetContent =
|
|
2570
|
+
if (fs16.existsSync(target)) {
|
|
2571
|
+
const targetContent = fs16.readFileSync(target, "utf-8");
|
|
2630
2572
|
const normalizedTarget = JSON.stringify(JSON.parse(targetContent), null, 2);
|
|
2631
2573
|
if (normalizedSource !== normalizedTarget) {
|
|
2632
2574
|
console.log(
|
|
2633
|
-
|
|
2575
|
+
chalk33.yellow("\n\u26A0\uFE0F Warning: settings.json differs from existing file")
|
|
2634
2576
|
);
|
|
2635
2577
|
console.log();
|
|
2636
2578
|
printDiff(targetContent, sourceContent);
|
|
2637
2579
|
const confirm = await promptConfirm(
|
|
2638
|
-
|
|
2580
|
+
chalk33.red("Overwrite existing settings.json?"),
|
|
2639
2581
|
false
|
|
2640
2582
|
);
|
|
2641
2583
|
if (!confirm) {
|
|
@@ -2644,26 +2586,26 @@ async function syncSettings(claudeDir, targetBase) {
|
|
|
2644
2586
|
}
|
|
2645
2587
|
}
|
|
2646
2588
|
}
|
|
2647
|
-
|
|
2589
|
+
fs16.copyFileSync(source, target);
|
|
2648
2590
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
2649
2591
|
}
|
|
2650
2592
|
|
|
2651
2593
|
// src/commands/sync.ts
|
|
2652
|
-
var __filename2 =
|
|
2653
|
-
var
|
|
2594
|
+
var __filename2 = fileURLToPath3(import.meta.url);
|
|
2595
|
+
var __dirname4 = path16.dirname(__filename2);
|
|
2654
2596
|
async function sync() {
|
|
2655
|
-
const claudeDir =
|
|
2656
|
-
const targetBase =
|
|
2597
|
+
const claudeDir = path16.join(__dirname4, "..", "claude");
|
|
2598
|
+
const targetBase = path16.join(os.homedir(), ".claude");
|
|
2657
2599
|
syncCommands(claudeDir, targetBase);
|
|
2658
2600
|
await syncSettings(claudeDir, targetBase);
|
|
2659
2601
|
}
|
|
2660
2602
|
function syncCommands(claudeDir, targetBase) {
|
|
2661
|
-
const sourceDir =
|
|
2662
|
-
const targetDir =
|
|
2663
|
-
|
|
2664
|
-
const files =
|
|
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);
|
|
2665
2607
|
for (const file of files) {
|
|
2666
|
-
|
|
2608
|
+
fs17.copyFileSync(path16.join(sourceDir, file), path16.join(targetDir, file));
|
|
2667
2609
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
2668
2610
|
}
|
|
2669
2611
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -2704,7 +2646,7 @@ Total: ${lines.length} hardcoded color(s)`);
|
|
|
2704
2646
|
|
|
2705
2647
|
// src/commands/verify/run.ts
|
|
2706
2648
|
import { spawn as spawn4 } from "child_process";
|
|
2707
|
-
import * as
|
|
2649
|
+
import * as path17 from "path";
|
|
2708
2650
|
function formatDuration(ms) {
|
|
2709
2651
|
if (ms < 1e3) {
|
|
2710
2652
|
return `${ms}ms`;
|
|
@@ -2734,7 +2676,7 @@ async function run2(options = {}) {
|
|
|
2734
2676
|
return;
|
|
2735
2677
|
}
|
|
2736
2678
|
const { packageJsonPath, verifyScripts } = result;
|
|
2737
|
-
const packageDir =
|
|
2679
|
+
const packageDir = path17.dirname(packageJsonPath);
|
|
2738
2680
|
console.log(`Running ${verifyScripts.length} verify script(s) in parallel:`);
|
|
2739
2681
|
for (const script of verifyScripts) {
|
|
2740
2682
|
console.log(` - ${script}`);
|
|
@@ -2821,7 +2763,6 @@ vscodeCommand.command("init").description("Add VS Code configuration files").act
|
|
|
2821
2763
|
var deployCommand = program.command("deploy").description("Netlify deployment utilities");
|
|
2822
2764
|
deployCommand.command("init").description("Initialize Netlify project and configure deployment").action(init);
|
|
2823
2765
|
deployCommand.command("redirect").description("Add trailing slash redirect script to index.html").action(redirect);
|
|
2824
|
-
program.command("enable-ralph").description("Enable ralph-wiggum plugin for spacetraders").action(enableRalph);
|
|
2825
2766
|
program.command("status-line").description("Format Claude Code status line from JSON stdin").action(statusLine);
|
|
2826
2767
|
program.command("notify").description(
|
|
2827
2768
|
"Show notification from Claude Code hook (reads JSON from stdin)"
|
package/package.json
CHANGED
|
@@ -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
|
-
}
|