@staff0rd/assist 0.49.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +286 -260
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Command } from "commander";
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@staff0rd/assist",
|
|
10
|
-
version: "0.
|
|
10
|
+
version: "0.50.0",
|
|
11
11
|
type: "module",
|
|
12
12
|
main: "dist/index.js",
|
|
13
13
|
bin: {
|
|
@@ -222,9 +222,9 @@ function isTraversable(value) {
|
|
|
222
222
|
function stepInto(current, key) {
|
|
223
223
|
return isTraversable(current) ? current[key] : void 0;
|
|
224
224
|
}
|
|
225
|
-
function getNestedValue(obj,
|
|
225
|
+
function getNestedValue(obj, path30) {
|
|
226
226
|
let current = obj;
|
|
227
|
-
for (const key of
|
|
227
|
+
for (const key of path30.split(".")) current = stepInto(current, key);
|
|
228
228
|
return current;
|
|
229
229
|
}
|
|
230
230
|
function isPlainObject(val) {
|
|
@@ -241,8 +241,8 @@ function buildNestedPath(root, keys) {
|
|
|
241
241
|
}
|
|
242
242
|
return current;
|
|
243
243
|
}
|
|
244
|
-
function setNestedValue(obj,
|
|
245
|
-
const keys =
|
|
244
|
+
function setNestedValue(obj, path30, value) {
|
|
245
|
+
const keys = path30.split(".");
|
|
246
246
|
const result = { ...obj };
|
|
247
247
|
buildNestedPath(result, keys)[keys[keys.length - 1]] = value;
|
|
248
248
|
return result;
|
|
@@ -311,7 +311,7 @@ function configList() {
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
// src/commands/verify/init/index.ts
|
|
314
|
-
import
|
|
314
|
+
import chalk15 from "chalk";
|
|
315
315
|
|
|
316
316
|
// src/shared/promptMultiselect.ts
|
|
317
317
|
import chalk3 from "chalk";
|
|
@@ -387,7 +387,8 @@ var expectedScripts = {
|
|
|
387
387
|
"verify:lint": "biome check --write .",
|
|
388
388
|
"verify:duplicate-code": "jscpd --format 'typescript,tsx' --exitCode 1 --ignore '**/*.test.*' -r consoleFull src",
|
|
389
389
|
"verify:test": "vitest run --reporter=dot --silent",
|
|
390
|
-
"verify:hardcoded-colors": "assist verify hardcoded-colors"
|
|
390
|
+
"verify:hardcoded-colors": "assist verify hardcoded-colors",
|
|
391
|
+
"verify:maintainability": "assist complexity maintainability ./src --threshold 60"
|
|
391
392
|
};
|
|
392
393
|
|
|
393
394
|
// src/commands/verify/setup/setupBuild.ts
|
|
@@ -726,12 +727,25 @@ async function setupLint(packageJsonPath) {
|
|
|
726
727
|
);
|
|
727
728
|
}
|
|
728
729
|
|
|
729
|
-
// src/commands/verify/setup/
|
|
730
|
+
// src/commands/verify/setup/setupMaintainability.ts
|
|
730
731
|
import * as path7 from "path";
|
|
731
732
|
import chalk13 from "chalk";
|
|
733
|
+
async function setupMaintainability(packageJsonPath) {
|
|
734
|
+
console.log(chalk13.blue("\nSetting up maintainability check..."));
|
|
735
|
+
addToKnipIgnoreBinaries(path7.dirname(packageJsonPath), "assist");
|
|
736
|
+
setupVerifyScript(
|
|
737
|
+
packageJsonPath,
|
|
738
|
+
"verify:maintainability",
|
|
739
|
+
expectedScripts["verify:maintainability"]
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// src/commands/verify/setup/setupTest.ts
|
|
744
|
+
import * as path8 from "path";
|
|
745
|
+
import chalk14 from "chalk";
|
|
732
746
|
async function setupTest(packageJsonPath) {
|
|
733
|
-
console.log(
|
|
734
|
-
const cwd =
|
|
747
|
+
console.log(chalk14.blue("\nSetting up vitest..."));
|
|
748
|
+
const cwd = path8.dirname(packageJsonPath);
|
|
735
749
|
const pkg = readPackageJson(packageJsonPath);
|
|
736
750
|
if (!pkg.devDependencies?.vitest && !installPackage("vitest", cwd)) {
|
|
737
751
|
return;
|
|
@@ -783,6 +797,7 @@ function detectExistingSetup(pkg) {
|
|
|
783
797
|
build: toolStatus(pkg, "verify:build", true),
|
|
784
798
|
typecheck: toolStatus(pkg, "verify:typecheck", true),
|
|
785
799
|
hardcodedColors: toolStatus(pkg, "verify:hardcoded-colors", true),
|
|
800
|
+
maintainability: toolStatus(pkg, "verify:maintainability", true),
|
|
786
801
|
hasOpenColor: !!pkg.dependencies?.["open-color"] || !!pkg.devDependencies?.["open-color"]
|
|
787
802
|
};
|
|
788
803
|
}
|
|
@@ -839,6 +854,12 @@ var options = [
|
|
|
839
854
|
label: "typecheck",
|
|
840
855
|
description: "TypeScript type checking",
|
|
841
856
|
extraCondition: (s) => s.hasTypescript && !s.hasVite
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
toolKey: "maintainability",
|
|
860
|
+
value: "maintainability",
|
|
861
|
+
label: "maintainability",
|
|
862
|
+
description: "Maintainability index threshold check"
|
|
842
863
|
}
|
|
843
864
|
];
|
|
844
865
|
|
|
@@ -868,37 +889,42 @@ function getSetupHandlers(hasVite, hasTypescript, hasOpenColor) {
|
|
|
868
889
|
test: (p) => setupTest(p),
|
|
869
890
|
build: (p) => setupBuild(p, hasVite, hasTypescript),
|
|
870
891
|
typecheck: (p) => setupTypecheck(p),
|
|
871
|
-
"hardcoded-colors": (p) => setupHardcodedColors(p, hasOpenColor)
|
|
892
|
+
"hardcoded-colors": (p) => setupHardcodedColors(p, hasOpenColor),
|
|
893
|
+
maintainability: (p) => setupMaintainability(p)
|
|
872
894
|
};
|
|
873
895
|
}
|
|
874
896
|
async function runSelectedSetups(selected, packageJsonPath, handlers) {
|
|
875
897
|
for (const choice of selected) {
|
|
876
898
|
await handlers[choice]?.(packageJsonPath);
|
|
877
899
|
}
|
|
878
|
-
console.log(
|
|
900
|
+
console.log(chalk15.green(`
|
|
879
901
|
Added ${selected.length} verify script(s):`));
|
|
880
902
|
for (const choice of selected) {
|
|
881
|
-
console.log(
|
|
903
|
+
console.log(chalk15.green(` - verify:${choice}`));
|
|
882
904
|
}
|
|
883
|
-
console.log(
|
|
905
|
+
console.log(chalk15.dim("\nRun 'assist verify' to run all verify scripts"));
|
|
884
906
|
}
|
|
885
|
-
async function
|
|
886
|
-
const { packageJsonPath, pkg } = requirePackageJson();
|
|
887
|
-
const setup = detectExistingSetup(pkg);
|
|
888
|
-
const availableOptions = getAvailableOptions(setup);
|
|
907
|
+
async function promptForScripts(availableOptions) {
|
|
889
908
|
if (availableOptions.length === 0) {
|
|
890
|
-
console.log(
|
|
891
|
-
return;
|
|
909
|
+
console.log(chalk15.green("All verify scripts are already configured!"));
|
|
910
|
+
return null;
|
|
892
911
|
}
|
|
893
|
-
console.log(
|
|
912
|
+
console.log(chalk15.bold("Available verify scripts to add:\n"));
|
|
894
913
|
const selected = await promptMultiselect(
|
|
895
914
|
"Select verify scripts to add:",
|
|
896
915
|
availableOptions
|
|
897
916
|
);
|
|
898
917
|
if (selected.length === 0) {
|
|
899
|
-
console.log(
|
|
900
|
-
return;
|
|
918
|
+
console.log(chalk15.yellow("No scripts selected"));
|
|
919
|
+
return null;
|
|
901
920
|
}
|
|
921
|
+
return selected;
|
|
922
|
+
}
|
|
923
|
+
async function init2() {
|
|
924
|
+
const { packageJsonPath, pkg } = requirePackageJson();
|
|
925
|
+
const setup = detectExistingSetup(pkg);
|
|
926
|
+
const selected = await promptForScripts(getAvailableOptions(setup));
|
|
927
|
+
if (!selected) return;
|
|
902
928
|
const handlers = getSetupHandlers(
|
|
903
929
|
setup.hasVite,
|
|
904
930
|
setup.hasTypescript,
|
|
@@ -908,21 +934,21 @@ async function init2() {
|
|
|
908
934
|
}
|
|
909
935
|
|
|
910
936
|
// src/commands/vscode/init/index.ts
|
|
911
|
-
import
|
|
937
|
+
import chalk17 from "chalk";
|
|
912
938
|
|
|
913
939
|
// src/commands/vscode/init/createLaunchJson.ts
|
|
914
940
|
import * as fs3 from "fs";
|
|
915
|
-
import * as
|
|
916
|
-
import
|
|
941
|
+
import * as path9 from "path";
|
|
942
|
+
import chalk16 from "chalk";
|
|
917
943
|
function ensureVscodeFolder() {
|
|
918
|
-
const vscodeDir =
|
|
944
|
+
const vscodeDir = path9.join(process.cwd(), ".vscode");
|
|
919
945
|
if (!fs3.existsSync(vscodeDir)) {
|
|
920
946
|
fs3.mkdirSync(vscodeDir);
|
|
921
|
-
console.log(
|
|
947
|
+
console.log(chalk16.dim("Created .vscode folder"));
|
|
922
948
|
}
|
|
923
949
|
}
|
|
924
950
|
function removeVscodeFromGitignore() {
|
|
925
|
-
const gitignorePath =
|
|
951
|
+
const gitignorePath = path9.join(process.cwd(), ".gitignore");
|
|
926
952
|
if (!fs3.existsSync(gitignorePath)) {
|
|
927
953
|
return;
|
|
928
954
|
}
|
|
@@ -933,7 +959,7 @@ function removeVscodeFromGitignore() {
|
|
|
933
959
|
);
|
|
934
960
|
if (filteredLines.length !== lines.length) {
|
|
935
961
|
fs3.writeFileSync(gitignorePath, filteredLines.join("\n"));
|
|
936
|
-
console.log(
|
|
962
|
+
console.log(chalk16.dim("Removed .vscode references from .gitignore"));
|
|
937
963
|
}
|
|
938
964
|
}
|
|
939
965
|
function createLaunchJson() {
|
|
@@ -948,10 +974,10 @@ function createLaunchJson() {
|
|
|
948
974
|
}
|
|
949
975
|
]
|
|
950
976
|
};
|
|
951
|
-
const launchPath =
|
|
977
|
+
const launchPath = path9.join(process.cwd(), ".vscode", "launch.json");
|
|
952
978
|
fs3.writeFileSync(launchPath, `${JSON.stringify(launchConfig, null, " ")}
|
|
953
979
|
`);
|
|
954
|
-
console.log(
|
|
980
|
+
console.log(chalk16.green("Created .vscode/launch.json"));
|
|
955
981
|
}
|
|
956
982
|
function createSettingsJson() {
|
|
957
983
|
const settings = {
|
|
@@ -961,33 +987,33 @@ function createSettingsJson() {
|
|
|
961
987
|
"source.organizeImports.biome": "explicit"
|
|
962
988
|
}
|
|
963
989
|
};
|
|
964
|
-
const settingsPath =
|
|
990
|
+
const settingsPath = path9.join(process.cwd(), ".vscode", "settings.json");
|
|
965
991
|
fs3.writeFileSync(settingsPath, `${JSON.stringify(settings, null, " ")}
|
|
966
992
|
`);
|
|
967
|
-
console.log(
|
|
993
|
+
console.log(chalk16.green("Created .vscode/settings.json"));
|
|
968
994
|
}
|
|
969
995
|
function createExtensionsJson() {
|
|
970
996
|
const extensions = {
|
|
971
997
|
recommendations: ["biomejs.biome"]
|
|
972
998
|
};
|
|
973
|
-
const extensionsPath =
|
|
999
|
+
const extensionsPath = path9.join(process.cwd(), ".vscode", "extensions.json");
|
|
974
1000
|
fs3.writeFileSync(
|
|
975
1001
|
extensionsPath,
|
|
976
1002
|
`${JSON.stringify(extensions, null, " ")}
|
|
977
1003
|
`
|
|
978
1004
|
);
|
|
979
|
-
console.log(
|
|
1005
|
+
console.log(chalk16.green("Created .vscode/extensions.json"));
|
|
980
1006
|
}
|
|
981
1007
|
|
|
982
1008
|
// src/commands/vscode/init/detectVscodeSetup.ts
|
|
983
1009
|
import * as fs4 from "fs";
|
|
984
|
-
import * as
|
|
1010
|
+
import * as path10 from "path";
|
|
985
1011
|
function detectVscodeSetup(pkg) {
|
|
986
|
-
const vscodeDir =
|
|
1012
|
+
const vscodeDir = path10.join(process.cwd(), ".vscode");
|
|
987
1013
|
return {
|
|
988
1014
|
hasVscodeFolder: fs4.existsSync(vscodeDir),
|
|
989
|
-
hasLaunchJson: fs4.existsSync(
|
|
990
|
-
hasSettingsJson: fs4.existsSync(
|
|
1015
|
+
hasLaunchJson: fs4.existsSync(path10.join(vscodeDir, "launch.json")),
|
|
1016
|
+
hasSettingsJson: fs4.existsSync(path10.join(vscodeDir, "settings.json")),
|
|
991
1017
|
hasVite: !!pkg.devDependencies?.vite || !!pkg.dependencies?.vite
|
|
992
1018
|
};
|
|
993
1019
|
}
|
|
@@ -1021,23 +1047,23 @@ async function init3() {
|
|
|
1021
1047
|
const setup = detectVscodeSetup(pkg);
|
|
1022
1048
|
const availableOptions = getAvailableOptions2(setup);
|
|
1023
1049
|
if (availableOptions.length === 0) {
|
|
1024
|
-
console.log(
|
|
1050
|
+
console.log(chalk17.green("VS Code configuration already exists!"));
|
|
1025
1051
|
return;
|
|
1026
1052
|
}
|
|
1027
|
-
console.log(
|
|
1053
|
+
console.log(chalk17.bold("Available VS Code configurations to add:\n"));
|
|
1028
1054
|
const selected = await promptMultiselect(
|
|
1029
1055
|
"Select configurations to add:",
|
|
1030
1056
|
availableOptions
|
|
1031
1057
|
);
|
|
1032
1058
|
if (selected.length === 0) {
|
|
1033
|
-
console.log(
|
|
1059
|
+
console.log(chalk17.yellow("No configurations selected"));
|
|
1034
1060
|
return;
|
|
1035
1061
|
}
|
|
1036
1062
|
removeVscodeFromGitignore();
|
|
1037
1063
|
ensureVscodeFolder();
|
|
1038
1064
|
for (const choice of selected) SETUP_HANDLERS[choice]?.();
|
|
1039
1065
|
console.log(
|
|
1040
|
-
|
|
1066
|
+
chalk17.green(`
|
|
1041
1067
|
Added ${selected.length} VS Code configuration(s)`)
|
|
1042
1068
|
);
|
|
1043
1069
|
}
|
|
@@ -1050,12 +1076,12 @@ async function init4() {
|
|
|
1050
1076
|
|
|
1051
1077
|
// src/commands/lint/lint/runFileNameCheck.ts
|
|
1052
1078
|
import fs6 from "fs";
|
|
1053
|
-
import
|
|
1054
|
-
import
|
|
1079
|
+
import path12 from "path";
|
|
1080
|
+
import chalk18 from "chalk";
|
|
1055
1081
|
|
|
1056
1082
|
// src/shared/findSourceFiles.ts
|
|
1057
1083
|
import fs5 from "fs";
|
|
1058
|
-
import
|
|
1084
|
+
import path11 from "path";
|
|
1059
1085
|
var EXTENSIONS = [".ts", ".tsx"];
|
|
1060
1086
|
function findSourceFiles(dir, options2 = {}) {
|
|
1061
1087
|
const { includeTests = true } = options2;
|
|
@@ -1065,7 +1091,7 @@ function findSourceFiles(dir, options2 = {}) {
|
|
|
1065
1091
|
}
|
|
1066
1092
|
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
1067
1093
|
for (const entry of entries) {
|
|
1068
|
-
const fullPath =
|
|
1094
|
+
const fullPath = path11.join(dir, entry.name);
|
|
1069
1095
|
if (entry.isDirectory() && entry.name !== "node_modules") {
|
|
1070
1096
|
results.push(...findSourceFiles(fullPath, options2));
|
|
1071
1097
|
} else if (entry.isFile() && EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
|
|
@@ -1089,7 +1115,7 @@ function checkFileNames() {
|
|
|
1089
1115
|
const sourceFiles = findSourceFiles("src");
|
|
1090
1116
|
const violations = [];
|
|
1091
1117
|
for (const filePath of sourceFiles) {
|
|
1092
|
-
const fileName =
|
|
1118
|
+
const fileName = path12.basename(filePath);
|
|
1093
1119
|
const nameWithoutExt = fileName.replace(/\.(ts|tsx)$/, "");
|
|
1094
1120
|
if (/^[A-Z]/.test(nameWithoutExt)) {
|
|
1095
1121
|
const content = fs6.readFileSync(filePath, "utf-8");
|
|
@@ -1103,16 +1129,16 @@ function checkFileNames() {
|
|
|
1103
1129
|
function runFileNameCheck() {
|
|
1104
1130
|
const violations = checkFileNames();
|
|
1105
1131
|
if (violations.length > 0) {
|
|
1106
|
-
console.error(
|
|
1132
|
+
console.error(chalk18.red("\nFile name check failed:\n"));
|
|
1107
1133
|
console.error(
|
|
1108
|
-
|
|
1134
|
+
chalk18.red(
|
|
1109
1135
|
" Files without classes or React components should not start with a capital letter.\n"
|
|
1110
1136
|
)
|
|
1111
1137
|
);
|
|
1112
1138
|
for (const violation of violations) {
|
|
1113
|
-
console.error(
|
|
1139
|
+
console.error(chalk18.red(` ${violation.filePath}`));
|
|
1114
1140
|
console.error(
|
|
1115
|
-
|
|
1141
|
+
chalk18.gray(
|
|
1116
1142
|
` Rename to: ${violation.fileName.charAt(0).toLowerCase()}${violation.fileName.slice(1)}
|
|
1117
1143
|
`
|
|
1118
1144
|
)
|
|
@@ -1132,17 +1158,17 @@ function runFileNameCheck() {
|
|
|
1132
1158
|
import fs7 from "fs";
|
|
1133
1159
|
|
|
1134
1160
|
// src/commands/lint/shared.ts
|
|
1135
|
-
import
|
|
1161
|
+
import chalk19 from "chalk";
|
|
1136
1162
|
function reportViolations(violations, checkName, errorMessage, successMessage) {
|
|
1137
1163
|
if (violations.length > 0) {
|
|
1138
|
-
console.error(
|
|
1164
|
+
console.error(chalk19.red(`
|
|
1139
1165
|
${checkName} failed:
|
|
1140
1166
|
`));
|
|
1141
|
-
console.error(
|
|
1167
|
+
console.error(chalk19.red(` ${errorMessage}
|
|
1142
1168
|
`));
|
|
1143
1169
|
for (const violation of violations) {
|
|
1144
|
-
console.error(
|
|
1145
|
-
console.error(
|
|
1170
|
+
console.error(chalk19.red(` ${violation.filePath}:${violation.line}`));
|
|
1171
|
+
console.error(chalk19.gray(` ${violation.content}
|
|
1146
1172
|
`));
|
|
1147
1173
|
}
|
|
1148
1174
|
return false;
|
|
@@ -1274,7 +1300,7 @@ Total: ${lines.length} hardcoded color(s)`);
|
|
|
1274
1300
|
|
|
1275
1301
|
// src/commands/verify/run/index.ts
|
|
1276
1302
|
import { spawn } from "child_process";
|
|
1277
|
-
import * as
|
|
1303
|
+
import * as path13 from "path";
|
|
1278
1304
|
|
|
1279
1305
|
// src/commands/verify/run/createTimerCallback/printTaskStatuses.ts
|
|
1280
1306
|
function formatDuration(ms) {
|
|
@@ -1374,7 +1400,7 @@ function resolveVerifyScripts() {
|
|
|
1374
1400
|
return result;
|
|
1375
1401
|
}
|
|
1376
1402
|
function getPackageDir(found) {
|
|
1377
|
-
return
|
|
1403
|
+
return path13.dirname(found.packageJsonPath);
|
|
1378
1404
|
}
|
|
1379
1405
|
async function executeVerifyScripts(found, timer) {
|
|
1380
1406
|
printScriptList(found.verifyScripts);
|
|
@@ -1480,16 +1506,16 @@ import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSyn
|
|
|
1480
1506
|
|
|
1481
1507
|
// src/commands/deploy/init/index.ts
|
|
1482
1508
|
import { execSync as execSync8 } from "child_process";
|
|
1483
|
-
import
|
|
1509
|
+
import chalk21 from "chalk";
|
|
1484
1510
|
import enquirer3 from "enquirer";
|
|
1485
1511
|
|
|
1486
1512
|
// src/commands/deploy/init/updateWorkflow.ts
|
|
1487
1513
|
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
1488
|
-
import { dirname as
|
|
1514
|
+
import { dirname as dirname10, join as join7 } from "path";
|
|
1489
1515
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1490
|
-
import
|
|
1516
|
+
import chalk20 from "chalk";
|
|
1491
1517
|
var WORKFLOW_PATH = ".github/workflows/build.yml";
|
|
1492
|
-
var __dirname3 =
|
|
1518
|
+
var __dirname3 = dirname10(fileURLToPath2(import.meta.url));
|
|
1493
1519
|
function getExistingSiteId() {
|
|
1494
1520
|
if (!existsSync9(WORKFLOW_PATH)) {
|
|
1495
1521
|
return null;
|
|
@@ -1512,20 +1538,20 @@ async function updateWorkflow(siteId) {
|
|
|
1512
1538
|
if (existsSync9(WORKFLOW_PATH)) {
|
|
1513
1539
|
const oldContent = readFileSync7(WORKFLOW_PATH, "utf-8");
|
|
1514
1540
|
if (oldContent === newContent) {
|
|
1515
|
-
console.log(
|
|
1541
|
+
console.log(chalk20.green("build.yml is already up to date"));
|
|
1516
1542
|
return;
|
|
1517
1543
|
}
|
|
1518
|
-
console.log(
|
|
1544
|
+
console.log(chalk20.yellow("\nbuild.yml will be updated:"));
|
|
1519
1545
|
console.log();
|
|
1520
1546
|
printDiff(oldContent, newContent);
|
|
1521
|
-
const confirm = await promptConfirm(
|
|
1547
|
+
const confirm = await promptConfirm(chalk20.red("Update build.yml?"));
|
|
1522
1548
|
if (!confirm) {
|
|
1523
1549
|
console.log("Skipped build.yml update");
|
|
1524
1550
|
return;
|
|
1525
1551
|
}
|
|
1526
1552
|
}
|
|
1527
1553
|
writeFileSync7(WORKFLOW_PATH, newContent);
|
|
1528
|
-
console.log(
|
|
1554
|
+
console.log(chalk20.green(`
|
|
1529
1555
|
Created ${WORKFLOW_PATH}`));
|
|
1530
1556
|
}
|
|
1531
1557
|
|
|
@@ -1536,43 +1562,43 @@ async function ensureNetlifyCli() {
|
|
|
1536
1562
|
} catch (error) {
|
|
1537
1563
|
if (!(error instanceof Error) || !error.message.includes("command not found"))
|
|
1538
1564
|
throw error;
|
|
1539
|
-
console.error(
|
|
1565
|
+
console.error(chalk21.red("\nNetlify CLI is not installed.\n"));
|
|
1540
1566
|
const install = await promptConfirm("Would you like to install it now?");
|
|
1541
1567
|
if (!install) {
|
|
1542
1568
|
console.log(
|
|
1543
|
-
|
|
1569
|
+
chalk21.yellow(
|
|
1544
1570
|
"\nInstall it manually with: npm install -g netlify-cli\n"
|
|
1545
1571
|
)
|
|
1546
1572
|
);
|
|
1547
1573
|
process.exit(1);
|
|
1548
1574
|
}
|
|
1549
|
-
console.log(
|
|
1575
|
+
console.log(chalk21.dim("\nInstalling netlify-cli...\n"));
|
|
1550
1576
|
execSync8("npm install -g netlify-cli", { stdio: "inherit" });
|
|
1551
1577
|
console.log();
|
|
1552
1578
|
execSync8("netlify sites:create --disable-linking", { stdio: "inherit" });
|
|
1553
1579
|
}
|
|
1554
1580
|
}
|
|
1555
1581
|
function printSetupInstructions() {
|
|
1556
|
-
console.log(
|
|
1582
|
+
console.log(chalk21.bold("\nDeployment initialized successfully!"));
|
|
1557
1583
|
console.log(
|
|
1558
|
-
|
|
1584
|
+
chalk21.yellow("\nTo complete setup, create a personal access token at:")
|
|
1559
1585
|
);
|
|
1560
1586
|
console.log(
|
|
1561
|
-
|
|
1587
|
+
chalk21.cyan(
|
|
1562
1588
|
"https://app.netlify.com/user/applications#personal-access-tokens"
|
|
1563
1589
|
)
|
|
1564
1590
|
);
|
|
1565
1591
|
console.log(
|
|
1566
|
-
|
|
1592
|
+
chalk21.yellow(
|
|
1567
1593
|
"\nThen add it as NETLIFY_AUTH_TOKEN in your GitHub repository secrets."
|
|
1568
1594
|
)
|
|
1569
1595
|
);
|
|
1570
1596
|
}
|
|
1571
1597
|
async function init5() {
|
|
1572
|
-
console.log(
|
|
1598
|
+
console.log(chalk21.bold("Initializing Netlify deployment...\n"));
|
|
1573
1599
|
const existingSiteId = getExistingSiteId();
|
|
1574
1600
|
if (existingSiteId) {
|
|
1575
|
-
console.log(
|
|
1601
|
+
console.log(chalk21.dim(`Using existing site ID: ${existingSiteId}
|
|
1576
1602
|
`));
|
|
1577
1603
|
await updateWorkflow(existingSiteId);
|
|
1578
1604
|
return;
|
|
@@ -1666,11 +1692,11 @@ function detectPlatform() {
|
|
|
1666
1692
|
import { spawn as spawn2 } from "child_process";
|
|
1667
1693
|
import fs9 from "fs";
|
|
1668
1694
|
import { createRequire } from "module";
|
|
1669
|
-
import
|
|
1695
|
+
import path14 from "path";
|
|
1670
1696
|
var require2 = createRequire(import.meta.url);
|
|
1671
1697
|
function getSnoreToastPath() {
|
|
1672
|
-
const notifierPath =
|
|
1673
|
-
return
|
|
1698
|
+
const notifierPath = path14.dirname(require2.resolve("node-notifier"));
|
|
1699
|
+
return path14.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
|
|
1674
1700
|
}
|
|
1675
1701
|
function showWindowsNotificationFromWsl(options2) {
|
|
1676
1702
|
const { title, message, sound } = options2;
|
|
@@ -1751,20 +1777,20 @@ async function notify() {
|
|
|
1751
1777
|
}
|
|
1752
1778
|
|
|
1753
1779
|
// src/commands/complexity/analyze.ts
|
|
1754
|
-
import
|
|
1780
|
+
import chalk27 from "chalk";
|
|
1755
1781
|
|
|
1756
1782
|
// src/commands/complexity/cyclomatic.ts
|
|
1757
|
-
import
|
|
1783
|
+
import chalk23 from "chalk";
|
|
1758
1784
|
|
|
1759
1785
|
// src/commands/complexity/shared/index.ts
|
|
1760
1786
|
import fs11 from "fs";
|
|
1761
|
-
import
|
|
1762
|
-
import
|
|
1787
|
+
import path16 from "path";
|
|
1788
|
+
import chalk22 from "chalk";
|
|
1763
1789
|
import ts5 from "typescript";
|
|
1764
1790
|
|
|
1765
1791
|
// src/commands/complexity/findSourceFiles.ts
|
|
1766
1792
|
import fs10 from "fs";
|
|
1767
|
-
import
|
|
1793
|
+
import path15 from "path";
|
|
1768
1794
|
import { minimatch } from "minimatch";
|
|
1769
1795
|
function applyIgnoreGlobs(files) {
|
|
1770
1796
|
const { complexity } = loadConfig();
|
|
@@ -1779,7 +1805,7 @@ function walk(dir, results) {
|
|
|
1779
1805
|
const extensions = [".ts", ".tsx"];
|
|
1780
1806
|
const entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
1781
1807
|
for (const entry of entries) {
|
|
1782
|
-
const fullPath =
|
|
1808
|
+
const fullPath = path15.join(dir, entry.name);
|
|
1783
1809
|
if (entry.isDirectory()) {
|
|
1784
1810
|
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
1785
1811
|
walk(fullPath, results);
|
|
@@ -1995,7 +2021,7 @@ function countSloc(content) {
|
|
|
1995
2021
|
function createSourceFromFile(filePath) {
|
|
1996
2022
|
const content = fs11.readFileSync(filePath, "utf-8");
|
|
1997
2023
|
return ts5.createSourceFile(
|
|
1998
|
-
|
|
2024
|
+
path16.basename(filePath),
|
|
1999
2025
|
content,
|
|
2000
2026
|
ts5.ScriptTarget.Latest,
|
|
2001
2027
|
true,
|
|
@@ -2005,7 +2031,7 @@ function createSourceFromFile(filePath) {
|
|
|
2005
2031
|
function withSourceFiles(pattern2, callback) {
|
|
2006
2032
|
const files = findSourceFiles2(pattern2);
|
|
2007
2033
|
if (files.length === 0) {
|
|
2008
|
-
console.log(
|
|
2034
|
+
console.log(chalk22.yellow("No files found matching pattern"));
|
|
2009
2035
|
return void 0;
|
|
2010
2036
|
}
|
|
2011
2037
|
return callback(files);
|
|
@@ -2038,11 +2064,11 @@ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2038
2064
|
results.sort((a, b) => b.complexity - a.complexity);
|
|
2039
2065
|
for (const { file, name, complexity } of results) {
|
|
2040
2066
|
const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
|
|
2041
|
-
const color = exceedsThreshold ?
|
|
2042
|
-
console.log(`${color(`${file}:${name}`)} \u2192 ${
|
|
2067
|
+
const color = exceedsThreshold ? chalk23.red : chalk23.white;
|
|
2068
|
+
console.log(`${color(`${file}:${name}`)} \u2192 ${chalk23.cyan(complexity)}`);
|
|
2043
2069
|
}
|
|
2044
2070
|
console.log(
|
|
2045
|
-
|
|
2071
|
+
chalk23.dim(
|
|
2046
2072
|
`
|
|
2047
2073
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
2048
2074
|
)
|
|
@@ -2054,7 +2080,7 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
2054
2080
|
}
|
|
2055
2081
|
|
|
2056
2082
|
// src/commands/complexity/halstead.ts
|
|
2057
|
-
import
|
|
2083
|
+
import chalk24 from "chalk";
|
|
2058
2084
|
async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
2059
2085
|
withSourceFiles(pattern2, (files) => {
|
|
2060
2086
|
const results = [];
|
|
@@ -2069,13 +2095,13 @@ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2069
2095
|
results.sort((a, b) => b.metrics.effort - a.metrics.effort);
|
|
2070
2096
|
for (const { file, name, metrics } of results) {
|
|
2071
2097
|
const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
|
|
2072
|
-
const color = exceedsThreshold ?
|
|
2098
|
+
const color = exceedsThreshold ? chalk24.red : chalk24.white;
|
|
2073
2099
|
console.log(
|
|
2074
|
-
`${color(`${file}:${name}`)} \u2192 volume: ${
|
|
2100
|
+
`${color(`${file}:${name}`)} \u2192 volume: ${chalk24.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk24.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk24.magenta(metrics.effort.toFixed(1))}`
|
|
2075
2101
|
);
|
|
2076
2102
|
}
|
|
2077
2103
|
console.log(
|
|
2078
|
-
|
|
2104
|
+
chalk24.dim(
|
|
2079
2105
|
`
|
|
2080
2106
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
2081
2107
|
)
|
|
@@ -2090,24 +2116,24 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
2090
2116
|
import fs12 from "fs";
|
|
2091
2117
|
|
|
2092
2118
|
// src/commands/complexity/maintainability/displayMaintainabilityResults.ts
|
|
2093
|
-
import
|
|
2119
|
+
import chalk25 from "chalk";
|
|
2094
2120
|
function displayMaintainabilityResults(results, threshold) {
|
|
2095
2121
|
const filtered = threshold !== void 0 ? results.filter((r) => r.minMaintainability < threshold) : results;
|
|
2096
2122
|
if (threshold !== void 0 && filtered.length === 0) {
|
|
2097
|
-
console.log(
|
|
2123
|
+
console.log(chalk25.green("All files pass maintainability threshold"));
|
|
2098
2124
|
} else {
|
|
2099
2125
|
for (const { file, avgMaintainability, minMaintainability } of filtered) {
|
|
2100
|
-
const color = threshold !== void 0 ?
|
|
2126
|
+
const color = threshold !== void 0 ? chalk25.red : chalk25.white;
|
|
2101
2127
|
console.log(
|
|
2102
|
-
`${color(file)} \u2192 avg: ${
|
|
2128
|
+
`${color(file)} \u2192 avg: ${chalk25.cyan(avgMaintainability.toFixed(1))}, min: ${chalk25.yellow(minMaintainability.toFixed(1))}`
|
|
2103
2129
|
);
|
|
2104
2130
|
}
|
|
2105
2131
|
}
|
|
2106
|
-
console.log(
|
|
2132
|
+
console.log(chalk25.dim(`
|
|
2107
2133
|
Analyzed ${results.length} files`));
|
|
2108
2134
|
if (filtered.length > 0 && threshold !== void 0) {
|
|
2109
2135
|
console.error(
|
|
2110
|
-
|
|
2136
|
+
chalk25.red(
|
|
2111
2137
|
`
|
|
2112
2138
|
Fail: ${filtered.length} file(s) below threshold ${threshold}. Maintainability index (0\u2013100) is derived from Halstead volume, cyclomatic complexity, and lines of code. Focus on one file at a time \u2014 run 'assist complexity <file>' to see all metrics. For larger files, start by extracting responsibilities into smaller files.`
|
|
2113
2139
|
)
|
|
@@ -2166,7 +2192,7 @@ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2166
2192
|
|
|
2167
2193
|
// src/commands/complexity/sloc.ts
|
|
2168
2194
|
import fs13 from "fs";
|
|
2169
|
-
import
|
|
2195
|
+
import chalk26 from "chalk";
|
|
2170
2196
|
async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
2171
2197
|
withSourceFiles(pattern2, (files) => {
|
|
2172
2198
|
const results = [];
|
|
@@ -2182,12 +2208,12 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2182
2208
|
results.sort((a, b) => b.lines - a.lines);
|
|
2183
2209
|
for (const { file, lines } of results) {
|
|
2184
2210
|
const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
|
|
2185
|
-
const color = exceedsThreshold ?
|
|
2186
|
-
console.log(`${color(file)} \u2192 ${
|
|
2211
|
+
const color = exceedsThreshold ? chalk26.red : chalk26.white;
|
|
2212
|
+
console.log(`${color(file)} \u2192 ${chalk26.cyan(lines)} lines`);
|
|
2187
2213
|
}
|
|
2188
2214
|
const total = results.reduce((sum, r) => sum + r.lines, 0);
|
|
2189
2215
|
console.log(
|
|
2190
|
-
|
|
2216
|
+
chalk26.dim(`
|
|
2191
2217
|
Total: ${total} lines across ${files.length} files`)
|
|
2192
2218
|
);
|
|
2193
2219
|
if (hasViolation) {
|
|
@@ -2201,21 +2227,21 @@ async function analyze(pattern2) {
|
|
|
2201
2227
|
const searchPattern = pattern2.includes("*") || pattern2.includes("/") ? pattern2 : `**/${pattern2}`;
|
|
2202
2228
|
const files = findSourceFiles2(searchPattern);
|
|
2203
2229
|
if (files.length === 0) {
|
|
2204
|
-
console.log(
|
|
2230
|
+
console.log(chalk27.yellow("No files found matching pattern"));
|
|
2205
2231
|
return;
|
|
2206
2232
|
}
|
|
2207
2233
|
if (files.length === 1) {
|
|
2208
2234
|
const file = files[0];
|
|
2209
|
-
console.log(
|
|
2235
|
+
console.log(chalk27.bold.underline("SLOC"));
|
|
2210
2236
|
await sloc(file);
|
|
2211
2237
|
console.log();
|
|
2212
|
-
console.log(
|
|
2238
|
+
console.log(chalk27.bold.underline("Cyclomatic Complexity"));
|
|
2213
2239
|
await cyclomatic(file);
|
|
2214
2240
|
console.log();
|
|
2215
|
-
console.log(
|
|
2241
|
+
console.log(chalk27.bold.underline("Halstead Metrics"));
|
|
2216
2242
|
await halstead(file);
|
|
2217
2243
|
console.log();
|
|
2218
|
-
console.log(
|
|
2244
|
+
console.log(chalk27.bold.underline("Maintainability Index"));
|
|
2219
2245
|
await maintainability(file);
|
|
2220
2246
|
return;
|
|
2221
2247
|
}
|
|
@@ -2243,7 +2269,7 @@ function registerComplexity(program2) {
|
|
|
2243
2269
|
|
|
2244
2270
|
// src/commands/deploy/redirect.ts
|
|
2245
2271
|
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
2246
|
-
import
|
|
2272
|
+
import chalk28 from "chalk";
|
|
2247
2273
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
2248
2274
|
if (!window.location.pathname.endsWith('/')) {
|
|
2249
2275
|
window.location.href = \`\${window.location.pathname}/\${window.location.search}\${window.location.hash}\`;
|
|
@@ -2252,22 +2278,22 @@ var TRAILING_SLASH_SCRIPT = ` <script>
|
|
|
2252
2278
|
function redirect() {
|
|
2253
2279
|
const indexPath = "index.html";
|
|
2254
2280
|
if (!existsSync11(indexPath)) {
|
|
2255
|
-
console.log(
|
|
2281
|
+
console.log(chalk28.yellow("No index.html found"));
|
|
2256
2282
|
return;
|
|
2257
2283
|
}
|
|
2258
2284
|
const content = readFileSync9(indexPath, "utf-8");
|
|
2259
2285
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
2260
|
-
console.log(
|
|
2286
|
+
console.log(chalk28.dim("Trailing slash script already present"));
|
|
2261
2287
|
return;
|
|
2262
2288
|
}
|
|
2263
2289
|
const headCloseIndex = content.indexOf("</head>");
|
|
2264
2290
|
if (headCloseIndex === -1) {
|
|
2265
|
-
console.log(
|
|
2291
|
+
console.log(chalk28.red("Could not find </head> tag in index.html"));
|
|
2266
2292
|
return;
|
|
2267
2293
|
}
|
|
2268
2294
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
2269
2295
|
writeFileSync9(indexPath, newContent);
|
|
2270
|
-
console.log(
|
|
2296
|
+
console.log(chalk28.green("Added trailing slash redirect to index.html"));
|
|
2271
2297
|
}
|
|
2272
2298
|
|
|
2273
2299
|
// src/commands/registerDeploy.ts
|
|
@@ -2283,7 +2309,7 @@ import { basename as basename3 } from "path";
|
|
|
2283
2309
|
|
|
2284
2310
|
// src/commands/devlog/shared.ts
|
|
2285
2311
|
import { execSync as execSync10 } from "child_process";
|
|
2286
|
-
import
|
|
2312
|
+
import chalk29 from "chalk";
|
|
2287
2313
|
|
|
2288
2314
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
2289
2315
|
import { readdirSync, readFileSync as readFileSync10 } from "fs";
|
|
@@ -2344,13 +2370,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
|
|
|
2344
2370
|
}
|
|
2345
2371
|
function printCommitsWithFiles(commits, ignore2, verbose) {
|
|
2346
2372
|
for (const commit2 of commits) {
|
|
2347
|
-
console.log(` ${
|
|
2373
|
+
console.log(` ${chalk29.yellow(commit2.hash)} ${commit2.message}`);
|
|
2348
2374
|
if (verbose) {
|
|
2349
2375
|
const visibleFiles = commit2.files.filter(
|
|
2350
2376
|
(file) => !ignore2.some((p) => file.startsWith(p))
|
|
2351
2377
|
);
|
|
2352
2378
|
for (const file of visibleFiles) {
|
|
2353
|
-
console.log(` ${
|
|
2379
|
+
console.log(` ${chalk29.dim(file)}`);
|
|
2354
2380
|
}
|
|
2355
2381
|
}
|
|
2356
2382
|
}
|
|
@@ -2375,15 +2401,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
|
|
|
2375
2401
|
}
|
|
2376
2402
|
|
|
2377
2403
|
// src/commands/devlog/list/printDateHeader.ts
|
|
2378
|
-
import
|
|
2404
|
+
import chalk30 from "chalk";
|
|
2379
2405
|
function printDateHeader(date, isSkipped, entries) {
|
|
2380
2406
|
if (isSkipped) {
|
|
2381
|
-
console.log(`${
|
|
2407
|
+
console.log(`${chalk30.bold.blue(date)} ${chalk30.dim("skipped")}`);
|
|
2382
2408
|
} else if (entries && entries.length > 0) {
|
|
2383
|
-
const entryInfo = entries.map((e) => `${
|
|
2384
|
-
console.log(`${
|
|
2409
|
+
const entryInfo = entries.map((e) => `${chalk30.green(e.version)} ${e.title}`).join(" | ");
|
|
2410
|
+
console.log(`${chalk30.bold.blue(date)} ${entryInfo}`);
|
|
2385
2411
|
} else {
|
|
2386
|
-
console.log(`${
|
|
2412
|
+
console.log(`${chalk30.bold.blue(date)} ${chalk30.red("\u26A0 devlog missing")}`);
|
|
2387
2413
|
}
|
|
2388
2414
|
}
|
|
2389
2415
|
|
|
@@ -2486,24 +2512,24 @@ function bumpVersion(version2, type) {
|
|
|
2486
2512
|
|
|
2487
2513
|
// src/commands/devlog/next/displayNextEntry/index.ts
|
|
2488
2514
|
import { execSync as execSync13 } from "child_process";
|
|
2489
|
-
import
|
|
2515
|
+
import chalk32 from "chalk";
|
|
2490
2516
|
|
|
2491
2517
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
2492
|
-
import
|
|
2518
|
+
import chalk31 from "chalk";
|
|
2493
2519
|
function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
|
|
2494
2520
|
if (conventional && firstHash) {
|
|
2495
2521
|
const version2 = getVersionAtCommit(firstHash);
|
|
2496
2522
|
if (version2) {
|
|
2497
|
-
console.log(`${
|
|
2523
|
+
console.log(`${chalk31.bold("version:")} ${stripToMinor(version2)}`);
|
|
2498
2524
|
} else {
|
|
2499
|
-
console.log(`${
|
|
2525
|
+
console.log(`${chalk31.bold("version:")} ${chalk31.red("unknown")}`);
|
|
2500
2526
|
}
|
|
2501
2527
|
} else if (patchVersion && minorVersion) {
|
|
2502
2528
|
console.log(
|
|
2503
|
-
`${
|
|
2529
|
+
`${chalk31.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
2504
2530
|
);
|
|
2505
2531
|
} else {
|
|
2506
|
-
console.log(`${
|
|
2532
|
+
console.log(`${chalk31.bold("version:")} v0.1 (initial)`);
|
|
2507
2533
|
}
|
|
2508
2534
|
}
|
|
2509
2535
|
|
|
@@ -2550,16 +2576,16 @@ function noCommitsMessage(hasLastInfo) {
|
|
|
2550
2576
|
return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
|
|
2551
2577
|
}
|
|
2552
2578
|
function logName(repoName) {
|
|
2553
|
-
console.log(`${
|
|
2579
|
+
console.log(`${chalk32.bold("name:")} ${repoName}`);
|
|
2554
2580
|
}
|
|
2555
2581
|
function displayNextEntry(ctx, targetDate, commits) {
|
|
2556
2582
|
logName(ctx.repoName);
|
|
2557
2583
|
printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
|
|
2558
|
-
console.log(
|
|
2584
|
+
console.log(chalk32.bold.blue(targetDate));
|
|
2559
2585
|
printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
|
|
2560
2586
|
}
|
|
2561
2587
|
function logNoCommits(lastInfo) {
|
|
2562
|
-
console.log(
|
|
2588
|
+
console.log(chalk32.dim(noCommitsMessage(!!lastInfo)));
|
|
2563
2589
|
}
|
|
2564
2590
|
|
|
2565
2591
|
// src/commands/devlog/next/index.ts
|
|
@@ -2594,16 +2620,16 @@ function next(options2) {
|
|
|
2594
2620
|
}
|
|
2595
2621
|
|
|
2596
2622
|
// src/commands/devlog/skip.ts
|
|
2597
|
-
import
|
|
2623
|
+
import chalk33 from "chalk";
|
|
2598
2624
|
function skip(date) {
|
|
2599
2625
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
2600
|
-
console.log(
|
|
2626
|
+
console.log(chalk33.red("Invalid date format. Use YYYY-MM-DD"));
|
|
2601
2627
|
process.exit(1);
|
|
2602
2628
|
}
|
|
2603
2629
|
const config = loadConfig();
|
|
2604
2630
|
const skipDays = config.devlog?.skip?.days ?? [];
|
|
2605
2631
|
if (skipDays.includes(date)) {
|
|
2606
|
-
console.log(
|
|
2632
|
+
console.log(chalk33.yellow(`${date} is already in skip list`));
|
|
2607
2633
|
return;
|
|
2608
2634
|
}
|
|
2609
2635
|
skipDays.push(date);
|
|
@@ -2616,20 +2642,20 @@ function skip(date) {
|
|
|
2616
2642
|
}
|
|
2617
2643
|
};
|
|
2618
2644
|
saveConfig(config);
|
|
2619
|
-
console.log(
|
|
2645
|
+
console.log(chalk33.green(`Added ${date} to skip list`));
|
|
2620
2646
|
}
|
|
2621
2647
|
|
|
2622
2648
|
// src/commands/devlog/version.ts
|
|
2623
|
-
import
|
|
2649
|
+
import chalk34 from "chalk";
|
|
2624
2650
|
function version() {
|
|
2625
2651
|
const config = loadConfig();
|
|
2626
2652
|
const name = getRepoName();
|
|
2627
2653
|
const lastInfo = getLastVersionInfo(name, config);
|
|
2628
2654
|
const lastVersion = lastInfo?.version ?? null;
|
|
2629
2655
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
2630
|
-
console.log(`${
|
|
2631
|
-
console.log(`${
|
|
2632
|
-
console.log(`${
|
|
2656
|
+
console.log(`${chalk34.bold("name:")} ${name}`);
|
|
2657
|
+
console.log(`${chalk34.bold("last:")} ${lastVersion ?? chalk34.dim("none")}`);
|
|
2658
|
+
console.log(`${chalk34.bold("next:")} ${nextVersion ?? chalk34.dim("none")}`);
|
|
2633
2659
|
}
|
|
2634
2660
|
|
|
2635
2661
|
// src/commands/registerDevlog.ts
|
|
@@ -2886,20 +2912,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
2886
2912
|
}
|
|
2887
2913
|
|
|
2888
2914
|
// src/commands/prs/listComments/formatForHuman.ts
|
|
2889
|
-
import
|
|
2915
|
+
import chalk35 from "chalk";
|
|
2890
2916
|
function formatForHuman(comment) {
|
|
2891
2917
|
if (comment.type === "review") {
|
|
2892
|
-
const stateColor = comment.state === "APPROVED" ?
|
|
2918
|
+
const stateColor = comment.state === "APPROVED" ? chalk35.green : comment.state === "CHANGES_REQUESTED" ? chalk35.red : chalk35.yellow;
|
|
2893
2919
|
return [
|
|
2894
|
-
`${
|
|
2920
|
+
`${chalk35.cyan("Review")} by ${chalk35.bold(comment.user)} ${stateColor(`[${comment.state}]`)}`,
|
|
2895
2921
|
comment.body,
|
|
2896
2922
|
""
|
|
2897
2923
|
].join("\n");
|
|
2898
2924
|
}
|
|
2899
2925
|
const location = comment.line ? `:${comment.line}` : "";
|
|
2900
2926
|
return [
|
|
2901
|
-
`${
|
|
2902
|
-
|
|
2927
|
+
`${chalk35.cyan("Line comment")} by ${chalk35.bold(comment.user)} on ${chalk35.dim(`${comment.path}${location}`)}`,
|
|
2928
|
+
chalk35.dim(comment.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
2903
2929
|
comment.body,
|
|
2904
2930
|
""
|
|
2905
2931
|
].join("\n");
|
|
@@ -2978,13 +3004,13 @@ import { execSync as execSync19 } from "child_process";
|
|
|
2978
3004
|
import enquirer4 from "enquirer";
|
|
2979
3005
|
|
|
2980
3006
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
2981
|
-
import
|
|
3007
|
+
import chalk36 from "chalk";
|
|
2982
3008
|
var STATUS_MAP = {
|
|
2983
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
2984
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
3009
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk36.magenta("merged"), date: pr.mergedAt } : null,
|
|
3010
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk36.red("closed"), date: pr.closedAt } : null
|
|
2985
3011
|
};
|
|
2986
3012
|
function defaultStatus(pr) {
|
|
2987
|
-
return { label:
|
|
3013
|
+
return { label: chalk36.green("opened"), date: pr.createdAt };
|
|
2988
3014
|
}
|
|
2989
3015
|
function getStatus(pr) {
|
|
2990
3016
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -2993,11 +3019,11 @@ function formatDate(dateStr) {
|
|
|
2993
3019
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
2994
3020
|
}
|
|
2995
3021
|
function formatPrHeader(pr, status) {
|
|
2996
|
-
return `${
|
|
3022
|
+
return `${chalk36.cyan(`#${pr.number}`)} ${pr.title} ${chalk36.dim(`(${pr.author.login},`)} ${status.label} ${chalk36.dim(`${formatDate(status.date)})`)}`;
|
|
2997
3023
|
}
|
|
2998
3024
|
function logPrDetails(pr) {
|
|
2999
3025
|
console.log(
|
|
3000
|
-
|
|
3026
|
+
chalk36.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
3001
3027
|
);
|
|
3002
3028
|
console.log();
|
|
3003
3029
|
}
|
|
@@ -3161,10 +3187,10 @@ function registerPrs(program2) {
|
|
|
3161
3187
|
|
|
3162
3188
|
// src/commands/refactor/check/index.ts
|
|
3163
3189
|
import { spawn as spawn3 } from "child_process";
|
|
3164
|
-
import * as
|
|
3190
|
+
import * as path17 from "path";
|
|
3165
3191
|
|
|
3166
3192
|
// src/commands/refactor/logViolations.ts
|
|
3167
|
-
import
|
|
3193
|
+
import chalk37 from "chalk";
|
|
3168
3194
|
var DEFAULT_MAX_LINES = 100;
|
|
3169
3195
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
3170
3196
|
if (violations.length === 0) {
|
|
@@ -3173,43 +3199,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
3173
3199
|
}
|
|
3174
3200
|
return;
|
|
3175
3201
|
}
|
|
3176
|
-
console.error(
|
|
3202
|
+
console.error(chalk37.red(`
|
|
3177
3203
|
Refactor check failed:
|
|
3178
3204
|
`));
|
|
3179
|
-
console.error(
|
|
3205
|
+
console.error(chalk37.red(` The following files exceed ${maxLines} lines:
|
|
3180
3206
|
`));
|
|
3181
3207
|
for (const violation of violations) {
|
|
3182
|
-
console.error(
|
|
3208
|
+
console.error(chalk37.red(` ${violation.file} (${violation.lines} lines)`));
|
|
3183
3209
|
}
|
|
3184
3210
|
console.error(
|
|
3185
|
-
|
|
3211
|
+
chalk37.yellow(
|
|
3186
3212
|
`
|
|
3187
3213
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
3188
3214
|
way to refactor it, ignore it with:
|
|
3189
3215
|
`
|
|
3190
3216
|
)
|
|
3191
3217
|
);
|
|
3192
|
-
console.error(
|
|
3218
|
+
console.error(chalk37.gray(` assist refactor ignore <file>
|
|
3193
3219
|
`));
|
|
3194
3220
|
if (process.env.CLAUDECODE) {
|
|
3195
|
-
console.error(
|
|
3221
|
+
console.error(chalk37.cyan(`
|
|
3196
3222
|
## Extracting Code to New Files
|
|
3197
3223
|
`));
|
|
3198
3224
|
console.error(
|
|
3199
|
-
|
|
3225
|
+
chalk37.cyan(
|
|
3200
3226
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
3201
3227
|
`
|
|
3202
3228
|
)
|
|
3203
3229
|
);
|
|
3204
3230
|
console.error(
|
|
3205
|
-
|
|
3231
|
+
chalk37.cyan(
|
|
3206
3232
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
3207
3233
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
3208
3234
|
`
|
|
3209
3235
|
)
|
|
3210
3236
|
);
|
|
3211
3237
|
console.error(
|
|
3212
|
-
|
|
3238
|
+
chalk37.cyan(
|
|
3213
3239
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
3214
3240
|
domains, move it to a common/shared folder.
|
|
3215
3241
|
`
|
|
@@ -3338,7 +3364,7 @@ ${failed.length} verify script(s) failed:`);
|
|
|
3338
3364
|
async function runVerifyQuietly() {
|
|
3339
3365
|
const result = findPackageJsonWithVerifyScripts(process.cwd());
|
|
3340
3366
|
if (!result) return true;
|
|
3341
|
-
const packageDir =
|
|
3367
|
+
const packageDir = path17.dirname(result.packageJsonPath);
|
|
3342
3368
|
const results = await Promise.all(
|
|
3343
3369
|
result.verifyScripts.map((script) => runScript2(script, packageDir))
|
|
3344
3370
|
);
|
|
@@ -3365,11 +3391,11 @@ async function check(pattern2, options2) {
|
|
|
3365
3391
|
|
|
3366
3392
|
// src/commands/refactor/ignore.ts
|
|
3367
3393
|
import fs16 from "fs";
|
|
3368
|
-
import
|
|
3394
|
+
import chalk38 from "chalk";
|
|
3369
3395
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
3370
3396
|
function ignore(file) {
|
|
3371
3397
|
if (!fs16.existsSync(file)) {
|
|
3372
|
-
console.error(
|
|
3398
|
+
console.error(chalk38.red(`Error: File does not exist: ${file}`));
|
|
3373
3399
|
process.exit(1);
|
|
3374
3400
|
}
|
|
3375
3401
|
const content = fs16.readFileSync(file, "utf-8");
|
|
@@ -3385,18 +3411,18 @@ function ignore(file) {
|
|
|
3385
3411
|
fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
3386
3412
|
}
|
|
3387
3413
|
console.log(
|
|
3388
|
-
|
|
3414
|
+
chalk38.green(
|
|
3389
3415
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
3390
3416
|
)
|
|
3391
3417
|
);
|
|
3392
3418
|
}
|
|
3393
3419
|
|
|
3394
3420
|
// src/commands/refactor/restructure/index.ts
|
|
3395
|
-
import
|
|
3396
|
-
import
|
|
3421
|
+
import path26 from "path";
|
|
3422
|
+
import chalk41 from "chalk";
|
|
3397
3423
|
|
|
3398
3424
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
3399
|
-
import
|
|
3425
|
+
import path18 from "path";
|
|
3400
3426
|
import ts7 from "typescript";
|
|
3401
3427
|
|
|
3402
3428
|
// src/commands/refactor/restructure/buildImportGraph/getImportSpecifiers.ts
|
|
@@ -3423,7 +3449,7 @@ function loadParsedConfig(tsConfigPath) {
|
|
|
3423
3449
|
return ts7.parseJsonConfigFileContent(
|
|
3424
3450
|
configFile.config,
|
|
3425
3451
|
ts7.sys,
|
|
3426
|
-
|
|
3452
|
+
path18.dirname(tsConfigPath)
|
|
3427
3453
|
);
|
|
3428
3454
|
}
|
|
3429
3455
|
function addToSetMap(map, key, value) {
|
|
@@ -3439,7 +3465,7 @@ function resolveImport(specifier, filePath, options2) {
|
|
|
3439
3465
|
const resolved = ts7.resolveModuleName(specifier, filePath, options2, ts7.sys);
|
|
3440
3466
|
const resolvedPath = resolved.resolvedModule?.resolvedFileName;
|
|
3441
3467
|
if (!resolvedPath || resolvedPath.includes("node_modules")) return null;
|
|
3442
|
-
return
|
|
3468
|
+
return path18.resolve(resolvedPath);
|
|
3443
3469
|
}
|
|
3444
3470
|
function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
3445
3471
|
const parsed = loadParsedConfig(tsConfigPath);
|
|
@@ -3448,7 +3474,7 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
3448
3474
|
const importedBy = /* @__PURE__ */ new Map();
|
|
3449
3475
|
const imports = /* @__PURE__ */ new Map();
|
|
3450
3476
|
for (const sourceFile of program2.getSourceFiles()) {
|
|
3451
|
-
const filePath =
|
|
3477
|
+
const filePath = path18.resolve(sourceFile.fileName);
|
|
3452
3478
|
if (filePath.includes("node_modules")) continue;
|
|
3453
3479
|
for (const specifier of getImportSpecifiers(sourceFile)) {
|
|
3454
3480
|
const absTarget = resolveImport(specifier, filePath, parsed.options);
|
|
@@ -3462,12 +3488,12 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
3462
3488
|
}
|
|
3463
3489
|
|
|
3464
3490
|
// src/commands/refactor/restructure/clusterDirectories.ts
|
|
3465
|
-
import
|
|
3491
|
+
import path19 from "path";
|
|
3466
3492
|
function clusterDirectories(graph) {
|
|
3467
3493
|
const dirImportedBy = /* @__PURE__ */ new Map();
|
|
3468
3494
|
for (const edge of graph.edges) {
|
|
3469
|
-
const sourceDir =
|
|
3470
|
-
const targetDir =
|
|
3495
|
+
const sourceDir = path19.dirname(edge.source);
|
|
3496
|
+
const targetDir = path19.dirname(edge.target);
|
|
3471
3497
|
if (sourceDir === targetDir) continue;
|
|
3472
3498
|
if (!graph.files.has(edge.target)) continue;
|
|
3473
3499
|
const existing = dirImportedBy.get(targetDir) ?? /* @__PURE__ */ new Set();
|
|
@@ -3495,20 +3521,20 @@ function clusterDirectories(graph) {
|
|
|
3495
3521
|
return clusters;
|
|
3496
3522
|
}
|
|
3497
3523
|
function isAncestor(ancestor, descendant) {
|
|
3498
|
-
const rel =
|
|
3524
|
+
const rel = path19.relative(ancestor, descendant);
|
|
3499
3525
|
return !rel.startsWith("..") && rel !== "";
|
|
3500
3526
|
}
|
|
3501
3527
|
|
|
3502
3528
|
// src/commands/refactor/restructure/clusterFiles.ts
|
|
3503
|
-
import
|
|
3529
|
+
import path20 from "path";
|
|
3504
3530
|
function findRootParent(file, importedBy, visited) {
|
|
3505
3531
|
const importers = importedBy.get(file);
|
|
3506
3532
|
if (!importers || importers.size !== 1) return file;
|
|
3507
3533
|
const parent = [...importers][0];
|
|
3508
|
-
const parentDir =
|
|
3509
|
-
const fileDir =
|
|
3534
|
+
const parentDir = path20.dirname(parent);
|
|
3535
|
+
const fileDir = path20.dirname(file);
|
|
3510
3536
|
if (parentDir !== fileDir) return file;
|
|
3511
|
-
if (
|
|
3537
|
+
if (path20.basename(parent, path20.extname(parent)) === "index") return file;
|
|
3512
3538
|
if (visited.has(parent)) return file;
|
|
3513
3539
|
visited.add(parent);
|
|
3514
3540
|
return findRootParent(parent, importedBy, visited);
|
|
@@ -3516,16 +3542,16 @@ function findRootParent(file, importedBy, visited) {
|
|
|
3516
3542
|
function clusterFiles(graph) {
|
|
3517
3543
|
const clusters = /* @__PURE__ */ new Map();
|
|
3518
3544
|
for (const file of graph.files) {
|
|
3519
|
-
const basename7 =
|
|
3545
|
+
const basename7 = path20.basename(file, path20.extname(file));
|
|
3520
3546
|
if (basename7 === "index") continue;
|
|
3521
3547
|
const importers = graph.importedBy.get(file);
|
|
3522
3548
|
if (!importers || importers.size !== 1) continue;
|
|
3523
3549
|
const parent = [...importers][0];
|
|
3524
3550
|
if (!graph.files.has(parent)) continue;
|
|
3525
|
-
const parentDir =
|
|
3526
|
-
const fileDir =
|
|
3551
|
+
const parentDir = path20.dirname(parent);
|
|
3552
|
+
const fileDir = path20.dirname(file);
|
|
3527
3553
|
if (parentDir !== fileDir) continue;
|
|
3528
|
-
const parentBasename =
|
|
3554
|
+
const parentBasename = path20.basename(parent, path20.extname(parent));
|
|
3529
3555
|
if (parentBasename === "index") continue;
|
|
3530
3556
|
const root = findRootParent(parent, graph.importedBy, /* @__PURE__ */ new Set([file]));
|
|
3531
3557
|
if (!root || root === file) continue;
|
|
@@ -3537,7 +3563,7 @@ function clusterFiles(graph) {
|
|
|
3537
3563
|
}
|
|
3538
3564
|
|
|
3539
3565
|
// src/commands/refactor/restructure/computeRewrites/index.ts
|
|
3540
|
-
import
|
|
3566
|
+
import path21 from "path";
|
|
3541
3567
|
|
|
3542
3568
|
// src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
|
|
3543
3569
|
import fs17 from "fs";
|
|
@@ -3591,7 +3617,7 @@ function normalizeSpecifier(rel) {
|
|
|
3591
3617
|
);
|
|
3592
3618
|
}
|
|
3593
3619
|
function computeSpecifier(fromFile, toFile) {
|
|
3594
|
-
return normalizeSpecifier(
|
|
3620
|
+
return normalizeSpecifier(path21.relative(path21.dirname(fromFile), toFile));
|
|
3595
3621
|
}
|
|
3596
3622
|
function isAffected(edge, moveMap) {
|
|
3597
3623
|
return moveMap.has(edge.target) || moveMap.has(edge.source);
|
|
@@ -3635,51 +3661,51 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
3635
3661
|
}
|
|
3636
3662
|
|
|
3637
3663
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
3638
|
-
import
|
|
3639
|
-
import
|
|
3664
|
+
import path22 from "path";
|
|
3665
|
+
import chalk39 from "chalk";
|
|
3640
3666
|
function relPath(filePath) {
|
|
3641
|
-
return
|
|
3667
|
+
return path22.relative(process.cwd(), filePath);
|
|
3642
3668
|
}
|
|
3643
3669
|
function displayMoves(plan) {
|
|
3644
3670
|
if (plan.moves.length === 0) return;
|
|
3645
|
-
console.log(
|
|
3671
|
+
console.log(chalk39.bold("\nFile moves:"));
|
|
3646
3672
|
for (const move of plan.moves) {
|
|
3647
3673
|
console.log(
|
|
3648
|
-
` ${
|
|
3674
|
+
` ${chalk39.red(relPath(move.from))} \u2192 ${chalk39.green(relPath(move.to))}`
|
|
3649
3675
|
);
|
|
3650
|
-
console.log(
|
|
3676
|
+
console.log(chalk39.dim(` ${move.reason}`));
|
|
3651
3677
|
}
|
|
3652
3678
|
}
|
|
3653
3679
|
function displayRewrites(rewrites) {
|
|
3654
3680
|
if (rewrites.length === 0) return;
|
|
3655
3681
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
3656
|
-
console.log(
|
|
3682
|
+
console.log(chalk39.bold(`
|
|
3657
3683
|
Import rewrites (${affectedFiles.size} files):`));
|
|
3658
3684
|
for (const file of affectedFiles) {
|
|
3659
|
-
console.log(` ${
|
|
3685
|
+
console.log(` ${chalk39.cyan(relPath(file))}:`);
|
|
3660
3686
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
3661
3687
|
(r) => r.file === file
|
|
3662
3688
|
)) {
|
|
3663
3689
|
console.log(
|
|
3664
|
-
` ${
|
|
3690
|
+
` ${chalk39.red(`"${oldSpecifier}"`)} \u2192 ${chalk39.green(`"${newSpecifier}"`)}`
|
|
3665
3691
|
);
|
|
3666
3692
|
}
|
|
3667
3693
|
}
|
|
3668
3694
|
}
|
|
3669
3695
|
function displayPlan(plan) {
|
|
3670
3696
|
if (plan.warnings.length > 0) {
|
|
3671
|
-
console.log(
|
|
3672
|
-
for (const w of plan.warnings) console.log(
|
|
3697
|
+
console.log(chalk39.yellow("\nWarnings:"));
|
|
3698
|
+
for (const w of plan.warnings) console.log(chalk39.yellow(` ${w}`));
|
|
3673
3699
|
}
|
|
3674
3700
|
if (plan.newDirectories.length > 0) {
|
|
3675
|
-
console.log(
|
|
3701
|
+
console.log(chalk39.bold("\nNew directories:"));
|
|
3676
3702
|
for (const dir of plan.newDirectories)
|
|
3677
|
-
console.log(
|
|
3703
|
+
console.log(chalk39.green(` ${dir}/`));
|
|
3678
3704
|
}
|
|
3679
3705
|
displayMoves(plan);
|
|
3680
3706
|
displayRewrites(plan.rewrites);
|
|
3681
3707
|
console.log(
|
|
3682
|
-
|
|
3708
|
+
chalk39.dim(
|
|
3683
3709
|
`
|
|
3684
3710
|
Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
|
|
3685
3711
|
)
|
|
@@ -3688,33 +3714,33 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
3688
3714
|
|
|
3689
3715
|
// src/commands/refactor/restructure/executePlan.ts
|
|
3690
3716
|
import fs18 from "fs";
|
|
3691
|
-
import
|
|
3692
|
-
import
|
|
3717
|
+
import path23 from "path";
|
|
3718
|
+
import chalk40 from "chalk";
|
|
3693
3719
|
function executePlan(plan) {
|
|
3694
3720
|
const updatedContents = applyRewrites(plan.rewrites);
|
|
3695
3721
|
for (const [file, content] of updatedContents) {
|
|
3696
3722
|
fs18.writeFileSync(file, content, "utf-8");
|
|
3697
3723
|
console.log(
|
|
3698
|
-
|
|
3724
|
+
chalk40.cyan(` Rewrote imports in ${path23.relative(process.cwd(), file)}`)
|
|
3699
3725
|
);
|
|
3700
3726
|
}
|
|
3701
3727
|
for (const dir of plan.newDirectories) {
|
|
3702
3728
|
fs18.mkdirSync(dir, { recursive: true });
|
|
3703
|
-
console.log(
|
|
3729
|
+
console.log(chalk40.green(` Created ${path23.relative(process.cwd(), dir)}/`));
|
|
3704
3730
|
}
|
|
3705
3731
|
for (const move of plan.moves) {
|
|
3706
|
-
const targetDir =
|
|
3732
|
+
const targetDir = path23.dirname(move.to);
|
|
3707
3733
|
if (!fs18.existsSync(targetDir)) {
|
|
3708
3734
|
fs18.mkdirSync(targetDir, { recursive: true });
|
|
3709
3735
|
}
|
|
3710
3736
|
fs18.renameSync(move.from, move.to);
|
|
3711
3737
|
console.log(
|
|
3712
|
-
|
|
3713
|
-
` Moved ${
|
|
3738
|
+
chalk40.white(
|
|
3739
|
+
` Moved ${path23.relative(process.cwd(), move.from)} \u2192 ${path23.relative(process.cwd(), move.to)}`
|
|
3714
3740
|
)
|
|
3715
3741
|
);
|
|
3716
3742
|
}
|
|
3717
|
-
removeEmptyDirectories(plan.moves.map((m) =>
|
|
3743
|
+
removeEmptyDirectories(plan.moves.map((m) => path23.dirname(m.from)));
|
|
3718
3744
|
}
|
|
3719
3745
|
function removeEmptyDirectories(dirs) {
|
|
3720
3746
|
const unique = [...new Set(dirs)];
|
|
@@ -3724,8 +3750,8 @@ function removeEmptyDirectories(dirs) {
|
|
|
3724
3750
|
if (entries.length === 0) {
|
|
3725
3751
|
fs18.rmdirSync(dir);
|
|
3726
3752
|
console.log(
|
|
3727
|
-
|
|
3728
|
-
` Removed empty directory ${
|
|
3753
|
+
chalk40.dim(
|
|
3754
|
+
` Removed empty directory ${path23.relative(process.cwd(), dir)}`
|
|
3729
3755
|
)
|
|
3730
3756
|
);
|
|
3731
3757
|
}
|
|
@@ -3734,13 +3760,13 @@ function removeEmptyDirectories(dirs) {
|
|
|
3734
3760
|
|
|
3735
3761
|
// src/commands/refactor/restructure/planFileMoves/index.ts
|
|
3736
3762
|
import fs20 from "fs";
|
|
3737
|
-
import
|
|
3763
|
+
import path25 from "path";
|
|
3738
3764
|
|
|
3739
3765
|
// src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
|
|
3740
3766
|
import fs19 from "fs";
|
|
3741
|
-
import
|
|
3767
|
+
import path24 from "path";
|
|
3742
3768
|
function collectEntry(results, dir, entry) {
|
|
3743
|
-
const full =
|
|
3769
|
+
const full = path24.join(dir, entry.name);
|
|
3744
3770
|
const items = entry.isDirectory() ? listFilesRecursive(full) : [full];
|
|
3745
3771
|
results.push(...items);
|
|
3746
3772
|
}
|
|
@@ -3754,15 +3780,15 @@ function listFilesRecursive(dir) {
|
|
|
3754
3780
|
}
|
|
3755
3781
|
function addDirectoryFileMoves(moves, childDir, newLocation, reason) {
|
|
3756
3782
|
for (const file of listFilesRecursive(childDir)) {
|
|
3757
|
-
const rel =
|
|
3758
|
-
moves.push({ from: file, to:
|
|
3783
|
+
const rel = path24.relative(childDir, file);
|
|
3784
|
+
moves.push({ from: file, to: path24.join(newLocation, rel), reason });
|
|
3759
3785
|
}
|
|
3760
3786
|
}
|
|
3761
3787
|
function resolveChildDest(parentDir, childDir) {
|
|
3762
|
-
return
|
|
3788
|
+
return path24.join(parentDir, path24.basename(childDir));
|
|
3763
3789
|
}
|
|
3764
3790
|
function childMoveReason(parentDir) {
|
|
3765
|
-
return `Directory only imported from ${
|
|
3791
|
+
return `Directory only imported from ${path24.basename(parentDir)}/`;
|
|
3766
3792
|
}
|
|
3767
3793
|
function registerDirectoryMove(result, childDir, dest, parentDir) {
|
|
3768
3794
|
result.directories.push(dest);
|
|
@@ -3790,7 +3816,7 @@ function emptyResult() {
|
|
|
3790
3816
|
return { moves: [], directories: [], warnings: [] };
|
|
3791
3817
|
}
|
|
3792
3818
|
function childMoveData(child, newDir, parentBase) {
|
|
3793
|
-
const to =
|
|
3819
|
+
const to = path25.join(newDir, path25.basename(child));
|
|
3794
3820
|
return { from: child, to, reason: `Only imported by ${parentBase}` };
|
|
3795
3821
|
}
|
|
3796
3822
|
function addChildMoves(moves, children, newDir, parentBase) {
|
|
@@ -3803,15 +3829,15 @@ function checkDirConflict(result, label, dir) {
|
|
|
3803
3829
|
return true;
|
|
3804
3830
|
}
|
|
3805
3831
|
function getBaseName(filePath) {
|
|
3806
|
-
return
|
|
3832
|
+
return path25.basename(filePath, path25.extname(filePath));
|
|
3807
3833
|
}
|
|
3808
3834
|
function resolveClusterDir(parent) {
|
|
3809
|
-
return
|
|
3835
|
+
return path25.join(path25.dirname(parent), getBaseName(parent));
|
|
3810
3836
|
}
|
|
3811
3837
|
function createParentMove(parent, newDir) {
|
|
3812
3838
|
return {
|
|
3813
3839
|
from: parent,
|
|
3814
|
-
to:
|
|
3840
|
+
to: path25.join(newDir, `index${path25.extname(parent)}`),
|
|
3815
3841
|
reason: `Main module of new ${getBaseName(parent)}/ directory`
|
|
3816
3842
|
};
|
|
3817
3843
|
}
|
|
@@ -3835,7 +3861,7 @@ function planFileMoves(clusters) {
|
|
|
3835
3861
|
|
|
3836
3862
|
// src/commands/refactor/restructure/index.ts
|
|
3837
3863
|
function buildPlan(candidateFiles, tsConfigPath) {
|
|
3838
|
-
const candidates = new Set(candidateFiles.map((f) =>
|
|
3864
|
+
const candidates = new Set(candidateFiles.map((f) => path26.resolve(f)));
|
|
3839
3865
|
const graph = buildImportGraph(candidates, tsConfigPath);
|
|
3840
3866
|
const allProjectFiles = /* @__PURE__ */ new Set([
|
|
3841
3867
|
...graph.importedBy.keys(),
|
|
@@ -3855,22 +3881,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
3855
3881
|
const targetPattern = pattern2 ?? "src";
|
|
3856
3882
|
const files = findSourceFiles2(targetPattern);
|
|
3857
3883
|
if (files.length === 0) {
|
|
3858
|
-
console.log(
|
|
3884
|
+
console.log(chalk41.yellow("No files found matching pattern"));
|
|
3859
3885
|
return;
|
|
3860
3886
|
}
|
|
3861
|
-
const tsConfigPath =
|
|
3887
|
+
const tsConfigPath = path26.resolve("tsconfig.json");
|
|
3862
3888
|
const plan = buildPlan(files, tsConfigPath);
|
|
3863
3889
|
if (plan.moves.length === 0) {
|
|
3864
|
-
console.log(
|
|
3890
|
+
console.log(chalk41.green("No restructuring needed"));
|
|
3865
3891
|
return;
|
|
3866
3892
|
}
|
|
3867
3893
|
displayPlan(plan);
|
|
3868
3894
|
if (options2.apply) {
|
|
3869
|
-
console.log(
|
|
3895
|
+
console.log(chalk41.bold("\nApplying changes..."));
|
|
3870
3896
|
executePlan(plan);
|
|
3871
|
-
console.log(
|
|
3897
|
+
console.log(chalk41.green("\nRestructuring complete"));
|
|
3872
3898
|
} else {
|
|
3873
|
-
console.log(
|
|
3899
|
+
console.log(chalk41.dim("\nDry run. Use --apply to execute."));
|
|
3874
3900
|
}
|
|
3875
3901
|
}
|
|
3876
3902
|
|
|
@@ -4009,7 +4035,7 @@ async function configure() {
|
|
|
4009
4035
|
import { existsSync as existsSync16 } from "fs";
|
|
4010
4036
|
|
|
4011
4037
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
4012
|
-
import { dirname as
|
|
4038
|
+
import { dirname as dirname12, join as join15 } from "path";
|
|
4013
4039
|
|
|
4014
4040
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
4015
4041
|
import { renameSync } from "fs";
|
|
@@ -4059,11 +4085,11 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
4059
4085
|
for (let i = 0; i < vttFiles.length; i++) {
|
|
4060
4086
|
const vttFile = vttFiles[i];
|
|
4061
4087
|
if (!isValidDatePrefix(vttFile.filename)) {
|
|
4062
|
-
const vttFileDir =
|
|
4088
|
+
const vttFileDir = dirname12(vttFile.absolutePath);
|
|
4063
4089
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
4064
4090
|
if (newFilename) {
|
|
4065
4091
|
const newRelativePath = join15(
|
|
4066
|
-
|
|
4092
|
+
dirname12(vttFile.relativePath),
|
|
4067
4093
|
newFilename
|
|
4068
4094
|
);
|
|
4069
4095
|
vttFiles[i] = {
|
|
@@ -4081,7 +4107,7 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
4081
4107
|
|
|
4082
4108
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
4083
4109
|
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync13 } from "fs";
|
|
4084
|
-
import { basename as basename5, dirname as
|
|
4110
|
+
import { basename as basename5, dirname as dirname13, join as join16 } from "path";
|
|
4085
4111
|
|
|
4086
4112
|
// src/commands/transcript/cleanText.ts
|
|
4087
4113
|
function cleanText(text) {
|
|
@@ -4295,7 +4321,7 @@ function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
|
4295
4321
|
}
|
|
4296
4322
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
4297
4323
|
const mdFile = toMdFilename(vttFile.filename);
|
|
4298
|
-
const relativeDir =
|
|
4324
|
+
const relativeDir = dirname13(vttFile.relativePath);
|
|
4299
4325
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
4300
4326
|
const outputPath = join16(outputDir, mdFile);
|
|
4301
4327
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
@@ -4400,7 +4426,7 @@ async function format() {
|
|
|
4400
4426
|
|
|
4401
4427
|
// src/commands/transcript/summarise/index.ts
|
|
4402
4428
|
import { existsSync as existsSync18 } from "fs";
|
|
4403
|
-
import { basename as basename6, dirname as
|
|
4429
|
+
import { basename as basename6, dirname as dirname15, join as join18, relative as relative2 } from "path";
|
|
4404
4430
|
|
|
4405
4431
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
4406
4432
|
import {
|
|
@@ -4410,17 +4436,17 @@ import {
|
|
|
4410
4436
|
renameSync as renameSync2,
|
|
4411
4437
|
rmSync
|
|
4412
4438
|
} from "fs";
|
|
4413
|
-
import { dirname as
|
|
4439
|
+
import { dirname as dirname14, join as join17 } from "path";
|
|
4414
4440
|
|
|
4415
4441
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
4416
|
-
import
|
|
4442
|
+
import chalk42 from "chalk";
|
|
4417
4443
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
4418
4444
|
function validateStagedContent(filename, content) {
|
|
4419
4445
|
const firstLine = content.split("\n")[0];
|
|
4420
4446
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
4421
4447
|
if (!match) {
|
|
4422
4448
|
console.error(
|
|
4423
|
-
|
|
4449
|
+
chalk42.red(
|
|
4424
4450
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
4425
4451
|
)
|
|
4426
4452
|
);
|
|
@@ -4429,7 +4455,7 @@ function validateStagedContent(filename, content) {
|
|
|
4429
4455
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
4430
4456
|
if (!contentAfterLink) {
|
|
4431
4457
|
console.error(
|
|
4432
|
-
|
|
4458
|
+
chalk42.red(
|
|
4433
4459
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
4434
4460
|
)
|
|
4435
4461
|
);
|
|
@@ -4464,7 +4490,7 @@ function processStagedFile() {
|
|
|
4464
4490
|
process.exit(1);
|
|
4465
4491
|
}
|
|
4466
4492
|
const destPath = join17(summaryDir, matchingTranscript.relativePath);
|
|
4467
|
-
const destDir =
|
|
4493
|
+
const destDir = dirname14(destPath);
|
|
4468
4494
|
if (!existsSync17(destDir)) {
|
|
4469
4495
|
mkdirSync6(destDir, { recursive: true });
|
|
4470
4496
|
}
|
|
@@ -4478,7 +4504,7 @@ function processStagedFile() {
|
|
|
4478
4504
|
|
|
4479
4505
|
// src/commands/transcript/summarise/index.ts
|
|
4480
4506
|
function buildRelativeKey(relativePath, baseName) {
|
|
4481
|
-
const relDir =
|
|
4507
|
+
const relDir = dirname15(relativePath);
|
|
4482
4508
|
return relDir === "." ? baseName : join18(relDir, baseName);
|
|
4483
4509
|
}
|
|
4484
4510
|
function buildSummaryIndex(summaryDir) {
|
|
@@ -4514,7 +4540,7 @@ function summarise() {
|
|
|
4514
4540
|
const next2 = missing[0];
|
|
4515
4541
|
const outputFilename = `${getTranscriptBaseName(next2.filename)}.md`;
|
|
4516
4542
|
const outputPath = join18(STAGING_DIR, outputFilename);
|
|
4517
|
-
const summaryFileDir = join18(summaryDir,
|
|
4543
|
+
const summaryFileDir = join18(summaryDir, dirname15(next2.relativePath));
|
|
4518
4544
|
const relativeTranscriptPath = encodeURI(
|
|
4519
4545
|
relative2(summaryFileDir, next2.absolutePath).replace(/\\/g, "/")
|
|
4520
4546
|
);
|
|
@@ -4676,27 +4702,27 @@ async function statusLine() {
|
|
|
4676
4702
|
// src/commands/sync.ts
|
|
4677
4703
|
import * as fs23 from "fs";
|
|
4678
4704
|
import * as os from "os";
|
|
4679
|
-
import * as
|
|
4705
|
+
import * as path29 from "path";
|
|
4680
4706
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4681
4707
|
|
|
4682
4708
|
// src/commands/sync/syncClaudeMd.ts
|
|
4683
4709
|
import * as fs21 from "fs";
|
|
4684
|
-
import * as
|
|
4685
|
-
import
|
|
4710
|
+
import * as path27 from "path";
|
|
4711
|
+
import chalk43 from "chalk";
|
|
4686
4712
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
4687
|
-
const source =
|
|
4688
|
-
const target =
|
|
4713
|
+
const source = path27.join(claudeDir, "CLAUDE.md");
|
|
4714
|
+
const target = path27.join(targetBase, "CLAUDE.md");
|
|
4689
4715
|
const sourceContent = fs21.readFileSync(source, "utf-8");
|
|
4690
4716
|
if (fs21.existsSync(target)) {
|
|
4691
4717
|
const targetContent = fs21.readFileSync(target, "utf-8");
|
|
4692
4718
|
if (sourceContent !== targetContent) {
|
|
4693
4719
|
console.log(
|
|
4694
|
-
|
|
4720
|
+
chalk43.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
4695
4721
|
);
|
|
4696
4722
|
console.log();
|
|
4697
4723
|
printDiff(targetContent, sourceContent);
|
|
4698
4724
|
const confirm = await promptConfirm(
|
|
4699
|
-
|
|
4725
|
+
chalk43.red("Overwrite existing CLAUDE.md?"),
|
|
4700
4726
|
false
|
|
4701
4727
|
);
|
|
4702
4728
|
if (!confirm) {
|
|
@@ -4711,11 +4737,11 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
4711
4737
|
|
|
4712
4738
|
// src/commands/sync/syncSettings.ts
|
|
4713
4739
|
import * as fs22 from "fs";
|
|
4714
|
-
import * as
|
|
4715
|
-
import
|
|
4740
|
+
import * as path28 from "path";
|
|
4741
|
+
import chalk44 from "chalk";
|
|
4716
4742
|
async function syncSettings(claudeDir, targetBase) {
|
|
4717
|
-
const source =
|
|
4718
|
-
const target =
|
|
4743
|
+
const source = path28.join(claudeDir, "settings.json");
|
|
4744
|
+
const target = path28.join(targetBase, "settings.json");
|
|
4719
4745
|
const sourceContent = fs22.readFileSync(source, "utf-8");
|
|
4720
4746
|
const normalizedSource = JSON.stringify(JSON.parse(sourceContent), null, 2);
|
|
4721
4747
|
if (fs22.existsSync(target)) {
|
|
@@ -4723,12 +4749,12 @@ async function syncSettings(claudeDir, targetBase) {
|
|
|
4723
4749
|
const normalizedTarget = JSON.stringify(JSON.parse(targetContent), null, 2);
|
|
4724
4750
|
if (normalizedSource !== normalizedTarget) {
|
|
4725
4751
|
console.log(
|
|
4726
|
-
|
|
4752
|
+
chalk44.yellow("\n\u26A0\uFE0F Warning: settings.json differs from existing file")
|
|
4727
4753
|
);
|
|
4728
4754
|
console.log();
|
|
4729
4755
|
printDiff(targetContent, sourceContent);
|
|
4730
4756
|
const confirm = await promptConfirm(
|
|
4731
|
-
|
|
4757
|
+
chalk44.red("Overwrite existing settings.json?"),
|
|
4732
4758
|
false
|
|
4733
4759
|
);
|
|
4734
4760
|
if (!confirm) {
|
|
@@ -4743,21 +4769,21 @@ async function syncSettings(claudeDir, targetBase) {
|
|
|
4743
4769
|
|
|
4744
4770
|
// src/commands/sync.ts
|
|
4745
4771
|
var __filename2 = fileURLToPath3(import.meta.url);
|
|
4746
|
-
var __dirname4 =
|
|
4772
|
+
var __dirname4 = path29.dirname(__filename2);
|
|
4747
4773
|
async function sync() {
|
|
4748
|
-
const claudeDir =
|
|
4749
|
-
const targetBase =
|
|
4774
|
+
const claudeDir = path29.join(__dirname4, "..", "claude");
|
|
4775
|
+
const targetBase = path29.join(os.homedir(), ".claude");
|
|
4750
4776
|
syncCommands(claudeDir, targetBase);
|
|
4751
4777
|
await syncSettings(claudeDir, targetBase);
|
|
4752
4778
|
await syncClaudeMd(claudeDir, targetBase);
|
|
4753
4779
|
}
|
|
4754
4780
|
function syncCommands(claudeDir, targetBase) {
|
|
4755
|
-
const sourceDir =
|
|
4756
|
-
const targetDir =
|
|
4781
|
+
const sourceDir = path29.join(claudeDir, "commands");
|
|
4782
|
+
const targetDir = path29.join(targetBase, "commands");
|
|
4757
4783
|
fs23.mkdirSync(targetDir, { recursive: true });
|
|
4758
4784
|
const files = fs23.readdirSync(sourceDir);
|
|
4759
4785
|
for (const file of files) {
|
|
4760
|
-
fs23.copyFileSync(
|
|
4786
|
+
fs23.copyFileSync(path29.join(sourceDir, file), path29.join(targetDir, file));
|
|
4761
4787
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
4762
4788
|
}
|
|
4763
4789
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|