@staff0rd/assist 0.108.2 → 0.110.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/claude/CLAUDE.md +5 -0
- package/dist/commands/lint/lint/applyMoves.ts +50 -0
- package/dist/commands/lint/lint/checkFileNames.ts +81 -0
- package/dist/commands/lint/lint/createLintProject.ts +16 -0
- package/dist/commands/lint/lint/fixFileNameViolations.ts +16 -0
- package/dist/commands/lint/lint/index.ts +6 -2
- package/dist/commands/lint/lint/renameExports.ts +37 -0
- package/dist/commands/lint/lint/runFileNameCheck.ts +31 -55
- package/dist/index.js +752 -485
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.110.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -46,6 +46,7 @@ var package_default = {
|
|
|
46
46
|
"node-notifier": "^10.0.1",
|
|
47
47
|
semver: "^7.7.3",
|
|
48
48
|
"shell-quote": "^1.8.3",
|
|
49
|
+
"ts-morph": "^27.0.2",
|
|
49
50
|
typescript: "^5.9.3",
|
|
50
51
|
yaml: "^2.8.2",
|
|
51
52
|
zod: "^4.3.6"
|
|
@@ -88,10 +89,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
88
89
|
// src/shared/loadRawYaml.ts
|
|
89
90
|
import { existsSync, readFileSync } from "fs";
|
|
90
91
|
import { parse as parseYaml } from "yaml";
|
|
91
|
-
function loadRawYaml(
|
|
92
|
-
if (!existsSync(
|
|
92
|
+
function loadRawYaml(path43) {
|
|
93
|
+
if (!existsSync(path43)) return {};
|
|
93
94
|
try {
|
|
94
|
-
const content = readFileSync(
|
|
95
|
+
const content = readFileSync(path43, "utf-8");
|
|
95
96
|
return parseYaml(content) || {};
|
|
96
97
|
} catch {
|
|
97
98
|
return {};
|
|
@@ -329,9 +330,9 @@ function isTraversable(value) {
|
|
|
329
330
|
function stepInto(current, key) {
|
|
330
331
|
return isTraversable(current) ? current[key] : void 0;
|
|
331
332
|
}
|
|
332
|
-
function getNestedValue(obj,
|
|
333
|
+
function getNestedValue(obj, path43) {
|
|
333
334
|
let current = obj;
|
|
334
|
-
for (const key of
|
|
335
|
+
for (const key of path43.split(".")) current = stepInto(current, key);
|
|
335
336
|
return current;
|
|
336
337
|
}
|
|
337
338
|
|
|
@@ -372,8 +373,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
372
373
|
}
|
|
373
374
|
return ensureObject(container, resolved);
|
|
374
375
|
}
|
|
375
|
-
function setNestedValue(obj,
|
|
376
|
-
const keys =
|
|
376
|
+
function setNestedValue(obj, path43, value) {
|
|
377
|
+
const keys = path43.split(".");
|
|
377
378
|
const result = { ...obj };
|
|
378
379
|
let current = result;
|
|
379
380
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -442,7 +443,7 @@ function configList() {
|
|
|
442
443
|
}
|
|
443
444
|
|
|
444
445
|
// src/commands/verify/init/index.ts
|
|
445
|
-
import
|
|
446
|
+
import chalk16 from "chalk";
|
|
446
447
|
|
|
447
448
|
// src/shared/promptMultiselect.ts
|
|
448
449
|
import chalk3 from "chalk";
|
|
@@ -515,12 +516,13 @@ function findPackageJsonWithVerifyScripts(startDir) {
|
|
|
515
516
|
// src/commands/verify/setup/expectedScripts.ts
|
|
516
517
|
var expectedScripts = {
|
|
517
518
|
"verify:knip": "knip --no-progress --treat-config-hints-as-errors",
|
|
518
|
-
"verify:lint": "biome check --write .",
|
|
519
|
+
"verify:lint": "biome check --write --error-on-warnings .",
|
|
519
520
|
"verify:duplicate-code": "jscpd --format 'typescript,tsx' --exitCode 1 --ignore '**/*.test.*' -r consoleFull src",
|
|
520
521
|
"verify:test": "vitest run --reporter=dot --silent",
|
|
521
522
|
"verify:hardcoded-colors": "assist verify hardcoded-colors",
|
|
522
523
|
"verify:no-venv": "assist verify no-venv",
|
|
523
|
-
"verify:maintainability": "assist complexity maintainability ./src --threshold 60"
|
|
524
|
+
"verify:maintainability": "assist complexity maintainability ./src --threshold 60",
|
|
525
|
+
"verify:madge": "madge --circular --ts-config ./tsconfig.json --extensions ts,tsx src/"
|
|
524
526
|
};
|
|
525
527
|
|
|
526
528
|
// src/commands/verify/setup/setupBuild.ts
|
|
@@ -859,12 +861,30 @@ async function setupLint(packageJsonPath) {
|
|
|
859
861
|
);
|
|
860
862
|
}
|
|
861
863
|
|
|
862
|
-
// src/commands/verify/setup/
|
|
864
|
+
// src/commands/verify/setup/setupMadge.ts
|
|
863
865
|
import * as path7 from "path";
|
|
864
866
|
import chalk13 from "chalk";
|
|
867
|
+
async function setupMadge(packageJsonPath) {
|
|
868
|
+
console.log(chalk13.blue("\nSetting up madge..."));
|
|
869
|
+
const cwd = path7.dirname(packageJsonPath);
|
|
870
|
+
const pkg = readPackageJson(packageJsonPath);
|
|
871
|
+
const hasMadge = !!pkg.dependencies?.madge || !!pkg.devDependencies?.madge;
|
|
872
|
+
if (!hasMadge && !installPackage("madge", cwd)) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
setupVerifyScript(
|
|
876
|
+
packageJsonPath,
|
|
877
|
+
"verify:madge",
|
|
878
|
+
expectedScripts["verify:madge"]
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// src/commands/verify/setup/setupMaintainability.ts
|
|
883
|
+
import * as path8 from "path";
|
|
884
|
+
import chalk14 from "chalk";
|
|
865
885
|
async function setupMaintainability(packageJsonPath) {
|
|
866
|
-
console.log(
|
|
867
|
-
addToKnipIgnoreBinaries(
|
|
886
|
+
console.log(chalk14.blue("\nSetting up maintainability check..."));
|
|
887
|
+
addToKnipIgnoreBinaries(path8.dirname(packageJsonPath), "assist");
|
|
868
888
|
setupVerifyScript(
|
|
869
889
|
packageJsonPath,
|
|
870
890
|
"verify:maintainability",
|
|
@@ -873,11 +893,11 @@ async function setupMaintainability(packageJsonPath) {
|
|
|
873
893
|
}
|
|
874
894
|
|
|
875
895
|
// src/commands/verify/setup/setupTest.ts
|
|
876
|
-
import * as
|
|
877
|
-
import
|
|
896
|
+
import * as path9 from "path";
|
|
897
|
+
import chalk15 from "chalk";
|
|
878
898
|
async function setupTest(packageJsonPath) {
|
|
879
|
-
console.log(
|
|
880
|
-
const cwd =
|
|
899
|
+
console.log(chalk15.blue("\nSetting up vitest..."));
|
|
900
|
+
const cwd = path9.dirname(packageJsonPath);
|
|
881
901
|
const pkg = readPackageJson(packageJsonPath);
|
|
882
902
|
if (!pkg.devDependencies?.vitest && !installPackage("vitest", cwd)) {
|
|
883
903
|
return;
|
|
@@ -901,6 +921,9 @@ function getStatusLabel(status2) {
|
|
|
901
921
|
}
|
|
902
922
|
|
|
903
923
|
// src/commands/verify/init/detectExistingSetup/index.ts
|
|
924
|
+
function hasDep(pkg, name) {
|
|
925
|
+
return !!pkg.dependencies?.[name] || !!pkg.devDependencies?.[name];
|
|
926
|
+
}
|
|
904
927
|
function toolStatus(pkg, scriptName, hasPackage) {
|
|
905
928
|
const currentScript = pkg.scripts?.[scriptName];
|
|
906
929
|
const expectedCommand = expectedScripts[scriptName];
|
|
@@ -911,26 +934,20 @@ function toolStatus(pkg, scriptName, hasPackage) {
|
|
|
911
934
|
};
|
|
912
935
|
}
|
|
913
936
|
function detectExistingSetup(pkg) {
|
|
937
|
+
const status2 = (script, has) => toolStatus(pkg, script, has);
|
|
914
938
|
return {
|
|
915
|
-
knip:
|
|
916
|
-
biome:
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
),
|
|
921
|
-
jscpd: toolStatus(
|
|
922
|
-
pkg,
|
|
923
|
-
"verify:duplicate-code",
|
|
924
|
-
!!pkg.dependencies?.jscpd || !!pkg.devDependencies?.jscpd
|
|
925
|
-
),
|
|
926
|
-
test: toolStatus(pkg, "verify:test", !!pkg.devDependencies?.vitest),
|
|
927
|
-
hasVite: !!pkg.devDependencies?.vite || !!pkg.dependencies?.vite,
|
|
939
|
+
knip: status2("verify:knip", hasDep(pkg, "knip")),
|
|
940
|
+
biome: status2("verify:lint", hasDep(pkg, "@biomejs/biome")),
|
|
941
|
+
jscpd: status2("verify:duplicate-code", hasDep(pkg, "jscpd")),
|
|
942
|
+
test: status2("verify:test", hasDep(pkg, "vitest")),
|
|
943
|
+
hasVite: hasDep(pkg, "vite"),
|
|
928
944
|
hasTypescript: !!pkg.devDependencies?.typescript,
|
|
929
|
-
build:
|
|
930
|
-
typecheck:
|
|
931
|
-
hardcodedColors:
|
|
932
|
-
|
|
933
|
-
|
|
945
|
+
build: status2("verify:build", true),
|
|
946
|
+
typecheck: status2("verify:typecheck", true),
|
|
947
|
+
hardcodedColors: status2("verify:hardcoded-colors", true),
|
|
948
|
+
madge: status2("verify:madge", hasDep(pkg, "madge")),
|
|
949
|
+
maintainability: status2("verify:maintainability", true),
|
|
950
|
+
hasOpenColor: hasDep(pkg, "open-color")
|
|
934
951
|
};
|
|
935
952
|
}
|
|
936
953
|
|
|
@@ -987,6 +1004,12 @@ var options = [
|
|
|
987
1004
|
description: "TypeScript type checking",
|
|
988
1005
|
extraCondition: (s) => s.hasTypescript && !s.hasVite
|
|
989
1006
|
},
|
|
1007
|
+
{
|
|
1008
|
+
toolKey: "madge",
|
|
1009
|
+
value: "madge",
|
|
1010
|
+
label: "madge",
|
|
1011
|
+
description: "Circular dependency detection with madge"
|
|
1012
|
+
},
|
|
990
1013
|
{
|
|
991
1014
|
toolKey: "maintainability",
|
|
992
1015
|
value: "maintainability",
|
|
@@ -1022,6 +1045,7 @@ function getSetupHandlers(hasVite, hasTypescript, hasOpenColor) {
|
|
|
1022
1045
|
build: (p) => setupBuild(p, hasVite, hasTypescript),
|
|
1023
1046
|
typecheck: (p) => setupTypecheck(p),
|
|
1024
1047
|
"hardcoded-colors": (p) => setupHardcodedColors(p, hasOpenColor),
|
|
1048
|
+
madge: (p) => setupMadge(p),
|
|
1025
1049
|
maintainability: (p) => setupMaintainability(p)
|
|
1026
1050
|
};
|
|
1027
1051
|
}
|
|
@@ -1029,25 +1053,25 @@ async function runSelectedSetups(selected, packageJsonPath, handlers) {
|
|
|
1029
1053
|
for (const choice of selected) {
|
|
1030
1054
|
await handlers[choice]?.(packageJsonPath);
|
|
1031
1055
|
}
|
|
1032
|
-
console.log(
|
|
1056
|
+
console.log(chalk16.green(`
|
|
1033
1057
|
Added ${selected.length} verify script(s):`));
|
|
1034
1058
|
for (const choice of selected) {
|
|
1035
|
-
console.log(
|
|
1059
|
+
console.log(chalk16.green(` - verify:${choice}`));
|
|
1036
1060
|
}
|
|
1037
|
-
console.log(
|
|
1061
|
+
console.log(chalk16.dim("\nRun 'assist verify' to run all verify scripts"));
|
|
1038
1062
|
}
|
|
1039
1063
|
async function promptForScripts(availableOptions) {
|
|
1040
1064
|
if (availableOptions.length === 0) {
|
|
1041
|
-
console.log(
|
|
1065
|
+
console.log(chalk16.green("All verify scripts are already configured!"));
|
|
1042
1066
|
return null;
|
|
1043
1067
|
}
|
|
1044
|
-
console.log(
|
|
1068
|
+
console.log(chalk16.bold("Available verify scripts to add:\n"));
|
|
1045
1069
|
const selected = await promptMultiselect(
|
|
1046
1070
|
"Select verify scripts to add:",
|
|
1047
1071
|
availableOptions
|
|
1048
1072
|
);
|
|
1049
1073
|
if (selected.length === 0) {
|
|
1050
|
-
console.log(
|
|
1074
|
+
console.log(chalk16.yellow("No scripts selected"));
|
|
1051
1075
|
return null;
|
|
1052
1076
|
}
|
|
1053
1077
|
return selected;
|
|
@@ -1066,21 +1090,21 @@ async function init2() {
|
|
|
1066
1090
|
}
|
|
1067
1091
|
|
|
1068
1092
|
// src/commands/vscode/init/index.ts
|
|
1069
|
-
import
|
|
1093
|
+
import chalk18 from "chalk";
|
|
1070
1094
|
|
|
1071
1095
|
// src/commands/vscode/init/createLaunchJson.ts
|
|
1072
1096
|
import * as fs3 from "fs";
|
|
1073
|
-
import * as
|
|
1074
|
-
import
|
|
1097
|
+
import * as path10 from "path";
|
|
1098
|
+
import chalk17 from "chalk";
|
|
1075
1099
|
function ensureVscodeFolder() {
|
|
1076
|
-
const vscodeDir =
|
|
1100
|
+
const vscodeDir = path10.join(process.cwd(), ".vscode");
|
|
1077
1101
|
if (!fs3.existsSync(vscodeDir)) {
|
|
1078
1102
|
fs3.mkdirSync(vscodeDir);
|
|
1079
|
-
console.log(
|
|
1103
|
+
console.log(chalk17.dim("Created .vscode folder"));
|
|
1080
1104
|
}
|
|
1081
1105
|
}
|
|
1082
1106
|
function removeVscodeFromGitignore() {
|
|
1083
|
-
const gitignorePath =
|
|
1107
|
+
const gitignorePath = path10.join(process.cwd(), ".gitignore");
|
|
1084
1108
|
if (!fs3.existsSync(gitignorePath)) {
|
|
1085
1109
|
return;
|
|
1086
1110
|
}
|
|
@@ -1091,7 +1115,7 @@ function removeVscodeFromGitignore() {
|
|
|
1091
1115
|
);
|
|
1092
1116
|
if (filteredLines.length !== lines.length) {
|
|
1093
1117
|
fs3.writeFileSync(gitignorePath, filteredLines.join("\n"));
|
|
1094
|
-
console.log(
|
|
1118
|
+
console.log(chalk17.dim("Removed .vscode references from .gitignore"));
|
|
1095
1119
|
}
|
|
1096
1120
|
}
|
|
1097
1121
|
function createLaunchJson(type) {
|
|
@@ -1107,10 +1131,10 @@ function createLaunchJson(type) {
|
|
|
1107
1131
|
}
|
|
1108
1132
|
]
|
|
1109
1133
|
};
|
|
1110
|
-
const launchPath =
|
|
1134
|
+
const launchPath = path10.join(process.cwd(), ".vscode", "launch.json");
|
|
1111
1135
|
fs3.writeFileSync(launchPath, `${JSON.stringify(launchConfig, null, " ")}
|
|
1112
1136
|
`);
|
|
1113
|
-
console.log(
|
|
1137
|
+
console.log(chalk17.green("Created .vscode/launch.json"));
|
|
1114
1138
|
}
|
|
1115
1139
|
function createSettingsJson() {
|
|
1116
1140
|
const settings = {
|
|
@@ -1120,33 +1144,33 @@ function createSettingsJson() {
|
|
|
1120
1144
|
"source.organizeImports.biome": "explicit"
|
|
1121
1145
|
}
|
|
1122
1146
|
};
|
|
1123
|
-
const settingsPath =
|
|
1147
|
+
const settingsPath = path10.join(process.cwd(), ".vscode", "settings.json");
|
|
1124
1148
|
fs3.writeFileSync(settingsPath, `${JSON.stringify(settings, null, " ")}
|
|
1125
1149
|
`);
|
|
1126
|
-
console.log(
|
|
1150
|
+
console.log(chalk17.green("Created .vscode/settings.json"));
|
|
1127
1151
|
}
|
|
1128
1152
|
function createExtensionsJson() {
|
|
1129
1153
|
const extensions = {
|
|
1130
1154
|
recommendations: ["biomejs.biome"]
|
|
1131
1155
|
};
|
|
1132
|
-
const extensionsPath =
|
|
1156
|
+
const extensionsPath = path10.join(process.cwd(), ".vscode", "extensions.json");
|
|
1133
1157
|
fs3.writeFileSync(
|
|
1134
1158
|
extensionsPath,
|
|
1135
1159
|
`${JSON.stringify(extensions, null, " ")}
|
|
1136
1160
|
`
|
|
1137
1161
|
);
|
|
1138
|
-
console.log(
|
|
1162
|
+
console.log(chalk17.green("Created .vscode/extensions.json"));
|
|
1139
1163
|
}
|
|
1140
1164
|
|
|
1141
1165
|
// src/commands/vscode/init/detectVscodeSetup.ts
|
|
1142
1166
|
import * as fs4 from "fs";
|
|
1143
|
-
import * as
|
|
1167
|
+
import * as path11 from "path";
|
|
1144
1168
|
function detectVscodeSetup(pkg) {
|
|
1145
|
-
const vscodeDir =
|
|
1169
|
+
const vscodeDir = path11.join(process.cwd(), ".vscode");
|
|
1146
1170
|
return {
|
|
1147
1171
|
hasVscodeFolder: fs4.existsSync(vscodeDir),
|
|
1148
|
-
hasLaunchJson: fs4.existsSync(
|
|
1149
|
-
hasSettingsJson: fs4.existsSync(
|
|
1172
|
+
hasLaunchJson: fs4.existsSync(path11.join(vscodeDir, "launch.json")),
|
|
1173
|
+
hasSettingsJson: fs4.existsSync(path11.join(vscodeDir, "settings.json")),
|
|
1150
1174
|
hasVite: !!pkg.devDependencies?.vite || !!pkg.dependencies?.vite,
|
|
1151
1175
|
hasTsup: !!pkg.devDependencies?.tsup || !!pkg.dependencies?.tsup
|
|
1152
1176
|
};
|
|
@@ -1192,7 +1216,7 @@ function applySelections(selected, setup2) {
|
|
|
1192
1216
|
for (const choice of selected) handlers[choice]?.();
|
|
1193
1217
|
}
|
|
1194
1218
|
async function promptForOptions(options2) {
|
|
1195
|
-
console.log(
|
|
1219
|
+
console.log(chalk18.bold("Available VS Code configurations to add:\n"));
|
|
1196
1220
|
return promptMultiselect("Select configurations to add:", options2);
|
|
1197
1221
|
}
|
|
1198
1222
|
async function init3({ all = false } = {}) {
|
|
@@ -1200,17 +1224,17 @@ async function init3({ all = false } = {}) {
|
|
|
1200
1224
|
const setup2 = detectVscodeSetup(pkg);
|
|
1201
1225
|
const options2 = getAvailableOptions2(setup2);
|
|
1202
1226
|
if (options2.length === 0) {
|
|
1203
|
-
console.log(
|
|
1227
|
+
console.log(chalk18.green("VS Code configuration already exists!"));
|
|
1204
1228
|
return;
|
|
1205
1229
|
}
|
|
1206
1230
|
const selected = all ? options2.map((o) => o.value) : await promptForOptions(options2);
|
|
1207
1231
|
if (selected.length === 0) {
|
|
1208
|
-
console.log(
|
|
1232
|
+
console.log(chalk18.yellow("No configurations selected"));
|
|
1209
1233
|
return;
|
|
1210
1234
|
}
|
|
1211
1235
|
applySelections(selected, setup2);
|
|
1212
1236
|
console.log(
|
|
1213
|
-
|
|
1237
|
+
chalk18.green(`
|
|
1214
1238
|
Added ${selected.length} VS Code configuration(s)`)
|
|
1215
1239
|
);
|
|
1216
1240
|
}
|
|
@@ -1222,13 +1246,16 @@ async function init4() {
|
|
|
1222
1246
|
}
|
|
1223
1247
|
|
|
1224
1248
|
// src/commands/lint/lint/runFileNameCheck.ts
|
|
1249
|
+
import path17 from "path";
|
|
1250
|
+
import chalk20 from "chalk";
|
|
1251
|
+
|
|
1252
|
+
// src/commands/lint/lint/checkFileNames.ts
|
|
1225
1253
|
import fs6 from "fs";
|
|
1226
|
-
import
|
|
1227
|
-
import chalk18 from "chalk";
|
|
1254
|
+
import path13 from "path";
|
|
1228
1255
|
|
|
1229
1256
|
// src/shared/findSourceFiles.ts
|
|
1230
1257
|
import fs5 from "fs";
|
|
1231
|
-
import
|
|
1258
|
+
import path12 from "path";
|
|
1232
1259
|
var EXTENSIONS = [".ts", ".tsx"];
|
|
1233
1260
|
function findSourceFiles(dir, options2 = {}) {
|
|
1234
1261
|
const { includeTests = true } = options2;
|
|
@@ -1238,7 +1265,7 @@ function findSourceFiles(dir, options2 = {}) {
|
|
|
1238
1265
|
}
|
|
1239
1266
|
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
1240
1267
|
for (const entry of entries) {
|
|
1241
|
-
const fullPath =
|
|
1268
|
+
const fullPath = path12.join(dir, entry.name);
|
|
1242
1269
|
if (entry.isDirectory() && entry.name !== "node_modules") {
|
|
1243
1270
|
results.push(...findSourceFiles(fullPath, options2));
|
|
1244
1271
|
} else if (entry.isFile() && EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
|
|
@@ -1251,71 +1278,198 @@ function findSourceFiles(dir, options2 = {}) {
|
|
|
1251
1278
|
return results;
|
|
1252
1279
|
}
|
|
1253
1280
|
|
|
1254
|
-
// src/commands/lint/lint/
|
|
1281
|
+
// src/commands/lint/lint/checkFileNames.ts
|
|
1255
1282
|
function hasClassOrComponent(content) {
|
|
1256
1283
|
const classPattern = /^(export\s+)?(abstract\s+)?class\s+\w+/m;
|
|
1257
1284
|
const functionComponentPattern = /^(export\s+)?(default\s+)?function\s+[A-Z]\w*\s*\(/m;
|
|
1258
1285
|
const arrowComponentPattern = /^(export\s+)?(const|let)\s+[A-Z]\w*\s*=.*=>/m;
|
|
1259
1286
|
return classPattern.test(content) || functionComponentPattern.test(content) || arrowComponentPattern.test(content);
|
|
1260
1287
|
}
|
|
1288
|
+
function hasMatchingTypeExport(content, nameWithoutExt) {
|
|
1289
|
+
const typePattern = new RegExp(
|
|
1290
|
+
`^export\\s+type\\s+${nameWithoutExt}\\b`,
|
|
1291
|
+
"m"
|
|
1292
|
+
);
|
|
1293
|
+
const interfacePattern = new RegExp(
|
|
1294
|
+
`^export\\s+interface\\s+${nameWithoutExt}\\b`,
|
|
1295
|
+
"m"
|
|
1296
|
+
);
|
|
1297
|
+
return typePattern.test(content) || interfacePattern.test(content);
|
|
1298
|
+
}
|
|
1299
|
+
function suggestName(fileName) {
|
|
1300
|
+
const nameWithoutExt = fileName.replace(/\.(ts|tsx)$/, "");
|
|
1301
|
+
const ext = fileName.slice(nameWithoutExt.length);
|
|
1302
|
+
if (/^[A-Z][A-Z0-9]*(_[A-Z0-9]+)+$/.test(nameWithoutExt)) {
|
|
1303
|
+
const camel = nameWithoutExt.toLowerCase().replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
1304
|
+
return `${camel}${ext}`;
|
|
1305
|
+
}
|
|
1306
|
+
return `${nameWithoutExt.charAt(0).toLowerCase()}${nameWithoutExt.slice(1)}${ext}`;
|
|
1307
|
+
}
|
|
1261
1308
|
function checkFileNames() {
|
|
1262
1309
|
const sourceFiles = findSourceFiles("src");
|
|
1263
1310
|
const violations = [];
|
|
1264
1311
|
for (const filePath of sourceFiles) {
|
|
1265
|
-
const fileName =
|
|
1312
|
+
const fileName = path13.basename(filePath);
|
|
1266
1313
|
const nameWithoutExt = fileName.replace(/\.(ts|tsx)$/, "");
|
|
1314
|
+
if (/\.(stories|test)\.(ts|tsx)$/.test(fileName)) continue;
|
|
1267
1315
|
if (/^[A-Z]/.test(nameWithoutExt)) {
|
|
1268
1316
|
const content = fs6.readFileSync(filePath, "utf-8");
|
|
1269
|
-
if (!hasClassOrComponent(content)) {
|
|
1270
|
-
violations.push({
|
|
1317
|
+
if (!hasClassOrComponent(content) && !hasMatchingTypeExport(content, nameWithoutExt)) {
|
|
1318
|
+
violations.push({
|
|
1319
|
+
filePath,
|
|
1320
|
+
fileName,
|
|
1321
|
+
suggestedName: suggestName(fileName)
|
|
1322
|
+
});
|
|
1271
1323
|
}
|
|
1272
1324
|
}
|
|
1273
1325
|
}
|
|
1274
1326
|
return violations;
|
|
1275
1327
|
}
|
|
1276
|
-
|
|
1328
|
+
|
|
1329
|
+
// src/commands/lint/lint/fixFileNameViolations.ts
|
|
1330
|
+
import chalk19 from "chalk";
|
|
1331
|
+
|
|
1332
|
+
// src/commands/lint/lint/applyMoves.ts
|
|
1333
|
+
import fs7 from "fs";
|
|
1334
|
+
import path15 from "path";
|
|
1335
|
+
|
|
1336
|
+
// src/commands/lint/lint/renameExports.ts
|
|
1337
|
+
import path14 from "path";
|
|
1338
|
+
import { SyntaxKind } from "ts-morph";
|
|
1339
|
+
function nameWithoutExtension(filePath) {
|
|
1340
|
+
return path14.basename(filePath).replace(/\.(ts|tsx)$/, "");
|
|
1341
|
+
}
|
|
1342
|
+
function renameExports(project, absSource, absDest) {
|
|
1343
|
+
const oldName = nameWithoutExtension(absSource);
|
|
1344
|
+
const newName = nameWithoutExtension(absDest);
|
|
1345
|
+
const sourceFile = project.getSourceFile(absSource);
|
|
1346
|
+
if (!sourceFile) return [];
|
|
1347
|
+
const renamed = [];
|
|
1348
|
+
for (const [, declarations] of sourceFile.getExportedDeclarations()) {
|
|
1349
|
+
for (const decl of declarations) {
|
|
1350
|
+
const kind = decl.getKind();
|
|
1351
|
+
if (kind === SyntaxKind.TypeAliasDeclaration || kind === SyntaxKind.InterfaceDeclaration) {
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
const nameNode = decl.getFirstChildByKind(SyntaxKind.Identifier);
|
|
1355
|
+
if (!nameNode || nameNode.getText() !== oldName) continue;
|
|
1356
|
+
nameNode.rename(newName);
|
|
1357
|
+
renamed.push(`${oldName} \u2192 ${newName}`);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
return renamed;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// src/commands/lint/lint/applyMoves.ts
|
|
1364
|
+
function isCaseOnly(a, b) {
|
|
1365
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
1366
|
+
}
|
|
1367
|
+
function moveCaseInsensitive(absSource, absDest) {
|
|
1368
|
+
const tmp = `${absSource}.tmp`;
|
|
1369
|
+
fs7.renameSync(absSource, tmp);
|
|
1370
|
+
fs7.renameSync(tmp, absDest);
|
|
1371
|
+
}
|
|
1372
|
+
function applyMoves(project, moves, cwd, emit) {
|
|
1373
|
+
for (const { sourcePath, destPath } of moves) {
|
|
1374
|
+
const start3 = performance.now();
|
|
1375
|
+
const absSource = path15.resolve(sourcePath);
|
|
1376
|
+
const absDest = path15.resolve(destPath);
|
|
1377
|
+
for (const r of renameExports(project, absSource, absDest)) {
|
|
1378
|
+
emit(` Renamed export ${r} in ${sourcePath}`);
|
|
1379
|
+
}
|
|
1380
|
+
const sourceFile = project.getSourceFile(absSource);
|
|
1381
|
+
if (sourceFile) sourceFile.move(absDest);
|
|
1382
|
+
const ms = (performance.now() - start3).toFixed(0);
|
|
1383
|
+
const rel = `${path15.relative(cwd, absSource)} \u2192 ${path15.relative(cwd, absDest)}`;
|
|
1384
|
+
emit(` Renamed ${rel} (${ms}ms)`);
|
|
1385
|
+
}
|
|
1386
|
+
project.saveSync();
|
|
1387
|
+
for (const { sourcePath, destPath } of moves) {
|
|
1388
|
+
const absSource = path15.resolve(sourcePath);
|
|
1389
|
+
const absDest = path15.resolve(destPath);
|
|
1390
|
+
if (isCaseOnly(absSource, absDest) && fs7.existsSync(absSource)) {
|
|
1391
|
+
moveCaseInsensitive(absSource, absDest);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
// src/commands/lint/lint/createLintProject.ts
|
|
1397
|
+
import fs8 from "fs";
|
|
1398
|
+
import path16 from "path";
|
|
1399
|
+
import { Project } from "ts-morph";
|
|
1400
|
+
function createLintProject() {
|
|
1401
|
+
const tsConfigPath = path16.resolve("tsconfig.json");
|
|
1402
|
+
const project = fs8.existsSync(tsConfigPath) ? new Project({
|
|
1403
|
+
tsConfigFilePath: tsConfigPath,
|
|
1404
|
+
skipAddingFilesFromTsConfig: true
|
|
1405
|
+
}) : new Project();
|
|
1406
|
+
project.addSourceFilesAtPaths("src/**/*.{ts,tsx}");
|
|
1407
|
+
return project;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// src/commands/lint/lint/fixFileNameViolations.ts
|
|
1411
|
+
function fixFileNameViolations(moves) {
|
|
1412
|
+
const start3 = performance.now();
|
|
1413
|
+
const project = createLintProject();
|
|
1414
|
+
const cwd = process.cwd();
|
|
1415
|
+
applyMoves(project, moves, cwd, (line) => console.log(chalk19.green(line)));
|
|
1416
|
+
const ms = (performance.now() - start3).toFixed(0);
|
|
1417
|
+
console.log(chalk19.dim(` Done in ${ms}ms`));
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// src/commands/lint/lint/runFileNameCheck.ts
|
|
1421
|
+
function reportViolations(violations) {
|
|
1422
|
+
console.error(chalk20.red("\nFile name check failed:\n"));
|
|
1423
|
+
console.error(
|
|
1424
|
+
chalk20.red(
|
|
1425
|
+
" Files without classes or React components should not start with a capital letter.\n"
|
|
1426
|
+
)
|
|
1427
|
+
);
|
|
1428
|
+
for (const violation of violations) {
|
|
1429
|
+
console.error(chalk20.red(` ${violation.filePath}`));
|
|
1430
|
+
console.error(chalk20.gray(` Rename to: ${violation.suggestedName}
|
|
1431
|
+
`));
|
|
1432
|
+
}
|
|
1433
|
+
console.error(chalk20.dim(" Run with -f to auto-fix.\n"));
|
|
1434
|
+
}
|
|
1435
|
+
function runFileNameCheck(fix = false) {
|
|
1277
1436
|
const violations = checkFileNames();
|
|
1278
|
-
if (violations.length
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
" Files without classes or React components should not start with a capital letter.\n"
|
|
1283
|
-
)
|
|
1284
|
-
);
|
|
1285
|
-
for (const violation of violations) {
|
|
1286
|
-
console.error(chalk18.red(` ${violation.filePath}`));
|
|
1287
|
-
console.error(
|
|
1288
|
-
chalk18.gray(
|
|
1289
|
-
` Rename to: ${violation.fileName.charAt(0).toLowerCase()}${violation.fileName.slice(1)}
|
|
1290
|
-
`
|
|
1291
|
-
)
|
|
1437
|
+
if (violations.length === 0) {
|
|
1438
|
+
if (!process.env.CLAUDECODE) {
|
|
1439
|
+
console.log(
|
|
1440
|
+
"File name check passed. All PascalCase files contain classes or components."
|
|
1292
1441
|
);
|
|
1293
1442
|
}
|
|
1294
|
-
return
|
|
1443
|
+
return true;
|
|
1295
1444
|
}
|
|
1296
|
-
if (!
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
);
|
|
1445
|
+
if (!fix) {
|
|
1446
|
+
reportViolations(violations);
|
|
1447
|
+
return false;
|
|
1300
1448
|
}
|
|
1449
|
+
fixFileNameViolations(
|
|
1450
|
+
violations.map((v) => ({
|
|
1451
|
+
sourcePath: v.filePath,
|
|
1452
|
+
destPath: path17.join(path17.dirname(v.filePath), v.suggestedName)
|
|
1453
|
+
}))
|
|
1454
|
+
);
|
|
1301
1455
|
return true;
|
|
1302
1456
|
}
|
|
1303
1457
|
|
|
1304
1458
|
// src/commands/lint/lint/runImportExtensionCheck.ts
|
|
1305
|
-
import
|
|
1459
|
+
import fs9 from "fs";
|
|
1306
1460
|
|
|
1307
1461
|
// src/commands/lint/shared.ts
|
|
1308
|
-
import
|
|
1309
|
-
function
|
|
1462
|
+
import chalk21 from "chalk";
|
|
1463
|
+
function reportViolations2(violations, checkName, errorMessage, successMessage) {
|
|
1310
1464
|
if (violations.length > 0) {
|
|
1311
|
-
console.error(
|
|
1465
|
+
console.error(chalk21.red(`
|
|
1312
1466
|
${checkName} failed:
|
|
1313
1467
|
`));
|
|
1314
|
-
console.error(
|
|
1468
|
+
console.error(chalk21.red(` ${errorMessage}
|
|
1315
1469
|
`));
|
|
1316
1470
|
for (const violation of violations) {
|
|
1317
|
-
console.error(
|
|
1318
|
-
console.error(
|
|
1471
|
+
console.error(chalk21.red(` ${violation.filePath}:${violation.line}`));
|
|
1472
|
+
console.error(chalk21.gray(` ${violation.content}
|
|
1319
1473
|
`));
|
|
1320
1474
|
}
|
|
1321
1475
|
return false;
|
|
@@ -1328,7 +1482,7 @@ ${checkName} failed:
|
|
|
1328
1482
|
|
|
1329
1483
|
// src/commands/lint/lint/runImportExtensionCheck.ts
|
|
1330
1484
|
function checkForImportExtensions(filePath) {
|
|
1331
|
-
const content =
|
|
1485
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
1332
1486
|
const lines = content.split("\n");
|
|
1333
1487
|
const violations = [];
|
|
1334
1488
|
const importExtensionPattern = /from\s+["']\..*\.(js|ts)["']/;
|
|
@@ -1353,7 +1507,7 @@ function checkImportExtensions() {
|
|
|
1353
1507
|
return violations;
|
|
1354
1508
|
}
|
|
1355
1509
|
function runImportExtensionCheck() {
|
|
1356
|
-
return
|
|
1510
|
+
return reportViolations2(
|
|
1357
1511
|
checkImportExtensions(),
|
|
1358
1512
|
"Import extension check",
|
|
1359
1513
|
"File extensions in imports are not allowed. Use extensionless imports instead.",
|
|
@@ -1362,9 +1516,9 @@ function runImportExtensionCheck() {
|
|
|
1362
1516
|
}
|
|
1363
1517
|
|
|
1364
1518
|
// src/commands/lint/lint/runStaticImportCheck.ts
|
|
1365
|
-
import
|
|
1519
|
+
import fs10 from "fs";
|
|
1366
1520
|
function checkForDynamicImports(filePath) {
|
|
1367
|
-
const content =
|
|
1521
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1368
1522
|
const lines = content.split("\n");
|
|
1369
1523
|
const violations = [];
|
|
1370
1524
|
const requirePattern = /\brequire\s*\(/;
|
|
@@ -1390,7 +1544,7 @@ function checkStaticImports() {
|
|
|
1390
1544
|
return violations;
|
|
1391
1545
|
}
|
|
1392
1546
|
function runStaticImportCheck() {
|
|
1393
|
-
return
|
|
1547
|
+
return reportViolations2(
|
|
1394
1548
|
checkStaticImports(),
|
|
1395
1549
|
"Static import check",
|
|
1396
1550
|
"Dynamic imports are not allowed. Use static imports instead.",
|
|
@@ -1399,8 +1553,8 @@ function runStaticImportCheck() {
|
|
|
1399
1553
|
}
|
|
1400
1554
|
|
|
1401
1555
|
// src/commands/lint/lint/index.ts
|
|
1402
|
-
function lint() {
|
|
1403
|
-
const fileNamePassed = runFileNameCheck();
|
|
1556
|
+
function lint(options2 = {}) {
|
|
1557
|
+
const fileNamePassed = runFileNameCheck(options2.fix);
|
|
1404
1558
|
const staticImportPassed = runStaticImportCheck();
|
|
1405
1559
|
const importExtensionPassed = runImportExtensionCheck();
|
|
1406
1560
|
if (!fileNamePassed || !staticImportPassed || !importExtensionPassed) {
|
|
@@ -1457,7 +1611,7 @@ Total: ${lines.length} hardcoded color(s)`);
|
|
|
1457
1611
|
}
|
|
1458
1612
|
|
|
1459
1613
|
// src/commands/verify/run/resolveEntries.ts
|
|
1460
|
-
import * as
|
|
1614
|
+
import * as path18 from "path";
|
|
1461
1615
|
function buildFullCommand(command, args) {
|
|
1462
1616
|
return [shellQuote(command), ...(args ?? []).map(shellQuote)].join(" ");
|
|
1463
1617
|
}
|
|
@@ -1474,7 +1628,7 @@ function getRunEntries() {
|
|
|
1474
1628
|
function getPackageJsonEntries() {
|
|
1475
1629
|
const result = findPackageJsonWithVerifyScripts(process.cwd());
|
|
1476
1630
|
if (!result) return [];
|
|
1477
|
-
const cwd =
|
|
1631
|
+
const cwd = path18.dirname(result.packageJsonPath);
|
|
1478
1632
|
return result.verifyScripts.map((script) => ({
|
|
1479
1633
|
name: script,
|
|
1480
1634
|
fullCommand: `npm run ${script}`,
|
|
@@ -1795,16 +1949,16 @@ import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSyn
|
|
|
1795
1949
|
|
|
1796
1950
|
// src/commands/deploy/init/index.ts
|
|
1797
1951
|
import { execSync as execSync11 } from "child_process";
|
|
1798
|
-
import
|
|
1952
|
+
import chalk23 from "chalk";
|
|
1799
1953
|
import enquirer3 from "enquirer";
|
|
1800
1954
|
|
|
1801
1955
|
// src/commands/deploy/init/updateWorkflow.ts
|
|
1802
1956
|
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
1803
|
-
import { dirname as
|
|
1957
|
+
import { dirname as dirname11, join as join7 } from "path";
|
|
1804
1958
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1805
|
-
import
|
|
1959
|
+
import chalk22 from "chalk";
|
|
1806
1960
|
var WORKFLOW_PATH = ".github/workflows/build.yml";
|
|
1807
|
-
var __dirname3 =
|
|
1961
|
+
var __dirname3 = dirname11(fileURLToPath2(import.meta.url));
|
|
1808
1962
|
function getExistingSiteId() {
|
|
1809
1963
|
if (!existsSync10(WORKFLOW_PATH)) {
|
|
1810
1964
|
return null;
|
|
@@ -1827,20 +1981,20 @@ async function updateWorkflow(siteId) {
|
|
|
1827
1981
|
if (existsSync10(WORKFLOW_PATH)) {
|
|
1828
1982
|
const oldContent = readFileSync8(WORKFLOW_PATH, "utf-8");
|
|
1829
1983
|
if (oldContent === newContent) {
|
|
1830
|
-
console.log(
|
|
1984
|
+
console.log(chalk22.green("build.yml is already up to date"));
|
|
1831
1985
|
return;
|
|
1832
1986
|
}
|
|
1833
|
-
console.log(
|
|
1987
|
+
console.log(chalk22.yellow("\nbuild.yml will be updated:"));
|
|
1834
1988
|
console.log();
|
|
1835
1989
|
printDiff(oldContent, newContent);
|
|
1836
|
-
const confirm = await promptConfirm(
|
|
1990
|
+
const confirm = await promptConfirm(chalk22.red("Update build.yml?"));
|
|
1837
1991
|
if (!confirm) {
|
|
1838
1992
|
console.log("Skipped build.yml update");
|
|
1839
1993
|
return;
|
|
1840
1994
|
}
|
|
1841
1995
|
}
|
|
1842
1996
|
writeFileSync8(WORKFLOW_PATH, newContent);
|
|
1843
|
-
console.log(
|
|
1997
|
+
console.log(chalk22.green(`
|
|
1844
1998
|
Created ${WORKFLOW_PATH}`));
|
|
1845
1999
|
}
|
|
1846
2000
|
|
|
@@ -1851,43 +2005,43 @@ async function ensureNetlifyCli() {
|
|
|
1851
2005
|
} catch (error) {
|
|
1852
2006
|
if (!(error instanceof Error) || !error.message.includes("command not found"))
|
|
1853
2007
|
throw error;
|
|
1854
|
-
console.error(
|
|
2008
|
+
console.error(chalk23.red("\nNetlify CLI is not installed.\n"));
|
|
1855
2009
|
const install = await promptConfirm("Would you like to install it now?");
|
|
1856
2010
|
if (!install) {
|
|
1857
2011
|
console.log(
|
|
1858
|
-
|
|
2012
|
+
chalk23.yellow(
|
|
1859
2013
|
"\nInstall it manually with: npm install -g netlify-cli\n"
|
|
1860
2014
|
)
|
|
1861
2015
|
);
|
|
1862
2016
|
process.exit(1);
|
|
1863
2017
|
}
|
|
1864
|
-
console.log(
|
|
2018
|
+
console.log(chalk23.dim("\nInstalling netlify-cli...\n"));
|
|
1865
2019
|
execSync11("npm install -g netlify-cli", { stdio: "inherit" });
|
|
1866
2020
|
console.log();
|
|
1867
2021
|
execSync11("netlify sites:create --disable-linking", { stdio: "inherit" });
|
|
1868
2022
|
}
|
|
1869
2023
|
}
|
|
1870
2024
|
function printSetupInstructions() {
|
|
1871
|
-
console.log(
|
|
2025
|
+
console.log(chalk23.bold("\nDeployment initialized successfully!"));
|
|
1872
2026
|
console.log(
|
|
1873
|
-
|
|
2027
|
+
chalk23.yellow("\nTo complete setup, create a personal access token at:")
|
|
1874
2028
|
);
|
|
1875
2029
|
console.log(
|
|
1876
|
-
|
|
2030
|
+
chalk23.cyan(
|
|
1877
2031
|
"https://app.netlify.com/user/applications#personal-access-tokens"
|
|
1878
2032
|
)
|
|
1879
2033
|
);
|
|
1880
2034
|
console.log(
|
|
1881
|
-
|
|
2035
|
+
chalk23.yellow(
|
|
1882
2036
|
"\nThen add it as NETLIFY_AUTH_TOKEN in your GitHub repository secrets."
|
|
1883
2037
|
)
|
|
1884
2038
|
);
|
|
1885
2039
|
}
|
|
1886
2040
|
async function init5() {
|
|
1887
|
-
console.log(
|
|
2041
|
+
console.log(chalk23.bold("Initializing Netlify deployment...\n"));
|
|
1888
2042
|
const existingSiteId = getExistingSiteId();
|
|
1889
2043
|
if (existingSiteId) {
|
|
1890
|
-
console.log(
|
|
2044
|
+
console.log(chalk23.dim(`Using existing site ID: ${existingSiteId}
|
|
1891
2045
|
`));
|
|
1892
2046
|
await updateWorkflow(existingSiteId);
|
|
1893
2047
|
return;
|
|
@@ -1981,19 +2135,19 @@ function detectPlatform() {
|
|
|
1981
2135
|
|
|
1982
2136
|
// src/commands/notify/showNotification/showWindowsNotificationFromWsl.ts
|
|
1983
2137
|
import { spawn as spawn2 } from "child_process";
|
|
1984
|
-
import
|
|
2138
|
+
import fs11 from "fs";
|
|
1985
2139
|
import { createRequire } from "module";
|
|
1986
|
-
import
|
|
2140
|
+
import path19 from "path";
|
|
1987
2141
|
var require2 = createRequire(import.meta.url);
|
|
1988
2142
|
function getSnoreToastPath() {
|
|
1989
|
-
const notifierPath =
|
|
1990
|
-
return
|
|
2143
|
+
const notifierPath = path19.dirname(require2.resolve("node-notifier"));
|
|
2144
|
+
return path19.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
|
|
1991
2145
|
}
|
|
1992
2146
|
function showWindowsNotificationFromWsl(options2) {
|
|
1993
2147
|
const { title, message, sound } = options2;
|
|
1994
2148
|
const snoreToastPath = getSnoreToastPath();
|
|
1995
2149
|
try {
|
|
1996
|
-
|
|
2150
|
+
fs11.chmodSync(snoreToastPath, 493);
|
|
1997
2151
|
} catch {
|
|
1998
2152
|
}
|
|
1999
2153
|
const args = ["-t", title, "-m", message];
|
|
@@ -2067,12 +2221,12 @@ async function notify() {
|
|
|
2067
2221
|
|
|
2068
2222
|
// src/commands/backlog/add/index.ts
|
|
2069
2223
|
import { existsSync as existsSync13 } from "fs";
|
|
2070
|
-
import
|
|
2224
|
+
import chalk25 from "chalk";
|
|
2071
2225
|
|
|
2072
2226
|
// src/commands/backlog/shared.ts
|
|
2073
2227
|
import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
2074
2228
|
import { join as join8 } from "path";
|
|
2075
|
-
import
|
|
2229
|
+
import chalk24 from "chalk";
|
|
2076
2230
|
import { parse as parseYaml2, stringify as stringifyYaml3 } from "yaml";
|
|
2077
2231
|
|
|
2078
2232
|
// src/commands/backlog/types.ts
|
|
@@ -2116,7 +2270,7 @@ function findItem(items, id) {
|
|
|
2116
2270
|
function loadAndFindItem(id) {
|
|
2117
2271
|
if (!existsSync12(getBacklogPath())) {
|
|
2118
2272
|
console.log(
|
|
2119
|
-
|
|
2273
|
+
chalk24.yellow(
|
|
2120
2274
|
"No backlog found. Run 'assist backlog init' to create one."
|
|
2121
2275
|
)
|
|
2122
2276
|
);
|
|
@@ -2125,7 +2279,7 @@ function loadAndFindItem(id) {
|
|
|
2125
2279
|
const items = loadBacklog();
|
|
2126
2280
|
const item = findItem(items, Number.parseInt(id, 10));
|
|
2127
2281
|
if (!item) {
|
|
2128
|
-
console.log(
|
|
2282
|
+
console.log(chalk24.red(`Item #${id} not found.`));
|
|
2129
2283
|
return void 0;
|
|
2130
2284
|
}
|
|
2131
2285
|
return { items, item };
|
|
@@ -2223,7 +2377,7 @@ async function add() {
|
|
|
2223
2377
|
const backlogPath = getBacklogPath();
|
|
2224
2378
|
if (!existsSync13(backlogPath)) {
|
|
2225
2379
|
console.log(
|
|
2226
|
-
|
|
2380
|
+
chalk25.yellow(
|
|
2227
2381
|
"No backlog found. Run 'assist backlog init' to create one."
|
|
2228
2382
|
)
|
|
2229
2383
|
);
|
|
@@ -2244,67 +2398,67 @@ async function add() {
|
|
|
2244
2398
|
status: "todo"
|
|
2245
2399
|
});
|
|
2246
2400
|
saveBacklog(items);
|
|
2247
|
-
console.log(
|
|
2401
|
+
console.log(chalk25.green(`Added item #${id}: ${name}`));
|
|
2248
2402
|
}
|
|
2249
2403
|
|
|
2250
2404
|
// src/commands/backlog/delete/index.ts
|
|
2251
|
-
import
|
|
2405
|
+
import chalk26 from "chalk";
|
|
2252
2406
|
async function del(id) {
|
|
2253
2407
|
const name = removeItem(id);
|
|
2254
2408
|
if (name) {
|
|
2255
|
-
console.log(
|
|
2409
|
+
console.log(chalk26.green(`Deleted item #${id}: ${name}`));
|
|
2256
2410
|
}
|
|
2257
2411
|
}
|
|
2258
2412
|
|
|
2259
2413
|
// src/commands/backlog/done/index.ts
|
|
2260
|
-
import
|
|
2414
|
+
import chalk27 from "chalk";
|
|
2261
2415
|
async function done(id) {
|
|
2262
2416
|
const name = setStatus(id, "done");
|
|
2263
2417
|
if (name) {
|
|
2264
|
-
console.log(
|
|
2418
|
+
console.log(chalk27.green(`Completed item #${id}: ${name}`));
|
|
2265
2419
|
}
|
|
2266
2420
|
}
|
|
2267
2421
|
|
|
2268
2422
|
// src/commands/backlog/init/index.ts
|
|
2269
2423
|
import { existsSync as existsSync14 } from "fs";
|
|
2270
|
-
import
|
|
2424
|
+
import chalk28 from "chalk";
|
|
2271
2425
|
async function init6() {
|
|
2272
2426
|
const backlogPath = getBacklogPath();
|
|
2273
2427
|
if (existsSync14(backlogPath)) {
|
|
2274
|
-
console.log(
|
|
2428
|
+
console.log(chalk28.yellow("assist.backlog.yml already exists."));
|
|
2275
2429
|
return;
|
|
2276
2430
|
}
|
|
2277
2431
|
saveBacklog([]);
|
|
2278
|
-
console.log(
|
|
2432
|
+
console.log(chalk28.green("Created assist.backlog.yml"));
|
|
2279
2433
|
}
|
|
2280
2434
|
|
|
2281
2435
|
// src/commands/backlog/list/index.ts
|
|
2282
2436
|
import { existsSync as existsSync15 } from "fs";
|
|
2283
|
-
import
|
|
2437
|
+
import chalk29 from "chalk";
|
|
2284
2438
|
function statusIcon(status2) {
|
|
2285
2439
|
switch (status2) {
|
|
2286
2440
|
case "todo":
|
|
2287
|
-
return
|
|
2441
|
+
return chalk29.dim("[ ]");
|
|
2288
2442
|
case "in-progress":
|
|
2289
|
-
return
|
|
2443
|
+
return chalk29.yellow("[~]");
|
|
2290
2444
|
case "done":
|
|
2291
|
-
return
|
|
2445
|
+
return chalk29.green("[x]");
|
|
2292
2446
|
}
|
|
2293
2447
|
}
|
|
2294
2448
|
function typeLabel(type) {
|
|
2295
2449
|
switch (type) {
|
|
2296
2450
|
case "bug":
|
|
2297
|
-
return
|
|
2451
|
+
return chalk29.magenta("Bug");
|
|
2298
2452
|
case "story":
|
|
2299
|
-
return
|
|
2453
|
+
return chalk29.cyan("Story");
|
|
2300
2454
|
}
|
|
2301
2455
|
}
|
|
2302
2456
|
function printVerboseDetails(item) {
|
|
2303
2457
|
if (item.description) {
|
|
2304
|
-
console.log(` ${
|
|
2458
|
+
console.log(` ${chalk29.dim("Description:")} ${item.description}`);
|
|
2305
2459
|
}
|
|
2306
2460
|
if (item.acceptanceCriteria.length > 0) {
|
|
2307
|
-
console.log(` ${
|
|
2461
|
+
console.log(` ${chalk29.dim("Acceptance criteria:")}`);
|
|
2308
2462
|
for (const criterion of item.acceptanceCriteria) {
|
|
2309
2463
|
console.log(` - ${criterion}`);
|
|
2310
2464
|
}
|
|
@@ -2320,7 +2474,7 @@ async function list2(options2) {
|
|
|
2320
2474
|
const backlogPath = getBacklogPath();
|
|
2321
2475
|
if (!existsSync15(backlogPath)) {
|
|
2322
2476
|
console.log(
|
|
2323
|
-
|
|
2477
|
+
chalk29.yellow(
|
|
2324
2478
|
"No backlog found. Run 'assist backlog init' to create one."
|
|
2325
2479
|
)
|
|
2326
2480
|
);
|
|
@@ -2328,12 +2482,12 @@ async function list2(options2) {
|
|
|
2328
2482
|
}
|
|
2329
2483
|
const items = filterItems(loadBacklog(), options2);
|
|
2330
2484
|
if (items.length === 0) {
|
|
2331
|
-
console.log(
|
|
2485
|
+
console.log(chalk29.dim("Backlog is empty."));
|
|
2332
2486
|
return;
|
|
2333
2487
|
}
|
|
2334
2488
|
for (const item of items) {
|
|
2335
2489
|
console.log(
|
|
2336
|
-
`${statusIcon(item.status)} ${typeLabel(item.type)} ${
|
|
2490
|
+
`${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk29.dim(`#${item.id}`)} ${item.name}`
|
|
2337
2491
|
);
|
|
2338
2492
|
if (options2.verbose) {
|
|
2339
2493
|
printVerboseDetails(item);
|
|
@@ -2342,11 +2496,11 @@ async function list2(options2) {
|
|
|
2342
2496
|
}
|
|
2343
2497
|
|
|
2344
2498
|
// src/commands/backlog/start/index.ts
|
|
2345
|
-
import
|
|
2499
|
+
import chalk30 from "chalk";
|
|
2346
2500
|
async function start(id) {
|
|
2347
2501
|
const name = setStatus(id, "in-progress");
|
|
2348
2502
|
if (name) {
|
|
2349
|
-
console.log(
|
|
2503
|
+
console.log(chalk30.green(`Started item #${id}: ${name}`));
|
|
2350
2504
|
}
|
|
2351
2505
|
}
|
|
2352
2506
|
|
|
@@ -2356,15 +2510,15 @@ import { readFileSync as readFileSync12 } from "fs";
|
|
|
2356
2510
|
import {
|
|
2357
2511
|
createServer
|
|
2358
2512
|
} from "http";
|
|
2359
|
-
import { dirname as
|
|
2513
|
+
import { dirname as dirname12, join as join10 } from "path";
|
|
2360
2514
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2361
|
-
import
|
|
2515
|
+
import chalk31 from "chalk";
|
|
2362
2516
|
function respondJson(res, status2, data) {
|
|
2363
2517
|
res.writeHead(status2, { "Content-Type": "application/json" });
|
|
2364
2518
|
res.end(JSON.stringify(data));
|
|
2365
2519
|
}
|
|
2366
2520
|
function createBundleHandler(importMetaUrl, bundlePath) {
|
|
2367
|
-
const dir =
|
|
2521
|
+
const dir = dirname12(fileURLToPath3(importMetaUrl));
|
|
2368
2522
|
let cache;
|
|
2369
2523
|
return (_req, res) => {
|
|
2370
2524
|
if (!cache) {
|
|
@@ -2402,8 +2556,8 @@ function startWebServer(label2, port, handler) {
|
|
|
2402
2556
|
handler(req, res, port);
|
|
2403
2557
|
});
|
|
2404
2558
|
server.listen(port, () => {
|
|
2405
|
-
console.log(
|
|
2406
|
-
console.log(
|
|
2559
|
+
console.log(chalk31.green(`${label2}: ${url}`));
|
|
2560
|
+
console.log(chalk31.dim("Press Ctrl+C to stop"));
|
|
2407
2561
|
exec(`open ${url}`);
|
|
2408
2562
|
});
|
|
2409
2563
|
}
|
|
@@ -2633,22 +2787,22 @@ function extractGraphqlQuery(args) {
|
|
|
2633
2787
|
|
|
2634
2788
|
// src/shared/loadCliReads.ts
|
|
2635
2789
|
import { existsSync as existsSync16, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
|
|
2636
|
-
import { dirname as
|
|
2790
|
+
import { dirname as dirname13, resolve as resolve2 } from "path";
|
|
2637
2791
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2638
2792
|
var __filename2 = fileURLToPath4(import.meta.url);
|
|
2639
|
-
var __dirname4 =
|
|
2793
|
+
var __dirname4 = dirname13(__filename2);
|
|
2640
2794
|
function getCliReadsPath() {
|
|
2641
2795
|
return resolve2(__dirname4, "..", "assist.cli-reads");
|
|
2642
2796
|
}
|
|
2643
2797
|
var cachedLines;
|
|
2644
2798
|
function getCliReadsLines() {
|
|
2645
2799
|
if (cachedLines) return cachedLines;
|
|
2646
|
-
const
|
|
2647
|
-
if (!existsSync16(
|
|
2800
|
+
const path43 = getCliReadsPath();
|
|
2801
|
+
if (!existsSync16(path43)) {
|
|
2648
2802
|
cachedLines = [];
|
|
2649
2803
|
return cachedLines;
|
|
2650
2804
|
}
|
|
2651
|
-
cachedLines = readFileSync13(
|
|
2805
|
+
cachedLines = readFileSync13(path43, "utf-8").split("\n").filter((line) => line.trim() !== "");
|
|
2652
2806
|
return cachedLines;
|
|
2653
2807
|
}
|
|
2654
2808
|
function loadCliReads() {
|
|
@@ -2854,10 +3008,10 @@ import { join as join12 } from "path";
|
|
|
2854
3008
|
|
|
2855
3009
|
// src/shared/getInstallDir.ts
|
|
2856
3010
|
import { execSync as execSync13 } from "child_process";
|
|
2857
|
-
import { dirname as
|
|
3011
|
+
import { dirname as dirname14, resolve as resolve4 } from "path";
|
|
2858
3012
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
2859
3013
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
2860
|
-
var __dirname5 =
|
|
3014
|
+
var __dirname5 = dirname14(__filename3);
|
|
2861
3015
|
function getInstallDir() {
|
|
2862
3016
|
return resolve4(__dirname5, "..");
|
|
2863
3017
|
}
|
|
@@ -2894,11 +3048,11 @@ function assertCliExists(cli) {
|
|
|
2894
3048
|
}
|
|
2895
3049
|
|
|
2896
3050
|
// src/commands/permitCliReads/colorize.ts
|
|
2897
|
-
import
|
|
3051
|
+
import chalk32 from "chalk";
|
|
2898
3052
|
function colorize(plainOutput) {
|
|
2899
3053
|
return plainOutput.split("\n").map((line) => {
|
|
2900
|
-
if (line.startsWith(" R ")) return
|
|
2901
|
-
if (line.startsWith(" W ")) return
|
|
3054
|
+
if (line.startsWith(" R ")) return chalk32.green(line);
|
|
3055
|
+
if (line.startsWith(" W ")) return chalk32.red(line);
|
|
2902
3056
|
return line;
|
|
2903
3057
|
}).join("\n");
|
|
2904
3058
|
}
|
|
@@ -3000,14 +3154,14 @@ function showProgress(p, label2) {
|
|
|
3000
3154
|
const pct = Math.round(p.done / p.total * 100);
|
|
3001
3155
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
3002
3156
|
}
|
|
3003
|
-
async function resolveCommand(cli,
|
|
3004
|
-
showProgress(p,
|
|
3005
|
-
const subHelp = await runHelp([cli, ...
|
|
3157
|
+
async function resolveCommand(cli, path43, description, depth, p) {
|
|
3158
|
+
showProgress(p, path43.join(" "));
|
|
3159
|
+
const subHelp = await runHelp([cli, ...path43]);
|
|
3006
3160
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
3007
|
-
return [{ path:
|
|
3161
|
+
return [{ path: path43, description }];
|
|
3008
3162
|
}
|
|
3009
|
-
const children = await discoverAt(cli,
|
|
3010
|
-
return children.length > 0 ? children : [{ path:
|
|
3163
|
+
const children = await discoverAt(cli, path43, depth + 1, p);
|
|
3164
|
+
return children.length > 0 ? children : [{ path: path43, description }];
|
|
3011
3165
|
}
|
|
3012
3166
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
3013
3167
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -3155,9 +3309,9 @@ function logPath(cli) {
|
|
|
3155
3309
|
return join12(homedir4(), ".assist", `cli-discover-${safeName}.log`);
|
|
3156
3310
|
}
|
|
3157
3311
|
function readCache(cli) {
|
|
3158
|
-
const
|
|
3159
|
-
if (!existsSync18(
|
|
3160
|
-
return readFileSync15(
|
|
3312
|
+
const path43 = logPath(cli);
|
|
3313
|
+
if (!existsSync18(path43)) return void 0;
|
|
3314
|
+
return readFileSync15(path43, "utf-8");
|
|
3161
3315
|
}
|
|
3162
3316
|
function writeCache(cli, output) {
|
|
3163
3317
|
const dir = join12(homedir4(), ".assist");
|
|
@@ -3209,20 +3363,20 @@ function registerCliHook(program2) {
|
|
|
3209
3363
|
}
|
|
3210
3364
|
|
|
3211
3365
|
// src/commands/complexity/analyze.ts
|
|
3212
|
-
import
|
|
3366
|
+
import chalk38 from "chalk";
|
|
3213
3367
|
|
|
3214
3368
|
// src/commands/complexity/cyclomatic.ts
|
|
3215
|
-
import
|
|
3369
|
+
import chalk34 from "chalk";
|
|
3216
3370
|
|
|
3217
3371
|
// src/commands/complexity/shared/index.ts
|
|
3218
|
-
import
|
|
3219
|
-
import
|
|
3220
|
-
import
|
|
3372
|
+
import fs13 from "fs";
|
|
3373
|
+
import path21 from "path";
|
|
3374
|
+
import chalk33 from "chalk";
|
|
3221
3375
|
import ts5 from "typescript";
|
|
3222
3376
|
|
|
3223
3377
|
// src/commands/complexity/findSourceFiles.ts
|
|
3224
|
-
import
|
|
3225
|
-
import
|
|
3378
|
+
import fs12 from "fs";
|
|
3379
|
+
import path20 from "path";
|
|
3226
3380
|
import { minimatch as minimatch3 } from "minimatch";
|
|
3227
3381
|
function applyIgnoreGlobs(files) {
|
|
3228
3382
|
const { complexity } = loadConfig();
|
|
@@ -3231,13 +3385,13 @@ function applyIgnoreGlobs(files) {
|
|
|
3231
3385
|
);
|
|
3232
3386
|
}
|
|
3233
3387
|
function walk(dir, results) {
|
|
3234
|
-
if (!
|
|
3388
|
+
if (!fs12.existsSync(dir)) {
|
|
3235
3389
|
return;
|
|
3236
3390
|
}
|
|
3237
3391
|
const extensions = [".ts", ".tsx"];
|
|
3238
|
-
const entries =
|
|
3392
|
+
const entries = fs12.readdirSync(dir, { withFileTypes: true });
|
|
3239
3393
|
for (const entry of entries) {
|
|
3240
|
-
const fullPath =
|
|
3394
|
+
const fullPath = path20.join(dir, entry.name);
|
|
3241
3395
|
if (entry.isDirectory()) {
|
|
3242
3396
|
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
3243
3397
|
walk(fullPath, results);
|
|
@@ -3253,10 +3407,10 @@ function findSourceFiles2(pattern2, baseDir = ".") {
|
|
|
3253
3407
|
walk(baseDir, results);
|
|
3254
3408
|
return applyIgnoreGlobs(results.filter((f) => minimatch3(f, pattern2)));
|
|
3255
3409
|
}
|
|
3256
|
-
if (
|
|
3410
|
+
if (fs12.existsSync(pattern2) && fs12.statSync(pattern2).isFile()) {
|
|
3257
3411
|
return [pattern2];
|
|
3258
3412
|
}
|
|
3259
|
-
if (
|
|
3413
|
+
if (fs12.existsSync(pattern2) && fs12.statSync(pattern2).isDirectory()) {
|
|
3260
3414
|
walk(pattern2, results);
|
|
3261
3415
|
return applyIgnoreGlobs(results);
|
|
3262
3416
|
}
|
|
@@ -3451,9 +3605,9 @@ function countSloc(content) {
|
|
|
3451
3605
|
|
|
3452
3606
|
// src/commands/complexity/shared/index.ts
|
|
3453
3607
|
function createSourceFromFile(filePath) {
|
|
3454
|
-
const content =
|
|
3608
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
3455
3609
|
return ts5.createSourceFile(
|
|
3456
|
-
|
|
3610
|
+
path21.basename(filePath),
|
|
3457
3611
|
content,
|
|
3458
3612
|
ts5.ScriptTarget.Latest,
|
|
3459
3613
|
true,
|
|
@@ -3463,7 +3617,7 @@ function createSourceFromFile(filePath) {
|
|
|
3463
3617
|
function withSourceFiles(pattern2, callback) {
|
|
3464
3618
|
const files = findSourceFiles2(pattern2);
|
|
3465
3619
|
if (files.length === 0) {
|
|
3466
|
-
console.log(
|
|
3620
|
+
console.log(chalk33.yellow("No files found matching pattern"));
|
|
3467
3621
|
return void 0;
|
|
3468
3622
|
}
|
|
3469
3623
|
return callback(files);
|
|
@@ -3496,11 +3650,11 @@ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3496
3650
|
results.sort((a, b) => b.complexity - a.complexity);
|
|
3497
3651
|
for (const { file, name, complexity } of results) {
|
|
3498
3652
|
const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
|
|
3499
|
-
const color = exceedsThreshold ?
|
|
3500
|
-
console.log(`${color(`${file}:${name}`)} \u2192 ${
|
|
3653
|
+
const color = exceedsThreshold ? chalk34.red : chalk34.white;
|
|
3654
|
+
console.log(`${color(`${file}:${name}`)} \u2192 ${chalk34.cyan(complexity)}`);
|
|
3501
3655
|
}
|
|
3502
3656
|
console.log(
|
|
3503
|
-
|
|
3657
|
+
chalk34.dim(
|
|
3504
3658
|
`
|
|
3505
3659
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3506
3660
|
)
|
|
@@ -3512,7 +3666,7 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3512
3666
|
}
|
|
3513
3667
|
|
|
3514
3668
|
// src/commands/complexity/halstead.ts
|
|
3515
|
-
import
|
|
3669
|
+
import chalk35 from "chalk";
|
|
3516
3670
|
async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
3517
3671
|
withSourceFiles(pattern2, (files) => {
|
|
3518
3672
|
const results = [];
|
|
@@ -3527,13 +3681,13 @@ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3527
3681
|
results.sort((a, b) => b.metrics.effort - a.metrics.effort);
|
|
3528
3682
|
for (const { file, name, metrics } of results) {
|
|
3529
3683
|
const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
|
|
3530
|
-
const color = exceedsThreshold ?
|
|
3684
|
+
const color = exceedsThreshold ? chalk35.red : chalk35.white;
|
|
3531
3685
|
console.log(
|
|
3532
|
-
`${color(`${file}:${name}`)} \u2192 volume: ${
|
|
3686
|
+
`${color(`${file}:${name}`)} \u2192 volume: ${chalk35.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk35.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk35.magenta(metrics.effort.toFixed(1))}`
|
|
3533
3687
|
);
|
|
3534
3688
|
}
|
|
3535
3689
|
console.log(
|
|
3536
|
-
|
|
3690
|
+
chalk35.dim(
|
|
3537
3691
|
`
|
|
3538
3692
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3539
3693
|
)
|
|
@@ -3545,31 +3699,31 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3545
3699
|
}
|
|
3546
3700
|
|
|
3547
3701
|
// src/commands/complexity/maintainability/index.ts
|
|
3548
|
-
import
|
|
3702
|
+
import fs14 from "fs";
|
|
3549
3703
|
|
|
3550
3704
|
// src/commands/complexity/maintainability/displayMaintainabilityResults.ts
|
|
3551
|
-
import
|
|
3705
|
+
import chalk36 from "chalk";
|
|
3552
3706
|
function displayMaintainabilityResults(results, threshold) {
|
|
3553
3707
|
const filtered = threshold !== void 0 ? results.filter((r) => r.minMaintainability < threshold) : results;
|
|
3554
3708
|
if (threshold !== void 0 && filtered.length === 0) {
|
|
3555
|
-
console.log(
|
|
3709
|
+
console.log(chalk36.green("All files pass maintainability threshold"));
|
|
3556
3710
|
} else {
|
|
3557
3711
|
for (const { file, avgMaintainability, minMaintainability } of filtered) {
|
|
3558
|
-
const color = threshold !== void 0 ?
|
|
3712
|
+
const color = threshold !== void 0 ? chalk36.red : chalk36.white;
|
|
3559
3713
|
console.log(
|
|
3560
|
-
`${color(file)} \u2192 avg: ${
|
|
3714
|
+
`${color(file)} \u2192 avg: ${chalk36.cyan(avgMaintainability.toFixed(1))}, min: ${chalk36.yellow(minMaintainability.toFixed(1))}`
|
|
3561
3715
|
);
|
|
3562
3716
|
}
|
|
3563
3717
|
}
|
|
3564
|
-
console.log(
|
|
3718
|
+
console.log(chalk36.dim(`
|
|
3565
3719
|
Analyzed ${results.length} files`));
|
|
3566
3720
|
if (filtered.length > 0 && threshold !== void 0) {
|
|
3567
3721
|
console.error(
|
|
3568
|
-
|
|
3722
|
+
chalk36.red(
|
|
3569
3723
|
`
|
|
3570
3724
|
Fail: ${filtered.length} file(s) below threshold ${threshold}. Maintainability index (0\u2013100) is derived from Halstead volume, cyclomatic complexity, and lines of code.
|
|
3571
3725
|
|
|
3572
|
-
\u26A0\uFE0F ${
|
|
3726
|
+
\u26A0\uFE0F ${chalk36.bold("Diagnose and fix one file at a time")} \u2014 do not investigate or fix multiple files in parallel. Run 'assist complexity <file>' to see all metrics. For larger files, start by extracting responsibilities into smaller files.`
|
|
3573
3727
|
)
|
|
3574
3728
|
);
|
|
3575
3729
|
process.exit(1);
|
|
@@ -3587,7 +3741,7 @@ function calculateMaintainabilityIndex(halsteadVolume, cyclomaticComplexity, slo
|
|
|
3587
3741
|
function collectFileMetrics(files) {
|
|
3588
3742
|
const fileMetrics = /* @__PURE__ */ new Map();
|
|
3589
3743
|
for (const file of files) {
|
|
3590
|
-
const content =
|
|
3744
|
+
const content = fs14.readFileSync(file, "utf-8");
|
|
3591
3745
|
fileMetrics.set(file, { sloc: countSloc(content), functions: [] });
|
|
3592
3746
|
}
|
|
3593
3747
|
forEachFunction(files, (file, _name, node) => {
|
|
@@ -3625,14 +3779,14 @@ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3625
3779
|
}
|
|
3626
3780
|
|
|
3627
3781
|
// src/commands/complexity/sloc.ts
|
|
3628
|
-
import
|
|
3629
|
-
import
|
|
3782
|
+
import fs15 from "fs";
|
|
3783
|
+
import chalk37 from "chalk";
|
|
3630
3784
|
async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
3631
3785
|
withSourceFiles(pattern2, (files) => {
|
|
3632
3786
|
const results = [];
|
|
3633
3787
|
let hasViolation = false;
|
|
3634
3788
|
for (const file of files) {
|
|
3635
|
-
const content =
|
|
3789
|
+
const content = fs15.readFileSync(file, "utf-8");
|
|
3636
3790
|
const lines = countSloc(content);
|
|
3637
3791
|
results.push({ file, lines });
|
|
3638
3792
|
if (options2.threshold !== void 0 && lines > options2.threshold) {
|
|
@@ -3642,12 +3796,12 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3642
3796
|
results.sort((a, b) => b.lines - a.lines);
|
|
3643
3797
|
for (const { file, lines } of results) {
|
|
3644
3798
|
const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
|
|
3645
|
-
const color = exceedsThreshold ?
|
|
3646
|
-
console.log(`${color(file)} \u2192 ${
|
|
3799
|
+
const color = exceedsThreshold ? chalk37.red : chalk37.white;
|
|
3800
|
+
console.log(`${color(file)} \u2192 ${chalk37.cyan(lines)} lines`);
|
|
3647
3801
|
}
|
|
3648
3802
|
const total = results.reduce((sum, r) => sum + r.lines, 0);
|
|
3649
3803
|
console.log(
|
|
3650
|
-
|
|
3804
|
+
chalk37.dim(`
|
|
3651
3805
|
Total: ${total} lines across ${files.length} files`)
|
|
3652
3806
|
);
|
|
3653
3807
|
if (hasViolation) {
|
|
@@ -3661,21 +3815,21 @@ async function analyze(pattern2) {
|
|
|
3661
3815
|
const searchPattern = pattern2.includes("*") || pattern2.includes("/") ? pattern2 : `**/${pattern2}`;
|
|
3662
3816
|
const files = findSourceFiles2(searchPattern);
|
|
3663
3817
|
if (files.length === 0) {
|
|
3664
|
-
console.log(
|
|
3818
|
+
console.log(chalk38.yellow("No files found matching pattern"));
|
|
3665
3819
|
return;
|
|
3666
3820
|
}
|
|
3667
3821
|
if (files.length === 1) {
|
|
3668
3822
|
const file = files[0];
|
|
3669
|
-
console.log(
|
|
3823
|
+
console.log(chalk38.bold.underline("SLOC"));
|
|
3670
3824
|
await sloc(file);
|
|
3671
3825
|
console.log();
|
|
3672
|
-
console.log(
|
|
3826
|
+
console.log(chalk38.bold.underline("Cyclomatic Complexity"));
|
|
3673
3827
|
await cyclomatic(file);
|
|
3674
3828
|
console.log();
|
|
3675
|
-
console.log(
|
|
3829
|
+
console.log(chalk38.bold.underline("Halstead Metrics"));
|
|
3676
3830
|
await halstead(file);
|
|
3677
3831
|
console.log();
|
|
3678
|
-
console.log(
|
|
3832
|
+
console.log(chalk38.bold.underline("Maintainability Index"));
|
|
3679
3833
|
await maintainability(file);
|
|
3680
3834
|
return;
|
|
3681
3835
|
}
|
|
@@ -3703,7 +3857,7 @@ function registerComplexity(program2) {
|
|
|
3703
3857
|
|
|
3704
3858
|
// src/commands/deploy/redirect.ts
|
|
3705
3859
|
import { existsSync as existsSync19, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
3706
|
-
import
|
|
3860
|
+
import chalk39 from "chalk";
|
|
3707
3861
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
3708
3862
|
if (!window.location.pathname.endsWith('/')) {
|
|
3709
3863
|
window.location.href = \`\${window.location.pathname}/\${window.location.search}\${window.location.hash}\`;
|
|
@@ -3712,22 +3866,22 @@ var TRAILING_SLASH_SCRIPT = ` <script>
|
|
|
3712
3866
|
function redirect() {
|
|
3713
3867
|
const indexPath = "index.html";
|
|
3714
3868
|
if (!existsSync19(indexPath)) {
|
|
3715
|
-
console.log(
|
|
3869
|
+
console.log(chalk39.yellow("No index.html found"));
|
|
3716
3870
|
return;
|
|
3717
3871
|
}
|
|
3718
3872
|
const content = readFileSync16(indexPath, "utf-8");
|
|
3719
3873
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
3720
|
-
console.log(
|
|
3874
|
+
console.log(chalk39.dim("Trailing slash script already present"));
|
|
3721
3875
|
return;
|
|
3722
3876
|
}
|
|
3723
3877
|
const headCloseIndex = content.indexOf("</head>");
|
|
3724
3878
|
if (headCloseIndex === -1) {
|
|
3725
|
-
console.log(
|
|
3879
|
+
console.log(chalk39.red("Could not find </head> tag in index.html"));
|
|
3726
3880
|
return;
|
|
3727
3881
|
}
|
|
3728
3882
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
3729
3883
|
writeFileSync14(indexPath, newContent);
|
|
3730
|
-
console.log(
|
|
3884
|
+
console.log(chalk39.green("Added trailing slash redirect to index.html"));
|
|
3731
3885
|
}
|
|
3732
3886
|
|
|
3733
3887
|
// src/commands/registerDeploy.ts
|
|
@@ -3754,7 +3908,7 @@ function loadBlogSkipDays(repoName) {
|
|
|
3754
3908
|
|
|
3755
3909
|
// src/commands/devlog/shared.ts
|
|
3756
3910
|
import { execSync as execSync15 } from "child_process";
|
|
3757
|
-
import
|
|
3911
|
+
import chalk40 from "chalk";
|
|
3758
3912
|
|
|
3759
3913
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
3760
3914
|
import { readdirSync, readFileSync as readFileSync17 } from "fs";
|
|
@@ -3841,13 +3995,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
|
|
|
3841
3995
|
}
|
|
3842
3996
|
function printCommitsWithFiles(commits, ignore2, verbose) {
|
|
3843
3997
|
for (const commit2 of commits) {
|
|
3844
|
-
console.log(` ${
|
|
3998
|
+
console.log(` ${chalk40.yellow(commit2.hash)} ${commit2.message}`);
|
|
3845
3999
|
if (verbose) {
|
|
3846
4000
|
const visibleFiles = commit2.files.filter(
|
|
3847
4001
|
(file) => !ignore2.some((p) => file.startsWith(p))
|
|
3848
4002
|
);
|
|
3849
4003
|
for (const file of visibleFiles) {
|
|
3850
|
-
console.log(` ${
|
|
4004
|
+
console.log(` ${chalk40.dim(file)}`);
|
|
3851
4005
|
}
|
|
3852
4006
|
}
|
|
3853
4007
|
}
|
|
@@ -3872,15 +4026,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
|
|
|
3872
4026
|
}
|
|
3873
4027
|
|
|
3874
4028
|
// src/commands/devlog/list/printDateHeader.ts
|
|
3875
|
-
import
|
|
4029
|
+
import chalk41 from "chalk";
|
|
3876
4030
|
function printDateHeader(date, isSkipped, entries) {
|
|
3877
4031
|
if (isSkipped) {
|
|
3878
|
-
console.log(`${
|
|
4032
|
+
console.log(`${chalk41.bold.blue(date)} ${chalk41.dim("skipped")}`);
|
|
3879
4033
|
} else if (entries && entries.length > 0) {
|
|
3880
|
-
const entryInfo = entries.map((e) => `${
|
|
3881
|
-
console.log(`${
|
|
4034
|
+
const entryInfo = entries.map((e) => `${chalk41.green(e.version)} ${e.title}`).join(" | ");
|
|
4035
|
+
console.log(`${chalk41.bold.blue(date)} ${entryInfo}`);
|
|
3882
4036
|
} else {
|
|
3883
|
-
console.log(`${
|
|
4037
|
+
console.log(`${chalk41.bold.blue(date)} ${chalk41.red("\u26A0 devlog missing")}`);
|
|
3884
4038
|
}
|
|
3885
4039
|
}
|
|
3886
4040
|
|
|
@@ -3983,24 +4137,24 @@ function bumpVersion(version2, type) {
|
|
|
3983
4137
|
|
|
3984
4138
|
// src/commands/devlog/next/displayNextEntry/index.ts
|
|
3985
4139
|
import { execSync as execSync18 } from "child_process";
|
|
3986
|
-
import
|
|
4140
|
+
import chalk43 from "chalk";
|
|
3987
4141
|
|
|
3988
4142
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
3989
|
-
import
|
|
4143
|
+
import chalk42 from "chalk";
|
|
3990
4144
|
function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
|
|
3991
4145
|
if (conventional && firstHash) {
|
|
3992
4146
|
const version2 = getVersionAtCommit(firstHash);
|
|
3993
4147
|
if (version2) {
|
|
3994
|
-
console.log(`${
|
|
4148
|
+
console.log(`${chalk42.bold("version:")} ${stripToMinor(version2)}`);
|
|
3995
4149
|
} else {
|
|
3996
|
-
console.log(`${
|
|
4150
|
+
console.log(`${chalk42.bold("version:")} ${chalk42.red("unknown")}`);
|
|
3997
4151
|
}
|
|
3998
4152
|
} else if (patchVersion && minorVersion) {
|
|
3999
4153
|
console.log(
|
|
4000
|
-
`${
|
|
4154
|
+
`${chalk42.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
4001
4155
|
);
|
|
4002
4156
|
} else {
|
|
4003
|
-
console.log(`${
|
|
4157
|
+
console.log(`${chalk42.bold("version:")} v0.1 (initial)`);
|
|
4004
4158
|
}
|
|
4005
4159
|
}
|
|
4006
4160
|
|
|
@@ -4047,16 +4201,16 @@ function noCommitsMessage(hasLastInfo) {
|
|
|
4047
4201
|
return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
|
|
4048
4202
|
}
|
|
4049
4203
|
function logName(repoName) {
|
|
4050
|
-
console.log(`${
|
|
4204
|
+
console.log(`${chalk43.bold("name:")} ${repoName}`);
|
|
4051
4205
|
}
|
|
4052
4206
|
function displayNextEntry(ctx, targetDate, commits) {
|
|
4053
4207
|
logName(ctx.repoName);
|
|
4054
4208
|
printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
|
|
4055
|
-
console.log(
|
|
4209
|
+
console.log(chalk43.bold.blue(targetDate));
|
|
4056
4210
|
printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
|
|
4057
4211
|
}
|
|
4058
4212
|
function logNoCommits(lastInfo) {
|
|
4059
|
-
console.log(
|
|
4213
|
+
console.log(chalk43.dim(noCommitsMessage(!!lastInfo)));
|
|
4060
4214
|
}
|
|
4061
4215
|
|
|
4062
4216
|
// src/commands/devlog/next/index.ts
|
|
@@ -4097,11 +4251,11 @@ function next(options2) {
|
|
|
4097
4251
|
import { execSync as execSync19 } from "child_process";
|
|
4098
4252
|
|
|
4099
4253
|
// src/commands/devlog/repos/printReposTable.ts
|
|
4100
|
-
import
|
|
4254
|
+
import chalk44 from "chalk";
|
|
4101
4255
|
function colorStatus(status2) {
|
|
4102
|
-
if (status2 === "missing") return
|
|
4103
|
-
if (status2 === "outdated") return
|
|
4104
|
-
return
|
|
4256
|
+
if (status2 === "missing") return chalk44.red(status2);
|
|
4257
|
+
if (status2 === "outdated") return chalk44.yellow(status2);
|
|
4258
|
+
return chalk44.green(status2);
|
|
4105
4259
|
}
|
|
4106
4260
|
function formatRow(row, nameWidth) {
|
|
4107
4261
|
const devlog = (row.lastDevlog ?? "-").padEnd(11);
|
|
@@ -4115,8 +4269,8 @@ function printReposTable(rows) {
|
|
|
4115
4269
|
"Last Devlog".padEnd(11),
|
|
4116
4270
|
"Status"
|
|
4117
4271
|
].join(" ");
|
|
4118
|
-
console.log(
|
|
4119
|
-
console.log(
|
|
4272
|
+
console.log(chalk44.dim(header));
|
|
4273
|
+
console.log(chalk44.dim("-".repeat(header.length)));
|
|
4120
4274
|
for (const row of rows) {
|
|
4121
4275
|
console.log(formatRow(row, nameWidth));
|
|
4122
4276
|
}
|
|
@@ -4174,14 +4328,14 @@ function repos(options2) {
|
|
|
4174
4328
|
// src/commands/devlog/skip.ts
|
|
4175
4329
|
import { writeFileSync as writeFileSync15 } from "fs";
|
|
4176
4330
|
import { join as join15 } from "path";
|
|
4177
|
-
import
|
|
4331
|
+
import chalk45 from "chalk";
|
|
4178
4332
|
import { stringify as stringifyYaml4 } from "yaml";
|
|
4179
4333
|
function getBlogConfigPath() {
|
|
4180
4334
|
return join15(BLOG_REPO_ROOT, "assist.yml");
|
|
4181
4335
|
}
|
|
4182
4336
|
function skip(date) {
|
|
4183
4337
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
4184
|
-
console.log(
|
|
4338
|
+
console.log(chalk45.red("Invalid date format. Use YYYY-MM-DD"));
|
|
4185
4339
|
process.exit(1);
|
|
4186
4340
|
}
|
|
4187
4341
|
const repoName = getRepoName();
|
|
@@ -4192,7 +4346,7 @@ function skip(date) {
|
|
|
4192
4346
|
const skipDays = skip2[repoName] ?? [];
|
|
4193
4347
|
if (skipDays.includes(date)) {
|
|
4194
4348
|
console.log(
|
|
4195
|
-
|
|
4349
|
+
chalk45.yellow(`${date} is already in skip list for ${repoName}`)
|
|
4196
4350
|
);
|
|
4197
4351
|
return;
|
|
4198
4352
|
}
|
|
@@ -4202,20 +4356,20 @@ function skip(date) {
|
|
|
4202
4356
|
devlog.skip = skip2;
|
|
4203
4357
|
config.devlog = devlog;
|
|
4204
4358
|
writeFileSync15(configPath, stringifyYaml4(config, { lineWidth: 0 }));
|
|
4205
|
-
console.log(
|
|
4359
|
+
console.log(chalk45.green(`Added ${date} to skip list for ${repoName}`));
|
|
4206
4360
|
}
|
|
4207
4361
|
|
|
4208
4362
|
// src/commands/devlog/version.ts
|
|
4209
|
-
import
|
|
4363
|
+
import chalk46 from "chalk";
|
|
4210
4364
|
function version() {
|
|
4211
4365
|
const config = loadConfig();
|
|
4212
4366
|
const name = getRepoName();
|
|
4213
4367
|
const lastInfo = getLastVersionInfo(name, config);
|
|
4214
4368
|
const lastVersion = lastInfo?.version ?? null;
|
|
4215
4369
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
4216
|
-
console.log(`${
|
|
4217
|
-
console.log(`${
|
|
4218
|
-
console.log(`${
|
|
4370
|
+
console.log(`${chalk46.bold("name:")} ${name}`);
|
|
4371
|
+
console.log(`${chalk46.bold("last:")} ${lastVersion ?? chalk46.dim("none")}`);
|
|
4372
|
+
console.log(`${chalk46.bold("next:")} ${nextVersion ?? chalk46.dim("none")}`);
|
|
4219
4373
|
}
|
|
4220
4374
|
|
|
4221
4375
|
// src/commands/registerDevlog.ts
|
|
@@ -4238,7 +4392,7 @@ function registerDevlog(program2) {
|
|
|
4238
4392
|
|
|
4239
4393
|
// src/commands/jira/acceptanceCriteria.ts
|
|
4240
4394
|
import { execSync as execSync20 } from "child_process";
|
|
4241
|
-
import
|
|
4395
|
+
import chalk47 from "chalk";
|
|
4242
4396
|
|
|
4243
4397
|
// src/commands/jira/adfToText.ts
|
|
4244
4398
|
function renderInline(node) {
|
|
@@ -4313,21 +4467,21 @@ function acceptanceCriteria(issueKey) {
|
|
|
4313
4467
|
const stderr = error.stderr;
|
|
4314
4468
|
if (stderr.includes("unauthorized")) {
|
|
4315
4469
|
console.error(
|
|
4316
|
-
|
|
4470
|
+
chalk47.red("Jira authentication expired."),
|
|
4317
4471
|
"Run",
|
|
4318
|
-
|
|
4472
|
+
chalk47.cyan("assist jira auth"),
|
|
4319
4473
|
"to re-authenticate."
|
|
4320
4474
|
);
|
|
4321
4475
|
process.exit(1);
|
|
4322
4476
|
}
|
|
4323
4477
|
}
|
|
4324
|
-
console.error(
|
|
4478
|
+
console.error(chalk47.red(`Failed to fetch ${issueKey}.`));
|
|
4325
4479
|
process.exit(1);
|
|
4326
4480
|
}
|
|
4327
4481
|
const parsed = JSON.parse(result);
|
|
4328
4482
|
const acValue = parsed?.fields?.[field];
|
|
4329
4483
|
if (!acValue) {
|
|
4330
|
-
console.log(
|
|
4484
|
+
console.log(chalk47.yellow(`No acceptance criteria found on ${issueKey}.`));
|
|
4331
4485
|
return;
|
|
4332
4486
|
}
|
|
4333
4487
|
if (typeof acValue === "string") {
|
|
@@ -4356,10 +4510,10 @@ function getStorePath(filename) {
|
|
|
4356
4510
|
return join16(getStoreDir(), filename);
|
|
4357
4511
|
}
|
|
4358
4512
|
function loadJson(filename) {
|
|
4359
|
-
const
|
|
4360
|
-
if (existsSync20(
|
|
4513
|
+
const path43 = getStorePath(filename);
|
|
4514
|
+
if (existsSync20(path43)) {
|
|
4361
4515
|
try {
|
|
4362
|
-
return JSON.parse(readFileSync18(
|
|
4516
|
+
return JSON.parse(readFileSync18(path43, "utf-8"));
|
|
4363
4517
|
} catch {
|
|
4364
4518
|
return {};
|
|
4365
4519
|
}
|
|
@@ -4426,7 +4580,7 @@ function registerJira(program2) {
|
|
|
4426
4580
|
|
|
4427
4581
|
// src/commands/netframework/buildTree.ts
|
|
4428
4582
|
import { readFileSync as readFileSync19 } from "fs";
|
|
4429
|
-
import
|
|
4583
|
+
import path22 from "path";
|
|
4430
4584
|
var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
|
|
4431
4585
|
function getProjectRefs(csprojPath) {
|
|
4432
4586
|
const content = readFileSync19(csprojPath, "utf-8");
|
|
@@ -4437,14 +4591,14 @@ function getProjectRefs(csprojPath) {
|
|
|
4437
4591
|
return refs;
|
|
4438
4592
|
}
|
|
4439
4593
|
function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
|
|
4440
|
-
const abs =
|
|
4441
|
-
const rel =
|
|
4594
|
+
const abs = path22.resolve(csprojPath);
|
|
4595
|
+
const rel = path22.relative(repoRoot, abs);
|
|
4442
4596
|
const node = { path: abs, relativePath: rel, children: [] };
|
|
4443
4597
|
if (visited.has(abs)) return node;
|
|
4444
4598
|
visited.add(abs);
|
|
4445
|
-
const dir =
|
|
4599
|
+
const dir = path22.dirname(abs);
|
|
4446
4600
|
for (const ref of getProjectRefs(abs)) {
|
|
4447
|
-
const childAbs =
|
|
4601
|
+
const childAbs = path22.resolve(dir, ref);
|
|
4448
4602
|
try {
|
|
4449
4603
|
readFileSync19(childAbs);
|
|
4450
4604
|
node.children.push(buildTree(childAbs, repoRoot, visited));
|
|
@@ -4472,7 +4626,7 @@ function collectAllDeps(node) {
|
|
|
4472
4626
|
|
|
4473
4627
|
// src/commands/netframework/findContainingSolutions.ts
|
|
4474
4628
|
import { readdirSync as readdirSync2, readFileSync as readFileSync20, statSync } from "fs";
|
|
4475
|
-
import
|
|
4629
|
+
import path23 from "path";
|
|
4476
4630
|
function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
4477
4631
|
if (depth > maxDepth) return [];
|
|
4478
4632
|
const results = [];
|
|
@@ -4485,7 +4639,7 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
|
4485
4639
|
for (const entry of entries) {
|
|
4486
4640
|
if (entry.startsWith(".") || entry === "node_modules" || entry === "packages")
|
|
4487
4641
|
continue;
|
|
4488
|
-
const full =
|
|
4642
|
+
const full = path23.join(dir, entry);
|
|
4489
4643
|
try {
|
|
4490
4644
|
const stat = statSync(full);
|
|
4491
4645
|
if (stat.isFile() && entry.endsWith(".sln")) {
|
|
@@ -4499,8 +4653,8 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
|
4499
4653
|
return results;
|
|
4500
4654
|
}
|
|
4501
4655
|
function findContainingSolutions(csprojPath, repoRoot) {
|
|
4502
|
-
const csprojAbs =
|
|
4503
|
-
const csprojBasename =
|
|
4656
|
+
const csprojAbs = path23.resolve(csprojPath);
|
|
4657
|
+
const csprojBasename = path23.basename(csprojAbs);
|
|
4504
4658
|
const slnFiles = findSlnFiles(repoRoot, 3);
|
|
4505
4659
|
const matches = [];
|
|
4506
4660
|
const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
|
|
@@ -4508,7 +4662,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
|
|
|
4508
4662
|
try {
|
|
4509
4663
|
const content = readFileSync20(sln, "utf-8");
|
|
4510
4664
|
if (pattern2.test(content)) {
|
|
4511
|
-
matches.push(
|
|
4665
|
+
matches.push(path23.relative(repoRoot, sln));
|
|
4512
4666
|
}
|
|
4513
4667
|
} catch {
|
|
4514
4668
|
}
|
|
@@ -4520,30 +4674,30 @@ function escapeRegex(s) {
|
|
|
4520
4674
|
}
|
|
4521
4675
|
|
|
4522
4676
|
// src/commands/netframework/printTree.ts
|
|
4523
|
-
import
|
|
4677
|
+
import chalk48 from "chalk";
|
|
4524
4678
|
function printNodes(nodes, prefix2) {
|
|
4525
4679
|
for (let i = 0; i < nodes.length; i++) {
|
|
4526
4680
|
const isLast = i === nodes.length - 1;
|
|
4527
4681
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4528
4682
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
4529
4683
|
const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
|
|
4530
|
-
const label2 = isMissing ?
|
|
4684
|
+
const label2 = isMissing ? chalk48.red(nodes[i].relativePath) : nodes[i].relativePath;
|
|
4531
4685
|
console.log(`${prefix2}${connector}${label2}`);
|
|
4532
4686
|
printNodes(nodes[i].children, prefix2 + childPrefix);
|
|
4533
4687
|
}
|
|
4534
4688
|
}
|
|
4535
4689
|
function printTree(tree, totalCount, solutions) {
|
|
4536
|
-
console.log(
|
|
4537
|
-
console.log(
|
|
4690
|
+
console.log(chalk48.bold("\nProject Dependency Tree"));
|
|
4691
|
+
console.log(chalk48.cyan(tree.relativePath));
|
|
4538
4692
|
printNodes(tree.children, "");
|
|
4539
|
-
console.log(
|
|
4693
|
+
console.log(chalk48.dim(`
|
|
4540
4694
|
${totalCount} projects total (including root)`));
|
|
4541
|
-
console.log(
|
|
4695
|
+
console.log(chalk48.bold("\nSolution Membership"));
|
|
4542
4696
|
if (solutions.length === 0) {
|
|
4543
|
-
console.log(
|
|
4697
|
+
console.log(chalk48.yellow(" Not found in any .sln"));
|
|
4544
4698
|
} else {
|
|
4545
4699
|
for (const sln of solutions) {
|
|
4546
|
-
console.log(` ${
|
|
4700
|
+
console.log(` ${chalk48.green(sln)}`);
|
|
4547
4701
|
}
|
|
4548
4702
|
}
|
|
4549
4703
|
console.log();
|
|
@@ -4571,33 +4725,33 @@ function printJson(tree, totalCount, solutions) {
|
|
|
4571
4725
|
|
|
4572
4726
|
// src/commands/netframework/resolveCsproj.ts
|
|
4573
4727
|
import { existsSync as existsSync22 } from "fs";
|
|
4574
|
-
import
|
|
4575
|
-
import
|
|
4728
|
+
import path25 from "path";
|
|
4729
|
+
import chalk49 from "chalk";
|
|
4576
4730
|
|
|
4577
4731
|
// src/commands/netframework/findRepoRoot.ts
|
|
4578
4732
|
import { existsSync as existsSync21 } from "fs";
|
|
4579
|
-
import
|
|
4733
|
+
import path24 from "path";
|
|
4580
4734
|
function findRepoRoot(dir) {
|
|
4581
4735
|
let current = dir;
|
|
4582
|
-
while (current !==
|
|
4583
|
-
if (existsSync21(
|
|
4736
|
+
while (current !== path24.dirname(current)) {
|
|
4737
|
+
if (existsSync21(path24.join(current, ".git"))) {
|
|
4584
4738
|
return current;
|
|
4585
4739
|
}
|
|
4586
|
-
current =
|
|
4740
|
+
current = path24.dirname(current);
|
|
4587
4741
|
}
|
|
4588
4742
|
return null;
|
|
4589
4743
|
}
|
|
4590
4744
|
|
|
4591
4745
|
// src/commands/netframework/resolveCsproj.ts
|
|
4592
4746
|
function resolveCsproj(csprojPath) {
|
|
4593
|
-
const resolved =
|
|
4747
|
+
const resolved = path25.resolve(csprojPath);
|
|
4594
4748
|
if (!existsSync22(resolved)) {
|
|
4595
|
-
console.error(
|
|
4749
|
+
console.error(chalk49.red(`File not found: ${resolved}`));
|
|
4596
4750
|
process.exit(1);
|
|
4597
4751
|
}
|
|
4598
|
-
const repoRoot = findRepoRoot(
|
|
4752
|
+
const repoRoot = findRepoRoot(path25.dirname(resolved));
|
|
4599
4753
|
if (!repoRoot) {
|
|
4600
|
-
console.error(
|
|
4754
|
+
console.error(chalk49.red("Could not find git repository root"));
|
|
4601
4755
|
process.exit(1);
|
|
4602
4756
|
}
|
|
4603
4757
|
return { resolved, repoRoot };
|
|
@@ -4617,12 +4771,12 @@ async function deps(csprojPath, options2) {
|
|
|
4617
4771
|
}
|
|
4618
4772
|
|
|
4619
4773
|
// src/commands/netframework/inSln.ts
|
|
4620
|
-
import
|
|
4774
|
+
import chalk50 from "chalk";
|
|
4621
4775
|
async function inSln(csprojPath) {
|
|
4622
4776
|
const { resolved, repoRoot } = resolveCsproj(csprojPath);
|
|
4623
4777
|
const solutions = findContainingSolutions(resolved, repoRoot);
|
|
4624
4778
|
if (solutions.length === 0) {
|
|
4625
|
-
console.log(
|
|
4779
|
+
console.log(chalk50.yellow("Not found in any .sln file"));
|
|
4626
4780
|
process.exit(1);
|
|
4627
4781
|
}
|
|
4628
4782
|
for (const sln of solutions) {
|
|
@@ -4638,7 +4792,7 @@ function registerNetframework(program2) {
|
|
|
4638
4792
|
}
|
|
4639
4793
|
|
|
4640
4794
|
// src/commands/news/add/index.ts
|
|
4641
|
-
import
|
|
4795
|
+
import chalk51 from "chalk";
|
|
4642
4796
|
import enquirer5 from "enquirer";
|
|
4643
4797
|
async function add2(url) {
|
|
4644
4798
|
if (!url) {
|
|
@@ -4661,17 +4815,17 @@ async function add2(url) {
|
|
|
4661
4815
|
const news = config.news ?? {};
|
|
4662
4816
|
const feeds = news.feeds ?? [];
|
|
4663
4817
|
if (feeds.includes(url)) {
|
|
4664
|
-
console.log(
|
|
4818
|
+
console.log(chalk51.yellow("Feed already exists in config"));
|
|
4665
4819
|
return;
|
|
4666
4820
|
}
|
|
4667
4821
|
feeds.push(url);
|
|
4668
4822
|
config.news = { ...news, feeds };
|
|
4669
4823
|
saveGlobalConfig(config);
|
|
4670
|
-
console.log(
|
|
4824
|
+
console.log(chalk51.green(`Added feed: ${url}`));
|
|
4671
4825
|
}
|
|
4672
4826
|
|
|
4673
4827
|
// src/commands/news/web/handleRequest.ts
|
|
4674
|
-
import
|
|
4828
|
+
import chalk52 from "chalk";
|
|
4675
4829
|
|
|
4676
4830
|
// src/commands/news/web/shared.ts
|
|
4677
4831
|
import { decodeHTML } from "entities";
|
|
@@ -4807,17 +4961,17 @@ function prefetch() {
|
|
|
4807
4961
|
const config = loadConfig();
|
|
4808
4962
|
const total = config.news.feeds.length;
|
|
4809
4963
|
if (total === 0) return;
|
|
4810
|
-
process.stdout.write(
|
|
4964
|
+
process.stdout.write(chalk52.dim(`Fetching ${total} feed(s)\u2026 `));
|
|
4811
4965
|
prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
|
|
4812
4966
|
const width = 20;
|
|
4813
4967
|
const filled = Math.round(done2 / t * width);
|
|
4814
4968
|
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
4815
4969
|
process.stdout.write(
|
|
4816
|
-
`\r${
|
|
4970
|
+
`\r${chalk52.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
|
|
4817
4971
|
);
|
|
4818
4972
|
}).then((items) => {
|
|
4819
4973
|
process.stdout.write(
|
|
4820
|
-
`\r${
|
|
4974
|
+
`\r${chalk52.green(`Fetched ${items.length} items from ${total} feed(s)`)}
|
|
4821
4975
|
`
|
|
4822
4976
|
);
|
|
4823
4977
|
cachedItems = items;
|
|
@@ -4932,7 +5086,7 @@ function validateLine(line) {
|
|
|
4932
5086
|
process.exit(1);
|
|
4933
5087
|
}
|
|
4934
5088
|
}
|
|
4935
|
-
function comment(
|
|
5089
|
+
function comment(path43, line, body) {
|
|
4936
5090
|
validateBody(body);
|
|
4937
5091
|
validateLine(line);
|
|
4938
5092
|
try {
|
|
@@ -4952,7 +5106,7 @@ function comment(path35, line, body) {
|
|
|
4952
5106
|
"-f",
|
|
4953
5107
|
`body=${body}`,
|
|
4954
5108
|
"-f",
|
|
4955
|
-
`path=${
|
|
5109
|
+
`path=${path43}`,
|
|
4956
5110
|
"-F",
|
|
4957
5111
|
`line=${line}`
|
|
4958
5112
|
],
|
|
@@ -4961,7 +5115,7 @@ function comment(path35, line, body) {
|
|
|
4961
5115
|
if (result.status !== 0) {
|
|
4962
5116
|
throw new Error(result.stderr || result.stdout);
|
|
4963
5117
|
}
|
|
4964
|
-
console.log(`Added review comment on ${
|
|
5118
|
+
console.log(`Added review comment on ${path43}:${line}`);
|
|
4965
5119
|
} finally {
|
|
4966
5120
|
unlinkSync3(queryFile);
|
|
4967
5121
|
}
|
|
@@ -5178,20 +5332,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
5178
5332
|
}
|
|
5179
5333
|
|
|
5180
5334
|
// src/commands/prs/listComments/printComments.ts
|
|
5181
|
-
import
|
|
5335
|
+
import chalk53 from "chalk";
|
|
5182
5336
|
function formatForHuman(comment2) {
|
|
5183
5337
|
if (comment2.type === "review") {
|
|
5184
|
-
const stateColor = comment2.state === "APPROVED" ?
|
|
5338
|
+
const stateColor = comment2.state === "APPROVED" ? chalk53.green : comment2.state === "CHANGES_REQUESTED" ? chalk53.red : chalk53.yellow;
|
|
5185
5339
|
return [
|
|
5186
|
-
`${
|
|
5340
|
+
`${chalk53.cyan("Review")} by ${chalk53.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
|
|
5187
5341
|
comment2.body,
|
|
5188
5342
|
""
|
|
5189
5343
|
].join("\n");
|
|
5190
5344
|
}
|
|
5191
5345
|
const location = comment2.line ? `:${comment2.line}` : "";
|
|
5192
5346
|
return [
|
|
5193
|
-
`${
|
|
5194
|
-
|
|
5347
|
+
`${chalk53.cyan("Line comment")} by ${chalk53.bold(comment2.user)} on ${chalk53.dim(`${comment2.path}${location}`)}`,
|
|
5348
|
+
chalk53.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
5195
5349
|
comment2.body,
|
|
5196
5350
|
""
|
|
5197
5351
|
].join("\n");
|
|
@@ -5281,13 +5435,13 @@ import { execSync as execSync27 } from "child_process";
|
|
|
5281
5435
|
import enquirer6 from "enquirer";
|
|
5282
5436
|
|
|
5283
5437
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
5284
|
-
import
|
|
5438
|
+
import chalk54 from "chalk";
|
|
5285
5439
|
var STATUS_MAP = {
|
|
5286
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
5287
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
5440
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk54.magenta("merged"), date: pr.mergedAt } : null,
|
|
5441
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk54.red("closed"), date: pr.closedAt } : null
|
|
5288
5442
|
};
|
|
5289
5443
|
function defaultStatus(pr) {
|
|
5290
|
-
return { label:
|
|
5444
|
+
return { label: chalk54.green("opened"), date: pr.createdAt };
|
|
5291
5445
|
}
|
|
5292
5446
|
function getStatus2(pr) {
|
|
5293
5447
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -5296,11 +5450,11 @@ function formatDate(dateStr) {
|
|
|
5296
5450
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
5297
5451
|
}
|
|
5298
5452
|
function formatPrHeader(pr, status2) {
|
|
5299
|
-
return `${
|
|
5453
|
+
return `${chalk54.cyan(`#${pr.number}`)} ${pr.title} ${chalk54.dim(`(${pr.author.login},`)} ${status2.label} ${chalk54.dim(`${formatDate(status2.date)})`)}`;
|
|
5300
5454
|
}
|
|
5301
5455
|
function logPrDetails(pr) {
|
|
5302
5456
|
console.log(
|
|
5303
|
-
|
|
5457
|
+
chalk54.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
5304
5458
|
);
|
|
5305
5459
|
console.log();
|
|
5306
5460
|
}
|
|
@@ -5460,17 +5614,17 @@ function registerPrs(program2) {
|
|
|
5460
5614
|
prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason) => {
|
|
5461
5615
|
wontfix(Number.parseInt(commentId, 10), reason);
|
|
5462
5616
|
});
|
|
5463
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
5464
|
-
comment(
|
|
5617
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path43, line, body) => {
|
|
5618
|
+
comment(path43, Number.parseInt(line, 10), body);
|
|
5465
5619
|
});
|
|
5466
5620
|
}
|
|
5467
5621
|
|
|
5468
5622
|
// src/commands/refactor/check/index.ts
|
|
5469
5623
|
import { spawn as spawn3 } from "child_process";
|
|
5470
|
-
import * as
|
|
5624
|
+
import * as path26 from "path";
|
|
5471
5625
|
|
|
5472
5626
|
// src/commands/refactor/logViolations.ts
|
|
5473
|
-
import
|
|
5627
|
+
import chalk55 from "chalk";
|
|
5474
5628
|
var DEFAULT_MAX_LINES = 100;
|
|
5475
5629
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
5476
5630
|
if (violations.length === 0) {
|
|
@@ -5479,43 +5633,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
5479
5633
|
}
|
|
5480
5634
|
return;
|
|
5481
5635
|
}
|
|
5482
|
-
console.error(
|
|
5636
|
+
console.error(chalk55.red(`
|
|
5483
5637
|
Refactor check failed:
|
|
5484
5638
|
`));
|
|
5485
|
-
console.error(
|
|
5639
|
+
console.error(chalk55.red(` The following files exceed ${maxLines} lines:
|
|
5486
5640
|
`));
|
|
5487
5641
|
for (const violation of violations) {
|
|
5488
|
-
console.error(
|
|
5642
|
+
console.error(chalk55.red(` ${violation.file} (${violation.lines} lines)`));
|
|
5489
5643
|
}
|
|
5490
5644
|
console.error(
|
|
5491
|
-
|
|
5645
|
+
chalk55.yellow(
|
|
5492
5646
|
`
|
|
5493
5647
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
5494
5648
|
way to refactor it, ignore it with:
|
|
5495
5649
|
`
|
|
5496
5650
|
)
|
|
5497
5651
|
);
|
|
5498
|
-
console.error(
|
|
5652
|
+
console.error(chalk55.gray(` assist refactor ignore <file>
|
|
5499
5653
|
`));
|
|
5500
5654
|
if (process.env.CLAUDECODE) {
|
|
5501
|
-
console.error(
|
|
5655
|
+
console.error(chalk55.cyan(`
|
|
5502
5656
|
## Extracting Code to New Files
|
|
5503
5657
|
`));
|
|
5504
5658
|
console.error(
|
|
5505
|
-
|
|
5659
|
+
chalk55.cyan(
|
|
5506
5660
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
5507
5661
|
`
|
|
5508
5662
|
)
|
|
5509
5663
|
);
|
|
5510
5664
|
console.error(
|
|
5511
|
-
|
|
5665
|
+
chalk55.cyan(
|
|
5512
5666
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
5513
5667
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
5514
5668
|
`
|
|
5515
5669
|
)
|
|
5516
5670
|
);
|
|
5517
5671
|
console.error(
|
|
5518
|
-
|
|
5672
|
+
chalk55.cyan(
|
|
5519
5673
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
5520
5674
|
domains, move it to a common/shared folder.
|
|
5521
5675
|
`
|
|
@@ -5526,17 +5680,17 @@ Refactor check failed:
|
|
|
5526
5680
|
|
|
5527
5681
|
// src/commands/refactor/check/getViolations/index.ts
|
|
5528
5682
|
import { execSync as execSync29 } from "child_process";
|
|
5529
|
-
import
|
|
5683
|
+
import fs17 from "fs";
|
|
5530
5684
|
import { minimatch as minimatch4 } from "minimatch";
|
|
5531
5685
|
|
|
5532
5686
|
// src/commands/refactor/check/getViolations/getIgnoredFiles.ts
|
|
5533
|
-
import
|
|
5687
|
+
import fs16 from "fs";
|
|
5534
5688
|
var REFACTOR_YML_PATH = "refactor.yml";
|
|
5535
5689
|
function parseRefactorYml() {
|
|
5536
|
-
if (!
|
|
5690
|
+
if (!fs16.existsSync(REFACTOR_YML_PATH)) {
|
|
5537
5691
|
return [];
|
|
5538
5692
|
}
|
|
5539
|
-
const content =
|
|
5693
|
+
const content = fs16.readFileSync(REFACTOR_YML_PATH, "utf-8");
|
|
5540
5694
|
const entries = [];
|
|
5541
5695
|
const lines = content.split("\n");
|
|
5542
5696
|
let currentEntry = {};
|
|
@@ -5566,7 +5720,7 @@ function getIgnoredFiles() {
|
|
|
5566
5720
|
|
|
5567
5721
|
// src/commands/refactor/check/getViolations/index.ts
|
|
5568
5722
|
function countLines(filePath) {
|
|
5569
|
-
const content =
|
|
5723
|
+
const content = fs17.readFileSync(filePath, "utf-8");
|
|
5570
5724
|
return content.split("\n").length;
|
|
5571
5725
|
}
|
|
5572
5726
|
function getGitFiles(options2) {
|
|
@@ -5644,7 +5798,7 @@ ${failed.length} verify script(s) failed:`);
|
|
|
5644
5798
|
async function runVerifyQuietly() {
|
|
5645
5799
|
const result = findPackageJsonWithVerifyScripts(process.cwd());
|
|
5646
5800
|
if (!result) return true;
|
|
5647
|
-
const packageDir =
|
|
5801
|
+
const packageDir = path26.dirname(result.packageJsonPath);
|
|
5648
5802
|
const results = await Promise.all(
|
|
5649
5803
|
result.verifyScripts.map((script) => runScript(script, packageDir))
|
|
5650
5804
|
);
|
|
@@ -5670,39 +5824,147 @@ async function check(pattern2, options2) {
|
|
|
5670
5824
|
}
|
|
5671
5825
|
|
|
5672
5826
|
// src/commands/refactor/ignore.ts
|
|
5673
|
-
import
|
|
5674
|
-
import
|
|
5827
|
+
import fs18 from "fs";
|
|
5828
|
+
import chalk56 from "chalk";
|
|
5675
5829
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
5676
5830
|
function ignore(file) {
|
|
5677
|
-
if (!
|
|
5678
|
-
console.error(
|
|
5831
|
+
if (!fs18.existsSync(file)) {
|
|
5832
|
+
console.error(chalk56.red(`Error: File does not exist: ${file}`));
|
|
5679
5833
|
process.exit(1);
|
|
5680
5834
|
}
|
|
5681
|
-
const content =
|
|
5835
|
+
const content = fs18.readFileSync(file, "utf-8");
|
|
5682
5836
|
const lineCount = content.split("\n").length;
|
|
5683
5837
|
const maxLines = lineCount + 10;
|
|
5684
5838
|
const entry = `- file: ${file}
|
|
5685
5839
|
maxLines: ${maxLines}
|
|
5686
5840
|
`;
|
|
5687
|
-
if (
|
|
5688
|
-
const existing =
|
|
5689
|
-
|
|
5841
|
+
if (fs18.existsSync(REFACTOR_YML_PATH2)) {
|
|
5842
|
+
const existing = fs18.readFileSync(REFACTOR_YML_PATH2, "utf-8");
|
|
5843
|
+
fs18.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
|
|
5690
5844
|
} else {
|
|
5691
|
-
|
|
5845
|
+
fs18.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
5692
5846
|
}
|
|
5693
5847
|
console.log(
|
|
5694
|
-
|
|
5848
|
+
chalk56.green(
|
|
5695
5849
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
5696
5850
|
)
|
|
5697
5851
|
);
|
|
5698
5852
|
}
|
|
5699
5853
|
|
|
5700
|
-
// src/commands/refactor/
|
|
5701
|
-
import
|
|
5854
|
+
// src/commands/refactor/rename/index.ts
|
|
5855
|
+
import path27 from "path";
|
|
5702
5856
|
import chalk57 from "chalk";
|
|
5857
|
+
import { Project as Project2 } from "ts-morph";
|
|
5858
|
+
async function rename(source, destination, options2 = {}) {
|
|
5859
|
+
const sourcePath = path27.resolve(source);
|
|
5860
|
+
const destPath = path27.resolve(destination);
|
|
5861
|
+
const cwd = process.cwd();
|
|
5862
|
+
const relSource = path27.relative(cwd, sourcePath);
|
|
5863
|
+
const relDest = path27.relative(cwd, destPath);
|
|
5864
|
+
const project = new Project2({
|
|
5865
|
+
tsConfigFilePath: path27.resolve("tsconfig.json")
|
|
5866
|
+
});
|
|
5867
|
+
const sourceFile = project.getSourceFile(sourcePath);
|
|
5868
|
+
if (!sourceFile) {
|
|
5869
|
+
console.log(chalk57.red(`File not found in project: ${source}`));
|
|
5870
|
+
process.exit(1);
|
|
5871
|
+
}
|
|
5872
|
+
console.log(chalk57.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
5873
|
+
if (options2.apply) {
|
|
5874
|
+
sourceFile.move(destPath);
|
|
5875
|
+
await project.save();
|
|
5876
|
+
console.log(chalk57.green("Done"));
|
|
5877
|
+
} else {
|
|
5878
|
+
console.log(chalk57.dim("Dry run. Use --apply to execute."));
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
|
|
5882
|
+
// src/commands/refactor/renameSymbol/index.ts
|
|
5883
|
+
import path29 from "path";
|
|
5884
|
+
import chalk58 from "chalk";
|
|
5885
|
+
import { Project as Project3 } from "ts-morph";
|
|
5886
|
+
|
|
5887
|
+
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
5888
|
+
import { SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
5889
|
+
var declarationKinds = [
|
|
5890
|
+
SyntaxKind2.VariableDeclaration,
|
|
5891
|
+
SyntaxKind2.FunctionDeclaration,
|
|
5892
|
+
SyntaxKind2.ClassDeclaration,
|
|
5893
|
+
SyntaxKind2.InterfaceDeclaration,
|
|
5894
|
+
SyntaxKind2.TypeAliasDeclaration,
|
|
5895
|
+
SyntaxKind2.EnumDeclaration,
|
|
5896
|
+
SyntaxKind2.PropertyDeclaration,
|
|
5897
|
+
SyntaxKind2.MethodDeclaration,
|
|
5898
|
+
SyntaxKind2.Parameter
|
|
5899
|
+
];
|
|
5900
|
+
function isDeclaration(identifier) {
|
|
5901
|
+
const parent = identifier.getParent();
|
|
5902
|
+
return parent !== void 0 && declarationKinds.includes(parent.getKind());
|
|
5903
|
+
}
|
|
5904
|
+
function findSymbol(sourceFile, symbolName) {
|
|
5905
|
+
for (const id of sourceFile.getDescendantsOfKind(SyntaxKind2.Identifier)) {
|
|
5906
|
+
if (id.getText() === symbolName && isDeclaration(id)) return id;
|
|
5907
|
+
}
|
|
5908
|
+
return void 0;
|
|
5909
|
+
}
|
|
5910
|
+
|
|
5911
|
+
// src/commands/refactor/renameSymbol/groupReferences.ts
|
|
5912
|
+
import path28 from "path";
|
|
5913
|
+
function groupReferences(symbol, cwd) {
|
|
5914
|
+
const refs = symbol.findReferencesAsNodes();
|
|
5915
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
5916
|
+
for (const ref of refs) {
|
|
5917
|
+
const refFile = path28.relative(cwd, ref.getSourceFile().getFilePath());
|
|
5918
|
+
const lines = grouped.get(refFile) ?? [];
|
|
5919
|
+
if (!grouped.has(refFile)) grouped.set(refFile, lines);
|
|
5920
|
+
lines.push(ref.getStartLineNumber());
|
|
5921
|
+
}
|
|
5922
|
+
return grouped;
|
|
5923
|
+
}
|
|
5924
|
+
|
|
5925
|
+
// src/commands/refactor/renameSymbol/index.ts
|
|
5926
|
+
async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
5927
|
+
const filePath = path29.resolve(file);
|
|
5928
|
+
const tsConfigPath = path29.resolve("tsconfig.json");
|
|
5929
|
+
const cwd = process.cwd();
|
|
5930
|
+
const project = new Project3({ tsConfigFilePath: tsConfigPath });
|
|
5931
|
+
const sourceFile = project.getSourceFile(filePath);
|
|
5932
|
+
if (!sourceFile) {
|
|
5933
|
+
console.log(chalk58.red(`File not found in project: ${file}`));
|
|
5934
|
+
process.exit(1);
|
|
5935
|
+
}
|
|
5936
|
+
const symbol = findSymbol(sourceFile, oldName);
|
|
5937
|
+
if (!symbol) {
|
|
5938
|
+
console.log(chalk58.red(`Symbol "${oldName}" not found in ${file}`));
|
|
5939
|
+
process.exit(1);
|
|
5940
|
+
}
|
|
5941
|
+
const grouped = groupReferences(symbol, cwd);
|
|
5942
|
+
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
5943
|
+
console.log(
|
|
5944
|
+
chalk58.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
5945
|
+
`)
|
|
5946
|
+
);
|
|
5947
|
+
for (const [refFile, lines] of grouped) {
|
|
5948
|
+
console.log(
|
|
5949
|
+
` ${chalk58.dim(refFile)}: lines ${chalk58.cyan(lines.join(", "))}`
|
|
5950
|
+
);
|
|
5951
|
+
}
|
|
5952
|
+
if (options2.apply) {
|
|
5953
|
+
symbol.rename(newName);
|
|
5954
|
+
await project.save();
|
|
5955
|
+
console.log(chalk58.green(`
|
|
5956
|
+
Renamed ${oldName} \u2192 ${newName}`));
|
|
5957
|
+
} else {
|
|
5958
|
+
console.log(chalk58.dim("\nDry run. Use --apply to execute."));
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5961
|
+
|
|
5962
|
+
// src/commands/refactor/restructure/index.ts
|
|
5963
|
+
import path38 from "path";
|
|
5964
|
+
import chalk61 from "chalk";
|
|
5703
5965
|
|
|
5704
5966
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
5705
|
-
import
|
|
5967
|
+
import path30 from "path";
|
|
5706
5968
|
import ts7 from "typescript";
|
|
5707
5969
|
|
|
5708
5970
|
// src/commands/refactor/restructure/buildImportGraph/getImportSpecifiers.ts
|
|
@@ -5729,7 +5991,7 @@ function loadParsedConfig(tsConfigPath) {
|
|
|
5729
5991
|
return ts7.parseJsonConfigFileContent(
|
|
5730
5992
|
configFile.config,
|
|
5731
5993
|
ts7.sys,
|
|
5732
|
-
|
|
5994
|
+
path30.dirname(tsConfigPath)
|
|
5733
5995
|
);
|
|
5734
5996
|
}
|
|
5735
5997
|
function addToSetMap(map, key, value) {
|
|
@@ -5745,7 +6007,7 @@ function resolveImport(specifier, filePath, options2) {
|
|
|
5745
6007
|
const resolved = ts7.resolveModuleName(specifier, filePath, options2, ts7.sys);
|
|
5746
6008
|
const resolvedPath = resolved.resolvedModule?.resolvedFileName;
|
|
5747
6009
|
if (!resolvedPath || resolvedPath.includes("node_modules")) return null;
|
|
5748
|
-
return
|
|
6010
|
+
return path30.resolve(resolvedPath);
|
|
5749
6011
|
}
|
|
5750
6012
|
function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
5751
6013
|
const parsed = loadParsedConfig(tsConfigPath);
|
|
@@ -5754,7 +6016,7 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
5754
6016
|
const importedBy = /* @__PURE__ */ new Map();
|
|
5755
6017
|
const imports = /* @__PURE__ */ new Map();
|
|
5756
6018
|
for (const sourceFile of program2.getSourceFiles()) {
|
|
5757
|
-
const filePath =
|
|
6019
|
+
const filePath = path30.resolve(sourceFile.fileName);
|
|
5758
6020
|
if (filePath.includes("node_modules")) continue;
|
|
5759
6021
|
for (const specifier of getImportSpecifiers(sourceFile)) {
|
|
5760
6022
|
const absTarget = resolveImport(specifier, filePath, parsed.options);
|
|
@@ -5768,12 +6030,12 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
5768
6030
|
}
|
|
5769
6031
|
|
|
5770
6032
|
// src/commands/refactor/restructure/clusterDirectories.ts
|
|
5771
|
-
import
|
|
6033
|
+
import path31 from "path";
|
|
5772
6034
|
function clusterDirectories(graph) {
|
|
5773
6035
|
const dirImportedBy = /* @__PURE__ */ new Map();
|
|
5774
6036
|
for (const edge of graph.edges) {
|
|
5775
|
-
const sourceDir =
|
|
5776
|
-
const targetDir =
|
|
6037
|
+
const sourceDir = path31.dirname(edge.source);
|
|
6038
|
+
const targetDir = path31.dirname(edge.target);
|
|
5777
6039
|
if (sourceDir === targetDir) continue;
|
|
5778
6040
|
if (!graph.files.has(edge.target)) continue;
|
|
5779
6041
|
const existing = dirImportedBy.get(targetDir) ?? /* @__PURE__ */ new Set();
|
|
@@ -5801,20 +6063,20 @@ function clusterDirectories(graph) {
|
|
|
5801
6063
|
return clusters;
|
|
5802
6064
|
}
|
|
5803
6065
|
function isAncestor(ancestor, descendant) {
|
|
5804
|
-
const rel =
|
|
6066
|
+
const rel = path31.relative(ancestor, descendant);
|
|
5805
6067
|
return !rel.startsWith("..") && rel !== "";
|
|
5806
6068
|
}
|
|
5807
6069
|
|
|
5808
6070
|
// src/commands/refactor/restructure/clusterFiles.ts
|
|
5809
|
-
import
|
|
6071
|
+
import path32 from "path";
|
|
5810
6072
|
function findRootParent(file, importedBy, visited) {
|
|
5811
6073
|
const importers = importedBy.get(file);
|
|
5812
6074
|
if (!importers || importers.size !== 1) return file;
|
|
5813
6075
|
const parent = [...importers][0];
|
|
5814
|
-
const parentDir =
|
|
5815
|
-
const fileDir =
|
|
6076
|
+
const parentDir = path32.dirname(parent);
|
|
6077
|
+
const fileDir = path32.dirname(file);
|
|
5816
6078
|
if (parentDir !== fileDir) return file;
|
|
5817
|
-
if (
|
|
6079
|
+
if (path32.basename(parent, path32.extname(parent)) === "index") return file;
|
|
5818
6080
|
if (visited.has(parent)) return file;
|
|
5819
6081
|
visited.add(parent);
|
|
5820
6082
|
return findRootParent(parent, importedBy, visited);
|
|
@@ -5822,16 +6084,16 @@ function findRootParent(file, importedBy, visited) {
|
|
|
5822
6084
|
function clusterFiles(graph) {
|
|
5823
6085
|
const clusters = /* @__PURE__ */ new Map();
|
|
5824
6086
|
for (const file of graph.files) {
|
|
5825
|
-
const basename7 =
|
|
6087
|
+
const basename7 = path32.basename(file, path32.extname(file));
|
|
5826
6088
|
if (basename7 === "index") continue;
|
|
5827
6089
|
const importers = graph.importedBy.get(file);
|
|
5828
6090
|
if (!importers || importers.size !== 1) continue;
|
|
5829
6091
|
const parent = [...importers][0];
|
|
5830
6092
|
if (!graph.files.has(parent)) continue;
|
|
5831
|
-
const parentDir =
|
|
5832
|
-
const fileDir =
|
|
6093
|
+
const parentDir = path32.dirname(parent);
|
|
6094
|
+
const fileDir = path32.dirname(file);
|
|
5833
6095
|
if (parentDir !== fileDir) continue;
|
|
5834
|
-
const parentBasename =
|
|
6096
|
+
const parentBasename = path32.basename(parent, path32.extname(parent));
|
|
5835
6097
|
if (parentBasename === "index") continue;
|
|
5836
6098
|
const root = findRootParent(parent, graph.importedBy, /* @__PURE__ */ new Set([file]));
|
|
5837
6099
|
if (!root || root === file) continue;
|
|
@@ -5843,10 +6105,10 @@ function clusterFiles(graph) {
|
|
|
5843
6105
|
}
|
|
5844
6106
|
|
|
5845
6107
|
// src/commands/refactor/restructure/computeRewrites/index.ts
|
|
5846
|
-
import
|
|
6108
|
+
import path33 from "path";
|
|
5847
6109
|
|
|
5848
6110
|
// src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
|
|
5849
|
-
import
|
|
6111
|
+
import fs19 from "fs";
|
|
5850
6112
|
function getOrCreateList(map, key) {
|
|
5851
6113
|
const list4 = map.get(key) ?? [];
|
|
5852
6114
|
if (!map.has(key)) map.set(key, list4);
|
|
@@ -5865,7 +6127,7 @@ function rewriteSpecifier(content, oldSpecifier, newSpecifier) {
|
|
|
5865
6127
|
return content.replace(pattern2, `$1${newSpecifier}$2`);
|
|
5866
6128
|
}
|
|
5867
6129
|
function applyFileRewrites(file, fileRewrites) {
|
|
5868
|
-
let content =
|
|
6130
|
+
let content = fs19.readFileSync(file, "utf-8");
|
|
5869
6131
|
for (const { oldSpecifier, newSpecifier } of fileRewrites) {
|
|
5870
6132
|
content = rewriteSpecifier(content, oldSpecifier, newSpecifier);
|
|
5871
6133
|
}
|
|
@@ -5897,7 +6159,7 @@ function normalizeSpecifier(rel) {
|
|
|
5897
6159
|
);
|
|
5898
6160
|
}
|
|
5899
6161
|
function computeSpecifier(fromFile, toFile) {
|
|
5900
|
-
return normalizeSpecifier(
|
|
6162
|
+
return normalizeSpecifier(path33.relative(path33.dirname(fromFile), toFile));
|
|
5901
6163
|
}
|
|
5902
6164
|
function isAffected(edge, moveMap) {
|
|
5903
6165
|
return moveMap.has(edge.target) || moveMap.has(edge.source);
|
|
@@ -5941,51 +6203,51 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
5941
6203
|
}
|
|
5942
6204
|
|
|
5943
6205
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
5944
|
-
import
|
|
5945
|
-
import
|
|
6206
|
+
import path34 from "path";
|
|
6207
|
+
import chalk59 from "chalk";
|
|
5946
6208
|
function relPath(filePath) {
|
|
5947
|
-
return
|
|
6209
|
+
return path34.relative(process.cwd(), filePath);
|
|
5948
6210
|
}
|
|
5949
6211
|
function displayMoves(plan) {
|
|
5950
6212
|
if (plan.moves.length === 0) return;
|
|
5951
|
-
console.log(
|
|
6213
|
+
console.log(chalk59.bold("\nFile moves:"));
|
|
5952
6214
|
for (const move of plan.moves) {
|
|
5953
6215
|
console.log(
|
|
5954
|
-
` ${
|
|
6216
|
+
` ${chalk59.red(relPath(move.from))} \u2192 ${chalk59.green(relPath(move.to))}`
|
|
5955
6217
|
);
|
|
5956
|
-
console.log(
|
|
6218
|
+
console.log(chalk59.dim(` ${move.reason}`));
|
|
5957
6219
|
}
|
|
5958
6220
|
}
|
|
5959
6221
|
function displayRewrites(rewrites) {
|
|
5960
6222
|
if (rewrites.length === 0) return;
|
|
5961
6223
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
5962
|
-
console.log(
|
|
6224
|
+
console.log(chalk59.bold(`
|
|
5963
6225
|
Import rewrites (${affectedFiles.size} files):`));
|
|
5964
6226
|
for (const file of affectedFiles) {
|
|
5965
|
-
console.log(` ${
|
|
6227
|
+
console.log(` ${chalk59.cyan(relPath(file))}:`);
|
|
5966
6228
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
5967
6229
|
(r) => r.file === file
|
|
5968
6230
|
)) {
|
|
5969
6231
|
console.log(
|
|
5970
|
-
` ${
|
|
6232
|
+
` ${chalk59.red(`"${oldSpecifier}"`)} \u2192 ${chalk59.green(`"${newSpecifier}"`)}`
|
|
5971
6233
|
);
|
|
5972
6234
|
}
|
|
5973
6235
|
}
|
|
5974
6236
|
}
|
|
5975
6237
|
function displayPlan(plan) {
|
|
5976
6238
|
if (plan.warnings.length > 0) {
|
|
5977
|
-
console.log(
|
|
5978
|
-
for (const w of plan.warnings) console.log(
|
|
6239
|
+
console.log(chalk59.yellow("\nWarnings:"));
|
|
6240
|
+
for (const w of plan.warnings) console.log(chalk59.yellow(` ${w}`));
|
|
5979
6241
|
}
|
|
5980
6242
|
if (plan.newDirectories.length > 0) {
|
|
5981
|
-
console.log(
|
|
6243
|
+
console.log(chalk59.bold("\nNew directories:"));
|
|
5982
6244
|
for (const dir of plan.newDirectories)
|
|
5983
|
-
console.log(
|
|
6245
|
+
console.log(chalk59.green(` ${dir}/`));
|
|
5984
6246
|
}
|
|
5985
6247
|
displayMoves(plan);
|
|
5986
6248
|
displayRewrites(plan.rewrites);
|
|
5987
6249
|
console.log(
|
|
5988
|
-
|
|
6250
|
+
chalk59.dim(
|
|
5989
6251
|
`
|
|
5990
6252
|
Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
|
|
5991
6253
|
)
|
|
@@ -5993,45 +6255,45 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
5993
6255
|
}
|
|
5994
6256
|
|
|
5995
6257
|
// src/commands/refactor/restructure/executePlan.ts
|
|
5996
|
-
import
|
|
5997
|
-
import
|
|
5998
|
-
import
|
|
6258
|
+
import fs20 from "fs";
|
|
6259
|
+
import path35 from "path";
|
|
6260
|
+
import chalk60 from "chalk";
|
|
5999
6261
|
function executePlan(plan) {
|
|
6000
6262
|
const updatedContents = applyRewrites(plan.rewrites);
|
|
6001
6263
|
for (const [file, content] of updatedContents) {
|
|
6002
|
-
|
|
6264
|
+
fs20.writeFileSync(file, content, "utf-8");
|
|
6003
6265
|
console.log(
|
|
6004
|
-
|
|
6266
|
+
chalk60.cyan(` Rewrote imports in ${path35.relative(process.cwd(), file)}`)
|
|
6005
6267
|
);
|
|
6006
6268
|
}
|
|
6007
6269
|
for (const dir of plan.newDirectories) {
|
|
6008
|
-
|
|
6009
|
-
console.log(
|
|
6270
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
6271
|
+
console.log(chalk60.green(` Created ${path35.relative(process.cwd(), dir)}/`));
|
|
6010
6272
|
}
|
|
6011
6273
|
for (const move of plan.moves) {
|
|
6012
|
-
const targetDir =
|
|
6013
|
-
if (!
|
|
6014
|
-
|
|
6274
|
+
const targetDir = path35.dirname(move.to);
|
|
6275
|
+
if (!fs20.existsSync(targetDir)) {
|
|
6276
|
+
fs20.mkdirSync(targetDir, { recursive: true });
|
|
6015
6277
|
}
|
|
6016
|
-
|
|
6278
|
+
fs20.renameSync(move.from, move.to);
|
|
6017
6279
|
console.log(
|
|
6018
|
-
|
|
6019
|
-
` Moved ${
|
|
6280
|
+
chalk60.white(
|
|
6281
|
+
` Moved ${path35.relative(process.cwd(), move.from)} \u2192 ${path35.relative(process.cwd(), move.to)}`
|
|
6020
6282
|
)
|
|
6021
6283
|
);
|
|
6022
6284
|
}
|
|
6023
|
-
removeEmptyDirectories(plan.moves.map((m) =>
|
|
6285
|
+
removeEmptyDirectories(plan.moves.map((m) => path35.dirname(m.from)));
|
|
6024
6286
|
}
|
|
6025
6287
|
function removeEmptyDirectories(dirs) {
|
|
6026
6288
|
const unique = [...new Set(dirs)];
|
|
6027
6289
|
for (const dir of unique) {
|
|
6028
|
-
if (!
|
|
6029
|
-
const entries =
|
|
6290
|
+
if (!fs20.existsSync(dir)) continue;
|
|
6291
|
+
const entries = fs20.readdirSync(dir);
|
|
6030
6292
|
if (entries.length === 0) {
|
|
6031
|
-
|
|
6293
|
+
fs20.rmdirSync(dir);
|
|
6032
6294
|
console.log(
|
|
6033
|
-
|
|
6034
|
-
` Removed empty directory ${
|
|
6295
|
+
chalk60.dim(
|
|
6296
|
+
` Removed empty directory ${path35.relative(process.cwd(), dir)}`
|
|
6035
6297
|
)
|
|
6036
6298
|
);
|
|
6037
6299
|
}
|
|
@@ -6039,36 +6301,36 @@ function removeEmptyDirectories(dirs) {
|
|
|
6039
6301
|
}
|
|
6040
6302
|
|
|
6041
6303
|
// src/commands/refactor/restructure/planFileMoves/index.ts
|
|
6042
|
-
import
|
|
6043
|
-
import
|
|
6304
|
+
import fs22 from "fs";
|
|
6305
|
+
import path37 from "path";
|
|
6044
6306
|
|
|
6045
6307
|
// src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
|
|
6046
|
-
import
|
|
6047
|
-
import
|
|
6308
|
+
import fs21 from "fs";
|
|
6309
|
+
import path36 from "path";
|
|
6048
6310
|
function collectEntry(results, dir, entry) {
|
|
6049
|
-
const full =
|
|
6311
|
+
const full = path36.join(dir, entry.name);
|
|
6050
6312
|
const items = entry.isDirectory() ? listFilesRecursive(full) : [full];
|
|
6051
6313
|
results.push(...items);
|
|
6052
6314
|
}
|
|
6053
6315
|
function listFilesRecursive(dir) {
|
|
6054
|
-
if (!
|
|
6316
|
+
if (!fs21.existsSync(dir)) return [];
|
|
6055
6317
|
const results = [];
|
|
6056
|
-
for (const entry of
|
|
6318
|
+
for (const entry of fs21.readdirSync(dir, { withFileTypes: true })) {
|
|
6057
6319
|
collectEntry(results, dir, entry);
|
|
6058
6320
|
}
|
|
6059
6321
|
return results;
|
|
6060
6322
|
}
|
|
6061
6323
|
function addDirectoryFileMoves(moves, childDir, newLocation, reason) {
|
|
6062
6324
|
for (const file of listFilesRecursive(childDir)) {
|
|
6063
|
-
const rel =
|
|
6064
|
-
moves.push({ from: file, to:
|
|
6325
|
+
const rel = path36.relative(childDir, file);
|
|
6326
|
+
moves.push({ from: file, to: path36.join(newLocation, rel), reason });
|
|
6065
6327
|
}
|
|
6066
6328
|
}
|
|
6067
6329
|
function resolveChildDest(parentDir, childDir) {
|
|
6068
|
-
return
|
|
6330
|
+
return path36.join(parentDir, path36.basename(childDir));
|
|
6069
6331
|
}
|
|
6070
6332
|
function childMoveReason(parentDir) {
|
|
6071
|
-
return `Directory only imported from ${
|
|
6333
|
+
return `Directory only imported from ${path36.basename(parentDir)}/`;
|
|
6072
6334
|
}
|
|
6073
6335
|
function registerDirectoryMove(result, childDir, dest, parentDir) {
|
|
6074
6336
|
result.directories.push(dest);
|
|
@@ -6096,7 +6358,7 @@ function emptyResult() {
|
|
|
6096
6358
|
return { moves: [], directories: [], warnings: [] };
|
|
6097
6359
|
}
|
|
6098
6360
|
function childMoveData(child, newDir, parentBase) {
|
|
6099
|
-
const to =
|
|
6361
|
+
const to = path37.join(newDir, path37.basename(child));
|
|
6100
6362
|
return { from: child, to, reason: `Only imported by ${parentBase}` };
|
|
6101
6363
|
}
|
|
6102
6364
|
function addChildMoves(moves, children, newDir, parentBase) {
|
|
@@ -6104,20 +6366,20 @@ function addChildMoves(moves, children, newDir, parentBase) {
|
|
|
6104
6366
|
moves.push(childMoveData(child, newDir, parentBase));
|
|
6105
6367
|
}
|
|
6106
6368
|
function checkDirConflict(result, label2, dir) {
|
|
6107
|
-
if (!
|
|
6369
|
+
if (!fs22.existsSync(dir)) return false;
|
|
6108
6370
|
result.warnings.push(`Skipping ${label2}: directory ${dir} already exists`);
|
|
6109
6371
|
return true;
|
|
6110
6372
|
}
|
|
6111
6373
|
function getBaseName(filePath) {
|
|
6112
|
-
return
|
|
6374
|
+
return path37.basename(filePath, path37.extname(filePath));
|
|
6113
6375
|
}
|
|
6114
6376
|
function resolveClusterDir(parent) {
|
|
6115
|
-
return
|
|
6377
|
+
return path37.join(path37.dirname(parent), getBaseName(parent));
|
|
6116
6378
|
}
|
|
6117
6379
|
function createParentMove(parent, newDir) {
|
|
6118
6380
|
return {
|
|
6119
6381
|
from: parent,
|
|
6120
|
-
to:
|
|
6382
|
+
to: path37.join(newDir, `index${path37.extname(parent)}`),
|
|
6121
6383
|
reason: `Main module of new ${getBaseName(parent)}/ directory`
|
|
6122
6384
|
};
|
|
6123
6385
|
}
|
|
@@ -6141,7 +6403,7 @@ function planFileMoves(clusters) {
|
|
|
6141
6403
|
|
|
6142
6404
|
// src/commands/refactor/restructure/index.ts
|
|
6143
6405
|
function buildPlan(candidateFiles, tsConfigPath) {
|
|
6144
|
-
const candidates = new Set(candidateFiles.map((f) =>
|
|
6406
|
+
const candidates = new Set(candidateFiles.map((f) => path38.resolve(f)));
|
|
6145
6407
|
const graph = buildImportGraph(candidates, tsConfigPath);
|
|
6146
6408
|
const allProjectFiles = /* @__PURE__ */ new Set([
|
|
6147
6409
|
...graph.importedBy.keys(),
|
|
@@ -6161,22 +6423,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
6161
6423
|
const targetPattern = pattern2 ?? "src";
|
|
6162
6424
|
const files = findSourceFiles2(targetPattern);
|
|
6163
6425
|
if (files.length === 0) {
|
|
6164
|
-
console.log(
|
|
6426
|
+
console.log(chalk61.yellow("No files found matching pattern"));
|
|
6165
6427
|
return;
|
|
6166
6428
|
}
|
|
6167
|
-
const tsConfigPath =
|
|
6429
|
+
const tsConfigPath = path38.resolve("tsconfig.json");
|
|
6168
6430
|
const plan = buildPlan(files, tsConfigPath);
|
|
6169
6431
|
if (plan.moves.length === 0) {
|
|
6170
|
-
console.log(
|
|
6432
|
+
console.log(chalk61.green("No restructuring needed"));
|
|
6171
6433
|
return;
|
|
6172
6434
|
}
|
|
6173
6435
|
displayPlan(plan);
|
|
6174
6436
|
if (options2.apply) {
|
|
6175
|
-
console.log(
|
|
6437
|
+
console.log(chalk61.bold("\nApplying changes..."));
|
|
6176
6438
|
executePlan(plan);
|
|
6177
|
-
console.log(
|
|
6439
|
+
console.log(chalk61.green("\nRestructuring complete"));
|
|
6178
6440
|
} else {
|
|
6179
|
-
console.log(
|
|
6441
|
+
console.log(chalk61.dim("\nDry run. Use --apply to execute."));
|
|
6180
6442
|
}
|
|
6181
6443
|
}
|
|
6182
6444
|
|
|
@@ -6189,6 +6451,11 @@ function registerRefactor(program2) {
|
|
|
6189
6451
|
Number.parseInt
|
|
6190
6452
|
).action(check);
|
|
6191
6453
|
refactorCommand.command("ignore <file>").description("Add a file to the refactor ignore list").action(ignore);
|
|
6454
|
+
const renameCommand = refactorCommand.command("rename").description("Rename files or symbols with automatic import updates");
|
|
6455
|
+
renameCommand.command("file <source> <destination>").description("Rename/move a TypeScript file and update all imports").option("--apply", "Execute the rename (default: dry-run)").action(rename);
|
|
6456
|
+
renameCommand.command("symbol <file> <oldName> <newName>").description(
|
|
6457
|
+
"Rename a variable, function, class, or type across the project"
|
|
6458
|
+
).option("--apply", "Execute the rename (default: dry-run)").action(renameSymbol);
|
|
6192
6459
|
refactorCommand.command("restructure [pattern]").description(
|
|
6193
6460
|
"Analyze import graph and restructure tightly-coupled files into nested directories"
|
|
6194
6461
|
).option("--apply", "Execute the restructuring (default: dry-run)").option(
|
|
@@ -6315,7 +6582,7 @@ async function configure() {
|
|
|
6315
6582
|
import { existsSync as existsSync27 } from "fs";
|
|
6316
6583
|
|
|
6317
6584
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
6318
|
-
import { dirname as
|
|
6585
|
+
import { dirname as dirname16, join as join24 } from "path";
|
|
6319
6586
|
|
|
6320
6587
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
6321
6588
|
import { renameSync } from "fs";
|
|
@@ -6365,11 +6632,11 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
6365
6632
|
for (let i = 0; i < vttFiles.length; i++) {
|
|
6366
6633
|
const vttFile = vttFiles[i];
|
|
6367
6634
|
if (!isValidDatePrefix(vttFile.filename)) {
|
|
6368
|
-
const vttFileDir =
|
|
6635
|
+
const vttFileDir = dirname16(vttFile.absolutePath);
|
|
6369
6636
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
6370
6637
|
if (newFilename) {
|
|
6371
6638
|
const newRelativePath = join24(
|
|
6372
|
-
|
|
6639
|
+
dirname16(vttFile.relativePath),
|
|
6373
6640
|
newFilename
|
|
6374
6641
|
);
|
|
6375
6642
|
vttFiles[i] = {
|
|
@@ -6387,7 +6654,7 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
6387
6654
|
|
|
6388
6655
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
6389
6656
|
import { existsSync as existsSync26, mkdirSync as mkdirSync7, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "fs";
|
|
6390
|
-
import { basename as basename5, dirname as
|
|
6657
|
+
import { basename as basename5, dirname as dirname17, join as join25 } from "path";
|
|
6391
6658
|
|
|
6392
6659
|
// src/commands/transcript/cleanText.ts
|
|
6393
6660
|
function cleanText(text) {
|
|
@@ -6601,7 +6868,7 @@ function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
|
6601
6868
|
}
|
|
6602
6869
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
6603
6870
|
const mdFile = toMdFilename(vttFile.filename);
|
|
6604
|
-
const relativeDir =
|
|
6871
|
+
const relativeDir = dirname17(vttFile.relativePath);
|
|
6605
6872
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
6606
6873
|
const outputPath = join25(outputDir, mdFile);
|
|
6607
6874
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
@@ -6706,7 +6973,7 @@ async function format() {
|
|
|
6706
6973
|
|
|
6707
6974
|
// src/commands/transcript/summarise/index.ts
|
|
6708
6975
|
import { existsSync as existsSync29 } from "fs";
|
|
6709
|
-
import { basename as basename6, dirname as
|
|
6976
|
+
import { basename as basename6, dirname as dirname19, join as join27, relative as relative2 } from "path";
|
|
6710
6977
|
|
|
6711
6978
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
6712
6979
|
import {
|
|
@@ -6716,17 +6983,17 @@ import {
|
|
|
6716
6983
|
renameSync as renameSync2,
|
|
6717
6984
|
rmSync
|
|
6718
6985
|
} from "fs";
|
|
6719
|
-
import { dirname as
|
|
6986
|
+
import { dirname as dirname18, join as join26 } from "path";
|
|
6720
6987
|
|
|
6721
6988
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
6722
|
-
import
|
|
6989
|
+
import chalk62 from "chalk";
|
|
6723
6990
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
6724
6991
|
function validateStagedContent(filename, content) {
|
|
6725
6992
|
const firstLine = content.split("\n")[0];
|
|
6726
6993
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
6727
6994
|
if (!match) {
|
|
6728
6995
|
console.error(
|
|
6729
|
-
|
|
6996
|
+
chalk62.red(
|
|
6730
6997
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
6731
6998
|
)
|
|
6732
6999
|
);
|
|
@@ -6735,7 +7002,7 @@ function validateStagedContent(filename, content) {
|
|
|
6735
7002
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
6736
7003
|
if (!contentAfterLink) {
|
|
6737
7004
|
console.error(
|
|
6738
|
-
|
|
7005
|
+
chalk62.red(
|
|
6739
7006
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
6740
7007
|
)
|
|
6741
7008
|
);
|
|
@@ -6770,7 +7037,7 @@ function processStagedFile() {
|
|
|
6770
7037
|
process.exit(1);
|
|
6771
7038
|
}
|
|
6772
7039
|
const destPath = join26(summaryDir, matchingTranscript.relativePath);
|
|
6773
|
-
const destDir =
|
|
7040
|
+
const destDir = dirname18(destPath);
|
|
6774
7041
|
if (!existsSync28(destDir)) {
|
|
6775
7042
|
mkdirSync8(destDir, { recursive: true });
|
|
6776
7043
|
}
|
|
@@ -6784,7 +7051,7 @@ function processStagedFile() {
|
|
|
6784
7051
|
|
|
6785
7052
|
// src/commands/transcript/summarise/index.ts
|
|
6786
7053
|
function buildRelativeKey(relativePath, baseName) {
|
|
6787
|
-
const relDir =
|
|
7054
|
+
const relDir = dirname19(relativePath);
|
|
6788
7055
|
return relDir === "." ? baseName : join27(relDir, baseName);
|
|
6789
7056
|
}
|
|
6790
7057
|
function buildSummaryIndex(summaryDir) {
|
|
@@ -6820,7 +7087,7 @@ function summarise2() {
|
|
|
6820
7087
|
const next2 = missing[0];
|
|
6821
7088
|
const outputFilename = `${getTranscriptBaseName(next2.filename)}.md`;
|
|
6822
7089
|
const outputPath = join27(STAGING_DIR, outputFilename);
|
|
6823
|
-
const summaryFileDir = join27(summaryDir,
|
|
7090
|
+
const summaryFileDir = join27(summaryDir, dirname19(next2.relativePath));
|
|
6824
7091
|
const relativeTranscriptPath = encodeURI(
|
|
6825
7092
|
relative2(summaryFileDir, next2.absolutePath).replace(/\\/g, "/")
|
|
6826
7093
|
);
|
|
@@ -6870,9 +7137,9 @@ import { join as join29 } from "path";
|
|
|
6870
7137
|
|
|
6871
7138
|
// src/commands/voice/shared.ts
|
|
6872
7139
|
import { homedir as homedir7 } from "os";
|
|
6873
|
-
import { dirname as
|
|
7140
|
+
import { dirname as dirname20, join as join28 } from "path";
|
|
6874
7141
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
6875
|
-
var __dirname6 =
|
|
7142
|
+
var __dirname6 = dirname20(fileURLToPath6(import.meta.url));
|
|
6876
7143
|
var VOICE_DIR = join28(homedir7(), ".assist", "voice");
|
|
6877
7144
|
var voicePaths = {
|
|
6878
7145
|
dir: VOICE_DIR,
|
|
@@ -7128,7 +7395,7 @@ function registerVoice(program2) {
|
|
|
7128
7395
|
|
|
7129
7396
|
// src/commands/roam/auth.ts
|
|
7130
7397
|
import { randomBytes } from "crypto";
|
|
7131
|
-
import
|
|
7398
|
+
import chalk63 from "chalk";
|
|
7132
7399
|
|
|
7133
7400
|
// src/lib/openBrowser.ts
|
|
7134
7401
|
import { execSync as execSync31 } from "child_process";
|
|
@@ -7303,13 +7570,13 @@ async function auth() {
|
|
|
7303
7570
|
saveGlobalConfig(config);
|
|
7304
7571
|
const state = randomBytes(16).toString("hex");
|
|
7305
7572
|
console.log(
|
|
7306
|
-
|
|
7573
|
+
chalk63.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
7307
7574
|
);
|
|
7308
|
-
console.log(
|
|
7309
|
-
console.log(
|
|
7310
|
-
console.log(
|
|
7575
|
+
console.log(chalk63.white("http://localhost:14523/callback\n"));
|
|
7576
|
+
console.log(chalk63.blue("Opening browser for authorization..."));
|
|
7577
|
+
console.log(chalk63.dim("Waiting for authorization callback..."));
|
|
7311
7578
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
7312
|
-
console.log(
|
|
7579
|
+
console.log(chalk63.dim("Exchanging code for tokens..."));
|
|
7313
7580
|
const tokens = await exchangeToken({
|
|
7314
7581
|
code,
|
|
7315
7582
|
clientId,
|
|
@@ -7325,7 +7592,7 @@ async function auth() {
|
|
|
7325
7592
|
};
|
|
7326
7593
|
saveGlobalConfig(config);
|
|
7327
7594
|
console.log(
|
|
7328
|
-
|
|
7595
|
+
chalk63.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
7329
7596
|
);
|
|
7330
7597
|
}
|
|
7331
7598
|
|
|
@@ -7513,14 +7780,14 @@ function run2(name, args) {
|
|
|
7513
7780
|
}
|
|
7514
7781
|
|
|
7515
7782
|
// src/commands/statusLine.ts
|
|
7516
|
-
import
|
|
7783
|
+
import chalk64 from "chalk";
|
|
7517
7784
|
function formatNumber(num) {
|
|
7518
7785
|
return num.toLocaleString("en-US");
|
|
7519
7786
|
}
|
|
7520
7787
|
function colorizePercent(pct) {
|
|
7521
7788
|
const label2 = `${pct}%`;
|
|
7522
|
-
if (pct > 80) return
|
|
7523
|
-
if (pct > 40) return
|
|
7789
|
+
if (pct > 80) return chalk64.red(label2);
|
|
7790
|
+
if (pct > 40) return chalk64.yellow(label2);
|
|
7524
7791
|
return label2;
|
|
7525
7792
|
}
|
|
7526
7793
|
async function statusLine() {
|
|
@@ -7538,29 +7805,29 @@ async function statusLine() {
|
|
|
7538
7805
|
}
|
|
7539
7806
|
|
|
7540
7807
|
// src/commands/sync.ts
|
|
7541
|
-
import * as
|
|
7808
|
+
import * as fs25 from "fs";
|
|
7542
7809
|
import * as os from "os";
|
|
7543
|
-
import * as
|
|
7810
|
+
import * as path41 from "path";
|
|
7544
7811
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
7545
7812
|
|
|
7546
7813
|
// src/commands/sync/syncClaudeMd.ts
|
|
7547
|
-
import * as
|
|
7548
|
-
import * as
|
|
7549
|
-
import
|
|
7814
|
+
import * as fs23 from "fs";
|
|
7815
|
+
import * as path39 from "path";
|
|
7816
|
+
import chalk65 from "chalk";
|
|
7550
7817
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
7551
|
-
const source =
|
|
7552
|
-
const target =
|
|
7553
|
-
const sourceContent =
|
|
7554
|
-
if (
|
|
7555
|
-
const targetContent =
|
|
7818
|
+
const source = path39.join(claudeDir, "CLAUDE.md");
|
|
7819
|
+
const target = path39.join(targetBase, "CLAUDE.md");
|
|
7820
|
+
const sourceContent = fs23.readFileSync(source, "utf-8");
|
|
7821
|
+
if (fs23.existsSync(target)) {
|
|
7822
|
+
const targetContent = fs23.readFileSync(target, "utf-8");
|
|
7556
7823
|
if (sourceContent !== targetContent) {
|
|
7557
7824
|
console.log(
|
|
7558
|
-
|
|
7825
|
+
chalk65.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
7559
7826
|
);
|
|
7560
7827
|
console.log();
|
|
7561
7828
|
printDiff(targetContent, sourceContent);
|
|
7562
7829
|
const confirm = await promptConfirm(
|
|
7563
|
-
|
|
7830
|
+
chalk65.red("Overwrite existing CLAUDE.md?"),
|
|
7564
7831
|
false
|
|
7565
7832
|
);
|
|
7566
7833
|
if (!confirm) {
|
|
@@ -7569,21 +7836,21 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
7569
7836
|
}
|
|
7570
7837
|
}
|
|
7571
7838
|
}
|
|
7572
|
-
|
|
7839
|
+
fs23.copyFileSync(source, target);
|
|
7573
7840
|
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
7574
7841
|
}
|
|
7575
7842
|
|
|
7576
7843
|
// src/commands/sync/syncSettings.ts
|
|
7577
|
-
import * as
|
|
7578
|
-
import * as
|
|
7579
|
-
import
|
|
7844
|
+
import * as fs24 from "fs";
|
|
7845
|
+
import * as path40 from "path";
|
|
7846
|
+
import chalk66 from "chalk";
|
|
7580
7847
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
7581
|
-
const source =
|
|
7582
|
-
const target =
|
|
7583
|
-
const sourceContent =
|
|
7848
|
+
const source = path40.join(claudeDir, "settings.json");
|
|
7849
|
+
const target = path40.join(targetBase, "settings.json");
|
|
7850
|
+
const sourceContent = fs24.readFileSync(source, "utf-8");
|
|
7584
7851
|
const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
|
|
7585
|
-
if (
|
|
7586
|
-
const targetContent =
|
|
7852
|
+
if (fs24.existsSync(target)) {
|
|
7853
|
+
const targetContent = fs24.readFileSync(target, "utf-8");
|
|
7587
7854
|
const normalizedTarget = JSON.stringify(
|
|
7588
7855
|
JSON.parse(targetContent),
|
|
7589
7856
|
null,
|
|
@@ -7592,14 +7859,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7592
7859
|
if (mergedContent !== normalizedTarget) {
|
|
7593
7860
|
if (!options2?.yes) {
|
|
7594
7861
|
console.log(
|
|
7595
|
-
|
|
7862
|
+
chalk66.yellow(
|
|
7596
7863
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
7597
7864
|
)
|
|
7598
7865
|
);
|
|
7599
7866
|
console.log();
|
|
7600
7867
|
printDiff(targetContent, mergedContent);
|
|
7601
7868
|
const confirm = await promptConfirm(
|
|
7602
|
-
|
|
7869
|
+
chalk66.red("Overwrite existing settings.json?"),
|
|
7603
7870
|
false
|
|
7604
7871
|
);
|
|
7605
7872
|
if (!confirm) {
|
|
@@ -7609,27 +7876,27 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7609
7876
|
}
|
|
7610
7877
|
}
|
|
7611
7878
|
}
|
|
7612
|
-
|
|
7879
|
+
fs24.writeFileSync(target, mergedContent);
|
|
7613
7880
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
7614
7881
|
}
|
|
7615
7882
|
|
|
7616
7883
|
// src/commands/sync.ts
|
|
7617
7884
|
var __filename4 = fileURLToPath7(import.meta.url);
|
|
7618
|
-
var __dirname7 =
|
|
7885
|
+
var __dirname7 = path41.dirname(__filename4);
|
|
7619
7886
|
async function sync(options2) {
|
|
7620
|
-
const claudeDir =
|
|
7621
|
-
const targetBase =
|
|
7887
|
+
const claudeDir = path41.join(__dirname7, "..", "claude");
|
|
7888
|
+
const targetBase = path41.join(os.homedir(), ".claude");
|
|
7622
7889
|
syncCommands(claudeDir, targetBase);
|
|
7623
7890
|
await syncSettings(claudeDir, targetBase, { yes: options2?.yes });
|
|
7624
7891
|
await syncClaudeMd(claudeDir, targetBase);
|
|
7625
7892
|
}
|
|
7626
7893
|
function syncCommands(claudeDir, targetBase) {
|
|
7627
|
-
const sourceDir =
|
|
7628
|
-
const targetDir =
|
|
7629
|
-
|
|
7630
|
-
const files =
|
|
7894
|
+
const sourceDir = path41.join(claudeDir, "commands");
|
|
7895
|
+
const targetDir = path41.join(targetBase, "commands");
|
|
7896
|
+
fs25.mkdirSync(targetDir, { recursive: true });
|
|
7897
|
+
const files = fs25.readdirSync(sourceDir);
|
|
7631
7898
|
for (const file of files) {
|
|
7632
|
-
|
|
7899
|
+
fs25.copyFileSync(path41.join(sourceDir, file), path41.join(targetDir, file));
|
|
7633
7900
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
7634
7901
|
}
|
|
7635
7902
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -7637,15 +7904,15 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
7637
7904
|
|
|
7638
7905
|
// src/commands/update.ts
|
|
7639
7906
|
import { execSync as execSync32 } from "child_process";
|
|
7640
|
-
import * as
|
|
7907
|
+
import * as path42 from "path";
|
|
7641
7908
|
function isGlobalNpmInstall(dir) {
|
|
7642
7909
|
try {
|
|
7643
|
-
const resolved =
|
|
7644
|
-
if (resolved.split(
|
|
7910
|
+
const resolved = path42.resolve(dir);
|
|
7911
|
+
if (resolved.split(path42.sep).includes("node_modules")) {
|
|
7645
7912
|
return true;
|
|
7646
7913
|
}
|
|
7647
7914
|
const globalPrefix = execSync32("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
7648
|
-
return resolved.toLowerCase().startsWith(
|
|
7915
|
+
return resolved.toLowerCase().startsWith(path42.resolve(globalPrefix).toLowerCase());
|
|
7649
7916
|
} catch {
|
|
7650
7917
|
return false;
|
|
7651
7918
|
}
|
|
@@ -7694,7 +7961,7 @@ runCommand.command("add").description("Add a new run configuration to assist.yml
|
|
|
7694
7961
|
'\nPositional params can be added to the config manually:\n params:\n - name: env # assist run deploy prod \u2192 appends "prod"\n required: true\n - name: tag\n default: latest'
|
|
7695
7962
|
).allowUnknownOption().allowExcessArguments().action(() => add3());
|
|
7696
7963
|
registerNew(program);
|
|
7697
|
-
var lintCommand = program.command("lint").description("Run lint checks for conventions not enforced by biomejs").action(lint);
|
|
7964
|
+
var lintCommand = program.command("lint").description("Run lint checks for conventions not enforced by biomejs").option("-f, --fix", "Auto-fix violations where possible").action(lint);
|
|
7698
7965
|
lintCommand.command("init").description("Initialize Biome with standard linter config").action(init);
|
|
7699
7966
|
var vscodeCommand = program.command("vscode").description("VS Code configuration utilities");
|
|
7700
7967
|
vscodeCommand.command("init").description("Add VS Code configuration files").action(init3);
|