@staff0rd/assist 0.111.0 → 0.113.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 +7 -0
- package/claude/settings.json +3 -0
- package/dist/index.js +1121 -687
- 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.113.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -67,6 +67,7 @@ var package_default = {
|
|
|
67
67
|
jotai: "^2.18.0",
|
|
68
68
|
jscpd: "^4.0.5",
|
|
69
69
|
knip: "^5.71.0",
|
|
70
|
+
madge: "^8.0.0",
|
|
70
71
|
marked: "^15.0.12",
|
|
71
72
|
react: "^19.2.4",
|
|
72
73
|
"react-dom": "^19.2.4",
|
|
@@ -89,10 +90,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
89
90
|
// src/shared/loadRawYaml.ts
|
|
90
91
|
import { existsSync, readFileSync } from "fs";
|
|
91
92
|
import { parse as parseYaml } from "yaml";
|
|
92
|
-
function loadRawYaml(
|
|
93
|
-
if (!existsSync(
|
|
93
|
+
function loadRawYaml(path42) {
|
|
94
|
+
if (!existsSync(path42)) return {};
|
|
94
95
|
try {
|
|
95
|
-
const content = readFileSync(
|
|
96
|
+
const content = readFileSync(path42, "utf-8");
|
|
96
97
|
return parseYaml(content) || {};
|
|
97
98
|
} catch {
|
|
98
99
|
return {};
|
|
@@ -161,6 +162,17 @@ var assistConfigSchema = z.strictObject({
|
|
|
161
162
|
news: z.strictObject({
|
|
162
163
|
feeds: z.array(z.string()).default([])
|
|
163
164
|
}).default({ feeds: [] }),
|
|
165
|
+
ravendb: z.strictObject({
|
|
166
|
+
connections: z.array(
|
|
167
|
+
z.strictObject({
|
|
168
|
+
name: z.string(),
|
|
169
|
+
url: z.string(),
|
|
170
|
+
database: z.string(),
|
|
171
|
+
apiKeyRef: z.string()
|
|
172
|
+
})
|
|
173
|
+
).default([]),
|
|
174
|
+
defaultConnection: z.string().optional()
|
|
175
|
+
}).optional(),
|
|
164
176
|
voice: z.strictObject({
|
|
165
177
|
wakeWords: z.array(z.string()).default(DEFAULT_WAKE_WORDS),
|
|
166
178
|
mic: z.string().optional(),
|
|
@@ -330,9 +342,9 @@ function isTraversable(value) {
|
|
|
330
342
|
function stepInto(current, key) {
|
|
331
343
|
return isTraversable(current) ? current[key] : void 0;
|
|
332
344
|
}
|
|
333
|
-
function getNestedValue(obj,
|
|
345
|
+
function getNestedValue(obj, path42) {
|
|
334
346
|
let current = obj;
|
|
335
|
-
for (const key of
|
|
347
|
+
for (const key of path42.split(".")) current = stepInto(current, key);
|
|
336
348
|
return current;
|
|
337
349
|
}
|
|
338
350
|
|
|
@@ -373,8 +385,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
373
385
|
}
|
|
374
386
|
return ensureObject(container, resolved);
|
|
375
387
|
}
|
|
376
|
-
function setNestedValue(obj,
|
|
377
|
-
const keys =
|
|
388
|
+
function setNestedValue(obj, path42, value) {
|
|
389
|
+
const keys = path42.split(".");
|
|
378
390
|
const result = { ...obj };
|
|
379
391
|
let current = result;
|
|
380
392
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -443,7 +455,7 @@ function configList() {
|
|
|
443
455
|
}
|
|
444
456
|
|
|
445
457
|
// src/commands/verify/init/index.ts
|
|
446
|
-
import
|
|
458
|
+
import chalk17 from "chalk";
|
|
447
459
|
|
|
448
460
|
// src/shared/promptMultiselect.ts
|
|
449
461
|
import chalk3 from "chalk";
|
|
@@ -513,28 +525,12 @@ function findPackageJsonWithVerifyScripts(startDir) {
|
|
|
513
525
|
}
|
|
514
526
|
}
|
|
515
527
|
|
|
516
|
-
// src/commands/verify/setup/expectedScripts.ts
|
|
517
|
-
var expectedScripts = {
|
|
518
|
-
"verify:knip": "knip --no-progress --treat-config-hints-as-errors",
|
|
519
|
-
"verify:lint": "biome check --write --error-on-warnings .",
|
|
520
|
-
"verify:duplicate-code": "jscpd --format 'typescript,tsx' --exitCode 1 --ignore '**/*.test.*' -r consoleFull src",
|
|
521
|
-
"verify:test": "vitest run --reporter=dot --silent",
|
|
522
|
-
"verify:hardcoded-colors": "assist verify hardcoded-colors",
|
|
523
|
-
"verify:no-venv": "assist verify no-venv",
|
|
524
|
-
"verify:maintainability": "assist complexity maintainability ./src --threshold 60",
|
|
525
|
-
"verify:madge": "madge --circular --ts-config ./tsconfig.json --extensions ts,tsx src/"
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
// src/commands/verify/setup/setupBuild.ts
|
|
529
|
-
import chalk6 from "chalk";
|
|
530
|
-
|
|
531
528
|
// src/commands/verify/installPackage.ts
|
|
532
529
|
import { execSync as execSync2 } from "child_process";
|
|
533
|
-
import
|
|
534
|
-
import * as path2 from "path";
|
|
530
|
+
import { writeFileSync as writeFileSync2 } from "fs";
|
|
535
531
|
import chalk5 from "chalk";
|
|
536
532
|
function writePackageJson(filePath, pkg) {
|
|
537
|
-
|
|
533
|
+
writeFileSync2(filePath, `${JSON.stringify(pkg, null, 2)}
|
|
538
534
|
`);
|
|
539
535
|
}
|
|
540
536
|
function addScript(pkg, name, command) {
|
|
@@ -556,29 +552,6 @@ function installPackage(name, cwd) {
|
|
|
556
552
|
return false;
|
|
557
553
|
}
|
|
558
554
|
}
|
|
559
|
-
function addToKnipIgnoreBinaries(cwd, binary) {
|
|
560
|
-
const knipJsonPath = path2.join(cwd, "knip.json");
|
|
561
|
-
try {
|
|
562
|
-
let knipConfig;
|
|
563
|
-
if (fs2.existsSync(knipJsonPath)) {
|
|
564
|
-
knipConfig = JSON.parse(fs2.readFileSync(knipJsonPath, "utf-8"));
|
|
565
|
-
} else {
|
|
566
|
-
knipConfig = { $schema: "https://unpkg.com/knip@5/schema.json" };
|
|
567
|
-
}
|
|
568
|
-
const ignoreBinaries = knipConfig.ignoreBinaries ?? [];
|
|
569
|
-
if (!ignoreBinaries.includes(binary)) {
|
|
570
|
-
knipConfig.ignoreBinaries = [...ignoreBinaries, binary];
|
|
571
|
-
fs2.writeFileSync(
|
|
572
|
-
knipJsonPath,
|
|
573
|
-
`${JSON.stringify(knipConfig, null, " ")}
|
|
574
|
-
`
|
|
575
|
-
);
|
|
576
|
-
console.log(chalk5.dim(`Added '${binary}' to knip.json ignoreBinaries`));
|
|
577
|
-
}
|
|
578
|
-
} catch {
|
|
579
|
-
console.log(chalk5.yellow("Warning: Could not update knip.json"));
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
555
|
function setupVerifyScript(packageJsonPath, scriptName, command) {
|
|
583
556
|
writePackageJson(
|
|
584
557
|
packageJsonPath,
|
|
@@ -586,8 +559,43 @@ function setupVerifyScript(packageJsonPath, scriptName, command) {
|
|
|
586
559
|
);
|
|
587
560
|
}
|
|
588
561
|
|
|
562
|
+
// src/commands/verify/setupVerifyRunEntry.ts
|
|
563
|
+
var GLOBAL_COMMANDS = /* @__PURE__ */ new Set(["assist", "npm", "npx", "node"]);
|
|
564
|
+
function buildRunEntry(scriptName, command) {
|
|
565
|
+
const parts = command.split(/\s+/);
|
|
566
|
+
const needsNpx = !GLOBAL_COMMANDS.has(parts[0]);
|
|
567
|
+
const entry = {
|
|
568
|
+
name: scriptName,
|
|
569
|
+
command: needsNpx ? "npx" : parts[0]
|
|
570
|
+
};
|
|
571
|
+
const args = needsNpx ? parts : parts.slice(1);
|
|
572
|
+
if (args.length > 0) entry.args = args;
|
|
573
|
+
return entry;
|
|
574
|
+
}
|
|
575
|
+
function setupVerifyRunEntry(scriptName, command) {
|
|
576
|
+
const config = loadProjectConfig();
|
|
577
|
+
if (!config.run) config.run = [];
|
|
578
|
+
const runList = config.run;
|
|
579
|
+
if (runList.find((r) => r.name === scriptName)) return;
|
|
580
|
+
runList.push(buildRunEntry(scriptName, command));
|
|
581
|
+
saveConfig(config);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// src/commands/verify/setup/expectedScripts.ts
|
|
585
|
+
var expectedScripts = {
|
|
586
|
+
"verify:knip": "knip --no-progress --treat-config-hints-as-errors",
|
|
587
|
+
"verify:lint": "biome check --write --error-on-warnings .",
|
|
588
|
+
"verify:duplicate-code": "jscpd --format 'typescript,tsx' --exitCode 1 --ignore '**/*.test.*' -r consoleFull src",
|
|
589
|
+
"verify:test": "vitest run --reporter=dot --silent",
|
|
590
|
+
"verify:hardcoded-colors": "assist verify hardcoded-colors",
|
|
591
|
+
"verify:no-venv": "assist verify no-venv",
|
|
592
|
+
"verify:maintainability": "assist complexity maintainability ./src --threshold 60",
|
|
593
|
+
"verify:madge": "madge --circular --ts-config ./tsconfig.json --extensions ts,tsx src/"
|
|
594
|
+
};
|
|
595
|
+
|
|
589
596
|
// src/commands/verify/setup/setupBuild.ts
|
|
590
|
-
|
|
597
|
+
import chalk6 from "chalk";
|
|
598
|
+
async function setupBuild(_packageJsonPath, writer, hasVite, hasTypescript) {
|
|
591
599
|
console.log(chalk6.blue("\nSetting up build verification..."));
|
|
592
600
|
let command;
|
|
593
601
|
if (hasVite && hasTypescript) {
|
|
@@ -598,82 +606,96 @@ async function setupBuild(packageJsonPath, hasVite, hasTypescript) {
|
|
|
598
606
|
command = "npm run build";
|
|
599
607
|
}
|
|
600
608
|
console.log(chalk6.dim(`Using: ${command}`));
|
|
601
|
-
|
|
602
|
-
writePackageJson(packageJsonPath, addScript(pkg, "verify:build", command));
|
|
609
|
+
writer("verify:build", command);
|
|
603
610
|
}
|
|
604
|
-
async function setupTypecheck(
|
|
611
|
+
async function setupTypecheck(_packageJsonPath, writer) {
|
|
605
612
|
console.log(chalk6.blue("\nSetting up typecheck verification..."));
|
|
606
613
|
const command = "tsc --noEmit";
|
|
607
614
|
console.log(chalk6.dim(`Using: ${command}`));
|
|
608
|
-
|
|
609
|
-
writePackageJson(
|
|
610
|
-
packageJsonPath,
|
|
611
|
-
addScript(pkg, "verify:typecheck", command)
|
|
612
|
-
);
|
|
615
|
+
writer("verify:typecheck", command);
|
|
613
616
|
}
|
|
614
617
|
|
|
615
618
|
// src/commands/verify/setup/setupDuplicateCode.ts
|
|
616
|
-
import * as
|
|
619
|
+
import * as path2 from "path";
|
|
617
620
|
import chalk7 from "chalk";
|
|
618
|
-
async function setupDuplicateCode(packageJsonPath) {
|
|
621
|
+
async function setupDuplicateCode(packageJsonPath, writer) {
|
|
619
622
|
console.log(chalk7.blue("\nSetting up jscpd..."));
|
|
620
|
-
const cwd =
|
|
623
|
+
const cwd = path2.dirname(packageJsonPath);
|
|
621
624
|
const pkg = readPackageJson(packageJsonPath);
|
|
622
625
|
const hasJscpd = !!pkg.dependencies?.jscpd || !!pkg.devDependencies?.jscpd;
|
|
623
626
|
if (!hasJscpd && !installPackage("jscpd", cwd)) {
|
|
624
627
|
return;
|
|
625
628
|
}
|
|
626
|
-
|
|
627
|
-
packageJsonPath,
|
|
628
|
-
"verify:duplicate-code",
|
|
629
|
-
expectedScripts["verify:duplicate-code"]
|
|
630
|
-
);
|
|
629
|
+
writer("verify:duplicate-code", expectedScripts["verify:duplicate-code"]);
|
|
631
630
|
}
|
|
632
631
|
|
|
633
632
|
// src/commands/verify/setup/setupHardcodedColors.ts
|
|
634
|
-
import * as
|
|
633
|
+
import * as path3 from "path";
|
|
634
|
+
import chalk9 from "chalk";
|
|
635
|
+
|
|
636
|
+
// src/commands/verify/addToKnipIgnoreBinaries.ts
|
|
637
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
638
|
+
import { join as join3 } from "path";
|
|
635
639
|
import chalk8 from "chalk";
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
640
|
+
function loadKnipConfig(knipJsonPath) {
|
|
641
|
+
if (existsSync4(knipJsonPath)) {
|
|
642
|
+
return JSON.parse(readFileSync4(knipJsonPath, "utf-8"));
|
|
643
|
+
}
|
|
644
|
+
return { $schema: "https://unpkg.com/knip@5/schema.json" };
|
|
645
|
+
}
|
|
646
|
+
function addToKnipIgnoreBinaries(cwd, binary) {
|
|
647
|
+
const knipJsonPath = join3(cwd, "knip.json");
|
|
648
|
+
try {
|
|
649
|
+
const knipConfig = loadKnipConfig(knipJsonPath);
|
|
650
|
+
const ignoreBinaries = knipConfig.ignoreBinaries ?? [];
|
|
651
|
+
if (!ignoreBinaries.includes(binary)) {
|
|
652
|
+
knipConfig.ignoreBinaries = [...ignoreBinaries, binary];
|
|
653
|
+
writeFileSync3(
|
|
654
|
+
knipJsonPath,
|
|
655
|
+
`${JSON.stringify(knipConfig, null, " ")}
|
|
656
|
+
`
|
|
657
|
+
);
|
|
658
|
+
console.log(chalk8.dim(`Added '${binary}' to knip.json ignoreBinaries`));
|
|
659
|
+
}
|
|
660
|
+
} catch {
|
|
661
|
+
console.log(chalk8.yellow("Warning: Could not update knip.json"));
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// src/commands/verify/setup/setupHardcodedColors.ts
|
|
666
|
+
async function setupHardcodedColors(packageJsonPath, writer, hasOpenColor) {
|
|
667
|
+
console.log(chalk9.blue("\nSetting up hardcoded colors check..."));
|
|
668
|
+
const cwd = path3.dirname(packageJsonPath);
|
|
639
669
|
if (!hasOpenColor) {
|
|
640
670
|
installPackage("open-color", cwd);
|
|
641
671
|
}
|
|
642
672
|
addToKnipIgnoreBinaries(cwd, "assist");
|
|
643
|
-
|
|
644
|
-
packageJsonPath,
|
|
645
|
-
"verify:hardcoded-colors",
|
|
646
|
-
expectedScripts["verify:hardcoded-colors"]
|
|
647
|
-
);
|
|
673
|
+
writer("verify:hardcoded-colors", expectedScripts["verify:hardcoded-colors"]);
|
|
648
674
|
}
|
|
649
675
|
|
|
650
676
|
// src/commands/verify/setup/setupKnip.ts
|
|
651
|
-
import * as
|
|
652
|
-
import
|
|
653
|
-
async function setupKnip(packageJsonPath) {
|
|
654
|
-
console.log(
|
|
655
|
-
const cwd =
|
|
677
|
+
import * as path4 from "path";
|
|
678
|
+
import chalk10 from "chalk";
|
|
679
|
+
async function setupKnip(packageJsonPath, writer) {
|
|
680
|
+
console.log(chalk10.blue("\nSetting up knip..."));
|
|
681
|
+
const cwd = path4.dirname(packageJsonPath);
|
|
656
682
|
const pkg = readPackageJson(packageJsonPath);
|
|
657
683
|
if (!pkg.devDependencies?.knip && !installPackage("knip", cwd)) {
|
|
658
684
|
return;
|
|
659
685
|
}
|
|
660
|
-
|
|
661
|
-
packageJsonPath,
|
|
662
|
-
"verify:knip",
|
|
663
|
-
expectedScripts["verify:knip"]
|
|
664
|
-
);
|
|
686
|
+
writer("verify:knip", expectedScripts["verify:knip"]);
|
|
665
687
|
}
|
|
666
688
|
|
|
667
689
|
// src/commands/verify/setup/setupLint.ts
|
|
668
|
-
import * as
|
|
669
|
-
import
|
|
690
|
+
import * as path5 from "path";
|
|
691
|
+
import chalk13 from "chalk";
|
|
670
692
|
|
|
671
693
|
// src/commands/lint/init.ts
|
|
672
694
|
import { execSync as execSync4 } from "child_process";
|
|
673
|
-
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as
|
|
695
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
674
696
|
import { dirname as dirname5, join as join4 } from "path";
|
|
675
697
|
import { fileURLToPath } from "url";
|
|
676
|
-
import
|
|
698
|
+
import chalk12 from "chalk";
|
|
677
699
|
|
|
678
700
|
// src/shared/promptConfirm.ts
|
|
679
701
|
import enquirer2 from "enquirer";
|
|
@@ -694,7 +716,7 @@ async function promptConfirm(message, initial = true) {
|
|
|
694
716
|
|
|
695
717
|
// src/shared/removeEslint/index.ts
|
|
696
718
|
import { execSync as execSync3 } from "child_process";
|
|
697
|
-
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as
|
|
719
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
698
720
|
|
|
699
721
|
// src/shared/removeEslint/removeEslintConfigFiles.ts
|
|
700
722
|
import { existsSync as existsSync5, unlinkSync } from "fs";
|
|
@@ -744,7 +766,7 @@ function removeEslintFromPackageJson(options2) {
|
|
|
744
766
|
modified = removeEslintDeps(packageJson.devDependencies) || modified;
|
|
745
767
|
modified = removeEslintScripts(packageJson.scripts, options2) || modified;
|
|
746
768
|
if (modified) {
|
|
747
|
-
|
|
769
|
+
writeFileSync4(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
748
770
|
`);
|
|
749
771
|
console.log("Removed eslint references from package.json");
|
|
750
772
|
}
|
|
@@ -775,7 +797,7 @@ function removeEslintScripts(scripts, options2) {
|
|
|
775
797
|
}
|
|
776
798
|
|
|
777
799
|
// src/utils/printDiff.ts
|
|
778
|
-
import
|
|
800
|
+
import chalk11 from "chalk";
|
|
779
801
|
import * as diff from "diff";
|
|
780
802
|
function normalizeJson(content) {
|
|
781
803
|
try {
|
|
@@ -793,11 +815,11 @@ function printDiff(oldContent, newContent) {
|
|
|
793
815
|
const lines = change.value.replace(/\n$/, "").split("\n");
|
|
794
816
|
for (const line of lines) {
|
|
795
817
|
if (change.added) {
|
|
796
|
-
console.log(
|
|
818
|
+
console.log(chalk11.green(`+ ${line}`));
|
|
797
819
|
} else if (change.removed) {
|
|
798
|
-
console.log(
|
|
820
|
+
console.log(chalk11.red(`- ${line}`));
|
|
799
821
|
} else {
|
|
800
|
-
console.log(
|
|
822
|
+
console.log(chalk11.dim(` ${line}`));
|
|
801
823
|
}
|
|
802
824
|
}
|
|
803
825
|
}
|
|
@@ -831,22 +853,22 @@ async function init() {
|
|
|
831
853
|
console.log("biome.json already has the correct linter config");
|
|
832
854
|
return;
|
|
833
855
|
}
|
|
834
|
-
console.log(
|
|
856
|
+
console.log(chalk12.yellow("\n\u26A0\uFE0F biome.json will be updated:"));
|
|
835
857
|
console.log();
|
|
836
858
|
printDiff(oldContent, newContent);
|
|
837
|
-
const confirm = await promptConfirm(
|
|
859
|
+
const confirm = await promptConfirm(chalk12.red("Update biome.json?"));
|
|
838
860
|
if (!confirm) {
|
|
839
861
|
console.log("Skipped biome.json update");
|
|
840
862
|
return;
|
|
841
863
|
}
|
|
842
|
-
|
|
864
|
+
writeFileSync5(biomeConfigPath, newContent);
|
|
843
865
|
console.log("Updated biome.json with linter config");
|
|
844
866
|
}
|
|
845
867
|
|
|
846
868
|
// src/commands/verify/setup/setupLint.ts
|
|
847
|
-
async function setupLint(packageJsonPath) {
|
|
848
|
-
console.log(
|
|
849
|
-
const cwd =
|
|
869
|
+
async function setupLint(packageJsonPath, writer) {
|
|
870
|
+
console.log(chalk13.blue("\nSetting up biome..."));
|
|
871
|
+
const cwd = path5.dirname(packageJsonPath);
|
|
850
872
|
const pkg = readPackageJson(packageJsonPath);
|
|
851
873
|
if (!pkg.devDependencies?.["@biomejs/biome"]) {
|
|
852
874
|
if (!installPackage("@biomejs/biome", cwd)) {
|
|
@@ -854,59 +876,43 @@ async function setupLint(packageJsonPath) {
|
|
|
854
876
|
}
|
|
855
877
|
}
|
|
856
878
|
await init();
|
|
857
|
-
|
|
858
|
-
packageJsonPath,
|
|
859
|
-
"verify:lint",
|
|
860
|
-
expectedScripts["verify:lint"]
|
|
861
|
-
);
|
|
879
|
+
writer("verify:lint", expectedScripts["verify:lint"]);
|
|
862
880
|
}
|
|
863
881
|
|
|
864
882
|
// src/commands/verify/setup/setupMadge.ts
|
|
865
|
-
import * as
|
|
866
|
-
import
|
|
867
|
-
async function setupMadge(packageJsonPath) {
|
|
868
|
-
console.log(
|
|
869
|
-
const cwd =
|
|
883
|
+
import * as path6 from "path";
|
|
884
|
+
import chalk14 from "chalk";
|
|
885
|
+
async function setupMadge(packageJsonPath, writer) {
|
|
886
|
+
console.log(chalk14.blue("\nSetting up madge..."));
|
|
887
|
+
const cwd = path6.dirname(packageJsonPath);
|
|
870
888
|
const pkg = readPackageJson(packageJsonPath);
|
|
871
889
|
const hasMadge = !!pkg.dependencies?.madge || !!pkg.devDependencies?.madge;
|
|
872
890
|
if (!hasMadge && !installPackage("madge", cwd)) {
|
|
873
891
|
return;
|
|
874
892
|
}
|
|
875
|
-
|
|
876
|
-
packageJsonPath,
|
|
877
|
-
"verify:madge",
|
|
878
|
-
expectedScripts["verify:madge"]
|
|
879
|
-
);
|
|
893
|
+
writer("verify:madge", expectedScripts["verify:madge"]);
|
|
880
894
|
}
|
|
881
895
|
|
|
882
896
|
// src/commands/verify/setup/setupMaintainability.ts
|
|
883
|
-
import * as
|
|
884
|
-
import
|
|
885
|
-
async function setupMaintainability(packageJsonPath) {
|
|
886
|
-
console.log(
|
|
887
|
-
addToKnipIgnoreBinaries(
|
|
888
|
-
|
|
889
|
-
packageJsonPath,
|
|
890
|
-
"verify:maintainability",
|
|
891
|
-
expectedScripts["verify:maintainability"]
|
|
892
|
-
);
|
|
897
|
+
import * as path7 from "path";
|
|
898
|
+
import chalk15 from "chalk";
|
|
899
|
+
async function setupMaintainability(packageJsonPath, writer) {
|
|
900
|
+
console.log(chalk15.blue("\nSetting up maintainability check..."));
|
|
901
|
+
addToKnipIgnoreBinaries(path7.dirname(packageJsonPath), "assist");
|
|
902
|
+
writer("verify:maintainability", expectedScripts["verify:maintainability"]);
|
|
893
903
|
}
|
|
894
904
|
|
|
895
905
|
// src/commands/verify/setup/setupTest.ts
|
|
896
|
-
import * as
|
|
897
|
-
import
|
|
898
|
-
async function setupTest(packageJsonPath) {
|
|
899
|
-
console.log(
|
|
900
|
-
const cwd =
|
|
906
|
+
import * as path8 from "path";
|
|
907
|
+
import chalk16 from "chalk";
|
|
908
|
+
async function setupTest(packageJsonPath, writer) {
|
|
909
|
+
console.log(chalk16.blue("\nSetting up vitest..."));
|
|
910
|
+
const cwd = path8.dirname(packageJsonPath);
|
|
901
911
|
const pkg = readPackageJson(packageJsonPath);
|
|
902
912
|
if (!pkg.devDependencies?.vitest && !installPackage("vitest", cwd)) {
|
|
903
913
|
return;
|
|
904
914
|
}
|
|
905
|
-
|
|
906
|
-
packageJsonPath,
|
|
907
|
-
"verify:test",
|
|
908
|
-
expectedScripts["verify:test"]
|
|
909
|
-
);
|
|
915
|
+
writer("verify:test", expectedScripts["verify:test"]);
|
|
910
916
|
}
|
|
911
917
|
|
|
912
918
|
// src/commands/verify/init/detectExistingSetup/needsSetup.ts
|
|
@@ -924,30 +930,44 @@ function getStatusLabel(status2) {
|
|
|
924
930
|
function hasDep(pkg, name) {
|
|
925
931
|
return !!pkg.dependencies?.[name] || !!pkg.devDependencies?.[name];
|
|
926
932
|
}
|
|
927
|
-
function toolStatus(pkg, scriptName, hasPackage) {
|
|
933
|
+
function toolStatus(pkg, scriptName, hasPackage, configScriptNames) {
|
|
928
934
|
const currentScript = pkg.scripts?.[scriptName];
|
|
935
|
+
const hasConfigEntry = configScriptNames.has(scriptName) || [...configScriptNames].some((n) => n.startsWith(`${scriptName}-`));
|
|
929
936
|
const expectedCommand = expectedScripts[scriptName];
|
|
930
937
|
return {
|
|
931
938
|
hasPackage,
|
|
932
|
-
hasScript: !!currentScript,
|
|
939
|
+
hasScript: !!currentScript || hasConfigEntry,
|
|
933
940
|
isOutdated: !!currentScript && !!expectedCommand && currentScript !== expectedCommand
|
|
934
941
|
};
|
|
935
942
|
}
|
|
936
|
-
function
|
|
937
|
-
const
|
|
943
|
+
function loadConfigScriptNames() {
|
|
944
|
+
const config = loadConfig();
|
|
945
|
+
return new Set((config.run ?? []).map((r) => r.name));
|
|
946
|
+
}
|
|
947
|
+
function buildToolStatuses(pkg, configScriptNames) {
|
|
948
|
+
const status2 = (script, has) => toolStatus(pkg, script, has, configScriptNames);
|
|
938
949
|
return {
|
|
939
950
|
knip: status2("verify:knip", hasDep(pkg, "knip")),
|
|
940
951
|
biome: status2("verify:lint", hasDep(pkg, "@biomejs/biome")),
|
|
941
952
|
jscpd: status2("verify:duplicate-code", hasDep(pkg, "jscpd")),
|
|
942
953
|
test: status2("verify:test", hasDep(pkg, "vitest")),
|
|
943
|
-
hasVite: hasDep(pkg, "vite"),
|
|
944
|
-
hasTypescript: !!pkg.devDependencies?.typescript,
|
|
945
954
|
build: status2("verify:build", true),
|
|
946
955
|
typecheck: status2("verify:typecheck", true),
|
|
947
956
|
hardcodedColors: status2("verify:hardcoded-colors", true),
|
|
948
957
|
madge: status2("verify:madge", hasDep(pkg, "madge")),
|
|
949
|
-
maintainability: status2("verify:maintainability", true)
|
|
950
|
-
|
|
958
|
+
maintainability: status2("verify:maintainability", true)
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
function detectExistingSetup(pkg) {
|
|
962
|
+
const configScriptNames = loadConfigScriptNames();
|
|
963
|
+
return {
|
|
964
|
+
...buildToolStatuses(pkg, configScriptNames),
|
|
965
|
+
hasVite: hasDep(pkg, "vite"),
|
|
966
|
+
hasTypescript: !!pkg.devDependencies?.typescript,
|
|
967
|
+
hasOpenColor: hasDep(pkg, "open-color"),
|
|
968
|
+
hasConfigScripts: [...configScriptNames].some(
|
|
969
|
+
(n) => n.startsWith("verify:")
|
|
970
|
+
)
|
|
951
971
|
};
|
|
952
972
|
}
|
|
953
973
|
|
|
@@ -1035,43 +1055,45 @@ function getAvailableOptions(setup2) {
|
|
|
1035
1055
|
).map((def) => toVerifyOption(def, setup2));
|
|
1036
1056
|
}
|
|
1037
1057
|
|
|
1038
|
-
// src/commands/verify/init/
|
|
1058
|
+
// src/commands/verify/init/getSetupHandlers.ts
|
|
1039
1059
|
function getSetupHandlers(hasVite, hasTypescript, hasOpenColor) {
|
|
1040
1060
|
return {
|
|
1041
|
-
knip: (p) => setupKnip(p),
|
|
1042
|
-
lint: (p) => setupLint(p),
|
|
1043
|
-
"duplicate-code": (p) => setupDuplicateCode(p),
|
|
1044
|
-
test: (p) => setupTest(p),
|
|
1045
|
-
build: (p) => setupBuild(p, hasVite, hasTypescript),
|
|
1046
|
-
typecheck: (p) => setupTypecheck(p),
|
|
1047
|
-
"hardcoded-colors": (p) => setupHardcodedColors(p, hasOpenColor),
|
|
1048
|
-
madge: (p) => setupMadge(p),
|
|
1049
|
-
maintainability: (p) => setupMaintainability(p)
|
|
1061
|
+
knip: (p, w) => setupKnip(p, w),
|
|
1062
|
+
lint: (p, w) => setupLint(p, w),
|
|
1063
|
+
"duplicate-code": (p, w) => setupDuplicateCode(p, w),
|
|
1064
|
+
test: (p, w) => setupTest(p, w),
|
|
1065
|
+
build: (p, w) => setupBuild(p, w, hasVite, hasTypescript),
|
|
1066
|
+
typecheck: (p, w) => setupTypecheck(p, w),
|
|
1067
|
+
"hardcoded-colors": (p, w) => setupHardcodedColors(p, w, hasOpenColor),
|
|
1068
|
+
madge: (p, w) => setupMadge(p, w),
|
|
1069
|
+
maintainability: (p, w) => setupMaintainability(p, w)
|
|
1050
1070
|
};
|
|
1051
1071
|
}
|
|
1052
|
-
|
|
1072
|
+
|
|
1073
|
+
// src/commands/verify/init/index.ts
|
|
1074
|
+
async function runSelectedSetups(selected, packageJsonPath, writer, handlers) {
|
|
1053
1075
|
for (const choice of selected) {
|
|
1054
|
-
await handlers[choice]?.(packageJsonPath);
|
|
1076
|
+
await handlers[choice]?.(packageJsonPath, writer);
|
|
1055
1077
|
}
|
|
1056
|
-
console.log(
|
|
1078
|
+
console.log(chalk17.green(`
|
|
1057
1079
|
Added ${selected.length} verify script(s):`));
|
|
1058
1080
|
for (const choice of selected) {
|
|
1059
|
-
console.log(
|
|
1081
|
+
console.log(chalk17.green(` - verify:${choice}`));
|
|
1060
1082
|
}
|
|
1061
|
-
console.log(
|
|
1083
|
+
console.log(chalk17.dim("\nRun 'assist verify' to run all verify scripts"));
|
|
1062
1084
|
}
|
|
1063
1085
|
async function promptForScripts(availableOptions) {
|
|
1064
1086
|
if (availableOptions.length === 0) {
|
|
1065
|
-
console.log(
|
|
1087
|
+
console.log(chalk17.green("All verify scripts are already configured!"));
|
|
1066
1088
|
return null;
|
|
1067
1089
|
}
|
|
1068
|
-
console.log(
|
|
1090
|
+
console.log(chalk17.bold("Available verify scripts to add:\n"));
|
|
1069
1091
|
const selected = await promptMultiselect(
|
|
1070
1092
|
"Select verify scripts to add:",
|
|
1071
1093
|
availableOptions
|
|
1072
1094
|
);
|
|
1073
1095
|
if (selected.length === 0) {
|
|
1074
|
-
console.log(
|
|
1096
|
+
console.log(chalk17.yellow("No scripts selected"));
|
|
1075
1097
|
return null;
|
|
1076
1098
|
}
|
|
1077
1099
|
return selected;
|
|
@@ -1081,41 +1103,42 @@ async function init2() {
|
|
|
1081
1103
|
const setup2 = detectExistingSetup(pkg);
|
|
1082
1104
|
const selected = await promptForScripts(getAvailableOptions(setup2));
|
|
1083
1105
|
if (!selected) return;
|
|
1106
|
+
const writer = setup2.hasConfigScripts ? setupVerifyRunEntry : (name, cmd) => setupVerifyScript(packageJsonPath, name, cmd);
|
|
1084
1107
|
const handlers = getSetupHandlers(
|
|
1085
1108
|
setup2.hasVite,
|
|
1086
1109
|
setup2.hasTypescript,
|
|
1087
1110
|
setup2.hasOpenColor
|
|
1088
1111
|
);
|
|
1089
|
-
await runSelectedSetups(selected, packageJsonPath, handlers);
|
|
1112
|
+
await runSelectedSetups(selected, packageJsonPath, writer, handlers);
|
|
1090
1113
|
}
|
|
1091
1114
|
|
|
1092
1115
|
// src/commands/vscode/init/index.ts
|
|
1093
|
-
import
|
|
1116
|
+
import chalk19 from "chalk";
|
|
1094
1117
|
|
|
1095
1118
|
// src/commands/vscode/init/createLaunchJson.ts
|
|
1096
|
-
import * as
|
|
1097
|
-
import * as
|
|
1098
|
-
import
|
|
1119
|
+
import * as fs2 from "fs";
|
|
1120
|
+
import * as path9 from "path";
|
|
1121
|
+
import chalk18 from "chalk";
|
|
1099
1122
|
function ensureVscodeFolder() {
|
|
1100
|
-
const vscodeDir =
|
|
1101
|
-
if (!
|
|
1102
|
-
|
|
1103
|
-
console.log(
|
|
1123
|
+
const vscodeDir = path9.join(process.cwd(), ".vscode");
|
|
1124
|
+
if (!fs2.existsSync(vscodeDir)) {
|
|
1125
|
+
fs2.mkdirSync(vscodeDir);
|
|
1126
|
+
console.log(chalk18.dim("Created .vscode folder"));
|
|
1104
1127
|
}
|
|
1105
1128
|
}
|
|
1106
1129
|
function removeVscodeFromGitignore() {
|
|
1107
|
-
const gitignorePath =
|
|
1108
|
-
if (!
|
|
1130
|
+
const gitignorePath = path9.join(process.cwd(), ".gitignore");
|
|
1131
|
+
if (!fs2.existsSync(gitignorePath)) {
|
|
1109
1132
|
return;
|
|
1110
1133
|
}
|
|
1111
|
-
const content =
|
|
1134
|
+
const content = fs2.readFileSync(gitignorePath, "utf-8");
|
|
1112
1135
|
const lines = content.split("\n");
|
|
1113
1136
|
const filteredLines = lines.filter(
|
|
1114
1137
|
(line) => !line.trim().toLowerCase().includes(".vscode")
|
|
1115
1138
|
);
|
|
1116
1139
|
if (filteredLines.length !== lines.length) {
|
|
1117
|
-
|
|
1118
|
-
console.log(
|
|
1140
|
+
fs2.writeFileSync(gitignorePath, filteredLines.join("\n"));
|
|
1141
|
+
console.log(chalk18.dim("Removed .vscode references from .gitignore"));
|
|
1119
1142
|
}
|
|
1120
1143
|
}
|
|
1121
1144
|
function createLaunchJson(type) {
|
|
@@ -1131,10 +1154,10 @@ function createLaunchJson(type) {
|
|
|
1131
1154
|
}
|
|
1132
1155
|
]
|
|
1133
1156
|
};
|
|
1134
|
-
const launchPath =
|
|
1135
|
-
|
|
1157
|
+
const launchPath = path9.join(process.cwd(), ".vscode", "launch.json");
|
|
1158
|
+
fs2.writeFileSync(launchPath, `${JSON.stringify(launchConfig, null, " ")}
|
|
1136
1159
|
`);
|
|
1137
|
-
console.log(
|
|
1160
|
+
console.log(chalk18.green("Created .vscode/launch.json"));
|
|
1138
1161
|
}
|
|
1139
1162
|
function createSettingsJson() {
|
|
1140
1163
|
const settings = {
|
|
@@ -1144,33 +1167,33 @@ function createSettingsJson() {
|
|
|
1144
1167
|
"source.organizeImports.biome": "explicit"
|
|
1145
1168
|
}
|
|
1146
1169
|
};
|
|
1147
|
-
const settingsPath =
|
|
1148
|
-
|
|
1170
|
+
const settingsPath = path9.join(process.cwd(), ".vscode", "settings.json");
|
|
1171
|
+
fs2.writeFileSync(settingsPath, `${JSON.stringify(settings, null, " ")}
|
|
1149
1172
|
`);
|
|
1150
|
-
console.log(
|
|
1173
|
+
console.log(chalk18.green("Created .vscode/settings.json"));
|
|
1151
1174
|
}
|
|
1152
1175
|
function createExtensionsJson() {
|
|
1153
1176
|
const extensions = {
|
|
1154
1177
|
recommendations: ["biomejs.biome"]
|
|
1155
1178
|
};
|
|
1156
|
-
const extensionsPath =
|
|
1157
|
-
|
|
1179
|
+
const extensionsPath = path9.join(process.cwd(), ".vscode", "extensions.json");
|
|
1180
|
+
fs2.writeFileSync(
|
|
1158
1181
|
extensionsPath,
|
|
1159
1182
|
`${JSON.stringify(extensions, null, " ")}
|
|
1160
1183
|
`
|
|
1161
1184
|
);
|
|
1162
|
-
console.log(
|
|
1185
|
+
console.log(chalk18.green("Created .vscode/extensions.json"));
|
|
1163
1186
|
}
|
|
1164
1187
|
|
|
1165
1188
|
// src/commands/vscode/init/detectVscodeSetup.ts
|
|
1166
|
-
import * as
|
|
1167
|
-
import * as
|
|
1189
|
+
import * as fs3 from "fs";
|
|
1190
|
+
import * as path10 from "path";
|
|
1168
1191
|
function detectVscodeSetup(pkg) {
|
|
1169
|
-
const vscodeDir =
|
|
1192
|
+
const vscodeDir = path10.join(process.cwd(), ".vscode");
|
|
1170
1193
|
return {
|
|
1171
|
-
hasVscodeFolder:
|
|
1172
|
-
hasLaunchJson:
|
|
1173
|
-
hasSettingsJson:
|
|
1194
|
+
hasVscodeFolder: fs3.existsSync(vscodeDir),
|
|
1195
|
+
hasLaunchJson: fs3.existsSync(path10.join(vscodeDir, "launch.json")),
|
|
1196
|
+
hasSettingsJson: fs3.existsSync(path10.join(vscodeDir, "settings.json")),
|
|
1174
1197
|
hasVite: !!pkg.devDependencies?.vite || !!pkg.dependencies?.vite,
|
|
1175
1198
|
hasTsup: !!pkg.devDependencies?.tsup || !!pkg.dependencies?.tsup
|
|
1176
1199
|
};
|
|
@@ -1216,7 +1239,7 @@ function applySelections(selected, setup2) {
|
|
|
1216
1239
|
for (const choice of selected) handlers[choice]?.();
|
|
1217
1240
|
}
|
|
1218
1241
|
async function promptForOptions(options2) {
|
|
1219
|
-
console.log(
|
|
1242
|
+
console.log(chalk19.bold("Available VS Code configurations to add:\n"));
|
|
1220
1243
|
return promptMultiselect("Select configurations to add:", options2);
|
|
1221
1244
|
}
|
|
1222
1245
|
async function init3({ all = false } = {}) {
|
|
@@ -1224,17 +1247,17 @@ async function init3({ all = false } = {}) {
|
|
|
1224
1247
|
const setup2 = detectVscodeSetup(pkg);
|
|
1225
1248
|
const options2 = getAvailableOptions2(setup2);
|
|
1226
1249
|
if (options2.length === 0) {
|
|
1227
|
-
console.log(
|
|
1250
|
+
console.log(chalk19.green("VS Code configuration already exists!"));
|
|
1228
1251
|
return;
|
|
1229
1252
|
}
|
|
1230
1253
|
const selected = all ? options2.map((o) => o.value) : await promptForOptions(options2);
|
|
1231
1254
|
if (selected.length === 0) {
|
|
1232
|
-
console.log(
|
|
1255
|
+
console.log(chalk19.yellow("No configurations selected"));
|
|
1233
1256
|
return;
|
|
1234
1257
|
}
|
|
1235
1258
|
applySelections(selected, setup2);
|
|
1236
1259
|
console.log(
|
|
1237
|
-
|
|
1260
|
+
chalk19.green(`
|
|
1238
1261
|
Added ${selected.length} VS Code configuration(s)`)
|
|
1239
1262
|
);
|
|
1240
1263
|
}
|
|
@@ -1246,26 +1269,26 @@ async function init4() {
|
|
|
1246
1269
|
}
|
|
1247
1270
|
|
|
1248
1271
|
// src/commands/lint/lint/runFileNameCheck.ts
|
|
1249
|
-
import
|
|
1250
|
-
import
|
|
1272
|
+
import path16 from "path";
|
|
1273
|
+
import chalk21 from "chalk";
|
|
1251
1274
|
|
|
1252
1275
|
// src/commands/lint/lint/checkFileNames.ts
|
|
1253
|
-
import fs6 from "fs";
|
|
1254
|
-
import path13 from "path";
|
|
1255
|
-
|
|
1256
|
-
// src/shared/findSourceFiles.ts
|
|
1257
1276
|
import fs5 from "fs";
|
|
1258
1277
|
import path12 from "path";
|
|
1278
|
+
|
|
1279
|
+
// src/shared/findSourceFiles.ts
|
|
1280
|
+
import fs4 from "fs";
|
|
1281
|
+
import path11 from "path";
|
|
1259
1282
|
var EXTENSIONS = [".ts", ".tsx"];
|
|
1260
1283
|
function findSourceFiles(dir, options2 = {}) {
|
|
1261
1284
|
const { includeTests = true } = options2;
|
|
1262
1285
|
const results = [];
|
|
1263
|
-
if (!
|
|
1286
|
+
if (!fs4.existsSync(dir)) {
|
|
1264
1287
|
return results;
|
|
1265
1288
|
}
|
|
1266
|
-
const entries =
|
|
1289
|
+
const entries = fs4.readdirSync(dir, { withFileTypes: true });
|
|
1267
1290
|
for (const entry of entries) {
|
|
1268
|
-
const fullPath =
|
|
1291
|
+
const fullPath = path11.join(dir, entry.name);
|
|
1269
1292
|
if (entry.isDirectory() && entry.name !== "node_modules") {
|
|
1270
1293
|
results.push(...findSourceFiles(fullPath, options2));
|
|
1271
1294
|
} else if (entry.isFile() && EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
|
|
@@ -1309,11 +1332,11 @@ function checkFileNames() {
|
|
|
1309
1332
|
const sourceFiles = findSourceFiles("src");
|
|
1310
1333
|
const violations = [];
|
|
1311
1334
|
for (const filePath of sourceFiles) {
|
|
1312
|
-
const fileName =
|
|
1335
|
+
const fileName = path12.basename(filePath);
|
|
1313
1336
|
const nameWithoutExt = fileName.replace(/\.(ts|tsx)$/, "");
|
|
1314
1337
|
if (/\.(stories|test)\.(ts|tsx)$/.test(fileName)) continue;
|
|
1315
1338
|
if (/^[A-Z]/.test(nameWithoutExt)) {
|
|
1316
|
-
const content =
|
|
1339
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
1317
1340
|
if (!hasClassOrComponent(content) && !hasMatchingTypeExport(content, nameWithoutExt)) {
|
|
1318
1341
|
violations.push({
|
|
1319
1342
|
filePath,
|
|
@@ -1327,17 +1350,17 @@ function checkFileNames() {
|
|
|
1327
1350
|
}
|
|
1328
1351
|
|
|
1329
1352
|
// src/commands/lint/lint/fixFileNameViolations.ts
|
|
1330
|
-
import
|
|
1353
|
+
import chalk20 from "chalk";
|
|
1331
1354
|
|
|
1332
1355
|
// src/commands/lint/lint/applyMoves.ts
|
|
1333
|
-
import
|
|
1334
|
-
import
|
|
1356
|
+
import fs6 from "fs";
|
|
1357
|
+
import path14 from "path";
|
|
1335
1358
|
|
|
1336
1359
|
// src/commands/lint/lint/renameExports.ts
|
|
1337
|
-
import
|
|
1360
|
+
import path13 from "path";
|
|
1338
1361
|
import { SyntaxKind } from "ts-morph";
|
|
1339
1362
|
function nameWithoutExtension(filePath) {
|
|
1340
|
-
return
|
|
1363
|
+
return path13.basename(filePath).replace(/\.(ts|tsx)$/, "");
|
|
1341
1364
|
}
|
|
1342
1365
|
function renameExports(project, absSource, absDest) {
|
|
1343
1366
|
const oldName = nameWithoutExtension(absSource);
|
|
@@ -1366,40 +1389,40 @@ function isCaseOnly(a, b) {
|
|
|
1366
1389
|
}
|
|
1367
1390
|
function moveCaseInsensitive(absSource, absDest) {
|
|
1368
1391
|
const tmp = `${absSource}.tmp`;
|
|
1369
|
-
|
|
1370
|
-
|
|
1392
|
+
fs6.renameSync(absSource, tmp);
|
|
1393
|
+
fs6.renameSync(tmp, absDest);
|
|
1371
1394
|
}
|
|
1372
1395
|
function applyMoves(project, moves, cwd, emit) {
|
|
1373
1396
|
for (const { sourcePath, destPath } of moves) {
|
|
1374
1397
|
const start3 = performance.now();
|
|
1375
|
-
const absSource =
|
|
1376
|
-
const absDest =
|
|
1398
|
+
const absSource = path14.resolve(sourcePath);
|
|
1399
|
+
const absDest = path14.resolve(destPath);
|
|
1377
1400
|
for (const r of renameExports(project, absSource, absDest)) {
|
|
1378
1401
|
emit(` Renamed export ${r} in ${sourcePath}`);
|
|
1379
1402
|
}
|
|
1380
1403
|
const sourceFile = project.getSourceFile(absSource);
|
|
1381
1404
|
if (sourceFile) sourceFile.move(absDest);
|
|
1382
1405
|
const ms = (performance.now() - start3).toFixed(0);
|
|
1383
|
-
const rel = `${
|
|
1406
|
+
const rel = `${path14.relative(cwd, absSource)} \u2192 ${path14.relative(cwd, absDest)}`;
|
|
1384
1407
|
emit(` Renamed ${rel} (${ms}ms)`);
|
|
1385
1408
|
}
|
|
1386
1409
|
project.saveSync();
|
|
1387
1410
|
for (const { sourcePath, destPath } of moves) {
|
|
1388
|
-
const absSource =
|
|
1389
|
-
const absDest =
|
|
1390
|
-
if (isCaseOnly(absSource, absDest) &&
|
|
1411
|
+
const absSource = path14.resolve(sourcePath);
|
|
1412
|
+
const absDest = path14.resolve(destPath);
|
|
1413
|
+
if (isCaseOnly(absSource, absDest) && fs6.existsSync(absSource)) {
|
|
1391
1414
|
moveCaseInsensitive(absSource, absDest);
|
|
1392
1415
|
}
|
|
1393
1416
|
}
|
|
1394
1417
|
}
|
|
1395
1418
|
|
|
1396
1419
|
// src/commands/lint/lint/createLintProject.ts
|
|
1397
|
-
import
|
|
1398
|
-
import
|
|
1420
|
+
import fs7 from "fs";
|
|
1421
|
+
import path15 from "path";
|
|
1399
1422
|
import { Project } from "ts-morph";
|
|
1400
1423
|
function createLintProject() {
|
|
1401
|
-
const tsConfigPath =
|
|
1402
|
-
const project =
|
|
1424
|
+
const tsConfigPath = path15.resolve("tsconfig.json");
|
|
1425
|
+
const project = fs7.existsSync(tsConfigPath) ? new Project({
|
|
1403
1426
|
tsConfigFilePath: tsConfigPath,
|
|
1404
1427
|
skipAddingFilesFromTsConfig: true
|
|
1405
1428
|
}) : new Project();
|
|
@@ -1412,25 +1435,25 @@ function fixFileNameViolations(moves) {
|
|
|
1412
1435
|
const start3 = performance.now();
|
|
1413
1436
|
const project = createLintProject();
|
|
1414
1437
|
const cwd = process.cwd();
|
|
1415
|
-
applyMoves(project, moves, cwd, (line) => console.log(
|
|
1438
|
+
applyMoves(project, moves, cwd, (line) => console.log(chalk20.green(line)));
|
|
1416
1439
|
const ms = (performance.now() - start3).toFixed(0);
|
|
1417
|
-
console.log(
|
|
1440
|
+
console.log(chalk20.dim(` Done in ${ms}ms`));
|
|
1418
1441
|
}
|
|
1419
1442
|
|
|
1420
1443
|
// src/commands/lint/lint/runFileNameCheck.ts
|
|
1421
1444
|
function reportViolations(violations) {
|
|
1422
|
-
console.error(
|
|
1445
|
+
console.error(chalk21.red("\nFile name check failed:\n"));
|
|
1423
1446
|
console.error(
|
|
1424
|
-
|
|
1447
|
+
chalk21.red(
|
|
1425
1448
|
" Files without classes or React components should not start with a capital letter.\n"
|
|
1426
1449
|
)
|
|
1427
1450
|
);
|
|
1428
1451
|
for (const violation of violations) {
|
|
1429
|
-
console.error(
|
|
1430
|
-
console.error(
|
|
1452
|
+
console.error(chalk21.red(` ${violation.filePath}`));
|
|
1453
|
+
console.error(chalk21.gray(` Rename to: ${violation.suggestedName}
|
|
1431
1454
|
`));
|
|
1432
1455
|
}
|
|
1433
|
-
console.error(
|
|
1456
|
+
console.error(chalk21.dim(" Run with -f to auto-fix.\n"));
|
|
1434
1457
|
}
|
|
1435
1458
|
function runFileNameCheck(fix = false) {
|
|
1436
1459
|
const violations = checkFileNames();
|
|
@@ -1449,27 +1472,27 @@ function runFileNameCheck(fix = false) {
|
|
|
1449
1472
|
fixFileNameViolations(
|
|
1450
1473
|
violations.map((v) => ({
|
|
1451
1474
|
sourcePath: v.filePath,
|
|
1452
|
-
destPath:
|
|
1475
|
+
destPath: path16.join(path16.dirname(v.filePath), v.suggestedName)
|
|
1453
1476
|
}))
|
|
1454
1477
|
);
|
|
1455
1478
|
return true;
|
|
1456
1479
|
}
|
|
1457
1480
|
|
|
1458
1481
|
// src/commands/lint/lint/runImportExtensionCheck.ts
|
|
1459
|
-
import
|
|
1482
|
+
import fs8 from "fs";
|
|
1460
1483
|
|
|
1461
1484
|
// src/commands/lint/shared.ts
|
|
1462
|
-
import
|
|
1485
|
+
import chalk22 from "chalk";
|
|
1463
1486
|
function reportViolations2(violations, checkName, errorMessage, successMessage) {
|
|
1464
1487
|
if (violations.length > 0) {
|
|
1465
|
-
console.error(
|
|
1488
|
+
console.error(chalk22.red(`
|
|
1466
1489
|
${checkName} failed:
|
|
1467
1490
|
`));
|
|
1468
|
-
console.error(
|
|
1491
|
+
console.error(chalk22.red(` ${errorMessage}
|
|
1469
1492
|
`));
|
|
1470
1493
|
for (const violation of violations) {
|
|
1471
|
-
console.error(
|
|
1472
|
-
console.error(
|
|
1494
|
+
console.error(chalk22.red(` ${violation.filePath}:${violation.line}`));
|
|
1495
|
+
console.error(chalk22.gray(` ${violation.content}
|
|
1473
1496
|
`));
|
|
1474
1497
|
}
|
|
1475
1498
|
return false;
|
|
@@ -1482,7 +1505,7 @@ ${checkName} failed:
|
|
|
1482
1505
|
|
|
1483
1506
|
// src/commands/lint/lint/runImportExtensionCheck.ts
|
|
1484
1507
|
function checkForImportExtensions(filePath) {
|
|
1485
|
-
const content =
|
|
1508
|
+
const content = fs8.readFileSync(filePath, "utf-8");
|
|
1486
1509
|
const lines = content.split("\n");
|
|
1487
1510
|
const violations = [];
|
|
1488
1511
|
const importExtensionPattern = /from\s+["']\..*\.(js|ts)["']/;
|
|
@@ -1516,9 +1539,9 @@ function runImportExtensionCheck() {
|
|
|
1516
1539
|
}
|
|
1517
1540
|
|
|
1518
1541
|
// src/commands/lint/lint/runStaticImportCheck.ts
|
|
1519
|
-
import
|
|
1542
|
+
import fs9 from "fs";
|
|
1520
1543
|
function checkForDynamicImports(filePath) {
|
|
1521
|
-
const content =
|
|
1544
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
1522
1545
|
const lines = content.split("\n");
|
|
1523
1546
|
const violations = [];
|
|
1524
1547
|
const requirePattern = /\brequire\s*\(/;
|
|
@@ -1611,7 +1634,7 @@ Total: ${lines.length} hardcoded color(s)`);
|
|
|
1611
1634
|
}
|
|
1612
1635
|
|
|
1613
1636
|
// src/commands/verify/run/resolveEntries.ts
|
|
1614
|
-
import * as
|
|
1637
|
+
import * as path17 from "path";
|
|
1615
1638
|
function buildFullCommand(command, args) {
|
|
1616
1639
|
return [shellQuote(command), ...(args ?? []).map(shellQuote)].join(" ");
|
|
1617
1640
|
}
|
|
@@ -1628,7 +1651,7 @@ function getRunEntries() {
|
|
|
1628
1651
|
function getPackageJsonEntries() {
|
|
1629
1652
|
const result = findPackageJsonWithVerifyScripts(process.cwd());
|
|
1630
1653
|
if (!result) return [];
|
|
1631
|
-
const cwd =
|
|
1654
|
+
const cwd = path17.dirname(result.packageJsonPath);
|
|
1632
1655
|
return result.verifyScripts.map((script) => ({
|
|
1633
1656
|
name: script,
|
|
1634
1657
|
fullCommand: `npm run ${script}`,
|
|
@@ -1852,11 +1875,11 @@ async function run(options2 = {}) {
|
|
|
1852
1875
|
|
|
1853
1876
|
// src/commands/new/registerNew/initGit.ts
|
|
1854
1877
|
import { execSync as execSync8 } from "child_process";
|
|
1855
|
-
import { writeFileSync as
|
|
1878
|
+
import { writeFileSync as writeFileSync7 } from "fs";
|
|
1856
1879
|
function initGit() {
|
|
1857
1880
|
console.log("Initializing git repository...");
|
|
1858
1881
|
execSync8("git init", { stdio: "inherit" });
|
|
1859
|
-
|
|
1882
|
+
writeFileSync7(".gitignore", "dist\nnode_modules\n");
|
|
1860
1883
|
}
|
|
1861
1884
|
|
|
1862
1885
|
// src/commands/new/registerNew/newCli/initPackageJson.ts
|
|
@@ -1875,10 +1898,10 @@ function initPackageJson(name) {
|
|
|
1875
1898
|
}
|
|
1876
1899
|
|
|
1877
1900
|
// src/commands/new/registerNew/newCli/writeCliTemplate.ts
|
|
1878
|
-
import { mkdirSync as mkdirSync2, writeFileSync as
|
|
1901
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
1879
1902
|
function writeCliTemplate(name) {
|
|
1880
1903
|
console.log("Writing tsconfig.json...");
|
|
1881
|
-
|
|
1904
|
+
writeFileSync8(
|
|
1882
1905
|
"tsconfig.json",
|
|
1883
1906
|
JSON.stringify(
|
|
1884
1907
|
{
|
|
@@ -1902,7 +1925,7 @@ function writeCliTemplate(name) {
|
|
|
1902
1925
|
)
|
|
1903
1926
|
);
|
|
1904
1927
|
console.log("Writing tsup.config.ts...");
|
|
1905
|
-
|
|
1928
|
+
writeFileSync8(
|
|
1906
1929
|
"tsup.config.ts",
|
|
1907
1930
|
`import { defineConfig } from "tsup";
|
|
1908
1931
|
export default defineConfig({
|
|
@@ -1917,7 +1940,7 @@ export default defineConfig({
|
|
|
1917
1940
|
);
|
|
1918
1941
|
console.log("Writing src/index.ts...");
|
|
1919
1942
|
mkdirSync2("src", { recursive: true });
|
|
1920
|
-
|
|
1943
|
+
writeFileSync8(
|
|
1921
1944
|
"src/index.ts",
|
|
1922
1945
|
`#!/usr/bin/env node
|
|
1923
1946
|
import { Command } from "commander";
|
|
@@ -1945,18 +1968,18 @@ async function newCli() {
|
|
|
1945
1968
|
|
|
1946
1969
|
// src/commands/new/registerNew/newProject.ts
|
|
1947
1970
|
import { execSync as execSync12 } from "child_process";
|
|
1948
|
-
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as
|
|
1971
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
1949
1972
|
|
|
1950
1973
|
// src/commands/deploy/init/index.ts
|
|
1951
1974
|
import { execSync as execSync11 } from "child_process";
|
|
1952
|
-
import
|
|
1975
|
+
import chalk24 from "chalk";
|
|
1953
1976
|
import enquirer3 from "enquirer";
|
|
1954
1977
|
|
|
1955
1978
|
// src/commands/deploy/init/updateWorkflow.ts
|
|
1956
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as
|
|
1979
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
1957
1980
|
import { dirname as dirname11, join as join7 } from "path";
|
|
1958
1981
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1959
|
-
import
|
|
1982
|
+
import chalk23 from "chalk";
|
|
1960
1983
|
var WORKFLOW_PATH = ".github/workflows/build.yml";
|
|
1961
1984
|
var __dirname3 = dirname11(fileURLToPath2(import.meta.url));
|
|
1962
1985
|
function getExistingSiteId() {
|
|
@@ -1981,20 +2004,20 @@ async function updateWorkflow(siteId) {
|
|
|
1981
2004
|
if (existsSync10(WORKFLOW_PATH)) {
|
|
1982
2005
|
const oldContent = readFileSync8(WORKFLOW_PATH, "utf-8");
|
|
1983
2006
|
if (oldContent === newContent) {
|
|
1984
|
-
console.log(
|
|
2007
|
+
console.log(chalk23.green("build.yml is already up to date"));
|
|
1985
2008
|
return;
|
|
1986
2009
|
}
|
|
1987
|
-
console.log(
|
|
2010
|
+
console.log(chalk23.yellow("\nbuild.yml will be updated:"));
|
|
1988
2011
|
console.log();
|
|
1989
2012
|
printDiff(oldContent, newContent);
|
|
1990
|
-
const confirm = await promptConfirm(
|
|
2013
|
+
const confirm = await promptConfirm(chalk23.red("Update build.yml?"));
|
|
1991
2014
|
if (!confirm) {
|
|
1992
2015
|
console.log("Skipped build.yml update");
|
|
1993
2016
|
return;
|
|
1994
2017
|
}
|
|
1995
2018
|
}
|
|
1996
|
-
|
|
1997
|
-
console.log(
|
|
2019
|
+
writeFileSync9(WORKFLOW_PATH, newContent);
|
|
2020
|
+
console.log(chalk23.green(`
|
|
1998
2021
|
Created ${WORKFLOW_PATH}`));
|
|
1999
2022
|
}
|
|
2000
2023
|
|
|
@@ -2005,43 +2028,43 @@ async function ensureNetlifyCli() {
|
|
|
2005
2028
|
} catch (error) {
|
|
2006
2029
|
if (!(error instanceof Error) || !error.message.includes("command not found"))
|
|
2007
2030
|
throw error;
|
|
2008
|
-
console.error(
|
|
2031
|
+
console.error(chalk24.red("\nNetlify CLI is not installed.\n"));
|
|
2009
2032
|
const install = await promptConfirm("Would you like to install it now?");
|
|
2010
2033
|
if (!install) {
|
|
2011
2034
|
console.log(
|
|
2012
|
-
|
|
2035
|
+
chalk24.yellow(
|
|
2013
2036
|
"\nInstall it manually with: npm install -g netlify-cli\n"
|
|
2014
2037
|
)
|
|
2015
2038
|
);
|
|
2016
2039
|
process.exit(1);
|
|
2017
2040
|
}
|
|
2018
|
-
console.log(
|
|
2041
|
+
console.log(chalk24.dim("\nInstalling netlify-cli...\n"));
|
|
2019
2042
|
execSync11("npm install -g netlify-cli", { stdio: "inherit" });
|
|
2020
2043
|
console.log();
|
|
2021
2044
|
execSync11("netlify sites:create --disable-linking", { stdio: "inherit" });
|
|
2022
2045
|
}
|
|
2023
2046
|
}
|
|
2024
2047
|
function printSetupInstructions() {
|
|
2025
|
-
console.log(
|
|
2048
|
+
console.log(chalk24.bold("\nDeployment initialized successfully!"));
|
|
2026
2049
|
console.log(
|
|
2027
|
-
|
|
2050
|
+
chalk24.yellow("\nTo complete setup, create a personal access token at:")
|
|
2028
2051
|
);
|
|
2029
2052
|
console.log(
|
|
2030
|
-
|
|
2053
|
+
chalk24.cyan(
|
|
2031
2054
|
"https://app.netlify.com/user/applications#personal-access-tokens"
|
|
2032
2055
|
)
|
|
2033
2056
|
);
|
|
2034
2057
|
console.log(
|
|
2035
|
-
|
|
2058
|
+
chalk24.yellow(
|
|
2036
2059
|
"\nThen add it as NETLIFY_AUTH_TOKEN in your GitHub repository secrets."
|
|
2037
2060
|
)
|
|
2038
2061
|
);
|
|
2039
2062
|
}
|
|
2040
2063
|
async function init5() {
|
|
2041
|
-
console.log(
|
|
2064
|
+
console.log(chalk24.bold("Initializing Netlify deployment...\n"));
|
|
2042
2065
|
const existingSiteId = getExistingSiteId();
|
|
2043
2066
|
if (existingSiteId) {
|
|
2044
|
-
console.log(
|
|
2067
|
+
console.log(chalk24.dim(`Using existing site ID: ${existingSiteId}
|
|
2045
2068
|
`));
|
|
2046
2069
|
await updateWorkflow(existingSiteId);
|
|
2047
2070
|
return;
|
|
@@ -2087,7 +2110,7 @@ function addViteBaseConfig() {
|
|
|
2087
2110
|
'defineConfig({\n base: "./",'
|
|
2088
2111
|
);
|
|
2089
2112
|
if (updated !== content) {
|
|
2090
|
-
|
|
2113
|
+
writeFileSync10(viteConfigPath, updated);
|
|
2091
2114
|
console.log('Added base: "./" to vite.config.ts');
|
|
2092
2115
|
}
|
|
2093
2116
|
}
|
|
@@ -2135,19 +2158,19 @@ function detectPlatform() {
|
|
|
2135
2158
|
|
|
2136
2159
|
// src/commands/notify/showNotification/showWindowsNotificationFromWsl.ts
|
|
2137
2160
|
import { spawn as spawn2 } from "child_process";
|
|
2138
|
-
import
|
|
2161
|
+
import fs10 from "fs";
|
|
2139
2162
|
import { createRequire } from "module";
|
|
2140
|
-
import
|
|
2163
|
+
import path18 from "path";
|
|
2141
2164
|
var require2 = createRequire(import.meta.url);
|
|
2142
2165
|
function getSnoreToastPath() {
|
|
2143
|
-
const notifierPath =
|
|
2144
|
-
return
|
|
2166
|
+
const notifierPath = path18.dirname(require2.resolve("node-notifier"));
|
|
2167
|
+
return path18.join(notifierPath, "vendor", "snoreToast", "snoretoast-x64.exe");
|
|
2145
2168
|
}
|
|
2146
2169
|
function showWindowsNotificationFromWsl(options2) {
|
|
2147
2170
|
const { title, message, sound } = options2;
|
|
2148
2171
|
const snoreToastPath = getSnoreToastPath();
|
|
2149
2172
|
try {
|
|
2150
|
-
|
|
2173
|
+
fs10.chmodSync(snoreToastPath, 493);
|
|
2151
2174
|
} catch {
|
|
2152
2175
|
}
|
|
2153
2176
|
const args = ["-t", title, "-m", message];
|
|
@@ -2221,12 +2244,12 @@ async function notify() {
|
|
|
2221
2244
|
|
|
2222
2245
|
// src/commands/backlog/add/index.ts
|
|
2223
2246
|
import { existsSync as existsSync13 } from "fs";
|
|
2224
|
-
import
|
|
2247
|
+
import chalk26 from "chalk";
|
|
2225
2248
|
|
|
2226
2249
|
// src/commands/backlog/shared.ts
|
|
2227
|
-
import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as
|
|
2250
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
|
|
2228
2251
|
import { join as join8 } from "path";
|
|
2229
|
-
import
|
|
2252
|
+
import chalk25 from "chalk";
|
|
2230
2253
|
import { parse as parseYaml2, stringify as stringifyYaml3 } from "yaml";
|
|
2231
2254
|
|
|
2232
2255
|
// src/commands/backlog/types.ts
|
|
@@ -2262,7 +2285,7 @@ function loadBacklog() {
|
|
|
2262
2285
|
}
|
|
2263
2286
|
function saveBacklog(items) {
|
|
2264
2287
|
const backlogPath = getBacklogPath();
|
|
2265
|
-
|
|
2288
|
+
writeFileSync11(backlogPath, stringifyYaml3(items, { lineWidth: 0 }));
|
|
2266
2289
|
}
|
|
2267
2290
|
function findItem(items, id) {
|
|
2268
2291
|
return items.find((item) => item.id === id);
|
|
@@ -2270,7 +2293,7 @@ function findItem(items, id) {
|
|
|
2270
2293
|
function loadAndFindItem(id) {
|
|
2271
2294
|
if (!existsSync12(getBacklogPath())) {
|
|
2272
2295
|
console.log(
|
|
2273
|
-
|
|
2296
|
+
chalk25.yellow(
|
|
2274
2297
|
"No backlog found. Run 'assist backlog init' to create one."
|
|
2275
2298
|
)
|
|
2276
2299
|
);
|
|
@@ -2279,7 +2302,7 @@ function loadAndFindItem(id) {
|
|
|
2279
2302
|
const items = loadBacklog();
|
|
2280
2303
|
const item = findItem(items, Number.parseInt(id, 10));
|
|
2281
2304
|
if (!item) {
|
|
2282
|
-
console.log(
|
|
2305
|
+
console.log(chalk25.red(`Item #${id} not found.`));
|
|
2283
2306
|
return void 0;
|
|
2284
2307
|
}
|
|
2285
2308
|
return { items, item };
|
|
@@ -2304,7 +2327,7 @@ function getNextId(items) {
|
|
|
2304
2327
|
|
|
2305
2328
|
// src/commands/backlog/add/shared.ts
|
|
2306
2329
|
import { spawnSync } from "child_process";
|
|
2307
|
-
import { mkdtempSync, readFileSync as readFileSync11, unlinkSync as unlinkSync2, writeFileSync as
|
|
2330
|
+
import { mkdtempSync, readFileSync as readFileSync11, unlinkSync as unlinkSync2, writeFileSync as writeFileSync12 } from "fs";
|
|
2308
2331
|
import { tmpdir } from "os";
|
|
2309
2332
|
import { join as join9 } from "path";
|
|
2310
2333
|
import enquirer4 from "enquirer";
|
|
@@ -2348,7 +2371,7 @@ function openEditor() {
|
|
|
2348
2371
|
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
2349
2372
|
const dir = mkdtempSync(join9(tmpdir(), "assist-"));
|
|
2350
2373
|
const filePath = join9(dir, "description.md");
|
|
2351
|
-
|
|
2374
|
+
writeFileSync12(filePath, "");
|
|
2352
2375
|
const result = spawnSync(editor, [filePath], { stdio: "inherit" });
|
|
2353
2376
|
if (result.status !== 0) {
|
|
2354
2377
|
unlinkSync2(filePath);
|
|
@@ -2377,7 +2400,7 @@ async function add() {
|
|
|
2377
2400
|
const backlogPath = getBacklogPath();
|
|
2378
2401
|
if (!existsSync13(backlogPath)) {
|
|
2379
2402
|
console.log(
|
|
2380
|
-
|
|
2403
|
+
chalk26.yellow(
|
|
2381
2404
|
"No backlog found. Run 'assist backlog init' to create one."
|
|
2382
2405
|
)
|
|
2383
2406
|
);
|
|
@@ -2398,67 +2421,67 @@ async function add() {
|
|
|
2398
2421
|
status: "todo"
|
|
2399
2422
|
});
|
|
2400
2423
|
saveBacklog(items);
|
|
2401
|
-
console.log(
|
|
2424
|
+
console.log(chalk26.green(`Added item #${id}: ${name}`));
|
|
2402
2425
|
}
|
|
2403
2426
|
|
|
2404
2427
|
// src/commands/backlog/delete/index.ts
|
|
2405
|
-
import
|
|
2428
|
+
import chalk27 from "chalk";
|
|
2406
2429
|
async function del(id) {
|
|
2407
2430
|
const name = removeItem(id);
|
|
2408
2431
|
if (name) {
|
|
2409
|
-
console.log(
|
|
2432
|
+
console.log(chalk27.green(`Deleted item #${id}: ${name}`));
|
|
2410
2433
|
}
|
|
2411
2434
|
}
|
|
2412
2435
|
|
|
2413
2436
|
// src/commands/backlog/done/index.ts
|
|
2414
|
-
import
|
|
2437
|
+
import chalk28 from "chalk";
|
|
2415
2438
|
async function done(id) {
|
|
2416
2439
|
const name = setStatus(id, "done");
|
|
2417
2440
|
if (name) {
|
|
2418
|
-
console.log(
|
|
2441
|
+
console.log(chalk28.green(`Completed item #${id}: ${name}`));
|
|
2419
2442
|
}
|
|
2420
2443
|
}
|
|
2421
2444
|
|
|
2422
2445
|
// src/commands/backlog/init/index.ts
|
|
2423
2446
|
import { existsSync as existsSync14 } from "fs";
|
|
2424
|
-
import
|
|
2447
|
+
import chalk29 from "chalk";
|
|
2425
2448
|
async function init6() {
|
|
2426
2449
|
const backlogPath = getBacklogPath();
|
|
2427
2450
|
if (existsSync14(backlogPath)) {
|
|
2428
|
-
console.log(
|
|
2451
|
+
console.log(chalk29.yellow("assist.backlog.yml already exists."));
|
|
2429
2452
|
return;
|
|
2430
2453
|
}
|
|
2431
2454
|
saveBacklog([]);
|
|
2432
|
-
console.log(
|
|
2455
|
+
console.log(chalk29.green("Created assist.backlog.yml"));
|
|
2433
2456
|
}
|
|
2434
2457
|
|
|
2435
2458
|
// src/commands/backlog/list/index.ts
|
|
2436
2459
|
import { existsSync as existsSync15 } from "fs";
|
|
2437
|
-
import
|
|
2460
|
+
import chalk30 from "chalk";
|
|
2438
2461
|
function statusIcon(status2) {
|
|
2439
2462
|
switch (status2) {
|
|
2440
2463
|
case "todo":
|
|
2441
|
-
return
|
|
2464
|
+
return chalk30.dim("[ ]");
|
|
2442
2465
|
case "in-progress":
|
|
2443
|
-
return
|
|
2466
|
+
return chalk30.yellow("[~]");
|
|
2444
2467
|
case "done":
|
|
2445
|
-
return
|
|
2468
|
+
return chalk30.green("[x]");
|
|
2446
2469
|
}
|
|
2447
2470
|
}
|
|
2448
2471
|
function typeLabel(type) {
|
|
2449
2472
|
switch (type) {
|
|
2450
2473
|
case "bug":
|
|
2451
|
-
return
|
|
2474
|
+
return chalk30.magenta("Bug");
|
|
2452
2475
|
case "story":
|
|
2453
|
-
return
|
|
2476
|
+
return chalk30.cyan("Story");
|
|
2454
2477
|
}
|
|
2455
2478
|
}
|
|
2456
2479
|
function printVerboseDetails(item) {
|
|
2457
2480
|
if (item.description) {
|
|
2458
|
-
console.log(` ${
|
|
2481
|
+
console.log(` ${chalk30.dim("Description:")} ${item.description}`);
|
|
2459
2482
|
}
|
|
2460
2483
|
if (item.acceptanceCriteria.length > 0) {
|
|
2461
|
-
console.log(` ${
|
|
2484
|
+
console.log(` ${chalk30.dim("Acceptance criteria:")}`);
|
|
2462
2485
|
for (const criterion of item.acceptanceCriteria) {
|
|
2463
2486
|
console.log(` - ${criterion}`);
|
|
2464
2487
|
}
|
|
@@ -2474,7 +2497,7 @@ async function list2(options2) {
|
|
|
2474
2497
|
const backlogPath = getBacklogPath();
|
|
2475
2498
|
if (!existsSync15(backlogPath)) {
|
|
2476
2499
|
console.log(
|
|
2477
|
-
|
|
2500
|
+
chalk30.yellow(
|
|
2478
2501
|
"No backlog found. Run 'assist backlog init' to create one."
|
|
2479
2502
|
)
|
|
2480
2503
|
);
|
|
@@ -2482,12 +2505,12 @@ async function list2(options2) {
|
|
|
2482
2505
|
}
|
|
2483
2506
|
const items = filterItems(loadBacklog(), options2);
|
|
2484
2507
|
if (items.length === 0) {
|
|
2485
|
-
console.log(
|
|
2508
|
+
console.log(chalk30.dim("Backlog is empty."));
|
|
2486
2509
|
return;
|
|
2487
2510
|
}
|
|
2488
2511
|
for (const item of items) {
|
|
2489
2512
|
console.log(
|
|
2490
|
-
`${statusIcon(item.status)} ${typeLabel(item.type)} ${
|
|
2513
|
+
`${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk30.dim(`#${item.id}`)} ${item.name}`
|
|
2491
2514
|
);
|
|
2492
2515
|
if (options2.verbose) {
|
|
2493
2516
|
printVerboseDetails(item);
|
|
@@ -2496,11 +2519,11 @@ async function list2(options2) {
|
|
|
2496
2519
|
}
|
|
2497
2520
|
|
|
2498
2521
|
// src/commands/backlog/start/index.ts
|
|
2499
|
-
import
|
|
2522
|
+
import chalk31 from "chalk";
|
|
2500
2523
|
async function start(id) {
|
|
2501
2524
|
const name = setStatus(id, "in-progress");
|
|
2502
2525
|
if (name) {
|
|
2503
|
-
console.log(
|
|
2526
|
+
console.log(chalk31.green(`Started item #${id}: ${name}`));
|
|
2504
2527
|
}
|
|
2505
2528
|
}
|
|
2506
2529
|
|
|
@@ -2512,7 +2535,7 @@ import {
|
|
|
2512
2535
|
} from "http";
|
|
2513
2536
|
import { dirname as dirname12, join as join10 } from "path";
|
|
2514
2537
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2515
|
-
import
|
|
2538
|
+
import chalk32 from "chalk";
|
|
2516
2539
|
function respondJson(res, status2, data) {
|
|
2517
2540
|
res.writeHead(status2, { "Content-Type": "application/json" });
|
|
2518
2541
|
res.end(JSON.stringify(data));
|
|
@@ -2556,8 +2579,8 @@ function startWebServer(label2, port, handler) {
|
|
|
2556
2579
|
handler(req, res, port);
|
|
2557
2580
|
});
|
|
2558
2581
|
server.listen(port, () => {
|
|
2559
|
-
console.log(
|
|
2560
|
-
console.log(
|
|
2582
|
+
console.log(chalk32.green(`${label2}: ${url}`));
|
|
2583
|
+
console.log(chalk32.dim("Press Ctrl+C to stop"));
|
|
2561
2584
|
exec(`open ${url}`);
|
|
2562
2585
|
});
|
|
2563
2586
|
}
|
|
@@ -2786,7 +2809,7 @@ function extractGraphqlQuery(args) {
|
|
|
2786
2809
|
}
|
|
2787
2810
|
|
|
2788
2811
|
// src/shared/loadCliReads.ts
|
|
2789
|
-
import { existsSync as existsSync16, readFileSync as readFileSync13, writeFileSync as
|
|
2812
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
|
|
2790
2813
|
import { dirname as dirname13, resolve as resolve2 } from "path";
|
|
2791
2814
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2792
2815
|
var __filename2 = fileURLToPath4(import.meta.url);
|
|
@@ -2797,19 +2820,19 @@ function getCliReadsPath() {
|
|
|
2797
2820
|
var cachedLines;
|
|
2798
2821
|
function getCliReadsLines() {
|
|
2799
2822
|
if (cachedLines) return cachedLines;
|
|
2800
|
-
const
|
|
2801
|
-
if (!existsSync16(
|
|
2823
|
+
const path42 = getCliReadsPath();
|
|
2824
|
+
if (!existsSync16(path42)) {
|
|
2802
2825
|
cachedLines = [];
|
|
2803
2826
|
return cachedLines;
|
|
2804
2827
|
}
|
|
2805
|
-
cachedLines = readFileSync13(
|
|
2828
|
+
cachedLines = readFileSync13(path42, "utf-8").split("\n").filter((line) => line.trim() !== "");
|
|
2806
2829
|
return cachedLines;
|
|
2807
2830
|
}
|
|
2808
2831
|
function loadCliReads() {
|
|
2809
2832
|
return getCliReadsLines();
|
|
2810
2833
|
}
|
|
2811
2834
|
function saveCliReads(commands) {
|
|
2812
|
-
|
|
2835
|
+
writeFileSync13(getCliReadsPath(), `${commands.join("\n")}
|
|
2813
2836
|
`);
|
|
2814
2837
|
cachedLines = void 0;
|
|
2815
2838
|
}
|
|
@@ -3002,7 +3025,7 @@ ${reasons.join("\n")}`);
|
|
|
3002
3025
|
}
|
|
3003
3026
|
|
|
3004
3027
|
// src/commands/permitCliReads/index.ts
|
|
3005
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as
|
|
3028
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "fs";
|
|
3006
3029
|
import { homedir as homedir4 } from "os";
|
|
3007
3030
|
import { join as join12 } from "path";
|
|
3008
3031
|
|
|
@@ -3048,11 +3071,11 @@ function assertCliExists(cli) {
|
|
|
3048
3071
|
}
|
|
3049
3072
|
|
|
3050
3073
|
// src/commands/permitCliReads/colorize.ts
|
|
3051
|
-
import
|
|
3074
|
+
import chalk33 from "chalk";
|
|
3052
3075
|
function colorize(plainOutput) {
|
|
3053
3076
|
return plainOutput.split("\n").map((line) => {
|
|
3054
|
-
if (line.startsWith(" R ")) return
|
|
3055
|
-
if (line.startsWith(" W ")) return
|
|
3077
|
+
if (line.startsWith(" R ")) return chalk33.green(line);
|
|
3078
|
+
if (line.startsWith(" W ")) return chalk33.red(line);
|
|
3056
3079
|
return line;
|
|
3057
3080
|
}).join("\n");
|
|
3058
3081
|
}
|
|
@@ -3154,14 +3177,14 @@ function showProgress(p, label2) {
|
|
|
3154
3177
|
const pct = Math.round(p.done / p.total * 100);
|
|
3155
3178
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
3156
3179
|
}
|
|
3157
|
-
async function resolveCommand(cli,
|
|
3158
|
-
showProgress(p,
|
|
3159
|
-
const subHelp = await runHelp([cli, ...
|
|
3180
|
+
async function resolveCommand(cli, path42, description, depth, p) {
|
|
3181
|
+
showProgress(p, path42.join(" "));
|
|
3182
|
+
const subHelp = await runHelp([cli, ...path42]);
|
|
3160
3183
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
3161
|
-
return [{ path:
|
|
3184
|
+
return [{ path: path42, description }];
|
|
3162
3185
|
}
|
|
3163
|
-
const children = await discoverAt(cli,
|
|
3164
|
-
return children.length > 0 ? children : [{ path:
|
|
3186
|
+
const children = await discoverAt(cli, path42, depth + 1, p);
|
|
3187
|
+
return children.length > 0 ? children : [{ path: path42, description }];
|
|
3165
3188
|
}
|
|
3166
3189
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
3167
3190
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -3309,14 +3332,14 @@ function logPath(cli) {
|
|
|
3309
3332
|
return join12(homedir4(), ".assist", `cli-discover-${safeName}.log`);
|
|
3310
3333
|
}
|
|
3311
3334
|
function readCache(cli) {
|
|
3312
|
-
const
|
|
3313
|
-
if (!existsSync18(
|
|
3314
|
-
return readFileSync15(
|
|
3335
|
+
const path42 = logPath(cli);
|
|
3336
|
+
if (!existsSync18(path42)) return void 0;
|
|
3337
|
+
return readFileSync15(path42, "utf-8");
|
|
3315
3338
|
}
|
|
3316
3339
|
function writeCache(cli, output) {
|
|
3317
3340
|
const dir = join12(homedir4(), ".assist");
|
|
3318
3341
|
mkdirSync4(dir, { recursive: true });
|
|
3319
|
-
|
|
3342
|
+
writeFileSync14(logPath(cli), output);
|
|
3320
3343
|
}
|
|
3321
3344
|
async function permitCliReads(cli, options2 = { noCache: false }) {
|
|
3322
3345
|
if (!cli) {
|
|
@@ -3363,20 +3386,20 @@ function registerCliHook(program2) {
|
|
|
3363
3386
|
}
|
|
3364
3387
|
|
|
3365
3388
|
// src/commands/complexity/analyze.ts
|
|
3366
|
-
import
|
|
3389
|
+
import chalk39 from "chalk";
|
|
3367
3390
|
|
|
3368
3391
|
// src/commands/complexity/cyclomatic.ts
|
|
3369
|
-
import
|
|
3392
|
+
import chalk35 from "chalk";
|
|
3370
3393
|
|
|
3371
3394
|
// src/commands/complexity/shared/index.ts
|
|
3372
|
-
import
|
|
3373
|
-
import
|
|
3374
|
-
import
|
|
3395
|
+
import fs12 from "fs";
|
|
3396
|
+
import path20 from "path";
|
|
3397
|
+
import chalk34 from "chalk";
|
|
3375
3398
|
import ts5 from "typescript";
|
|
3376
3399
|
|
|
3377
3400
|
// src/commands/complexity/findSourceFiles.ts
|
|
3378
|
-
import
|
|
3379
|
-
import
|
|
3401
|
+
import fs11 from "fs";
|
|
3402
|
+
import path19 from "path";
|
|
3380
3403
|
import { minimatch as minimatch3 } from "minimatch";
|
|
3381
3404
|
function applyIgnoreGlobs(files) {
|
|
3382
3405
|
const { complexity } = loadConfig();
|
|
@@ -3385,13 +3408,13 @@ function applyIgnoreGlobs(files) {
|
|
|
3385
3408
|
);
|
|
3386
3409
|
}
|
|
3387
3410
|
function walk(dir, results) {
|
|
3388
|
-
if (!
|
|
3411
|
+
if (!fs11.existsSync(dir)) {
|
|
3389
3412
|
return;
|
|
3390
3413
|
}
|
|
3391
3414
|
const extensions = [".ts", ".tsx"];
|
|
3392
|
-
const entries =
|
|
3415
|
+
const entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
3393
3416
|
for (const entry of entries) {
|
|
3394
|
-
const fullPath =
|
|
3417
|
+
const fullPath = path19.join(dir, entry.name);
|
|
3395
3418
|
if (entry.isDirectory()) {
|
|
3396
3419
|
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
3397
3420
|
walk(fullPath, results);
|
|
@@ -3407,10 +3430,10 @@ function findSourceFiles2(pattern2, baseDir = ".") {
|
|
|
3407
3430
|
walk(baseDir, results);
|
|
3408
3431
|
return applyIgnoreGlobs(results.filter((f) => minimatch3(f, pattern2)));
|
|
3409
3432
|
}
|
|
3410
|
-
if (
|
|
3433
|
+
if (fs11.existsSync(pattern2) && fs11.statSync(pattern2).isFile()) {
|
|
3411
3434
|
return [pattern2];
|
|
3412
3435
|
}
|
|
3413
|
-
if (
|
|
3436
|
+
if (fs11.existsSync(pattern2) && fs11.statSync(pattern2).isDirectory()) {
|
|
3414
3437
|
walk(pattern2, results);
|
|
3415
3438
|
return applyIgnoreGlobs(results);
|
|
3416
3439
|
}
|
|
@@ -3605,9 +3628,9 @@ function countSloc(content) {
|
|
|
3605
3628
|
|
|
3606
3629
|
// src/commands/complexity/shared/index.ts
|
|
3607
3630
|
function createSourceFromFile(filePath) {
|
|
3608
|
-
const content =
|
|
3631
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
3609
3632
|
return ts5.createSourceFile(
|
|
3610
|
-
|
|
3633
|
+
path20.basename(filePath),
|
|
3611
3634
|
content,
|
|
3612
3635
|
ts5.ScriptTarget.Latest,
|
|
3613
3636
|
true,
|
|
@@ -3617,7 +3640,7 @@ function createSourceFromFile(filePath) {
|
|
|
3617
3640
|
function withSourceFiles(pattern2, callback) {
|
|
3618
3641
|
const files = findSourceFiles2(pattern2);
|
|
3619
3642
|
if (files.length === 0) {
|
|
3620
|
-
console.log(
|
|
3643
|
+
console.log(chalk34.yellow("No files found matching pattern"));
|
|
3621
3644
|
return void 0;
|
|
3622
3645
|
}
|
|
3623
3646
|
return callback(files);
|
|
@@ -3650,11 +3673,11 @@ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3650
3673
|
results.sort((a, b) => b.complexity - a.complexity);
|
|
3651
3674
|
for (const { file, name, complexity } of results) {
|
|
3652
3675
|
const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
|
|
3653
|
-
const color = exceedsThreshold ?
|
|
3654
|
-
console.log(`${color(`${file}:${name}`)} \u2192 ${
|
|
3676
|
+
const color = exceedsThreshold ? chalk35.red : chalk35.white;
|
|
3677
|
+
console.log(`${color(`${file}:${name}`)} \u2192 ${chalk35.cyan(complexity)}`);
|
|
3655
3678
|
}
|
|
3656
3679
|
console.log(
|
|
3657
|
-
|
|
3680
|
+
chalk35.dim(
|
|
3658
3681
|
`
|
|
3659
3682
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3660
3683
|
)
|
|
@@ -3666,7 +3689,7 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3666
3689
|
}
|
|
3667
3690
|
|
|
3668
3691
|
// src/commands/complexity/halstead.ts
|
|
3669
|
-
import
|
|
3692
|
+
import chalk36 from "chalk";
|
|
3670
3693
|
async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
3671
3694
|
withSourceFiles(pattern2, (files) => {
|
|
3672
3695
|
const results = [];
|
|
@@ -3681,13 +3704,13 @@ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3681
3704
|
results.sort((a, b) => b.metrics.effort - a.metrics.effort);
|
|
3682
3705
|
for (const { file, name, metrics } of results) {
|
|
3683
3706
|
const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
|
|
3684
|
-
const color = exceedsThreshold ?
|
|
3707
|
+
const color = exceedsThreshold ? chalk36.red : chalk36.white;
|
|
3685
3708
|
console.log(
|
|
3686
|
-
`${color(`${file}:${name}`)} \u2192 volume: ${
|
|
3709
|
+
`${color(`${file}:${name}`)} \u2192 volume: ${chalk36.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk36.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk36.magenta(metrics.effort.toFixed(1))}`
|
|
3687
3710
|
);
|
|
3688
3711
|
}
|
|
3689
3712
|
console.log(
|
|
3690
|
-
|
|
3713
|
+
chalk36.dim(
|
|
3691
3714
|
`
|
|
3692
3715
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3693
3716
|
)
|
|
@@ -3699,31 +3722,31 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3699
3722
|
}
|
|
3700
3723
|
|
|
3701
3724
|
// src/commands/complexity/maintainability/index.ts
|
|
3702
|
-
import
|
|
3725
|
+
import fs13 from "fs";
|
|
3703
3726
|
|
|
3704
3727
|
// src/commands/complexity/maintainability/displayMaintainabilityResults.ts
|
|
3705
|
-
import
|
|
3728
|
+
import chalk37 from "chalk";
|
|
3706
3729
|
function displayMaintainabilityResults(results, threshold) {
|
|
3707
3730
|
const filtered = threshold !== void 0 ? results.filter((r) => r.minMaintainability < threshold) : results;
|
|
3708
3731
|
if (threshold !== void 0 && filtered.length === 0) {
|
|
3709
|
-
console.log(
|
|
3732
|
+
console.log(chalk37.green("All files pass maintainability threshold"));
|
|
3710
3733
|
} else {
|
|
3711
3734
|
for (const { file, avgMaintainability, minMaintainability } of filtered) {
|
|
3712
|
-
const color = threshold !== void 0 ?
|
|
3735
|
+
const color = threshold !== void 0 ? chalk37.red : chalk37.white;
|
|
3713
3736
|
console.log(
|
|
3714
|
-
`${color(file)} \u2192 avg: ${
|
|
3737
|
+
`${color(file)} \u2192 avg: ${chalk37.cyan(avgMaintainability.toFixed(1))}, min: ${chalk37.yellow(minMaintainability.toFixed(1))}`
|
|
3715
3738
|
);
|
|
3716
3739
|
}
|
|
3717
3740
|
}
|
|
3718
|
-
console.log(
|
|
3741
|
+
console.log(chalk37.dim(`
|
|
3719
3742
|
Analyzed ${results.length} files`));
|
|
3720
3743
|
if (filtered.length > 0 && threshold !== void 0) {
|
|
3721
3744
|
console.error(
|
|
3722
|
-
|
|
3745
|
+
chalk37.red(
|
|
3723
3746
|
`
|
|
3724
3747
|
Fail: ${filtered.length} file(s) below threshold ${threshold}. Maintainability index (0\u2013100) is derived from Halstead volume, cyclomatic complexity, and lines of code.
|
|
3725
3748
|
|
|
3726
|
-
\u26A0\uFE0F ${
|
|
3749
|
+
\u26A0\uFE0F ${chalk37.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.`
|
|
3727
3750
|
)
|
|
3728
3751
|
);
|
|
3729
3752
|
process.exit(1);
|
|
@@ -3741,7 +3764,7 @@ function calculateMaintainabilityIndex(halsteadVolume, cyclomaticComplexity, slo
|
|
|
3741
3764
|
function collectFileMetrics(files) {
|
|
3742
3765
|
const fileMetrics = /* @__PURE__ */ new Map();
|
|
3743
3766
|
for (const file of files) {
|
|
3744
|
-
const content =
|
|
3767
|
+
const content = fs13.readFileSync(file, "utf-8");
|
|
3745
3768
|
fileMetrics.set(file, { sloc: countSloc(content), functions: [] });
|
|
3746
3769
|
}
|
|
3747
3770
|
forEachFunction(files, (file, _name, node) => {
|
|
@@ -3779,14 +3802,14 @@ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3779
3802
|
}
|
|
3780
3803
|
|
|
3781
3804
|
// src/commands/complexity/sloc.ts
|
|
3782
|
-
import
|
|
3783
|
-
import
|
|
3805
|
+
import fs14 from "fs";
|
|
3806
|
+
import chalk38 from "chalk";
|
|
3784
3807
|
async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
3785
3808
|
withSourceFiles(pattern2, (files) => {
|
|
3786
3809
|
const results = [];
|
|
3787
3810
|
let hasViolation = false;
|
|
3788
3811
|
for (const file of files) {
|
|
3789
|
-
const content =
|
|
3812
|
+
const content = fs14.readFileSync(file, "utf-8");
|
|
3790
3813
|
const lines = countSloc(content);
|
|
3791
3814
|
results.push({ file, lines });
|
|
3792
3815
|
if (options2.threshold !== void 0 && lines > options2.threshold) {
|
|
@@ -3796,12 +3819,12 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3796
3819
|
results.sort((a, b) => b.lines - a.lines);
|
|
3797
3820
|
for (const { file, lines } of results) {
|
|
3798
3821
|
const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
|
|
3799
|
-
const color = exceedsThreshold ?
|
|
3800
|
-
console.log(`${color(file)} \u2192 ${
|
|
3822
|
+
const color = exceedsThreshold ? chalk38.red : chalk38.white;
|
|
3823
|
+
console.log(`${color(file)} \u2192 ${chalk38.cyan(lines)} lines`);
|
|
3801
3824
|
}
|
|
3802
3825
|
const total = results.reduce((sum, r) => sum + r.lines, 0);
|
|
3803
3826
|
console.log(
|
|
3804
|
-
|
|
3827
|
+
chalk38.dim(`
|
|
3805
3828
|
Total: ${total} lines across ${files.length} files`)
|
|
3806
3829
|
);
|
|
3807
3830
|
if (hasViolation) {
|
|
@@ -3815,21 +3838,21 @@ async function analyze(pattern2) {
|
|
|
3815
3838
|
const searchPattern = pattern2.includes("*") || pattern2.includes("/") ? pattern2 : `**/${pattern2}`;
|
|
3816
3839
|
const files = findSourceFiles2(searchPattern);
|
|
3817
3840
|
if (files.length === 0) {
|
|
3818
|
-
console.log(
|
|
3841
|
+
console.log(chalk39.yellow("No files found matching pattern"));
|
|
3819
3842
|
return;
|
|
3820
3843
|
}
|
|
3821
3844
|
if (files.length === 1) {
|
|
3822
3845
|
const file = files[0];
|
|
3823
|
-
console.log(
|
|
3846
|
+
console.log(chalk39.bold.underline("SLOC"));
|
|
3824
3847
|
await sloc(file);
|
|
3825
3848
|
console.log();
|
|
3826
|
-
console.log(
|
|
3849
|
+
console.log(chalk39.bold.underline("Cyclomatic Complexity"));
|
|
3827
3850
|
await cyclomatic(file);
|
|
3828
3851
|
console.log();
|
|
3829
|
-
console.log(
|
|
3852
|
+
console.log(chalk39.bold.underline("Halstead Metrics"));
|
|
3830
3853
|
await halstead(file);
|
|
3831
3854
|
console.log();
|
|
3832
|
-
console.log(
|
|
3855
|
+
console.log(chalk39.bold.underline("Maintainability Index"));
|
|
3833
3856
|
await maintainability(file);
|
|
3834
3857
|
return;
|
|
3835
3858
|
}
|
|
@@ -3856,8 +3879,8 @@ function registerComplexity(program2) {
|
|
|
3856
3879
|
}
|
|
3857
3880
|
|
|
3858
3881
|
// src/commands/deploy/redirect.ts
|
|
3859
|
-
import { existsSync as existsSync19, readFileSync as readFileSync16, writeFileSync as
|
|
3860
|
-
import
|
|
3882
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
|
|
3883
|
+
import chalk40 from "chalk";
|
|
3861
3884
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
3862
3885
|
if (!window.location.pathname.endsWith('/')) {
|
|
3863
3886
|
window.location.href = \`\${window.location.pathname}/\${window.location.search}\${window.location.hash}\`;
|
|
@@ -3866,22 +3889,22 @@ var TRAILING_SLASH_SCRIPT = ` <script>
|
|
|
3866
3889
|
function redirect() {
|
|
3867
3890
|
const indexPath = "index.html";
|
|
3868
3891
|
if (!existsSync19(indexPath)) {
|
|
3869
|
-
console.log(
|
|
3892
|
+
console.log(chalk40.yellow("No index.html found"));
|
|
3870
3893
|
return;
|
|
3871
3894
|
}
|
|
3872
3895
|
const content = readFileSync16(indexPath, "utf-8");
|
|
3873
3896
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
3874
|
-
console.log(
|
|
3897
|
+
console.log(chalk40.dim("Trailing slash script already present"));
|
|
3875
3898
|
return;
|
|
3876
3899
|
}
|
|
3877
3900
|
const headCloseIndex = content.indexOf("</head>");
|
|
3878
3901
|
if (headCloseIndex === -1) {
|
|
3879
|
-
console.log(
|
|
3902
|
+
console.log(chalk40.red("Could not find </head> tag in index.html"));
|
|
3880
3903
|
return;
|
|
3881
3904
|
}
|
|
3882
3905
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
3883
|
-
|
|
3884
|
-
console.log(
|
|
3906
|
+
writeFileSync15(indexPath, newContent);
|
|
3907
|
+
console.log(chalk40.green("Added trailing slash redirect to index.html"));
|
|
3885
3908
|
}
|
|
3886
3909
|
|
|
3887
3910
|
// src/commands/registerDeploy.ts
|
|
@@ -3908,7 +3931,7 @@ function loadBlogSkipDays(repoName) {
|
|
|
3908
3931
|
|
|
3909
3932
|
// src/commands/devlog/shared.ts
|
|
3910
3933
|
import { execSync as execSync15 } from "child_process";
|
|
3911
|
-
import
|
|
3934
|
+
import chalk41 from "chalk";
|
|
3912
3935
|
|
|
3913
3936
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
3914
3937
|
import { readdirSync, readFileSync as readFileSync17 } from "fs";
|
|
@@ -3995,13 +4018,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
|
|
|
3995
4018
|
}
|
|
3996
4019
|
function printCommitsWithFiles(commits, ignore2, verbose) {
|
|
3997
4020
|
for (const commit2 of commits) {
|
|
3998
|
-
console.log(` ${
|
|
4021
|
+
console.log(` ${chalk41.yellow(commit2.hash)} ${commit2.message}`);
|
|
3999
4022
|
if (verbose) {
|
|
4000
4023
|
const visibleFiles = commit2.files.filter(
|
|
4001
4024
|
(file) => !ignore2.some((p) => file.startsWith(p))
|
|
4002
4025
|
);
|
|
4003
4026
|
for (const file of visibleFiles) {
|
|
4004
|
-
console.log(` ${
|
|
4027
|
+
console.log(` ${chalk41.dim(file)}`);
|
|
4005
4028
|
}
|
|
4006
4029
|
}
|
|
4007
4030
|
}
|
|
@@ -4026,15 +4049,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
|
|
|
4026
4049
|
}
|
|
4027
4050
|
|
|
4028
4051
|
// src/commands/devlog/list/printDateHeader.ts
|
|
4029
|
-
import
|
|
4052
|
+
import chalk42 from "chalk";
|
|
4030
4053
|
function printDateHeader(date, isSkipped, entries) {
|
|
4031
4054
|
if (isSkipped) {
|
|
4032
|
-
console.log(`${
|
|
4055
|
+
console.log(`${chalk42.bold.blue(date)} ${chalk42.dim("skipped")}`);
|
|
4033
4056
|
} else if (entries && entries.length > 0) {
|
|
4034
|
-
const entryInfo = entries.map((e) => `${
|
|
4035
|
-
console.log(`${
|
|
4057
|
+
const entryInfo = entries.map((e) => `${chalk42.green(e.version)} ${e.title}`).join(" | ");
|
|
4058
|
+
console.log(`${chalk42.bold.blue(date)} ${entryInfo}`);
|
|
4036
4059
|
} else {
|
|
4037
|
-
console.log(`${
|
|
4060
|
+
console.log(`${chalk42.bold.blue(date)} ${chalk42.red("\u26A0 devlog missing")}`);
|
|
4038
4061
|
}
|
|
4039
4062
|
}
|
|
4040
4063
|
|
|
@@ -4137,24 +4160,24 @@ function bumpVersion(version2, type) {
|
|
|
4137
4160
|
|
|
4138
4161
|
// src/commands/devlog/next/displayNextEntry/index.ts
|
|
4139
4162
|
import { execSync as execSync18 } from "child_process";
|
|
4140
|
-
import
|
|
4163
|
+
import chalk44 from "chalk";
|
|
4141
4164
|
|
|
4142
4165
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
4143
|
-
import
|
|
4166
|
+
import chalk43 from "chalk";
|
|
4144
4167
|
function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
|
|
4145
4168
|
if (conventional && firstHash) {
|
|
4146
4169
|
const version2 = getVersionAtCommit(firstHash);
|
|
4147
4170
|
if (version2) {
|
|
4148
|
-
console.log(`${
|
|
4171
|
+
console.log(`${chalk43.bold("version:")} ${stripToMinor(version2)}`);
|
|
4149
4172
|
} else {
|
|
4150
|
-
console.log(`${
|
|
4173
|
+
console.log(`${chalk43.bold("version:")} ${chalk43.red("unknown")}`);
|
|
4151
4174
|
}
|
|
4152
4175
|
} else if (patchVersion && minorVersion) {
|
|
4153
4176
|
console.log(
|
|
4154
|
-
`${
|
|
4177
|
+
`${chalk43.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
4155
4178
|
);
|
|
4156
4179
|
} else {
|
|
4157
|
-
console.log(`${
|
|
4180
|
+
console.log(`${chalk43.bold("version:")} v0.1 (initial)`);
|
|
4158
4181
|
}
|
|
4159
4182
|
}
|
|
4160
4183
|
|
|
@@ -4201,16 +4224,16 @@ function noCommitsMessage(hasLastInfo) {
|
|
|
4201
4224
|
return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
|
|
4202
4225
|
}
|
|
4203
4226
|
function logName(repoName) {
|
|
4204
|
-
console.log(`${
|
|
4227
|
+
console.log(`${chalk44.bold("name:")} ${repoName}`);
|
|
4205
4228
|
}
|
|
4206
4229
|
function displayNextEntry(ctx, targetDate, commits) {
|
|
4207
4230
|
logName(ctx.repoName);
|
|
4208
4231
|
printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
|
|
4209
|
-
console.log(
|
|
4232
|
+
console.log(chalk44.bold.blue(targetDate));
|
|
4210
4233
|
printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
|
|
4211
4234
|
}
|
|
4212
4235
|
function logNoCommits(lastInfo) {
|
|
4213
|
-
console.log(
|
|
4236
|
+
console.log(chalk44.dim(noCommitsMessage(!!lastInfo)));
|
|
4214
4237
|
}
|
|
4215
4238
|
|
|
4216
4239
|
// src/commands/devlog/next/index.ts
|
|
@@ -4251,11 +4274,11 @@ function next(options2) {
|
|
|
4251
4274
|
import { execSync as execSync19 } from "child_process";
|
|
4252
4275
|
|
|
4253
4276
|
// src/commands/devlog/repos/printReposTable.ts
|
|
4254
|
-
import
|
|
4277
|
+
import chalk45 from "chalk";
|
|
4255
4278
|
function colorStatus(status2) {
|
|
4256
|
-
if (status2 === "missing") return
|
|
4257
|
-
if (status2 === "outdated") return
|
|
4258
|
-
return
|
|
4279
|
+
if (status2 === "missing") return chalk45.red(status2);
|
|
4280
|
+
if (status2 === "outdated") return chalk45.yellow(status2);
|
|
4281
|
+
return chalk45.green(status2);
|
|
4259
4282
|
}
|
|
4260
4283
|
function formatRow(row, nameWidth) {
|
|
4261
4284
|
const devlog = (row.lastDevlog ?? "-").padEnd(11);
|
|
@@ -4269,8 +4292,8 @@ function printReposTable(rows) {
|
|
|
4269
4292
|
"Last Devlog".padEnd(11),
|
|
4270
4293
|
"Status"
|
|
4271
4294
|
].join(" ");
|
|
4272
|
-
console.log(
|
|
4273
|
-
console.log(
|
|
4295
|
+
console.log(chalk45.dim(header));
|
|
4296
|
+
console.log(chalk45.dim("-".repeat(header.length)));
|
|
4274
4297
|
for (const row of rows) {
|
|
4275
4298
|
console.log(formatRow(row, nameWidth));
|
|
4276
4299
|
}
|
|
@@ -4326,16 +4349,16 @@ function repos(options2) {
|
|
|
4326
4349
|
}
|
|
4327
4350
|
|
|
4328
4351
|
// src/commands/devlog/skip.ts
|
|
4329
|
-
import { writeFileSync as
|
|
4352
|
+
import { writeFileSync as writeFileSync16 } from "fs";
|
|
4330
4353
|
import { join as join15 } from "path";
|
|
4331
|
-
import
|
|
4354
|
+
import chalk46 from "chalk";
|
|
4332
4355
|
import { stringify as stringifyYaml4 } from "yaml";
|
|
4333
4356
|
function getBlogConfigPath() {
|
|
4334
4357
|
return join15(BLOG_REPO_ROOT, "assist.yml");
|
|
4335
4358
|
}
|
|
4336
4359
|
function skip(date) {
|
|
4337
4360
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
4338
|
-
console.log(
|
|
4361
|
+
console.log(chalk46.red("Invalid date format. Use YYYY-MM-DD"));
|
|
4339
4362
|
process.exit(1);
|
|
4340
4363
|
}
|
|
4341
4364
|
const repoName = getRepoName();
|
|
@@ -4346,7 +4369,7 @@ function skip(date) {
|
|
|
4346
4369
|
const skipDays = skip2[repoName] ?? [];
|
|
4347
4370
|
if (skipDays.includes(date)) {
|
|
4348
4371
|
console.log(
|
|
4349
|
-
|
|
4372
|
+
chalk46.yellow(`${date} is already in skip list for ${repoName}`)
|
|
4350
4373
|
);
|
|
4351
4374
|
return;
|
|
4352
4375
|
}
|
|
@@ -4355,21 +4378,21 @@ function skip(date) {
|
|
|
4355
4378
|
skip2[repoName] = skipDays;
|
|
4356
4379
|
devlog.skip = skip2;
|
|
4357
4380
|
config.devlog = devlog;
|
|
4358
|
-
|
|
4359
|
-
console.log(
|
|
4381
|
+
writeFileSync16(configPath, stringifyYaml4(config, { lineWidth: 0 }));
|
|
4382
|
+
console.log(chalk46.green(`Added ${date} to skip list for ${repoName}`));
|
|
4360
4383
|
}
|
|
4361
4384
|
|
|
4362
4385
|
// src/commands/devlog/version.ts
|
|
4363
|
-
import
|
|
4386
|
+
import chalk47 from "chalk";
|
|
4364
4387
|
function version() {
|
|
4365
4388
|
const config = loadConfig();
|
|
4366
4389
|
const name = getRepoName();
|
|
4367
4390
|
const lastInfo = getLastVersionInfo(name, config);
|
|
4368
4391
|
const lastVersion = lastInfo?.version ?? null;
|
|
4369
4392
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
4370
|
-
console.log(`${
|
|
4371
|
-
console.log(`${
|
|
4372
|
-
console.log(`${
|
|
4393
|
+
console.log(`${chalk47.bold("name:")} ${name}`);
|
|
4394
|
+
console.log(`${chalk47.bold("last:")} ${lastVersion ?? chalk47.dim("none")}`);
|
|
4395
|
+
console.log(`${chalk47.bold("next:")} ${nextVersion ?? chalk47.dim("none")}`);
|
|
4373
4396
|
}
|
|
4374
4397
|
|
|
4375
4398
|
// src/commands/registerDevlog.ts
|
|
@@ -4392,7 +4415,7 @@ function registerDevlog(program2) {
|
|
|
4392
4415
|
|
|
4393
4416
|
// src/commands/jira/acceptanceCriteria.ts
|
|
4394
4417
|
import { execSync as execSync20 } from "child_process";
|
|
4395
|
-
import
|
|
4418
|
+
import chalk48 from "chalk";
|
|
4396
4419
|
|
|
4397
4420
|
// src/commands/jira/adfToText.ts
|
|
4398
4421
|
function renderInline(node) {
|
|
@@ -4467,21 +4490,21 @@ function acceptanceCriteria(issueKey) {
|
|
|
4467
4490
|
const stderr = error.stderr;
|
|
4468
4491
|
if (stderr.includes("unauthorized")) {
|
|
4469
4492
|
console.error(
|
|
4470
|
-
|
|
4493
|
+
chalk48.red("Jira authentication expired."),
|
|
4471
4494
|
"Run",
|
|
4472
|
-
|
|
4495
|
+
chalk48.cyan("assist jira auth"),
|
|
4473
4496
|
"to re-authenticate."
|
|
4474
4497
|
);
|
|
4475
4498
|
process.exit(1);
|
|
4476
4499
|
}
|
|
4477
4500
|
}
|
|
4478
|
-
console.error(
|
|
4501
|
+
console.error(chalk48.red(`Failed to fetch ${issueKey}.`));
|
|
4479
4502
|
process.exit(1);
|
|
4480
4503
|
}
|
|
4481
4504
|
const parsed = JSON.parse(result);
|
|
4482
4505
|
const acValue = parsed?.fields?.[field];
|
|
4483
4506
|
if (!acValue) {
|
|
4484
|
-
console.log(
|
|
4507
|
+
console.log(chalk48.yellow(`No acceptance criteria found on ${issueKey}.`));
|
|
4485
4508
|
return;
|
|
4486
4509
|
}
|
|
4487
4510
|
if (typeof acValue === "string") {
|
|
@@ -4500,7 +4523,7 @@ import { execSync as execSync21 } from "child_process";
|
|
|
4500
4523
|
import Enquirer from "enquirer";
|
|
4501
4524
|
|
|
4502
4525
|
// src/shared/loadJson.ts
|
|
4503
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as
|
|
4526
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "fs";
|
|
4504
4527
|
import { homedir as homedir6 } from "os";
|
|
4505
4528
|
import { join as join16 } from "path";
|
|
4506
4529
|
function getStoreDir() {
|
|
@@ -4510,10 +4533,10 @@ function getStorePath(filename) {
|
|
|
4510
4533
|
return join16(getStoreDir(), filename);
|
|
4511
4534
|
}
|
|
4512
4535
|
function loadJson(filename) {
|
|
4513
|
-
const
|
|
4514
|
-
if (existsSync20(
|
|
4536
|
+
const path42 = getStorePath(filename);
|
|
4537
|
+
if (existsSync20(path42)) {
|
|
4515
4538
|
try {
|
|
4516
|
-
return JSON.parse(readFileSync18(
|
|
4539
|
+
return JSON.parse(readFileSync18(path42, "utf-8"));
|
|
4517
4540
|
} catch {
|
|
4518
4541
|
return {};
|
|
4519
4542
|
}
|
|
@@ -4525,19 +4548,19 @@ function saveJson(filename, data) {
|
|
|
4525
4548
|
if (!existsSync20(dir)) {
|
|
4526
4549
|
mkdirSync5(dir, { recursive: true });
|
|
4527
4550
|
}
|
|
4528
|
-
|
|
4551
|
+
writeFileSync17(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
4529
4552
|
}
|
|
4530
4553
|
|
|
4531
4554
|
// src/commands/jira/jiraAuth.ts
|
|
4532
4555
|
var CONFIG_FILE = "jira.json";
|
|
4533
4556
|
async function promptCredentials(config) {
|
|
4534
|
-
const { Input, Password } = Enquirer;
|
|
4535
|
-
const site = await new
|
|
4557
|
+
const { Input: Input2, Password } = Enquirer;
|
|
4558
|
+
const site = await new Input2({
|
|
4536
4559
|
name: "site",
|
|
4537
4560
|
message: "Jira site (e.g., mycompany.atlassian.net):",
|
|
4538
4561
|
initial: config.site
|
|
4539
4562
|
}).run();
|
|
4540
|
-
const email = await new
|
|
4563
|
+
const email = await new Input2({
|
|
4541
4564
|
name: "email",
|
|
4542
4565
|
message: "Email:",
|
|
4543
4566
|
initial: config.email
|
|
@@ -4580,7 +4603,7 @@ function registerJira(program2) {
|
|
|
4580
4603
|
|
|
4581
4604
|
// src/commands/netframework/buildTree.ts
|
|
4582
4605
|
import { readFileSync as readFileSync19 } from "fs";
|
|
4583
|
-
import
|
|
4606
|
+
import path21 from "path";
|
|
4584
4607
|
var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
|
|
4585
4608
|
function getProjectRefs(csprojPath) {
|
|
4586
4609
|
const content = readFileSync19(csprojPath, "utf-8");
|
|
@@ -4591,14 +4614,14 @@ function getProjectRefs(csprojPath) {
|
|
|
4591
4614
|
return refs;
|
|
4592
4615
|
}
|
|
4593
4616
|
function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
|
|
4594
|
-
const abs =
|
|
4595
|
-
const rel =
|
|
4617
|
+
const abs = path21.resolve(csprojPath);
|
|
4618
|
+
const rel = path21.relative(repoRoot, abs);
|
|
4596
4619
|
const node = { path: abs, relativePath: rel, children: [] };
|
|
4597
4620
|
if (visited.has(abs)) return node;
|
|
4598
4621
|
visited.add(abs);
|
|
4599
|
-
const dir =
|
|
4622
|
+
const dir = path21.dirname(abs);
|
|
4600
4623
|
for (const ref of getProjectRefs(abs)) {
|
|
4601
|
-
const childAbs =
|
|
4624
|
+
const childAbs = path21.resolve(dir, ref);
|
|
4602
4625
|
try {
|
|
4603
4626
|
readFileSync19(childAbs);
|
|
4604
4627
|
node.children.push(buildTree(childAbs, repoRoot, visited));
|
|
@@ -4626,7 +4649,7 @@ function collectAllDeps(node) {
|
|
|
4626
4649
|
|
|
4627
4650
|
// src/commands/netframework/findContainingSolutions.ts
|
|
4628
4651
|
import { readdirSync as readdirSync2, readFileSync as readFileSync20, statSync } from "fs";
|
|
4629
|
-
import
|
|
4652
|
+
import path22 from "path";
|
|
4630
4653
|
function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
4631
4654
|
if (depth > maxDepth) return [];
|
|
4632
4655
|
const results = [];
|
|
@@ -4639,7 +4662,7 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
|
4639
4662
|
for (const entry of entries) {
|
|
4640
4663
|
if (entry.startsWith(".") || entry === "node_modules" || entry === "packages")
|
|
4641
4664
|
continue;
|
|
4642
|
-
const full =
|
|
4665
|
+
const full = path22.join(dir, entry);
|
|
4643
4666
|
try {
|
|
4644
4667
|
const stat = statSync(full);
|
|
4645
4668
|
if (stat.isFile() && entry.endsWith(".sln")) {
|
|
@@ -4653,8 +4676,8 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
|
4653
4676
|
return results;
|
|
4654
4677
|
}
|
|
4655
4678
|
function findContainingSolutions(csprojPath, repoRoot) {
|
|
4656
|
-
const csprojAbs =
|
|
4657
|
-
const csprojBasename =
|
|
4679
|
+
const csprojAbs = path22.resolve(csprojPath);
|
|
4680
|
+
const csprojBasename = path22.basename(csprojAbs);
|
|
4658
4681
|
const slnFiles = findSlnFiles(repoRoot, 3);
|
|
4659
4682
|
const matches = [];
|
|
4660
4683
|
const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
|
|
@@ -4662,7 +4685,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
|
|
|
4662
4685
|
try {
|
|
4663
4686
|
const content = readFileSync20(sln, "utf-8");
|
|
4664
4687
|
if (pattern2.test(content)) {
|
|
4665
|
-
matches.push(
|
|
4688
|
+
matches.push(path22.relative(repoRoot, sln));
|
|
4666
4689
|
}
|
|
4667
4690
|
} catch {
|
|
4668
4691
|
}
|
|
@@ -4674,30 +4697,30 @@ function escapeRegex(s) {
|
|
|
4674
4697
|
}
|
|
4675
4698
|
|
|
4676
4699
|
// src/commands/netframework/printTree.ts
|
|
4677
|
-
import
|
|
4700
|
+
import chalk49 from "chalk";
|
|
4678
4701
|
function printNodes(nodes, prefix2) {
|
|
4679
4702
|
for (let i = 0; i < nodes.length; i++) {
|
|
4680
4703
|
const isLast = i === nodes.length - 1;
|
|
4681
4704
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4682
4705
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
4683
4706
|
const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
|
|
4684
|
-
const label2 = isMissing ?
|
|
4707
|
+
const label2 = isMissing ? chalk49.red(nodes[i].relativePath) : nodes[i].relativePath;
|
|
4685
4708
|
console.log(`${prefix2}${connector}${label2}`);
|
|
4686
4709
|
printNodes(nodes[i].children, prefix2 + childPrefix);
|
|
4687
4710
|
}
|
|
4688
4711
|
}
|
|
4689
4712
|
function printTree(tree, totalCount, solutions) {
|
|
4690
|
-
console.log(
|
|
4691
|
-
console.log(
|
|
4713
|
+
console.log(chalk49.bold("\nProject Dependency Tree"));
|
|
4714
|
+
console.log(chalk49.cyan(tree.relativePath));
|
|
4692
4715
|
printNodes(tree.children, "");
|
|
4693
|
-
console.log(
|
|
4716
|
+
console.log(chalk49.dim(`
|
|
4694
4717
|
${totalCount} projects total (including root)`));
|
|
4695
|
-
console.log(
|
|
4718
|
+
console.log(chalk49.bold("\nSolution Membership"));
|
|
4696
4719
|
if (solutions.length === 0) {
|
|
4697
|
-
console.log(
|
|
4720
|
+
console.log(chalk49.yellow(" Not found in any .sln"));
|
|
4698
4721
|
} else {
|
|
4699
4722
|
for (const sln of solutions) {
|
|
4700
|
-
console.log(` ${
|
|
4723
|
+
console.log(` ${chalk49.green(sln)}`);
|
|
4701
4724
|
}
|
|
4702
4725
|
}
|
|
4703
4726
|
console.log();
|
|
@@ -4725,33 +4748,33 @@ function printJson(tree, totalCount, solutions) {
|
|
|
4725
4748
|
|
|
4726
4749
|
// src/commands/netframework/resolveCsproj.ts
|
|
4727
4750
|
import { existsSync as existsSync22 } from "fs";
|
|
4728
|
-
import
|
|
4729
|
-
import
|
|
4751
|
+
import path24 from "path";
|
|
4752
|
+
import chalk50 from "chalk";
|
|
4730
4753
|
|
|
4731
4754
|
// src/commands/netframework/findRepoRoot.ts
|
|
4732
4755
|
import { existsSync as existsSync21 } from "fs";
|
|
4733
|
-
import
|
|
4756
|
+
import path23 from "path";
|
|
4734
4757
|
function findRepoRoot(dir) {
|
|
4735
4758
|
let current = dir;
|
|
4736
|
-
while (current !==
|
|
4737
|
-
if (existsSync21(
|
|
4759
|
+
while (current !== path23.dirname(current)) {
|
|
4760
|
+
if (existsSync21(path23.join(current, ".git"))) {
|
|
4738
4761
|
return current;
|
|
4739
4762
|
}
|
|
4740
|
-
current =
|
|
4763
|
+
current = path23.dirname(current);
|
|
4741
4764
|
}
|
|
4742
4765
|
return null;
|
|
4743
4766
|
}
|
|
4744
4767
|
|
|
4745
4768
|
// src/commands/netframework/resolveCsproj.ts
|
|
4746
4769
|
function resolveCsproj(csprojPath) {
|
|
4747
|
-
const resolved =
|
|
4770
|
+
const resolved = path24.resolve(csprojPath);
|
|
4748
4771
|
if (!existsSync22(resolved)) {
|
|
4749
|
-
console.error(
|
|
4772
|
+
console.error(chalk50.red(`File not found: ${resolved}`));
|
|
4750
4773
|
process.exit(1);
|
|
4751
4774
|
}
|
|
4752
|
-
const repoRoot = findRepoRoot(
|
|
4775
|
+
const repoRoot = findRepoRoot(path24.dirname(resolved));
|
|
4753
4776
|
if (!repoRoot) {
|
|
4754
|
-
console.error(
|
|
4777
|
+
console.error(chalk50.red("Could not find git repository root"));
|
|
4755
4778
|
process.exit(1);
|
|
4756
4779
|
}
|
|
4757
4780
|
return { resolved, repoRoot };
|
|
@@ -4771,12 +4794,12 @@ async function deps(csprojPath, options2) {
|
|
|
4771
4794
|
}
|
|
4772
4795
|
|
|
4773
4796
|
// src/commands/netframework/inSln.ts
|
|
4774
|
-
import
|
|
4797
|
+
import chalk51 from "chalk";
|
|
4775
4798
|
async function inSln(csprojPath) {
|
|
4776
4799
|
const { resolved, repoRoot } = resolveCsproj(csprojPath);
|
|
4777
4800
|
const solutions = findContainingSolutions(resolved, repoRoot);
|
|
4778
4801
|
if (solutions.length === 0) {
|
|
4779
|
-
console.log(
|
|
4802
|
+
console.log(chalk51.yellow("Not found in any .sln file"));
|
|
4780
4803
|
process.exit(1);
|
|
4781
4804
|
}
|
|
4782
4805
|
for (const sln of solutions) {
|
|
@@ -4792,7 +4815,7 @@ function registerNetframework(program2) {
|
|
|
4792
4815
|
}
|
|
4793
4816
|
|
|
4794
4817
|
// src/commands/news/add/index.ts
|
|
4795
|
-
import
|
|
4818
|
+
import chalk52 from "chalk";
|
|
4796
4819
|
import enquirer5 from "enquirer";
|
|
4797
4820
|
async function add2(url) {
|
|
4798
4821
|
if (!url) {
|
|
@@ -4815,17 +4838,17 @@ async function add2(url) {
|
|
|
4815
4838
|
const news = config.news ?? {};
|
|
4816
4839
|
const feeds = news.feeds ?? [];
|
|
4817
4840
|
if (feeds.includes(url)) {
|
|
4818
|
-
console.log(
|
|
4841
|
+
console.log(chalk52.yellow("Feed already exists in config"));
|
|
4819
4842
|
return;
|
|
4820
4843
|
}
|
|
4821
4844
|
feeds.push(url);
|
|
4822
4845
|
config.news = { ...news, feeds };
|
|
4823
4846
|
saveGlobalConfig(config);
|
|
4824
|
-
console.log(
|
|
4847
|
+
console.log(chalk52.green(`Added feed: ${url}`));
|
|
4825
4848
|
}
|
|
4826
4849
|
|
|
4827
4850
|
// src/commands/news/web/handleRequest.ts
|
|
4828
|
-
import
|
|
4851
|
+
import chalk53 from "chalk";
|
|
4829
4852
|
|
|
4830
4853
|
// src/commands/news/web/shared.ts
|
|
4831
4854
|
import { decodeHTML } from "entities";
|
|
@@ -4961,17 +4984,17 @@ function prefetch() {
|
|
|
4961
4984
|
const config = loadConfig();
|
|
4962
4985
|
const total = config.news.feeds.length;
|
|
4963
4986
|
if (total === 0) return;
|
|
4964
|
-
process.stdout.write(
|
|
4987
|
+
process.stdout.write(chalk53.dim(`Fetching ${total} feed(s)\u2026 `));
|
|
4965
4988
|
prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
|
|
4966
4989
|
const width = 20;
|
|
4967
4990
|
const filled = Math.round(done2 / t * width);
|
|
4968
4991
|
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
4969
4992
|
process.stdout.write(
|
|
4970
|
-
`\r${
|
|
4993
|
+
`\r${chalk53.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
|
|
4971
4994
|
);
|
|
4972
4995
|
}).then((items) => {
|
|
4973
4996
|
process.stdout.write(
|
|
4974
|
-
`\r${
|
|
4997
|
+
`\r${chalk53.green(`Fetched ${items.length} items from ${total} feed(s)`)}
|
|
4975
4998
|
`
|
|
4976
4999
|
);
|
|
4977
5000
|
cachedItems = items;
|
|
@@ -5017,7 +5040,7 @@ function registerNews(program2) {
|
|
|
5017
5040
|
|
|
5018
5041
|
// src/commands/prs/comment.ts
|
|
5019
5042
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
5020
|
-
import { unlinkSync as unlinkSync3, writeFileSync as
|
|
5043
|
+
import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync18 } from "fs";
|
|
5021
5044
|
import { tmpdir as tmpdir2 } from "os";
|
|
5022
5045
|
import { join as join17 } from "path";
|
|
5023
5046
|
|
|
@@ -5086,13 +5109,13 @@ function validateLine(line) {
|
|
|
5086
5109
|
process.exit(1);
|
|
5087
5110
|
}
|
|
5088
5111
|
}
|
|
5089
|
-
function comment(
|
|
5112
|
+
function comment(path42, line, body) {
|
|
5090
5113
|
validateBody(body);
|
|
5091
5114
|
validateLine(line);
|
|
5092
5115
|
try {
|
|
5093
5116
|
const prId = getCurrentPrNodeId();
|
|
5094
5117
|
const queryFile = join17(tmpdir2(), `gh-query-${Date.now()}.graphql`);
|
|
5095
|
-
|
|
5118
|
+
writeFileSync18(queryFile, MUTATION);
|
|
5096
5119
|
try {
|
|
5097
5120
|
const result = spawnSync2(
|
|
5098
5121
|
"gh",
|
|
@@ -5106,7 +5129,7 @@ function comment(path43, line, body) {
|
|
|
5106
5129
|
"-f",
|
|
5107
5130
|
`body=${body}`,
|
|
5108
5131
|
"-f",
|
|
5109
|
-
`path=${
|
|
5132
|
+
`path=${path42}`,
|
|
5110
5133
|
"-F",
|
|
5111
5134
|
`line=${line}`
|
|
5112
5135
|
],
|
|
@@ -5115,7 +5138,7 @@ function comment(path43, line, body) {
|
|
|
5115
5138
|
if (result.status !== 0) {
|
|
5116
5139
|
throw new Error(result.stderr || result.stdout);
|
|
5117
5140
|
}
|
|
5118
|
-
console.log(`Added review comment on ${
|
|
5141
|
+
console.log(`Added review comment on ${path42}:${line}`);
|
|
5119
5142
|
} finally {
|
|
5120
5143
|
unlinkSync3(queryFile);
|
|
5121
5144
|
}
|
|
@@ -5134,7 +5157,7 @@ import { execSync as execSync24 } from "child_process";
|
|
|
5134
5157
|
|
|
5135
5158
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
5136
5159
|
import { execSync as execSync23 } from "child_process";
|
|
5137
|
-
import { unlinkSync as unlinkSync5, writeFileSync as
|
|
5160
|
+
import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "fs";
|
|
5138
5161
|
import { tmpdir as tmpdir3 } from "os";
|
|
5139
5162
|
import { join as join19 } from "path";
|
|
5140
5163
|
|
|
@@ -5171,7 +5194,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
5171
5194
|
function resolveThread(threadId) {
|
|
5172
5195
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
5173
5196
|
const queryFile = join19(tmpdir3(), `gh-mutation-${Date.now()}.graphql`);
|
|
5174
|
-
|
|
5197
|
+
writeFileSync19(queryFile, mutation);
|
|
5175
5198
|
try {
|
|
5176
5199
|
execSync23(
|
|
5177
5200
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
@@ -5252,19 +5275,19 @@ function fixed(commentId, sha) {
|
|
|
5252
5275
|
}
|
|
5253
5276
|
|
|
5254
5277
|
// src/commands/prs/listComments/index.ts
|
|
5255
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync6, writeFileSync as
|
|
5278
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync6, writeFileSync as writeFileSync21 } from "fs";
|
|
5256
5279
|
import { join as join21 } from "path";
|
|
5257
5280
|
import { stringify } from "yaml";
|
|
5258
5281
|
|
|
5259
5282
|
// src/commands/prs/fetchThreadIds.ts
|
|
5260
5283
|
import { execSync as execSync25 } from "child_process";
|
|
5261
|
-
import { unlinkSync as unlinkSync6, writeFileSync as
|
|
5284
|
+
import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync20 } from "fs";
|
|
5262
5285
|
import { tmpdir as tmpdir4 } from "os";
|
|
5263
5286
|
import { join as join20 } from "path";
|
|
5264
5287
|
var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
|
|
5265
5288
|
function fetchThreadIds(org, repo, prNumber) {
|
|
5266
5289
|
const queryFile = join20(tmpdir4(), `gh-query-${Date.now()}.graphql`);
|
|
5267
|
-
|
|
5290
|
+
writeFileSync20(queryFile, THREAD_QUERY);
|
|
5268
5291
|
try {
|
|
5269
5292
|
const result = execSync25(
|
|
5270
5293
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
@@ -5332,20 +5355,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
5332
5355
|
}
|
|
5333
5356
|
|
|
5334
5357
|
// src/commands/prs/listComments/printComments.ts
|
|
5335
|
-
import
|
|
5358
|
+
import chalk54 from "chalk";
|
|
5336
5359
|
function formatForHuman(comment2) {
|
|
5337
5360
|
if (comment2.type === "review") {
|
|
5338
|
-
const stateColor = comment2.state === "APPROVED" ?
|
|
5361
|
+
const stateColor = comment2.state === "APPROVED" ? chalk54.green : comment2.state === "CHANGES_REQUESTED" ? chalk54.red : chalk54.yellow;
|
|
5339
5362
|
return [
|
|
5340
|
-
`${
|
|
5363
|
+
`${chalk54.cyan("Review")} by ${chalk54.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
|
|
5341
5364
|
comment2.body,
|
|
5342
5365
|
""
|
|
5343
5366
|
].join("\n");
|
|
5344
5367
|
}
|
|
5345
5368
|
const location = comment2.line ? `:${comment2.line}` : "";
|
|
5346
5369
|
return [
|
|
5347
|
-
`${
|
|
5348
|
-
|
|
5370
|
+
`${chalk54.cyan("Line comment")} by ${chalk54.bold(comment2.user)} on ${chalk54.dim(`${comment2.path}${location}`)}`,
|
|
5371
|
+
chalk54.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
5349
5372
|
comment2.body,
|
|
5350
5373
|
""
|
|
5351
5374
|
].join("\n");
|
|
@@ -5387,7 +5410,7 @@ function writeCommentsCache(prNumber, comments) {
|
|
|
5387
5410
|
comments
|
|
5388
5411
|
};
|
|
5389
5412
|
const cachePath = join21(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
5390
|
-
|
|
5413
|
+
writeFileSync21(cachePath, stringify(cacheData));
|
|
5391
5414
|
}
|
|
5392
5415
|
function handleKnownErrors(error) {
|
|
5393
5416
|
if (isGhNotInstalled(error)) {
|
|
@@ -5435,13 +5458,13 @@ import { execSync as execSync27 } from "child_process";
|
|
|
5435
5458
|
import enquirer6 from "enquirer";
|
|
5436
5459
|
|
|
5437
5460
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
5438
|
-
import
|
|
5461
|
+
import chalk55 from "chalk";
|
|
5439
5462
|
var STATUS_MAP = {
|
|
5440
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
5441
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
5463
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk55.magenta("merged"), date: pr.mergedAt } : null,
|
|
5464
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk55.red("closed"), date: pr.closedAt } : null
|
|
5442
5465
|
};
|
|
5443
5466
|
function defaultStatus(pr) {
|
|
5444
|
-
return { label:
|
|
5467
|
+
return { label: chalk55.green("opened"), date: pr.createdAt };
|
|
5445
5468
|
}
|
|
5446
5469
|
function getStatus2(pr) {
|
|
5447
5470
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -5450,11 +5473,11 @@ function formatDate(dateStr) {
|
|
|
5450
5473
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
5451
5474
|
}
|
|
5452
5475
|
function formatPrHeader(pr, status2) {
|
|
5453
|
-
return `${
|
|
5476
|
+
return `${chalk55.cyan(`#${pr.number}`)} ${pr.title} ${chalk55.dim(`(${pr.author.login},`)} ${status2.label} ${chalk55.dim(`${formatDate(status2.date)})`)}`;
|
|
5454
5477
|
}
|
|
5455
5478
|
function logPrDetails(pr) {
|
|
5456
5479
|
console.log(
|
|
5457
|
-
|
|
5480
|
+
chalk55.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
5458
5481
|
);
|
|
5459
5482
|
console.log();
|
|
5460
5483
|
}
|
|
@@ -5614,17 +5637,425 @@ function registerPrs(program2) {
|
|
|
5614
5637
|
prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason) => {
|
|
5615
5638
|
wontfix(Number.parseInt(commentId, 10), reason);
|
|
5616
5639
|
});
|
|
5617
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
5618
|
-
comment(
|
|
5640
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path42, line, body) => {
|
|
5641
|
+
comment(path42, Number.parseInt(line, 10), body);
|
|
5642
|
+
});
|
|
5643
|
+
}
|
|
5644
|
+
|
|
5645
|
+
// src/commands/ravendb/ravendbAuth.ts
|
|
5646
|
+
import chalk60 from "chalk";
|
|
5647
|
+
|
|
5648
|
+
// src/commands/ravendb/loadConnections.ts
|
|
5649
|
+
function loadConnections() {
|
|
5650
|
+
const raw = loadGlobalConfigRaw();
|
|
5651
|
+
const ravendb = raw.ravendb;
|
|
5652
|
+
return ravendb?.connections ?? [];
|
|
5653
|
+
}
|
|
5654
|
+
function saveConnections(connections) {
|
|
5655
|
+
const raw = loadGlobalConfigRaw();
|
|
5656
|
+
const ravendb = raw.ravendb ?? {};
|
|
5657
|
+
ravendb.connections = connections;
|
|
5658
|
+
raw.ravendb = ravendb;
|
|
5659
|
+
saveGlobalConfig(raw);
|
|
5660
|
+
}
|
|
5661
|
+
|
|
5662
|
+
// src/commands/ravendb/promptConnection.ts
|
|
5663
|
+
import chalk58 from "chalk";
|
|
5664
|
+
import Enquirer3 from "enquirer";
|
|
5665
|
+
|
|
5666
|
+
// src/commands/ravendb/selectOpSecret.ts
|
|
5667
|
+
import chalk57 from "chalk";
|
|
5668
|
+
import Enquirer2 from "enquirer";
|
|
5669
|
+
|
|
5670
|
+
// src/commands/ravendb/searchItems.ts
|
|
5671
|
+
import { execSync as execSync29 } from "child_process";
|
|
5672
|
+
import chalk56 from "chalk";
|
|
5673
|
+
function opExec(args) {
|
|
5674
|
+
return execSync29(`op ${args}`, {
|
|
5675
|
+
encoding: "utf-8",
|
|
5676
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5677
|
+
}).trim();
|
|
5678
|
+
}
|
|
5679
|
+
function searchItems(search) {
|
|
5680
|
+
let items;
|
|
5681
|
+
try {
|
|
5682
|
+
items = JSON.parse(opExec("item list --format=json"));
|
|
5683
|
+
} catch {
|
|
5684
|
+
console.error(
|
|
5685
|
+
chalk56.red(
|
|
5686
|
+
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
5687
|
+
)
|
|
5688
|
+
);
|
|
5689
|
+
process.exit(1);
|
|
5690
|
+
}
|
|
5691
|
+
const lower = search.toLowerCase();
|
|
5692
|
+
return items.filter((i) => i.title.toLowerCase().includes(lower));
|
|
5693
|
+
}
|
|
5694
|
+
function getItemFields(itemId) {
|
|
5695
|
+
try {
|
|
5696
|
+
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
5697
|
+
return item.fields.filter((f) => f.reference && f.label);
|
|
5698
|
+
} catch {
|
|
5699
|
+
console.error(chalk56.red("Failed to get item details from 1Password."));
|
|
5700
|
+
process.exit(1);
|
|
5701
|
+
}
|
|
5702
|
+
}
|
|
5703
|
+
|
|
5704
|
+
// src/commands/ravendb/selectOpSecret.ts
|
|
5705
|
+
var { Input, Select } = Enquirer2;
|
|
5706
|
+
async function selectOne(message, choices) {
|
|
5707
|
+
if (choices.length === 1) return choices[0].value;
|
|
5708
|
+
const selected = await new Select({ name: "choice", message, choices }).run();
|
|
5709
|
+
return choices.find((c) => c.name === selected)?.value ?? selected;
|
|
5710
|
+
}
|
|
5711
|
+
async function selectOpSecret(searchTerm) {
|
|
5712
|
+
const search = searchTerm ?? await new Input({
|
|
5713
|
+
name: "search",
|
|
5714
|
+
message: "Search 1Password for API key item:"
|
|
5715
|
+
}).run();
|
|
5716
|
+
const items = searchItems(search);
|
|
5717
|
+
if (items.length === 0) {
|
|
5718
|
+
console.error(chalk57.red(`No items found matching "${search}".`));
|
|
5719
|
+
process.exit(1);
|
|
5720
|
+
}
|
|
5721
|
+
const itemId = await selectOne(
|
|
5722
|
+
"Select item:",
|
|
5723
|
+
items.map((i) => ({ name: `${i.title} (${i.vault.name})`, value: i.id }))
|
|
5724
|
+
);
|
|
5725
|
+
const fields = getItemFields(itemId);
|
|
5726
|
+
if (fields.length === 0) {
|
|
5727
|
+
console.error(chalk57.red("No fields with references found on this item."));
|
|
5728
|
+
process.exit(1);
|
|
5729
|
+
}
|
|
5730
|
+
const ref = await selectOne(
|
|
5731
|
+
"Select field:",
|
|
5732
|
+
fields.map((f) => ({ name: f.label, value: f.reference }))
|
|
5733
|
+
);
|
|
5734
|
+
return ref;
|
|
5735
|
+
}
|
|
5736
|
+
|
|
5737
|
+
// src/commands/ravendb/promptConnection.ts
|
|
5738
|
+
async function promptConnection(existingNames) {
|
|
5739
|
+
const { Input: Input2 } = Enquirer3;
|
|
5740
|
+
const name = await new Input2({
|
|
5741
|
+
name: "name",
|
|
5742
|
+
message: "Connection name:"
|
|
5743
|
+
}).run();
|
|
5744
|
+
if (existingNames.includes(name)) {
|
|
5745
|
+
console.error(chalk58.red(`Connection "${name}" already exists.`));
|
|
5746
|
+
process.exit(1);
|
|
5747
|
+
}
|
|
5748
|
+
const url = await new Input2({
|
|
5749
|
+
name: "url",
|
|
5750
|
+
message: "RavenDB base URL (e.g. https://host.ravenhq.com):"
|
|
5751
|
+
}).run();
|
|
5752
|
+
const database = await new Input2({
|
|
5753
|
+
name: "database",
|
|
5754
|
+
message: "Database name:"
|
|
5755
|
+
}).run();
|
|
5756
|
+
if (!name || !url || !database) {
|
|
5757
|
+
console.error(chalk58.red("All fields are required."));
|
|
5758
|
+
process.exit(1);
|
|
5759
|
+
}
|
|
5760
|
+
const apiKeyRef = await selectOpSecret();
|
|
5761
|
+
console.log(chalk58.dim(`Using: ${apiKeyRef}`));
|
|
5762
|
+
return { name, url, database, apiKeyRef };
|
|
5763
|
+
}
|
|
5764
|
+
|
|
5765
|
+
// src/commands/ravendb/ravendbSetConnection.ts
|
|
5766
|
+
import chalk59 from "chalk";
|
|
5767
|
+
function ravendbSetConnection(name) {
|
|
5768
|
+
const raw = loadGlobalConfigRaw();
|
|
5769
|
+
const ravendb = raw.ravendb ?? {};
|
|
5770
|
+
const connections = ravendb.connections ?? [];
|
|
5771
|
+
if (!connections.some((c) => c.name === name)) {
|
|
5772
|
+
console.error(chalk59.red(`Connection "${name}" not found.`));
|
|
5773
|
+
console.error(
|
|
5774
|
+
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
5775
|
+
);
|
|
5776
|
+
process.exit(1);
|
|
5777
|
+
}
|
|
5778
|
+
ravendb.defaultConnection = name;
|
|
5779
|
+
raw.ravendb = ravendb;
|
|
5780
|
+
saveGlobalConfig(raw);
|
|
5781
|
+
console.log(`Default connection set to "${name}".`);
|
|
5782
|
+
}
|
|
5783
|
+
|
|
5784
|
+
// src/commands/ravendb/ravendbAuth.ts
|
|
5785
|
+
async function ravendbAuth(options2) {
|
|
5786
|
+
const connections = loadConnections();
|
|
5787
|
+
if (options2.list) {
|
|
5788
|
+
if (connections.length === 0) {
|
|
5789
|
+
console.log("No RavenDB connections configured.");
|
|
5790
|
+
return;
|
|
5791
|
+
}
|
|
5792
|
+
for (const c of connections) {
|
|
5793
|
+
console.log(
|
|
5794
|
+
`${chalk60.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`
|
|
5795
|
+
);
|
|
5796
|
+
}
|
|
5797
|
+
return;
|
|
5798
|
+
}
|
|
5799
|
+
if (options2.remove) {
|
|
5800
|
+
const filtered = connections.filter((c) => c.name !== options2.remove);
|
|
5801
|
+
if (filtered.length === connections.length) {
|
|
5802
|
+
console.error(chalk60.red(`Connection "${options2.remove}" not found.`));
|
|
5803
|
+
process.exit(1);
|
|
5804
|
+
}
|
|
5805
|
+
saveConnections(filtered);
|
|
5806
|
+
console.log(`Removed connection "${options2.remove}".`);
|
|
5807
|
+
return;
|
|
5808
|
+
}
|
|
5809
|
+
const isFirst = connections.length === 0;
|
|
5810
|
+
const newConnection = await promptConnection(connections.map((c) => c.name));
|
|
5811
|
+
connections.push(newConnection);
|
|
5812
|
+
saveConnections(connections);
|
|
5813
|
+
if (isFirst) {
|
|
5814
|
+
ravendbSetConnection(newConnection.name);
|
|
5815
|
+
}
|
|
5816
|
+
console.log(`Connection "${newConnection.name}" saved.`);
|
|
5817
|
+
}
|
|
5818
|
+
|
|
5819
|
+
// src/commands/ravendb/ravendbCollections.ts
|
|
5820
|
+
import chalk64 from "chalk";
|
|
5821
|
+
|
|
5822
|
+
// src/commands/ravendb/ravenFetch.ts
|
|
5823
|
+
import chalk62 from "chalk";
|
|
5824
|
+
|
|
5825
|
+
// src/commands/ravendb/getAccessToken.ts
|
|
5826
|
+
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
5827
|
+
var TOKEN_CACHE_MS = 50 * 60 * 1e3;
|
|
5828
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
5829
|
+
function clearCachedToken(apiKey) {
|
|
5830
|
+
tokenCache.delete(apiKey);
|
|
5831
|
+
}
|
|
5832
|
+
async function getAccessToken(apiKey) {
|
|
5833
|
+
const now = Date.now();
|
|
5834
|
+
const cached2 = tokenCache.get(apiKey);
|
|
5835
|
+
if (cached2 && now < cached2.expiry) {
|
|
5836
|
+
return cached2.token;
|
|
5837
|
+
}
|
|
5838
|
+
const response = await fetch(OAUTH_URL, {
|
|
5839
|
+
method: "GET",
|
|
5840
|
+
headers: {
|
|
5841
|
+
"Api-Key": apiKey,
|
|
5842
|
+
grant_type: "client_credentials"
|
|
5843
|
+
}
|
|
5844
|
+
});
|
|
5845
|
+
if (!response.ok) {
|
|
5846
|
+
const errorText = await response.text();
|
|
5847
|
+
throw new Error(
|
|
5848
|
+
`Failed to get access token: ${response.status} ${response.statusText}
|
|
5849
|
+
${errorText}`
|
|
5850
|
+
);
|
|
5851
|
+
}
|
|
5852
|
+
const tokenData = await response.json();
|
|
5853
|
+
const token = JSON.stringify(tokenData);
|
|
5854
|
+
tokenCache.set(apiKey, { token, expiry: now + TOKEN_CACHE_MS });
|
|
5855
|
+
return token;
|
|
5856
|
+
}
|
|
5857
|
+
|
|
5858
|
+
// src/commands/ravendb/resolveOpSecret.ts
|
|
5859
|
+
import { execSync as execSync30 } from "child_process";
|
|
5860
|
+
import chalk61 from "chalk";
|
|
5861
|
+
function resolveOpSecret(reference) {
|
|
5862
|
+
if (!reference.startsWith("op://")) {
|
|
5863
|
+
console.error(chalk61.red(`Invalid secret reference: must start with op://`));
|
|
5864
|
+
process.exit(1);
|
|
5865
|
+
}
|
|
5866
|
+
try {
|
|
5867
|
+
return execSync30(`op read "${reference}"`, {
|
|
5868
|
+
encoding: "utf-8",
|
|
5869
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5870
|
+
}).trim();
|
|
5871
|
+
} catch {
|
|
5872
|
+
console.error(
|
|
5873
|
+
chalk61.red(
|
|
5874
|
+
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
5875
|
+
)
|
|
5876
|
+
);
|
|
5877
|
+
process.exit(1);
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
|
|
5881
|
+
// src/commands/ravendb/ravenFetch.ts
|
|
5882
|
+
async function ravenFetch(connection, path42) {
|
|
5883
|
+
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
5884
|
+
let accessToken = await getAccessToken(apiKey);
|
|
5885
|
+
const url = `${connection.url}${path42}`;
|
|
5886
|
+
const headers = {
|
|
5887
|
+
Authorization: `Bearer ${accessToken}`,
|
|
5888
|
+
"Content-Type": "application/json"
|
|
5889
|
+
};
|
|
5890
|
+
let response = await fetch(url, { headers });
|
|
5891
|
+
if (response.status === 401) {
|
|
5892
|
+
clearCachedToken(apiKey);
|
|
5893
|
+
accessToken = await getAccessToken(apiKey);
|
|
5894
|
+
headers.Authorization = `Bearer ${accessToken}`;
|
|
5895
|
+
response = await fetch(url, { headers });
|
|
5896
|
+
}
|
|
5897
|
+
if (!response.ok) {
|
|
5898
|
+
const body = await response.text();
|
|
5899
|
+
console.error(
|
|
5900
|
+
chalk62.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
5901
|
+
);
|
|
5902
|
+
console.error(body.substring(0, 500));
|
|
5903
|
+
process.exit(1);
|
|
5904
|
+
}
|
|
5905
|
+
return response.json();
|
|
5906
|
+
}
|
|
5907
|
+
|
|
5908
|
+
// src/commands/ravendb/resolveConnection.ts
|
|
5909
|
+
import chalk63 from "chalk";
|
|
5910
|
+
function loadRavendb() {
|
|
5911
|
+
const raw = loadGlobalConfigRaw();
|
|
5912
|
+
const ravendb = raw.ravendb;
|
|
5913
|
+
return {
|
|
5914
|
+
connections: ravendb?.connections ?? [],
|
|
5915
|
+
defaultConnection: ravendb?.defaultConnection
|
|
5916
|
+
};
|
|
5917
|
+
}
|
|
5918
|
+
function resolveConnection(name) {
|
|
5919
|
+
const { connections, defaultConnection } = loadRavendb();
|
|
5920
|
+
const connectionName = name ?? defaultConnection;
|
|
5921
|
+
if (!connectionName) {
|
|
5922
|
+
console.error(
|
|
5923
|
+
chalk63.red(
|
|
5924
|
+
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
5925
|
+
)
|
|
5926
|
+
);
|
|
5927
|
+
process.exit(1);
|
|
5928
|
+
}
|
|
5929
|
+
const connection = connections.find((c) => c.name === connectionName);
|
|
5930
|
+
if (!connection) {
|
|
5931
|
+
console.error(chalk63.red(`Connection "${connectionName}" not found.`));
|
|
5932
|
+
console.error(
|
|
5933
|
+
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
5934
|
+
);
|
|
5935
|
+
console.error("Run assist ravendb auth to add a connection.");
|
|
5936
|
+
process.exit(1);
|
|
5937
|
+
}
|
|
5938
|
+
return connection;
|
|
5939
|
+
}
|
|
5940
|
+
function resolveArgs(first, second) {
|
|
5941
|
+
const { connections } = loadRavendb();
|
|
5942
|
+
const isConnection = first && connections.some((c) => c.name === first);
|
|
5943
|
+
if (isConnection) {
|
|
5944
|
+
return { connection: resolveConnection(first), collection: second };
|
|
5945
|
+
}
|
|
5946
|
+
return { connection: resolveConnection(void 0), collection: first };
|
|
5947
|
+
}
|
|
5948
|
+
|
|
5949
|
+
// src/commands/ravendb/ravendbCollections.ts
|
|
5950
|
+
async function ravendbCollections(connectionName) {
|
|
5951
|
+
const connection = resolveConnection(connectionName);
|
|
5952
|
+
const data = await ravenFetch(
|
|
5953
|
+
connection,
|
|
5954
|
+
`/databases/${encodeURIComponent(connection.database)}/collections/stats`
|
|
5955
|
+
);
|
|
5956
|
+
const collections = data.Collections ?? [];
|
|
5957
|
+
if (collections.length === 0) {
|
|
5958
|
+
console.log("No collections found.");
|
|
5959
|
+
return;
|
|
5960
|
+
}
|
|
5961
|
+
for (const c of collections) {
|
|
5962
|
+
console.log(`${chalk64.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
5963
|
+
}
|
|
5964
|
+
}
|
|
5965
|
+
|
|
5966
|
+
// src/commands/ravendb/ravendbQuery.ts
|
|
5967
|
+
import chalk66 from "chalk";
|
|
5968
|
+
|
|
5969
|
+
// src/commands/ravendb/fetchAllPages.ts
|
|
5970
|
+
import chalk65 from "chalk";
|
|
5971
|
+
|
|
5972
|
+
// src/commands/ravendb/buildQueryPath.ts
|
|
5973
|
+
function buildQueryPath(opts) {
|
|
5974
|
+
const db = encodeURIComponent(opts.db);
|
|
5975
|
+
let path42;
|
|
5976
|
+
if (opts.collection) {
|
|
5977
|
+
path42 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
5978
|
+
} else {
|
|
5979
|
+
path42 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
5980
|
+
}
|
|
5981
|
+
if (opts.query) {
|
|
5982
|
+
path42 += `&query=${encodeURIComponent(opts.query)}`;
|
|
5983
|
+
}
|
|
5984
|
+
return path42;
|
|
5985
|
+
}
|
|
5986
|
+
|
|
5987
|
+
// src/commands/ravendb/fetchAllPages.ts
|
|
5988
|
+
async function fetchAllPages(connection, opts) {
|
|
5989
|
+
const allResults = [];
|
|
5990
|
+
let start3 = 0;
|
|
5991
|
+
while (true) {
|
|
5992
|
+
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
5993
|
+
const path42 = buildQueryPath({
|
|
5994
|
+
db: connection.database,
|
|
5995
|
+
collection: opts.collection,
|
|
5996
|
+
start: start3,
|
|
5997
|
+
pageSize: effectivePageSize,
|
|
5998
|
+
sort: opts.sort,
|
|
5999
|
+
query: opts.query
|
|
6000
|
+
});
|
|
6001
|
+
const data = await ravenFetch(connection, path42);
|
|
6002
|
+
const results = data.Results ?? [];
|
|
6003
|
+
const totalResults = data.TotalResults ?? 0;
|
|
6004
|
+
if (results.length === 0) break;
|
|
6005
|
+
allResults.push(...results);
|
|
6006
|
+
start3 += results.length;
|
|
6007
|
+
process.stderr.write(
|
|
6008
|
+
`\r${chalk65.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
6009
|
+
);
|
|
6010
|
+
if (start3 >= totalResults) break;
|
|
6011
|
+
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
6012
|
+
}
|
|
6013
|
+
if (allResults.length > 0) {
|
|
6014
|
+
process.stderr.write("\n");
|
|
6015
|
+
}
|
|
6016
|
+
return allResults;
|
|
6017
|
+
}
|
|
6018
|
+
|
|
6019
|
+
// src/commands/ravendb/ravendbQuery.ts
|
|
6020
|
+
async function ravendbQuery(connectionName, collection, options2) {
|
|
6021
|
+
const resolved = resolveArgs(connectionName, collection);
|
|
6022
|
+
if (!resolved.collection && !options2.query) {
|
|
6023
|
+
console.error(chalk66.red("Provide a collection name or --query filter."));
|
|
6024
|
+
process.exit(1);
|
|
6025
|
+
}
|
|
6026
|
+
const { collection: col } = resolved;
|
|
6027
|
+
const connection = resolved.connection;
|
|
6028
|
+
const allResults = await fetchAllPages(connection, {
|
|
6029
|
+
collection: col,
|
|
6030
|
+
pageSize: Number.parseInt(options2.pageSize ?? "25", 10),
|
|
6031
|
+
sort: options2.sort ?? "-@metadata.Last-Modified",
|
|
6032
|
+
query: options2.query,
|
|
6033
|
+
limit: options2.limit ? Number.parseInt(options2.limit, 10) : void 0
|
|
5619
6034
|
});
|
|
6035
|
+
console.log(JSON.stringify(allResults, null, 2));
|
|
6036
|
+
}
|
|
6037
|
+
|
|
6038
|
+
// src/commands/registerRavendb.ts
|
|
6039
|
+
function registerRavendb(program2) {
|
|
6040
|
+
const cmd = program2.command("ravendb").description("RavenDB query utilities");
|
|
6041
|
+
cmd.command("auth").description("Configure a named RavenDB connection").option("--list", "List configured connections").option("--remove <name>", "Remove a configured connection").action((options2) => ravendbAuth(options2));
|
|
6042
|
+
cmd.command("set-connection <name>").description("Set the default connection").action((name) => ravendbSetConnection(name));
|
|
6043
|
+
cmd.command("query [connection] [collection]").description("Query a RavenDB collection").option("--page-size <n>", "Documents per page", "25").option(
|
|
6044
|
+
"--sort <field>",
|
|
6045
|
+
"Sort field (prefix - for descending)",
|
|
6046
|
+
"-@metadata.Last-Modified"
|
|
6047
|
+
).option("--query <lucene>", "Lucene filter query").option("--limit <n>", "Max total documents to fetch").action(
|
|
6048
|
+
(connection, collection, options2) => ravendbQuery(connection, collection, options2)
|
|
6049
|
+
);
|
|
6050
|
+
cmd.command("collections [connection]").description("List collections in a RavenDB database").action((connection) => ravendbCollections(connection));
|
|
5620
6051
|
}
|
|
5621
6052
|
|
|
5622
6053
|
// src/commands/refactor/check/index.ts
|
|
5623
6054
|
import { spawn as spawn3 } from "child_process";
|
|
5624
|
-
import * as
|
|
6055
|
+
import * as path25 from "path";
|
|
5625
6056
|
|
|
5626
6057
|
// src/commands/refactor/logViolations.ts
|
|
5627
|
-
import
|
|
6058
|
+
import chalk67 from "chalk";
|
|
5628
6059
|
var DEFAULT_MAX_LINES = 100;
|
|
5629
6060
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
5630
6061
|
if (violations.length === 0) {
|
|
@@ -5633,43 +6064,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
5633
6064
|
}
|
|
5634
6065
|
return;
|
|
5635
6066
|
}
|
|
5636
|
-
console.error(
|
|
6067
|
+
console.error(chalk67.red(`
|
|
5637
6068
|
Refactor check failed:
|
|
5638
6069
|
`));
|
|
5639
|
-
console.error(
|
|
6070
|
+
console.error(chalk67.red(` The following files exceed ${maxLines} lines:
|
|
5640
6071
|
`));
|
|
5641
6072
|
for (const violation of violations) {
|
|
5642
|
-
console.error(
|
|
6073
|
+
console.error(chalk67.red(` ${violation.file} (${violation.lines} lines)`));
|
|
5643
6074
|
}
|
|
5644
6075
|
console.error(
|
|
5645
|
-
|
|
6076
|
+
chalk67.yellow(
|
|
5646
6077
|
`
|
|
5647
6078
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
5648
6079
|
way to refactor it, ignore it with:
|
|
5649
6080
|
`
|
|
5650
6081
|
)
|
|
5651
6082
|
);
|
|
5652
|
-
console.error(
|
|
6083
|
+
console.error(chalk67.gray(` assist refactor ignore <file>
|
|
5653
6084
|
`));
|
|
5654
6085
|
if (process.env.CLAUDECODE) {
|
|
5655
|
-
console.error(
|
|
6086
|
+
console.error(chalk67.cyan(`
|
|
5656
6087
|
## Extracting Code to New Files
|
|
5657
6088
|
`));
|
|
5658
6089
|
console.error(
|
|
5659
|
-
|
|
6090
|
+
chalk67.cyan(
|
|
5660
6091
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
5661
6092
|
`
|
|
5662
6093
|
)
|
|
5663
6094
|
);
|
|
5664
6095
|
console.error(
|
|
5665
|
-
|
|
6096
|
+
chalk67.cyan(
|
|
5666
6097
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
5667
6098
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
5668
6099
|
`
|
|
5669
6100
|
)
|
|
5670
6101
|
);
|
|
5671
6102
|
console.error(
|
|
5672
|
-
|
|
6103
|
+
chalk67.cyan(
|
|
5673
6104
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
5674
6105
|
domains, move it to a common/shared folder.
|
|
5675
6106
|
`
|
|
@@ -5679,18 +6110,18 @@ Refactor check failed:
|
|
|
5679
6110
|
}
|
|
5680
6111
|
|
|
5681
6112
|
// src/commands/refactor/check/getViolations/index.ts
|
|
5682
|
-
import { execSync as
|
|
5683
|
-
import
|
|
6113
|
+
import { execSync as execSync31 } from "child_process";
|
|
6114
|
+
import fs16 from "fs";
|
|
5684
6115
|
import { minimatch as minimatch4 } from "minimatch";
|
|
5685
6116
|
|
|
5686
6117
|
// src/commands/refactor/check/getViolations/getIgnoredFiles.ts
|
|
5687
|
-
import
|
|
6118
|
+
import fs15 from "fs";
|
|
5688
6119
|
var REFACTOR_YML_PATH = "refactor.yml";
|
|
5689
6120
|
function parseRefactorYml() {
|
|
5690
|
-
if (!
|
|
6121
|
+
if (!fs15.existsSync(REFACTOR_YML_PATH)) {
|
|
5691
6122
|
return [];
|
|
5692
6123
|
}
|
|
5693
|
-
const content =
|
|
6124
|
+
const content = fs15.readFileSync(REFACTOR_YML_PATH, "utf-8");
|
|
5694
6125
|
const entries = [];
|
|
5695
6126
|
const lines = content.split("\n");
|
|
5696
6127
|
let currentEntry = {};
|
|
@@ -5720,7 +6151,7 @@ function getIgnoredFiles() {
|
|
|
5720
6151
|
|
|
5721
6152
|
// src/commands/refactor/check/getViolations/index.ts
|
|
5722
6153
|
function countLines(filePath) {
|
|
5723
|
-
const content =
|
|
6154
|
+
const content = fs16.readFileSync(filePath, "utf-8");
|
|
5724
6155
|
return content.split("\n").length;
|
|
5725
6156
|
}
|
|
5726
6157
|
function getGitFiles(options2) {
|
|
@@ -5729,7 +6160,7 @@ function getGitFiles(options2) {
|
|
|
5729
6160
|
}
|
|
5730
6161
|
const files = /* @__PURE__ */ new Set();
|
|
5731
6162
|
if (options2.staged || options2.modified) {
|
|
5732
|
-
const staged =
|
|
6163
|
+
const staged = execSync31("git diff --cached --name-only", {
|
|
5733
6164
|
encoding: "utf-8"
|
|
5734
6165
|
});
|
|
5735
6166
|
for (const file of staged.trim().split("\n").filter(Boolean)) {
|
|
@@ -5737,7 +6168,7 @@ function getGitFiles(options2) {
|
|
|
5737
6168
|
}
|
|
5738
6169
|
}
|
|
5739
6170
|
if (options2.unstaged || options2.modified) {
|
|
5740
|
-
const unstaged =
|
|
6171
|
+
const unstaged = execSync31("git diff --name-only", { encoding: "utf-8" });
|
|
5741
6172
|
for (const file of unstaged.trim().split("\n").filter(Boolean)) {
|
|
5742
6173
|
files.add(file);
|
|
5743
6174
|
}
|
|
@@ -5798,7 +6229,7 @@ ${failed.length} verify script(s) failed:`);
|
|
|
5798
6229
|
async function runVerifyQuietly() {
|
|
5799
6230
|
const result = findPackageJsonWithVerifyScripts(process.cwd());
|
|
5800
6231
|
if (!result) return true;
|
|
5801
|
-
const packageDir =
|
|
6232
|
+
const packageDir = path25.dirname(result.packageJsonPath);
|
|
5802
6233
|
const results = await Promise.all(
|
|
5803
6234
|
result.verifyScripts.map((script) => runScript(script, packageDir))
|
|
5804
6235
|
);
|
|
@@ -5824,64 +6255,64 @@ async function check(pattern2, options2) {
|
|
|
5824
6255
|
}
|
|
5825
6256
|
|
|
5826
6257
|
// src/commands/refactor/ignore.ts
|
|
5827
|
-
import
|
|
5828
|
-
import
|
|
6258
|
+
import fs17 from "fs";
|
|
6259
|
+
import chalk68 from "chalk";
|
|
5829
6260
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
5830
6261
|
function ignore(file) {
|
|
5831
|
-
if (!
|
|
5832
|
-
console.error(
|
|
6262
|
+
if (!fs17.existsSync(file)) {
|
|
6263
|
+
console.error(chalk68.red(`Error: File does not exist: ${file}`));
|
|
5833
6264
|
process.exit(1);
|
|
5834
6265
|
}
|
|
5835
|
-
const content =
|
|
6266
|
+
const content = fs17.readFileSync(file, "utf-8");
|
|
5836
6267
|
const lineCount = content.split("\n").length;
|
|
5837
6268
|
const maxLines = lineCount + 10;
|
|
5838
6269
|
const entry = `- file: ${file}
|
|
5839
6270
|
maxLines: ${maxLines}
|
|
5840
6271
|
`;
|
|
5841
|
-
if (
|
|
5842
|
-
const existing =
|
|
5843
|
-
|
|
6272
|
+
if (fs17.existsSync(REFACTOR_YML_PATH2)) {
|
|
6273
|
+
const existing = fs17.readFileSync(REFACTOR_YML_PATH2, "utf-8");
|
|
6274
|
+
fs17.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
|
|
5844
6275
|
} else {
|
|
5845
|
-
|
|
6276
|
+
fs17.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
5846
6277
|
}
|
|
5847
6278
|
console.log(
|
|
5848
|
-
|
|
6279
|
+
chalk68.green(
|
|
5849
6280
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
5850
6281
|
)
|
|
5851
6282
|
);
|
|
5852
6283
|
}
|
|
5853
6284
|
|
|
5854
6285
|
// src/commands/refactor/rename/index.ts
|
|
5855
|
-
import
|
|
5856
|
-
import
|
|
6286
|
+
import path26 from "path";
|
|
6287
|
+
import chalk69 from "chalk";
|
|
5857
6288
|
import { Project as Project2 } from "ts-morph";
|
|
5858
6289
|
async function rename(source, destination, options2 = {}) {
|
|
5859
|
-
const sourcePath =
|
|
5860
|
-
const destPath =
|
|
6290
|
+
const sourcePath = path26.resolve(source);
|
|
6291
|
+
const destPath = path26.resolve(destination);
|
|
5861
6292
|
const cwd = process.cwd();
|
|
5862
|
-
const relSource =
|
|
5863
|
-
const relDest =
|
|
6293
|
+
const relSource = path26.relative(cwd, sourcePath);
|
|
6294
|
+
const relDest = path26.relative(cwd, destPath);
|
|
5864
6295
|
const project = new Project2({
|
|
5865
|
-
tsConfigFilePath:
|
|
6296
|
+
tsConfigFilePath: path26.resolve("tsconfig.json")
|
|
5866
6297
|
});
|
|
5867
6298
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
5868
6299
|
if (!sourceFile) {
|
|
5869
|
-
console.log(
|
|
6300
|
+
console.log(chalk69.red(`File not found in project: ${source}`));
|
|
5870
6301
|
process.exit(1);
|
|
5871
6302
|
}
|
|
5872
|
-
console.log(
|
|
6303
|
+
console.log(chalk69.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
5873
6304
|
if (options2.apply) {
|
|
5874
6305
|
sourceFile.move(destPath);
|
|
5875
6306
|
await project.save();
|
|
5876
|
-
console.log(
|
|
6307
|
+
console.log(chalk69.green("Done"));
|
|
5877
6308
|
} else {
|
|
5878
|
-
console.log(
|
|
6309
|
+
console.log(chalk69.dim("Dry run. Use --apply to execute."));
|
|
5879
6310
|
}
|
|
5880
6311
|
}
|
|
5881
6312
|
|
|
5882
6313
|
// src/commands/refactor/renameSymbol/index.ts
|
|
5883
|
-
import
|
|
5884
|
-
import
|
|
6314
|
+
import path28 from "path";
|
|
6315
|
+
import chalk70 from "chalk";
|
|
5885
6316
|
import { Project as Project3 } from "ts-morph";
|
|
5886
6317
|
|
|
5887
6318
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
@@ -5909,12 +6340,12 @@ function findSymbol(sourceFile, symbolName) {
|
|
|
5909
6340
|
}
|
|
5910
6341
|
|
|
5911
6342
|
// src/commands/refactor/renameSymbol/groupReferences.ts
|
|
5912
|
-
import
|
|
6343
|
+
import path27 from "path";
|
|
5913
6344
|
function groupReferences(symbol, cwd) {
|
|
5914
6345
|
const refs = symbol.findReferencesAsNodes();
|
|
5915
6346
|
const grouped = /* @__PURE__ */ new Map();
|
|
5916
6347
|
for (const ref of refs) {
|
|
5917
|
-
const refFile =
|
|
6348
|
+
const refFile = path27.relative(cwd, ref.getSourceFile().getFilePath());
|
|
5918
6349
|
const lines = grouped.get(refFile) ?? [];
|
|
5919
6350
|
if (!grouped.has(refFile)) grouped.set(refFile, lines);
|
|
5920
6351
|
lines.push(ref.getStartLineNumber());
|
|
@@ -5924,47 +6355,47 @@ function groupReferences(symbol, cwd) {
|
|
|
5924
6355
|
|
|
5925
6356
|
// src/commands/refactor/renameSymbol/index.ts
|
|
5926
6357
|
async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
5927
|
-
const filePath =
|
|
5928
|
-
const tsConfigPath =
|
|
6358
|
+
const filePath = path28.resolve(file);
|
|
6359
|
+
const tsConfigPath = path28.resolve("tsconfig.json");
|
|
5929
6360
|
const cwd = process.cwd();
|
|
5930
6361
|
const project = new Project3({ tsConfigFilePath: tsConfigPath });
|
|
5931
6362
|
const sourceFile = project.getSourceFile(filePath);
|
|
5932
6363
|
if (!sourceFile) {
|
|
5933
|
-
console.log(
|
|
6364
|
+
console.log(chalk70.red(`File not found in project: ${file}`));
|
|
5934
6365
|
process.exit(1);
|
|
5935
6366
|
}
|
|
5936
6367
|
const symbol = findSymbol(sourceFile, oldName);
|
|
5937
6368
|
if (!symbol) {
|
|
5938
|
-
console.log(
|
|
6369
|
+
console.log(chalk70.red(`Symbol "${oldName}" not found in ${file}`));
|
|
5939
6370
|
process.exit(1);
|
|
5940
6371
|
}
|
|
5941
6372
|
const grouped = groupReferences(symbol, cwd);
|
|
5942
6373
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
5943
6374
|
console.log(
|
|
5944
|
-
|
|
6375
|
+
chalk70.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
5945
6376
|
`)
|
|
5946
6377
|
);
|
|
5947
6378
|
for (const [refFile, lines] of grouped) {
|
|
5948
6379
|
console.log(
|
|
5949
|
-
` ${
|
|
6380
|
+
` ${chalk70.dim(refFile)}: lines ${chalk70.cyan(lines.join(", "))}`
|
|
5950
6381
|
);
|
|
5951
6382
|
}
|
|
5952
6383
|
if (options2.apply) {
|
|
5953
6384
|
symbol.rename(newName);
|
|
5954
6385
|
await project.save();
|
|
5955
|
-
console.log(
|
|
6386
|
+
console.log(chalk70.green(`
|
|
5956
6387
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
5957
6388
|
} else {
|
|
5958
|
-
console.log(
|
|
6389
|
+
console.log(chalk70.dim("\nDry run. Use --apply to execute."));
|
|
5959
6390
|
}
|
|
5960
6391
|
}
|
|
5961
6392
|
|
|
5962
6393
|
// src/commands/refactor/restructure/index.ts
|
|
5963
|
-
import
|
|
5964
|
-
import
|
|
6394
|
+
import path37 from "path";
|
|
6395
|
+
import chalk73 from "chalk";
|
|
5965
6396
|
|
|
5966
6397
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
5967
|
-
import
|
|
6398
|
+
import path29 from "path";
|
|
5968
6399
|
import ts7 from "typescript";
|
|
5969
6400
|
|
|
5970
6401
|
// src/commands/refactor/restructure/buildImportGraph/getImportSpecifiers.ts
|
|
@@ -5991,7 +6422,7 @@ function loadParsedConfig(tsConfigPath) {
|
|
|
5991
6422
|
return ts7.parseJsonConfigFileContent(
|
|
5992
6423
|
configFile.config,
|
|
5993
6424
|
ts7.sys,
|
|
5994
|
-
|
|
6425
|
+
path29.dirname(tsConfigPath)
|
|
5995
6426
|
);
|
|
5996
6427
|
}
|
|
5997
6428
|
function addToSetMap(map, key, value) {
|
|
@@ -6007,7 +6438,7 @@ function resolveImport(specifier, filePath, options2) {
|
|
|
6007
6438
|
const resolved = ts7.resolveModuleName(specifier, filePath, options2, ts7.sys);
|
|
6008
6439
|
const resolvedPath = resolved.resolvedModule?.resolvedFileName;
|
|
6009
6440
|
if (!resolvedPath || resolvedPath.includes("node_modules")) return null;
|
|
6010
|
-
return
|
|
6441
|
+
return path29.resolve(resolvedPath);
|
|
6011
6442
|
}
|
|
6012
6443
|
function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
6013
6444
|
const parsed = loadParsedConfig(tsConfigPath);
|
|
@@ -6016,7 +6447,7 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
6016
6447
|
const importedBy = /* @__PURE__ */ new Map();
|
|
6017
6448
|
const imports = /* @__PURE__ */ new Map();
|
|
6018
6449
|
for (const sourceFile of program2.getSourceFiles()) {
|
|
6019
|
-
const filePath =
|
|
6450
|
+
const filePath = path29.resolve(sourceFile.fileName);
|
|
6020
6451
|
if (filePath.includes("node_modules")) continue;
|
|
6021
6452
|
for (const specifier of getImportSpecifiers(sourceFile)) {
|
|
6022
6453
|
const absTarget = resolveImport(specifier, filePath, parsed.options);
|
|
@@ -6030,12 +6461,12 @@ function buildImportGraph(candidateFiles, tsConfigPath) {
|
|
|
6030
6461
|
}
|
|
6031
6462
|
|
|
6032
6463
|
// src/commands/refactor/restructure/clusterDirectories.ts
|
|
6033
|
-
import
|
|
6464
|
+
import path30 from "path";
|
|
6034
6465
|
function clusterDirectories(graph) {
|
|
6035
6466
|
const dirImportedBy = /* @__PURE__ */ new Map();
|
|
6036
6467
|
for (const edge of graph.edges) {
|
|
6037
|
-
const sourceDir =
|
|
6038
|
-
const targetDir =
|
|
6468
|
+
const sourceDir = path30.dirname(edge.source);
|
|
6469
|
+
const targetDir = path30.dirname(edge.target);
|
|
6039
6470
|
if (sourceDir === targetDir) continue;
|
|
6040
6471
|
if (!graph.files.has(edge.target)) continue;
|
|
6041
6472
|
const existing = dirImportedBy.get(targetDir) ?? /* @__PURE__ */ new Set();
|
|
@@ -6063,20 +6494,20 @@ function clusterDirectories(graph) {
|
|
|
6063
6494
|
return clusters;
|
|
6064
6495
|
}
|
|
6065
6496
|
function isAncestor(ancestor, descendant) {
|
|
6066
|
-
const rel =
|
|
6497
|
+
const rel = path30.relative(ancestor, descendant);
|
|
6067
6498
|
return !rel.startsWith("..") && rel !== "";
|
|
6068
6499
|
}
|
|
6069
6500
|
|
|
6070
6501
|
// src/commands/refactor/restructure/clusterFiles.ts
|
|
6071
|
-
import
|
|
6502
|
+
import path31 from "path";
|
|
6072
6503
|
function findRootParent(file, importedBy, visited) {
|
|
6073
6504
|
const importers = importedBy.get(file);
|
|
6074
6505
|
if (!importers || importers.size !== 1) return file;
|
|
6075
6506
|
const parent = [...importers][0];
|
|
6076
|
-
const parentDir =
|
|
6077
|
-
const fileDir =
|
|
6507
|
+
const parentDir = path31.dirname(parent);
|
|
6508
|
+
const fileDir = path31.dirname(file);
|
|
6078
6509
|
if (parentDir !== fileDir) return file;
|
|
6079
|
-
if (
|
|
6510
|
+
if (path31.basename(parent, path31.extname(parent)) === "index") return file;
|
|
6080
6511
|
if (visited.has(parent)) return file;
|
|
6081
6512
|
visited.add(parent);
|
|
6082
6513
|
return findRootParent(parent, importedBy, visited);
|
|
@@ -6084,16 +6515,16 @@ function findRootParent(file, importedBy, visited) {
|
|
|
6084
6515
|
function clusterFiles(graph) {
|
|
6085
6516
|
const clusters = /* @__PURE__ */ new Map();
|
|
6086
6517
|
for (const file of graph.files) {
|
|
6087
|
-
const basename7 =
|
|
6518
|
+
const basename7 = path31.basename(file, path31.extname(file));
|
|
6088
6519
|
if (basename7 === "index") continue;
|
|
6089
6520
|
const importers = graph.importedBy.get(file);
|
|
6090
6521
|
if (!importers || importers.size !== 1) continue;
|
|
6091
6522
|
const parent = [...importers][0];
|
|
6092
6523
|
if (!graph.files.has(parent)) continue;
|
|
6093
|
-
const parentDir =
|
|
6094
|
-
const fileDir =
|
|
6524
|
+
const parentDir = path31.dirname(parent);
|
|
6525
|
+
const fileDir = path31.dirname(file);
|
|
6095
6526
|
if (parentDir !== fileDir) continue;
|
|
6096
|
-
const parentBasename =
|
|
6527
|
+
const parentBasename = path31.basename(parent, path31.extname(parent));
|
|
6097
6528
|
if (parentBasename === "index") continue;
|
|
6098
6529
|
const root = findRootParent(parent, graph.importedBy, /* @__PURE__ */ new Set([file]));
|
|
6099
6530
|
if (!root || root === file) continue;
|
|
@@ -6105,10 +6536,10 @@ function clusterFiles(graph) {
|
|
|
6105
6536
|
}
|
|
6106
6537
|
|
|
6107
6538
|
// src/commands/refactor/restructure/computeRewrites/index.ts
|
|
6108
|
-
import
|
|
6539
|
+
import path32 from "path";
|
|
6109
6540
|
|
|
6110
6541
|
// src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
|
|
6111
|
-
import
|
|
6542
|
+
import fs18 from "fs";
|
|
6112
6543
|
function getOrCreateList(map, key) {
|
|
6113
6544
|
const list4 = map.get(key) ?? [];
|
|
6114
6545
|
if (!map.has(key)) map.set(key, list4);
|
|
@@ -6127,7 +6558,7 @@ function rewriteSpecifier(content, oldSpecifier, newSpecifier) {
|
|
|
6127
6558
|
return content.replace(pattern2, `$1${newSpecifier}$2`);
|
|
6128
6559
|
}
|
|
6129
6560
|
function applyFileRewrites(file, fileRewrites) {
|
|
6130
|
-
let content =
|
|
6561
|
+
let content = fs18.readFileSync(file, "utf-8");
|
|
6131
6562
|
for (const { oldSpecifier, newSpecifier } of fileRewrites) {
|
|
6132
6563
|
content = rewriteSpecifier(content, oldSpecifier, newSpecifier);
|
|
6133
6564
|
}
|
|
@@ -6159,7 +6590,7 @@ function normalizeSpecifier(rel) {
|
|
|
6159
6590
|
);
|
|
6160
6591
|
}
|
|
6161
6592
|
function computeSpecifier(fromFile, toFile) {
|
|
6162
|
-
return normalizeSpecifier(
|
|
6593
|
+
return normalizeSpecifier(path32.relative(path32.dirname(fromFile), toFile));
|
|
6163
6594
|
}
|
|
6164
6595
|
function isAffected(edge, moveMap) {
|
|
6165
6596
|
return moveMap.has(edge.target) || moveMap.has(edge.source);
|
|
@@ -6203,51 +6634,51 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
6203
6634
|
}
|
|
6204
6635
|
|
|
6205
6636
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
6206
|
-
import
|
|
6207
|
-
import
|
|
6637
|
+
import path33 from "path";
|
|
6638
|
+
import chalk71 from "chalk";
|
|
6208
6639
|
function relPath(filePath) {
|
|
6209
|
-
return
|
|
6640
|
+
return path33.relative(process.cwd(), filePath);
|
|
6210
6641
|
}
|
|
6211
6642
|
function displayMoves(plan) {
|
|
6212
6643
|
if (plan.moves.length === 0) return;
|
|
6213
|
-
console.log(
|
|
6644
|
+
console.log(chalk71.bold("\nFile moves:"));
|
|
6214
6645
|
for (const move of plan.moves) {
|
|
6215
6646
|
console.log(
|
|
6216
|
-
` ${
|
|
6647
|
+
` ${chalk71.red(relPath(move.from))} \u2192 ${chalk71.green(relPath(move.to))}`
|
|
6217
6648
|
);
|
|
6218
|
-
console.log(
|
|
6649
|
+
console.log(chalk71.dim(` ${move.reason}`));
|
|
6219
6650
|
}
|
|
6220
6651
|
}
|
|
6221
6652
|
function displayRewrites(rewrites) {
|
|
6222
6653
|
if (rewrites.length === 0) return;
|
|
6223
6654
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
6224
|
-
console.log(
|
|
6655
|
+
console.log(chalk71.bold(`
|
|
6225
6656
|
Import rewrites (${affectedFiles.size} files):`));
|
|
6226
6657
|
for (const file of affectedFiles) {
|
|
6227
|
-
console.log(` ${
|
|
6658
|
+
console.log(` ${chalk71.cyan(relPath(file))}:`);
|
|
6228
6659
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
6229
6660
|
(r) => r.file === file
|
|
6230
6661
|
)) {
|
|
6231
6662
|
console.log(
|
|
6232
|
-
` ${
|
|
6663
|
+
` ${chalk71.red(`"${oldSpecifier}"`)} \u2192 ${chalk71.green(`"${newSpecifier}"`)}`
|
|
6233
6664
|
);
|
|
6234
6665
|
}
|
|
6235
6666
|
}
|
|
6236
6667
|
}
|
|
6237
6668
|
function displayPlan(plan) {
|
|
6238
6669
|
if (plan.warnings.length > 0) {
|
|
6239
|
-
console.log(
|
|
6240
|
-
for (const w of plan.warnings) console.log(
|
|
6670
|
+
console.log(chalk71.yellow("\nWarnings:"));
|
|
6671
|
+
for (const w of plan.warnings) console.log(chalk71.yellow(` ${w}`));
|
|
6241
6672
|
}
|
|
6242
6673
|
if (plan.newDirectories.length > 0) {
|
|
6243
|
-
console.log(
|
|
6674
|
+
console.log(chalk71.bold("\nNew directories:"));
|
|
6244
6675
|
for (const dir of plan.newDirectories)
|
|
6245
|
-
console.log(
|
|
6676
|
+
console.log(chalk71.green(` ${dir}/`));
|
|
6246
6677
|
}
|
|
6247
6678
|
displayMoves(plan);
|
|
6248
6679
|
displayRewrites(plan.rewrites);
|
|
6249
6680
|
console.log(
|
|
6250
|
-
|
|
6681
|
+
chalk71.dim(
|
|
6251
6682
|
`
|
|
6252
6683
|
Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
|
|
6253
6684
|
)
|
|
@@ -6255,45 +6686,45 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
6255
6686
|
}
|
|
6256
6687
|
|
|
6257
6688
|
// src/commands/refactor/restructure/executePlan.ts
|
|
6258
|
-
import
|
|
6259
|
-
import
|
|
6260
|
-
import
|
|
6689
|
+
import fs19 from "fs";
|
|
6690
|
+
import path34 from "path";
|
|
6691
|
+
import chalk72 from "chalk";
|
|
6261
6692
|
function executePlan(plan) {
|
|
6262
6693
|
const updatedContents = applyRewrites(plan.rewrites);
|
|
6263
6694
|
for (const [file, content] of updatedContents) {
|
|
6264
|
-
|
|
6695
|
+
fs19.writeFileSync(file, content, "utf-8");
|
|
6265
6696
|
console.log(
|
|
6266
|
-
|
|
6697
|
+
chalk72.cyan(` Rewrote imports in ${path34.relative(process.cwd(), file)}`)
|
|
6267
6698
|
);
|
|
6268
6699
|
}
|
|
6269
6700
|
for (const dir of plan.newDirectories) {
|
|
6270
|
-
|
|
6271
|
-
console.log(
|
|
6701
|
+
fs19.mkdirSync(dir, { recursive: true });
|
|
6702
|
+
console.log(chalk72.green(` Created ${path34.relative(process.cwd(), dir)}/`));
|
|
6272
6703
|
}
|
|
6273
6704
|
for (const move of plan.moves) {
|
|
6274
|
-
const targetDir =
|
|
6275
|
-
if (!
|
|
6276
|
-
|
|
6705
|
+
const targetDir = path34.dirname(move.to);
|
|
6706
|
+
if (!fs19.existsSync(targetDir)) {
|
|
6707
|
+
fs19.mkdirSync(targetDir, { recursive: true });
|
|
6277
6708
|
}
|
|
6278
|
-
|
|
6709
|
+
fs19.renameSync(move.from, move.to);
|
|
6279
6710
|
console.log(
|
|
6280
|
-
|
|
6281
|
-
` Moved ${
|
|
6711
|
+
chalk72.white(
|
|
6712
|
+
` Moved ${path34.relative(process.cwd(), move.from)} \u2192 ${path34.relative(process.cwd(), move.to)}`
|
|
6282
6713
|
)
|
|
6283
6714
|
);
|
|
6284
6715
|
}
|
|
6285
|
-
removeEmptyDirectories(plan.moves.map((m) =>
|
|
6716
|
+
removeEmptyDirectories(plan.moves.map((m) => path34.dirname(m.from)));
|
|
6286
6717
|
}
|
|
6287
6718
|
function removeEmptyDirectories(dirs) {
|
|
6288
6719
|
const unique = [...new Set(dirs)];
|
|
6289
6720
|
for (const dir of unique) {
|
|
6290
|
-
if (!
|
|
6291
|
-
const entries =
|
|
6721
|
+
if (!fs19.existsSync(dir)) continue;
|
|
6722
|
+
const entries = fs19.readdirSync(dir);
|
|
6292
6723
|
if (entries.length === 0) {
|
|
6293
|
-
|
|
6724
|
+
fs19.rmdirSync(dir);
|
|
6294
6725
|
console.log(
|
|
6295
|
-
|
|
6296
|
-
` Removed empty directory ${
|
|
6726
|
+
chalk72.dim(
|
|
6727
|
+
` Removed empty directory ${path34.relative(process.cwd(), dir)}`
|
|
6297
6728
|
)
|
|
6298
6729
|
);
|
|
6299
6730
|
}
|
|
@@ -6301,14 +6732,24 @@ function removeEmptyDirectories(dirs) {
|
|
|
6301
6732
|
}
|
|
6302
6733
|
|
|
6303
6734
|
// src/commands/refactor/restructure/planFileMoves/index.ts
|
|
6304
|
-
import
|
|
6305
|
-
|
|
6735
|
+
import path36 from "path";
|
|
6736
|
+
|
|
6737
|
+
// src/commands/refactor/restructure/planFileMoves/shared.ts
|
|
6738
|
+
import fs20 from "fs";
|
|
6739
|
+
function emptyResult() {
|
|
6740
|
+
return { moves: [], directories: [], warnings: [] };
|
|
6741
|
+
}
|
|
6742
|
+
function checkDirConflict(result, label2, dir) {
|
|
6743
|
+
if (!fs20.existsSync(dir)) return false;
|
|
6744
|
+
result.warnings.push(`Skipping ${label2}: directory ${dir} already exists`);
|
|
6745
|
+
return true;
|
|
6746
|
+
}
|
|
6306
6747
|
|
|
6307
6748
|
// src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
|
|
6308
6749
|
import fs21 from "fs";
|
|
6309
|
-
import
|
|
6750
|
+
import path35 from "path";
|
|
6310
6751
|
function collectEntry(results, dir, entry) {
|
|
6311
|
-
const full =
|
|
6752
|
+
const full = path35.join(dir, entry.name);
|
|
6312
6753
|
const items = entry.isDirectory() ? listFilesRecursive(full) : [full];
|
|
6313
6754
|
results.push(...items);
|
|
6314
6755
|
}
|
|
@@ -6322,15 +6763,15 @@ function listFilesRecursive(dir) {
|
|
|
6322
6763
|
}
|
|
6323
6764
|
function addDirectoryFileMoves(moves, childDir, newLocation, reason) {
|
|
6324
6765
|
for (const file of listFilesRecursive(childDir)) {
|
|
6325
|
-
const rel =
|
|
6326
|
-
moves.push({ from: file, to:
|
|
6766
|
+
const rel = path35.relative(childDir, file);
|
|
6767
|
+
moves.push({ from: file, to: path35.join(newLocation, rel), reason });
|
|
6327
6768
|
}
|
|
6328
6769
|
}
|
|
6329
6770
|
function resolveChildDest(parentDir, childDir) {
|
|
6330
|
-
return
|
|
6771
|
+
return path35.join(parentDir, path35.basename(childDir));
|
|
6331
6772
|
}
|
|
6332
6773
|
function childMoveReason(parentDir) {
|
|
6333
|
-
return `Directory only imported from ${
|
|
6774
|
+
return `Directory only imported from ${path35.basename(parentDir)}/`;
|
|
6334
6775
|
}
|
|
6335
6776
|
function registerDirectoryMove(result, childDir, dest, parentDir) {
|
|
6336
6777
|
result.directories.push(dest);
|
|
@@ -6354,32 +6795,24 @@ function planDirectoryMoves(clusters) {
|
|
|
6354
6795
|
}
|
|
6355
6796
|
|
|
6356
6797
|
// src/commands/refactor/restructure/planFileMoves/index.ts
|
|
6357
|
-
function emptyResult() {
|
|
6358
|
-
return { moves: [], directories: [], warnings: [] };
|
|
6359
|
-
}
|
|
6360
6798
|
function childMoveData(child, newDir, parentBase) {
|
|
6361
|
-
const to =
|
|
6799
|
+
const to = path36.join(newDir, path36.basename(child));
|
|
6362
6800
|
return { from: child, to, reason: `Only imported by ${parentBase}` };
|
|
6363
6801
|
}
|
|
6364
6802
|
function addChildMoves(moves, children, newDir, parentBase) {
|
|
6365
6803
|
for (const child of children)
|
|
6366
6804
|
moves.push(childMoveData(child, newDir, parentBase));
|
|
6367
6805
|
}
|
|
6368
|
-
function checkDirConflict(result, label2, dir) {
|
|
6369
|
-
if (!fs22.existsSync(dir)) return false;
|
|
6370
|
-
result.warnings.push(`Skipping ${label2}: directory ${dir} already exists`);
|
|
6371
|
-
return true;
|
|
6372
|
-
}
|
|
6373
6806
|
function getBaseName(filePath) {
|
|
6374
|
-
return
|
|
6807
|
+
return path36.basename(filePath, path36.extname(filePath));
|
|
6375
6808
|
}
|
|
6376
6809
|
function resolveClusterDir(parent) {
|
|
6377
|
-
return
|
|
6810
|
+
return path36.join(path36.dirname(parent), getBaseName(parent));
|
|
6378
6811
|
}
|
|
6379
6812
|
function createParentMove(parent, newDir) {
|
|
6380
6813
|
return {
|
|
6381
6814
|
from: parent,
|
|
6382
|
-
to:
|
|
6815
|
+
to: path36.join(newDir, `index${path36.extname(parent)}`),
|
|
6383
6816
|
reason: `Main module of new ${getBaseName(parent)}/ directory`
|
|
6384
6817
|
};
|
|
6385
6818
|
}
|
|
@@ -6403,7 +6836,7 @@ function planFileMoves(clusters) {
|
|
|
6403
6836
|
|
|
6404
6837
|
// src/commands/refactor/restructure/index.ts
|
|
6405
6838
|
function buildPlan(candidateFiles, tsConfigPath) {
|
|
6406
|
-
const candidates = new Set(candidateFiles.map((f) =>
|
|
6839
|
+
const candidates = new Set(candidateFiles.map((f) => path37.resolve(f)));
|
|
6407
6840
|
const graph = buildImportGraph(candidates, tsConfigPath);
|
|
6408
6841
|
const allProjectFiles = /* @__PURE__ */ new Set([
|
|
6409
6842
|
...graph.importedBy.keys(),
|
|
@@ -6423,22 +6856,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
6423
6856
|
const targetPattern = pattern2 ?? "src";
|
|
6424
6857
|
const files = findSourceFiles2(targetPattern);
|
|
6425
6858
|
if (files.length === 0) {
|
|
6426
|
-
console.log(
|
|
6859
|
+
console.log(chalk73.yellow("No files found matching pattern"));
|
|
6427
6860
|
return;
|
|
6428
6861
|
}
|
|
6429
|
-
const tsConfigPath =
|
|
6862
|
+
const tsConfigPath = path37.resolve("tsconfig.json");
|
|
6430
6863
|
const plan = buildPlan(files, tsConfigPath);
|
|
6431
6864
|
if (plan.moves.length === 0) {
|
|
6432
|
-
console.log(
|
|
6865
|
+
console.log(chalk73.green("No restructuring needed"));
|
|
6433
6866
|
return;
|
|
6434
6867
|
}
|
|
6435
6868
|
displayPlan(plan);
|
|
6436
6869
|
if (options2.apply) {
|
|
6437
|
-
console.log(
|
|
6870
|
+
console.log(chalk73.bold("\nApplying changes..."));
|
|
6438
6871
|
executePlan(plan);
|
|
6439
|
-
console.log(
|
|
6872
|
+
console.log(chalk73.green("\nRestructuring complete"));
|
|
6440
6873
|
} else {
|
|
6441
|
-
console.log(
|
|
6874
|
+
console.log(chalk73.dim("\nDry run. Use --apply to execute."));
|
|
6442
6875
|
}
|
|
6443
6876
|
}
|
|
6444
6877
|
|
|
@@ -6653,7 +7086,7 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
6653
7086
|
}
|
|
6654
7087
|
|
|
6655
7088
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
6656
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync7, readFileSync as readFileSync22, writeFileSync as
|
|
7089
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync7, readFileSync as readFileSync22, writeFileSync as writeFileSync22 } from "fs";
|
|
6657
7090
|
import { basename as basename5, dirname as dirname17, join as join25 } from "path";
|
|
6658
7091
|
|
|
6659
7092
|
// src/commands/transcript/cleanText.ts
|
|
@@ -6904,7 +7337,7 @@ function readAndParseCues(inputPath) {
|
|
|
6904
7337
|
return processCues(readFileSync22(inputPath, "utf-8"));
|
|
6905
7338
|
}
|
|
6906
7339
|
function writeFormatted(outputPath, content) {
|
|
6907
|
-
|
|
7340
|
+
writeFileSync22(outputPath, content, "utf-8");
|
|
6908
7341
|
console.log(`Written: ${outputPath}`);
|
|
6909
7342
|
}
|
|
6910
7343
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -6986,14 +7419,14 @@ import {
|
|
|
6986
7419
|
import { dirname as dirname18, join as join26 } from "path";
|
|
6987
7420
|
|
|
6988
7421
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
6989
|
-
import
|
|
7422
|
+
import chalk74 from "chalk";
|
|
6990
7423
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
6991
7424
|
function validateStagedContent(filename, content) {
|
|
6992
7425
|
const firstLine = content.split("\n")[0];
|
|
6993
7426
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
6994
7427
|
if (!match) {
|
|
6995
7428
|
console.error(
|
|
6996
|
-
|
|
7429
|
+
chalk74.red(
|
|
6997
7430
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
6998
7431
|
)
|
|
6999
7432
|
);
|
|
@@ -7002,7 +7435,7 @@ function validateStagedContent(filename, content) {
|
|
|
7002
7435
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
7003
7436
|
if (!contentAfterLink) {
|
|
7004
7437
|
console.error(
|
|
7005
|
-
|
|
7438
|
+
chalk74.red(
|
|
7006
7439
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
7007
7440
|
)
|
|
7008
7441
|
);
|
|
@@ -7202,8 +7635,8 @@ import { mkdirSync as mkdirSync10 } from "fs";
|
|
|
7202
7635
|
import { join as join31 } from "path";
|
|
7203
7636
|
|
|
7204
7637
|
// src/commands/voice/checkLockFile.ts
|
|
7205
|
-
import { execSync as
|
|
7206
|
-
import { existsSync as existsSync31, mkdirSync as mkdirSync9, readFileSync as readFileSync25, writeFileSync as
|
|
7638
|
+
import { execSync as execSync32 } from "child_process";
|
|
7639
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync9, readFileSync as readFileSync25, writeFileSync as writeFileSync23 } from "fs";
|
|
7207
7640
|
import { join as join30 } from "path";
|
|
7208
7641
|
function isProcessAlive(pid) {
|
|
7209
7642
|
try {
|
|
@@ -7231,7 +7664,7 @@ function bootstrapVenv() {
|
|
|
7231
7664
|
if (existsSync31(getVenvPython())) return;
|
|
7232
7665
|
console.log("Setting up Python environment...");
|
|
7233
7666
|
const pythonDir = getPythonDir();
|
|
7234
|
-
|
|
7667
|
+
execSync32(
|
|
7235
7668
|
`uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
|
|
7236
7669
|
{
|
|
7237
7670
|
stdio: "inherit",
|
|
@@ -7242,7 +7675,7 @@ function bootstrapVenv() {
|
|
|
7242
7675
|
function writeLockFile(pid) {
|
|
7243
7676
|
const lockFile = getLockFile();
|
|
7244
7677
|
mkdirSync9(join30(lockFile, ".."), { recursive: true });
|
|
7245
|
-
|
|
7678
|
+
writeFileSync23(
|
|
7246
7679
|
lockFile,
|
|
7247
7680
|
JSON.stringify({
|
|
7248
7681
|
pid,
|
|
@@ -7270,7 +7703,7 @@ function setup() {
|
|
|
7270
7703
|
|
|
7271
7704
|
// src/commands/voice/start.ts
|
|
7272
7705
|
import { spawn as spawn4 } from "child_process";
|
|
7273
|
-
import { mkdirSync as mkdirSync11, writeFileSync as
|
|
7706
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync24 } from "fs";
|
|
7274
7707
|
import { join as join32 } from "path";
|
|
7275
7708
|
|
|
7276
7709
|
// src/commands/voice/buildDaemonEnv.ts
|
|
@@ -7299,7 +7732,7 @@ function spawnBackground(python, script, env) {
|
|
|
7299
7732
|
console.error("Failed to start voice daemon");
|
|
7300
7733
|
process.exit(1);
|
|
7301
7734
|
}
|
|
7302
|
-
|
|
7735
|
+
writeFileSync24(voicePaths.pid, String(pid));
|
|
7303
7736
|
writeLockFile(pid);
|
|
7304
7737
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
7305
7738
|
}
|
|
@@ -7395,14 +7828,14 @@ function registerVoice(program2) {
|
|
|
7395
7828
|
|
|
7396
7829
|
// src/commands/roam/auth.ts
|
|
7397
7830
|
import { randomBytes } from "crypto";
|
|
7398
|
-
import
|
|
7831
|
+
import chalk75 from "chalk";
|
|
7399
7832
|
|
|
7400
7833
|
// src/lib/openBrowser.ts
|
|
7401
|
-
import { execSync as
|
|
7834
|
+
import { execSync as execSync33 } from "child_process";
|
|
7402
7835
|
function tryExec(commands) {
|
|
7403
7836
|
for (const cmd of commands) {
|
|
7404
7837
|
try {
|
|
7405
|
-
|
|
7838
|
+
execSync33(cmd);
|
|
7406
7839
|
return true;
|
|
7407
7840
|
} catch {
|
|
7408
7841
|
}
|
|
@@ -7570,13 +8003,13 @@ async function auth() {
|
|
|
7570
8003
|
saveGlobalConfig(config);
|
|
7571
8004
|
const state = randomBytes(16).toString("hex");
|
|
7572
8005
|
console.log(
|
|
7573
|
-
|
|
8006
|
+
chalk75.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
7574
8007
|
);
|
|
7575
|
-
console.log(
|
|
7576
|
-
console.log(
|
|
7577
|
-
console.log(
|
|
8008
|
+
console.log(chalk75.white("http://localhost:14523/callback\n"));
|
|
8009
|
+
console.log(chalk75.blue("Opening browser for authorization..."));
|
|
8010
|
+
console.log(chalk75.dim("Waiting for authorization callback..."));
|
|
7578
8011
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
7579
|
-
console.log(
|
|
8012
|
+
console.log(chalk75.dim("Exchanging code for tokens..."));
|
|
7580
8013
|
const tokens = await exchangeToken({
|
|
7581
8014
|
code,
|
|
7582
8015
|
clientId,
|
|
@@ -7592,7 +8025,7 @@ async function auth() {
|
|
|
7592
8025
|
};
|
|
7593
8026
|
saveGlobalConfig(config);
|
|
7594
8027
|
console.log(
|
|
7595
|
-
|
|
8028
|
+
chalk75.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
7596
8029
|
);
|
|
7597
8030
|
}
|
|
7598
8031
|
|
|
@@ -7639,7 +8072,7 @@ function resolveParams(params, cliArgs) {
|
|
|
7639
8072
|
}
|
|
7640
8073
|
|
|
7641
8074
|
// src/commands/run/add.ts
|
|
7642
|
-
import { mkdirSync as mkdirSync12, writeFileSync as
|
|
8075
|
+
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync25 } from "fs";
|
|
7643
8076
|
import { join as join33 } from "path";
|
|
7644
8077
|
function findAddIndex() {
|
|
7645
8078
|
const addIndex = process.argv.indexOf("add");
|
|
@@ -7657,7 +8090,7 @@ function parseAddArguments() {
|
|
|
7657
8090
|
const addIndex = findAddIndex();
|
|
7658
8091
|
return addIndex === -1 ? null : extractAddArgs(addIndex);
|
|
7659
8092
|
}
|
|
7660
|
-
function
|
|
8093
|
+
function buildRunEntry2(name, command, args) {
|
|
7661
8094
|
const entry = {
|
|
7662
8095
|
name,
|
|
7663
8096
|
command
|
|
@@ -7690,7 +8123,7 @@ function getOrInitRunList() {
|
|
|
7690
8123
|
function saveNewRunConfig(name, command, args) {
|
|
7691
8124
|
const { config, runList } = getOrInitRunList();
|
|
7692
8125
|
ensureNoDuplicate(runList, name);
|
|
7693
|
-
runList.push(
|
|
8126
|
+
runList.push(buildRunEntry2(name, command, args));
|
|
7694
8127
|
saveConfig(config);
|
|
7695
8128
|
}
|
|
7696
8129
|
function createCommandFile(name) {
|
|
@@ -7703,7 +8136,7 @@ description: Run ${name}
|
|
|
7703
8136
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
7704
8137
|
`;
|
|
7705
8138
|
const filePath = join33(dir, `${name}.md`);
|
|
7706
|
-
|
|
8139
|
+
writeFileSync25(filePath, content);
|
|
7707
8140
|
console.log(`Created command file: ${filePath}`);
|
|
7708
8141
|
}
|
|
7709
8142
|
function add3() {
|
|
@@ -7780,14 +8213,14 @@ function run2(name, args) {
|
|
|
7780
8213
|
}
|
|
7781
8214
|
|
|
7782
8215
|
// src/commands/statusLine.ts
|
|
7783
|
-
import
|
|
8216
|
+
import chalk76 from "chalk";
|
|
7784
8217
|
function formatNumber(num) {
|
|
7785
8218
|
return num.toLocaleString("en-US");
|
|
7786
8219
|
}
|
|
7787
8220
|
function colorizePercent(pct) {
|
|
7788
8221
|
const label2 = `${pct}%`;
|
|
7789
|
-
if (pct > 80) return
|
|
7790
|
-
if (pct > 40) return
|
|
8222
|
+
if (pct > 80) return chalk76.red(label2);
|
|
8223
|
+
if (pct > 40) return chalk76.yellow(label2);
|
|
7791
8224
|
return label2;
|
|
7792
8225
|
}
|
|
7793
8226
|
async function statusLine() {
|
|
@@ -7805,29 +8238,29 @@ async function statusLine() {
|
|
|
7805
8238
|
}
|
|
7806
8239
|
|
|
7807
8240
|
// src/commands/sync.ts
|
|
7808
|
-
import * as
|
|
8241
|
+
import * as fs24 from "fs";
|
|
7809
8242
|
import * as os from "os";
|
|
7810
|
-
import * as
|
|
8243
|
+
import * as path40 from "path";
|
|
7811
8244
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
7812
8245
|
|
|
7813
8246
|
// src/commands/sync/syncClaudeMd.ts
|
|
7814
|
-
import * as
|
|
7815
|
-
import * as
|
|
7816
|
-
import
|
|
8247
|
+
import * as fs22 from "fs";
|
|
8248
|
+
import * as path38 from "path";
|
|
8249
|
+
import chalk77 from "chalk";
|
|
7817
8250
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
7818
|
-
const source =
|
|
7819
|
-
const target =
|
|
7820
|
-
const sourceContent =
|
|
7821
|
-
if (
|
|
7822
|
-
const targetContent =
|
|
8251
|
+
const source = path38.join(claudeDir, "CLAUDE.md");
|
|
8252
|
+
const target = path38.join(targetBase, "CLAUDE.md");
|
|
8253
|
+
const sourceContent = fs22.readFileSync(source, "utf-8");
|
|
8254
|
+
if (fs22.existsSync(target)) {
|
|
8255
|
+
const targetContent = fs22.readFileSync(target, "utf-8");
|
|
7823
8256
|
if (sourceContent !== targetContent) {
|
|
7824
8257
|
console.log(
|
|
7825
|
-
|
|
8258
|
+
chalk77.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
7826
8259
|
);
|
|
7827
8260
|
console.log();
|
|
7828
8261
|
printDiff(targetContent, sourceContent);
|
|
7829
8262
|
const confirm = await promptConfirm(
|
|
7830
|
-
|
|
8263
|
+
chalk77.red("Overwrite existing CLAUDE.md?"),
|
|
7831
8264
|
false
|
|
7832
8265
|
);
|
|
7833
8266
|
if (!confirm) {
|
|
@@ -7836,21 +8269,21 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
7836
8269
|
}
|
|
7837
8270
|
}
|
|
7838
8271
|
}
|
|
7839
|
-
|
|
8272
|
+
fs22.copyFileSync(source, target);
|
|
7840
8273
|
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
7841
8274
|
}
|
|
7842
8275
|
|
|
7843
8276
|
// src/commands/sync/syncSettings.ts
|
|
7844
|
-
import * as
|
|
7845
|
-
import * as
|
|
7846
|
-
import
|
|
8277
|
+
import * as fs23 from "fs";
|
|
8278
|
+
import * as path39 from "path";
|
|
8279
|
+
import chalk78 from "chalk";
|
|
7847
8280
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
7848
|
-
const source =
|
|
7849
|
-
const target =
|
|
7850
|
-
const sourceContent =
|
|
8281
|
+
const source = path39.join(claudeDir, "settings.json");
|
|
8282
|
+
const target = path39.join(targetBase, "settings.json");
|
|
8283
|
+
const sourceContent = fs23.readFileSync(source, "utf-8");
|
|
7851
8284
|
const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
|
|
7852
|
-
if (
|
|
7853
|
-
const targetContent =
|
|
8285
|
+
if (fs23.existsSync(target)) {
|
|
8286
|
+
const targetContent = fs23.readFileSync(target, "utf-8");
|
|
7854
8287
|
const normalizedTarget = JSON.stringify(
|
|
7855
8288
|
JSON.parse(targetContent),
|
|
7856
8289
|
null,
|
|
@@ -7859,14 +8292,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7859
8292
|
if (mergedContent !== normalizedTarget) {
|
|
7860
8293
|
if (!options2?.yes) {
|
|
7861
8294
|
console.log(
|
|
7862
|
-
|
|
8295
|
+
chalk78.yellow(
|
|
7863
8296
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
7864
8297
|
)
|
|
7865
8298
|
);
|
|
7866
8299
|
console.log();
|
|
7867
8300
|
printDiff(targetContent, mergedContent);
|
|
7868
8301
|
const confirm = await promptConfirm(
|
|
7869
|
-
|
|
8302
|
+
chalk78.red("Overwrite existing settings.json?"),
|
|
7870
8303
|
false
|
|
7871
8304
|
);
|
|
7872
8305
|
if (!confirm) {
|
|
@@ -7876,43 +8309,43 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7876
8309
|
}
|
|
7877
8310
|
}
|
|
7878
8311
|
}
|
|
7879
|
-
|
|
8312
|
+
fs23.writeFileSync(target, mergedContent);
|
|
7880
8313
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
7881
8314
|
}
|
|
7882
8315
|
|
|
7883
8316
|
// src/commands/sync.ts
|
|
7884
8317
|
var __filename4 = fileURLToPath7(import.meta.url);
|
|
7885
|
-
var __dirname7 =
|
|
8318
|
+
var __dirname7 = path40.dirname(__filename4);
|
|
7886
8319
|
async function sync(options2) {
|
|
7887
|
-
const claudeDir =
|
|
7888
|
-
const targetBase =
|
|
8320
|
+
const claudeDir = path40.join(__dirname7, "..", "claude");
|
|
8321
|
+
const targetBase = path40.join(os.homedir(), ".claude");
|
|
7889
8322
|
syncCommands(claudeDir, targetBase);
|
|
7890
8323
|
await syncSettings(claudeDir, targetBase, { yes: options2?.yes });
|
|
7891
8324
|
await syncClaudeMd(claudeDir, targetBase);
|
|
7892
8325
|
}
|
|
7893
8326
|
function syncCommands(claudeDir, targetBase) {
|
|
7894
|
-
const sourceDir =
|
|
7895
|
-
const targetDir =
|
|
7896
|
-
|
|
7897
|
-
const files =
|
|
8327
|
+
const sourceDir = path40.join(claudeDir, "commands");
|
|
8328
|
+
const targetDir = path40.join(targetBase, "commands");
|
|
8329
|
+
fs24.mkdirSync(targetDir, { recursive: true });
|
|
8330
|
+
const files = fs24.readdirSync(sourceDir);
|
|
7898
8331
|
for (const file of files) {
|
|
7899
|
-
|
|
8332
|
+
fs24.copyFileSync(path40.join(sourceDir, file), path40.join(targetDir, file));
|
|
7900
8333
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
7901
8334
|
}
|
|
7902
8335
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
7903
8336
|
}
|
|
7904
8337
|
|
|
7905
8338
|
// src/commands/update.ts
|
|
7906
|
-
import { execSync as
|
|
7907
|
-
import * as
|
|
8339
|
+
import { execSync as execSync34 } from "child_process";
|
|
8340
|
+
import * as path41 from "path";
|
|
7908
8341
|
function isGlobalNpmInstall(dir) {
|
|
7909
8342
|
try {
|
|
7910
|
-
const resolved =
|
|
7911
|
-
if (resolved.split(
|
|
8343
|
+
const resolved = path41.resolve(dir);
|
|
8344
|
+
if (resolved.split(path41.sep).includes("node_modules")) {
|
|
7912
8345
|
return true;
|
|
7913
8346
|
}
|
|
7914
|
-
const globalPrefix =
|
|
7915
|
-
return resolved.toLowerCase().startsWith(
|
|
8347
|
+
const globalPrefix = execSync34("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
8348
|
+
return resolved.toLowerCase().startsWith(path41.resolve(globalPrefix).toLowerCase());
|
|
7916
8349
|
} catch {
|
|
7917
8350
|
return false;
|
|
7918
8351
|
}
|
|
@@ -7922,18 +8355,18 @@ async function update() {
|
|
|
7922
8355
|
console.log(`Assist is installed at: ${installDir}`);
|
|
7923
8356
|
if (isGitRepo(installDir)) {
|
|
7924
8357
|
console.log("Detected git repo installation, pulling latest...");
|
|
7925
|
-
|
|
8358
|
+
execSync34("git pull", { cwd: installDir, stdio: "inherit" });
|
|
7926
8359
|
console.log("Installing dependencies...");
|
|
7927
|
-
|
|
8360
|
+
execSync34("npm i", { cwd: installDir, stdio: "inherit" });
|
|
7928
8361
|
console.log("Building...");
|
|
7929
|
-
|
|
8362
|
+
execSync34("npm run build", { cwd: installDir, stdio: "inherit" });
|
|
7930
8363
|
console.log("Syncing commands...");
|
|
7931
|
-
|
|
8364
|
+
execSync34("assist sync", { stdio: "inherit" });
|
|
7932
8365
|
} else if (isGlobalNpmInstall(installDir)) {
|
|
7933
8366
|
console.log("Detected global npm installation, updating...");
|
|
7934
|
-
|
|
8367
|
+
execSync34("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
|
|
7935
8368
|
console.log("Syncing commands...");
|
|
7936
|
-
|
|
8369
|
+
execSync34("assist sync", { stdio: "inherit" });
|
|
7937
8370
|
} else {
|
|
7938
8371
|
console.error(
|
|
7939
8372
|
"Could not determine installation method. Expected a git repo or global npm install."
|
|
@@ -7982,6 +8415,7 @@ registerDeploy(program);
|
|
|
7982
8415
|
registerComplexity(program);
|
|
7983
8416
|
registerNetframework(program);
|
|
7984
8417
|
registerNews(program);
|
|
8418
|
+
registerRavendb(program);
|
|
7985
8419
|
registerTranscript(program);
|
|
7986
8420
|
registerVoice(program);
|
|
7987
8421
|
program.parse();
|