workflow-agent-cli 2.8.1 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/{chunk-2WUPMAH3.js → chunk-YEOQZ7XC.js} +11 -4
- package/dist/chunk-YEOQZ7XC.js.map +1 -0
- package/dist/chunk-ZLDJ2OGO.js +386 -0
- package/dist/chunk-ZLDJ2OGO.js.map +1 -0
- package/dist/cli/index.js +921 -382
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9 -1
- package/dist/scripts/postinstall.js +1 -1
- package/dist/validators/index.d.ts +32 -2
- package/dist/validators/index.js +9 -1
- package/package.json +33 -32
- package/dist/chunk-2WUPMAH3.js.map +0 -1
- package/dist/chunk-NMHWD2GA.js +0 -175
- package/dist/chunk-NMHWD2GA.js.map +0 -1
- package/dist/{schema-BUu8Cefw.d.ts → schema-D0zTM83x.d.ts} +4 -4
package/dist/cli/index.js
CHANGED
|
@@ -10,10 +10,12 @@ import {
|
|
|
10
10
|
stageAllChanges
|
|
11
11
|
} from "../chunk-6NWQLGHI.js";
|
|
12
12
|
import {
|
|
13
|
+
applyReferenceFix,
|
|
13
14
|
validateBranchName,
|
|
14
15
|
validateCommitMessage,
|
|
16
|
+
validateDocumentReferences,
|
|
15
17
|
validatePRTitle
|
|
16
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-ZLDJ2OGO.js";
|
|
17
19
|
import {
|
|
18
20
|
hasConfig,
|
|
19
21
|
loadConfig,
|
|
@@ -29,7 +31,7 @@ import {
|
|
|
29
31
|
installMandatoryTemplates,
|
|
30
32
|
templateMetadata,
|
|
31
33
|
updateTemplates
|
|
32
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-YEOQZ7XC.js";
|
|
33
35
|
|
|
34
36
|
// src/cli/index.ts
|
|
35
37
|
import { Command } from "commander";
|
|
@@ -316,10 +318,10 @@ async function initCommand(options) {
|
|
|
316
318
|
try {
|
|
317
319
|
const presetModule = await import(`@workflow/scopes-${preset}`);
|
|
318
320
|
scopes = presetModule.scopes || presetModule.default.scopes;
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
+
const spinner10 = p.spinner();
|
|
322
|
+
spinner10.start(`Loading ${presetModule.default?.name || preset} preset`);
|
|
321
323
|
await new Promise((resolve2) => setTimeout(resolve2, 500));
|
|
322
|
-
|
|
324
|
+
spinner10.stop(`\u2713 Loaded ${scopes.length} scopes from preset`);
|
|
323
325
|
} catch (error) {
|
|
324
326
|
console.log(
|
|
325
327
|
chalk.yellow(
|
|
@@ -357,17 +359,17 @@ async function initCommand(options) {
|
|
|
357
359
|
if (!existsSync(workflowDir)) {
|
|
358
360
|
await mkdir(workflowDir, { recursive: true });
|
|
359
361
|
}
|
|
360
|
-
const shouldGenerateGuidelines = await p.confirm({
|
|
362
|
+
const shouldGenerateGuidelines = options.yes || isNonInteractive ? true : await p.confirm({
|
|
361
363
|
message: "Generate workflow guidelines from templates?",
|
|
362
364
|
initialValue: true
|
|
363
365
|
});
|
|
364
|
-
if (p.isCancel(shouldGenerateGuidelines)) {
|
|
366
|
+
if (!isNonInteractive && p.isCancel(shouldGenerateGuidelines)) {
|
|
365
367
|
p.cancel("Initialization cancelled");
|
|
366
368
|
process.exit(0);
|
|
367
369
|
}
|
|
368
370
|
if (shouldGenerateGuidelines) {
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
+
const spinner10 = p.spinner();
|
|
372
|
+
spinner10.start("Generating guidelines...");
|
|
371
373
|
try {
|
|
372
374
|
const templatesDir = join(__dirname, "../../templates");
|
|
373
375
|
await validateTemplateDirectory(templatesDir);
|
|
@@ -379,7 +381,7 @@ async function initCommand(options) {
|
|
|
379
381
|
guidelinesDir,
|
|
380
382
|
context
|
|
381
383
|
);
|
|
382
|
-
|
|
384
|
+
spinner10.stop(`\u2713 Generated ${renderedFiles.length} guideline documents`);
|
|
383
385
|
const instructionsSpinner = p.spinner();
|
|
384
386
|
instructionsSpinner.start("Generating AI agent instructions...");
|
|
385
387
|
const result = generateCopilotInstructions(cwd, { silent: true });
|
|
@@ -389,7 +391,7 @@ async function initCommand(options) {
|
|
|
389
391
|
instructionsSpinner.stop("\u26A0\uFE0F Could not generate copilot instructions");
|
|
390
392
|
}
|
|
391
393
|
} catch (error) {
|
|
392
|
-
|
|
394
|
+
spinner10.stop("\u26A0\uFE0F Could not generate guidelines");
|
|
393
395
|
console.log(
|
|
394
396
|
chalk.yellow(
|
|
395
397
|
`
|
|
@@ -401,11 +403,11 @@ Reason: ${error instanceof Error ? error.message : String(error)}`
|
|
|
401
403
|
);
|
|
402
404
|
}
|
|
403
405
|
}
|
|
404
|
-
const shouldAutoSetup = options.yes ? true : await p.confirm({
|
|
406
|
+
const shouldAutoSetup = options.yes || isNonInteractive ? true : await p.confirm({
|
|
405
407
|
message: "Set up linting, formatting, testing, and CI automatically?",
|
|
406
408
|
initialValue: true
|
|
407
409
|
});
|
|
408
|
-
if (p.isCancel(shouldAutoSetup)) {
|
|
410
|
+
if (!isNonInteractive && p.isCancel(shouldAutoSetup)) {
|
|
409
411
|
p.cancel("Initialization cancelled");
|
|
410
412
|
process.exit(0);
|
|
411
413
|
}
|
|
@@ -588,7 +590,204 @@ async function suggestCommand(feedback, options = {}) {
|
|
|
588
590
|
|
|
589
591
|
// src/cli/commands/doctor.ts
|
|
590
592
|
import chalk5 from "chalk";
|
|
591
|
-
|
|
593
|
+
import { existsSync as existsSync3 } from "fs";
|
|
594
|
+
import { join as join3 } from "path";
|
|
595
|
+
|
|
596
|
+
// src/utils/hooks.ts
|
|
597
|
+
import { existsSync as existsSync2 } from "fs";
|
|
598
|
+
import { readFile, writeFile as writeFile2, unlink, chmod, rename, mkdir as mkdir2 } from "fs/promises";
|
|
599
|
+
import { join as join2 } from "path";
|
|
600
|
+
function getGitHooksDir(projectPath = process.cwd()) {
|
|
601
|
+
return join2(projectPath, ".git", "hooks");
|
|
602
|
+
}
|
|
603
|
+
function hasGitRepo(projectPath = process.cwd()) {
|
|
604
|
+
return existsSync2(join2(projectPath, ".git"));
|
|
605
|
+
}
|
|
606
|
+
function generatePreCommitHook(config) {
|
|
607
|
+
const checks = config?.preCommit || ["validate-branch", "check-guidelines"];
|
|
608
|
+
const checkCommands = checks.map((check) => {
|
|
609
|
+
switch (check) {
|
|
610
|
+
case "validate-branch":
|
|
611
|
+
return " workflow validate branch";
|
|
612
|
+
case "validate-commit":
|
|
613
|
+
return " workflow validate commit";
|
|
614
|
+
case "check-guidelines":
|
|
615
|
+
return " workflow doctor --check-guidelines-only 2>/dev/null || true";
|
|
616
|
+
case "validate-scopes":
|
|
617
|
+
return " workflow config validate";
|
|
618
|
+
default:
|
|
619
|
+
return "";
|
|
620
|
+
}
|
|
621
|
+
}).filter(Boolean).join("\n");
|
|
622
|
+
return `#!/bin/sh
|
|
623
|
+
# Workflow Agent pre-commit hook
|
|
624
|
+
# Auto-generated - do not edit manually
|
|
625
|
+
# To reinstall: workflow hooks install
|
|
626
|
+
# To uninstall: workflow hooks uninstall
|
|
627
|
+
|
|
628
|
+
# Skip in CI environment
|
|
629
|
+
if [ -n "\${CI:-}" ] || [ -n "\${GITHUB_ACTIONS:-}" ] || [ -n "\${GITLAB_CI:-}" ]; then
|
|
630
|
+
exit 0
|
|
631
|
+
fi
|
|
632
|
+
|
|
633
|
+
# Run workflow checks
|
|
634
|
+
${checkCommands}
|
|
635
|
+
|
|
636
|
+
# Run original hook if it exists
|
|
637
|
+
if [ -f ".git/hooks/pre-commit.original" ]; then
|
|
638
|
+
.git/hooks/pre-commit.original "$@"
|
|
639
|
+
fi
|
|
640
|
+
`;
|
|
641
|
+
}
|
|
642
|
+
function generateCommitMsgHook(config) {
|
|
643
|
+
const checks = config?.commitMsg || ["validate-commit"];
|
|
644
|
+
const checkCommands = checks.map((check) => {
|
|
645
|
+
switch (check) {
|
|
646
|
+
case "validate-commit":
|
|
647
|
+
return ' workflow validate commit "$(cat "$1")"';
|
|
648
|
+
default:
|
|
649
|
+
return "";
|
|
650
|
+
}
|
|
651
|
+
}).filter(Boolean).join("\n");
|
|
652
|
+
return `#!/bin/sh
|
|
653
|
+
# Workflow Agent commit-msg hook
|
|
654
|
+
# Auto-generated - do not edit manually
|
|
655
|
+
# To reinstall: workflow hooks install
|
|
656
|
+
# To uninstall: workflow hooks uninstall
|
|
657
|
+
|
|
658
|
+
# Skip in CI environment
|
|
659
|
+
if [ -n "\${CI:-}" ] || [ -n "\${GITHUB_ACTIONS:-}" ] || [ -n "\${GITLAB_CI:-}" ]; then
|
|
660
|
+
exit 0
|
|
661
|
+
fi
|
|
662
|
+
|
|
663
|
+
# Run workflow checks
|
|
664
|
+
${checkCommands}
|
|
665
|
+
|
|
666
|
+
# Run original hook if it exists
|
|
667
|
+
if [ -f ".git/hooks/commit-msg.original" ]; then
|
|
668
|
+
.git/hooks/commit-msg.original "$@"
|
|
669
|
+
fi
|
|
670
|
+
`;
|
|
671
|
+
}
|
|
672
|
+
async function isWorkflowHook(hookPath) {
|
|
673
|
+
try {
|
|
674
|
+
const content = await readFile(hookPath, "utf-8");
|
|
675
|
+
return content.includes("Workflow Agent") && content.includes("Auto-generated");
|
|
676
|
+
} catch {
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
async function getHookStatus(hookType, projectPath = process.cwd()) {
|
|
681
|
+
const hooksDir = getGitHooksDir(projectPath);
|
|
682
|
+
const hookPath = join2(hooksDir, hookType);
|
|
683
|
+
const originalPath = join2(hooksDir, `${hookType}.original`);
|
|
684
|
+
const status = {
|
|
685
|
+
installed: false,
|
|
686
|
+
hookType,
|
|
687
|
+
hasExistingHook: false,
|
|
688
|
+
wrappedOriginal: false
|
|
689
|
+
};
|
|
690
|
+
if (!existsSync2(hookPath)) {
|
|
691
|
+
return status;
|
|
692
|
+
}
|
|
693
|
+
status.hasExistingHook = true;
|
|
694
|
+
if (await isWorkflowHook(hookPath)) {
|
|
695
|
+
status.installed = true;
|
|
696
|
+
status.wrappedOriginal = existsSync2(originalPath);
|
|
697
|
+
}
|
|
698
|
+
return status;
|
|
699
|
+
}
|
|
700
|
+
async function getAllHooksStatus(projectPath = process.cwd()) {
|
|
701
|
+
return Promise.all([
|
|
702
|
+
getHookStatus("pre-commit", projectPath),
|
|
703
|
+
getHookStatus("commit-msg", projectPath)
|
|
704
|
+
]);
|
|
705
|
+
}
|
|
706
|
+
async function installSingleHook(hookType, config, projectPath = process.cwd()) {
|
|
707
|
+
const hooksDir = getGitHooksDir(projectPath);
|
|
708
|
+
const hookPath = join2(hooksDir, hookType);
|
|
709
|
+
const originalPath = join2(hooksDir, `${hookType}.original`);
|
|
710
|
+
const result = {
|
|
711
|
+
success: false,
|
|
712
|
+
hookType,
|
|
713
|
+
wrappedExisting: false
|
|
714
|
+
};
|
|
715
|
+
try {
|
|
716
|
+
if (!existsSync2(hooksDir)) {
|
|
717
|
+
await mkdir2(hooksDir, { recursive: true });
|
|
718
|
+
}
|
|
719
|
+
if (existsSync2(hookPath)) {
|
|
720
|
+
const isOurs = await isWorkflowHook(hookPath);
|
|
721
|
+
if (!isOurs) {
|
|
722
|
+
await rename(hookPath, originalPath);
|
|
723
|
+
result.wrappedExisting = true;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
const hookContent = hookType === "pre-commit" ? generatePreCommitHook(config) : generateCommitMsgHook(config);
|
|
727
|
+
await writeFile2(hookPath, hookContent, "utf-8");
|
|
728
|
+
await chmod(hookPath, 493);
|
|
729
|
+
result.success = true;
|
|
730
|
+
} catch (error) {
|
|
731
|
+
result.error = error instanceof Error ? error.message : String(error);
|
|
732
|
+
}
|
|
733
|
+
return result;
|
|
734
|
+
}
|
|
735
|
+
async function installHooks(config, projectPath = process.cwd()) {
|
|
736
|
+
if (!hasGitRepo(projectPath)) {
|
|
737
|
+
return [
|
|
738
|
+
{
|
|
739
|
+
success: false,
|
|
740
|
+
hookType: "pre-commit",
|
|
741
|
+
wrappedExisting: false,
|
|
742
|
+
error: "No git repository found. Run git init first."
|
|
743
|
+
}
|
|
744
|
+
];
|
|
745
|
+
}
|
|
746
|
+
const results = await Promise.all([
|
|
747
|
+
installSingleHook("pre-commit", config, projectPath),
|
|
748
|
+
installSingleHook("commit-msg", config, projectPath)
|
|
749
|
+
]);
|
|
750
|
+
return results;
|
|
751
|
+
}
|
|
752
|
+
async function uninstallSingleHook(hookType, projectPath = process.cwd()) {
|
|
753
|
+
const hooksDir = getGitHooksDir(projectPath);
|
|
754
|
+
const hookPath = join2(hooksDir, hookType);
|
|
755
|
+
const originalPath = join2(hooksDir, `${hookType}.original`);
|
|
756
|
+
const result = {
|
|
757
|
+
success: false,
|
|
758
|
+
hookType,
|
|
759
|
+
wrappedExisting: false
|
|
760
|
+
};
|
|
761
|
+
try {
|
|
762
|
+
if (!existsSync2(hookPath)) {
|
|
763
|
+
result.success = true;
|
|
764
|
+
return result;
|
|
765
|
+
}
|
|
766
|
+
const isOurs = await isWorkflowHook(hookPath);
|
|
767
|
+
if (!isOurs) {
|
|
768
|
+
result.error = "Hook is not managed by Workflow Agent";
|
|
769
|
+
return result;
|
|
770
|
+
}
|
|
771
|
+
await unlink(hookPath);
|
|
772
|
+
if (existsSync2(originalPath)) {
|
|
773
|
+
await rename(originalPath, hookPath);
|
|
774
|
+
result.wrappedExisting = true;
|
|
775
|
+
}
|
|
776
|
+
result.success = true;
|
|
777
|
+
} catch (error) {
|
|
778
|
+
result.error = error instanceof Error ? error.message : String(error);
|
|
779
|
+
}
|
|
780
|
+
return result;
|
|
781
|
+
}
|
|
782
|
+
async function uninstallHooks(projectPath = process.cwd()) {
|
|
783
|
+
return Promise.all([
|
|
784
|
+
uninstallSingleHook("pre-commit", projectPath),
|
|
785
|
+
uninstallSingleHook("commit-msg", projectPath)
|
|
786
|
+
]);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// src/cli/commands/doctor.ts
|
|
790
|
+
async function doctorCommand(options) {
|
|
592
791
|
console.log(chalk5.bold.cyan("\n\u{1F3E5} Workflow Agent Health Check\n"));
|
|
593
792
|
const config = await loadConfig();
|
|
594
793
|
if (!config) {
|
|
@@ -601,25 +800,72 @@ async function doctorCommand() {
|
|
|
601
800
|
console.log(chalk5.dim(` Scopes: ${config.scopes.length} configured`));
|
|
602
801
|
console.log(chalk5.dim(` Enforcement: ${config.enforcement}`));
|
|
603
802
|
console.log(chalk5.dim(` Language: ${config.language}`));
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
803
|
+
const cwd = process.cwd();
|
|
804
|
+
const guidelinesDir = join3(cwd, "guidelines");
|
|
805
|
+
const mandatoryFiles = getMandatoryTemplateFilenames();
|
|
806
|
+
const missingFiles = [];
|
|
807
|
+
console.log(chalk5.cyan("\n\u{1F4DA} Guidelines Check:\n"));
|
|
808
|
+
for (const filename of mandatoryFiles) {
|
|
809
|
+
const filePath = join3(guidelinesDir, filename);
|
|
810
|
+
if (existsSync3(filePath)) {
|
|
811
|
+
console.log(chalk5.green(`\u2713 ${filename}`));
|
|
812
|
+
} else {
|
|
813
|
+
console.log(chalk5.red(`\u2717 ${filename} (missing)`));
|
|
814
|
+
missingFiles.push(filename);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
if (missingFiles.length === 0) {
|
|
818
|
+
console.log(
|
|
819
|
+
chalk5.green(`
|
|
820
|
+
\u2713 All ${mandatoryFiles.length} mandatory guidelines present`)
|
|
821
|
+
);
|
|
822
|
+
} else {
|
|
823
|
+
console.log(
|
|
824
|
+
chalk5.red(
|
|
825
|
+
`
|
|
826
|
+
\u2717 Missing ${missingFiles.length} mandatory guideline(s)`
|
|
827
|
+
)
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
if (options?.checkGuidelinesOnly) {
|
|
831
|
+
process.exit(missingFiles.length > 0 ? 1 : 0);
|
|
832
|
+
}
|
|
833
|
+
console.log(chalk5.cyan("\n\u{1F517} Git Hooks Check:\n"));
|
|
834
|
+
if (!hasGitRepo(cwd)) {
|
|
835
|
+
console.log(chalk5.yellow("\u26A0 No git repository found"));
|
|
836
|
+
console.log(chalk5.dim(" Run: git init"));
|
|
837
|
+
} else {
|
|
838
|
+
const hooksStatus = getAllHooksStatus(cwd);
|
|
839
|
+
for (const status of hooksStatus) {
|
|
840
|
+
if (status.installed) {
|
|
841
|
+
console.log(chalk5.green(`\u2713 ${status.hookType}: installed`));
|
|
842
|
+
} else {
|
|
843
|
+
console.log(chalk5.yellow(`\u26A0 ${status.hookType}: not installed`));
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const allInstalled = hooksStatus.every((s) => s.installed);
|
|
847
|
+
if (!allInstalled) {
|
|
848
|
+
console.log(chalk5.dim("\n Run: workflow hooks install"));
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
if (missingFiles.length > 0) {
|
|
852
|
+
process.exit(1);
|
|
853
|
+
}
|
|
608
854
|
}
|
|
609
855
|
|
|
610
856
|
// src/cli/commands/setup.ts
|
|
611
857
|
import * as p3 from "@clack/prompts";
|
|
612
858
|
import chalk6 from "chalk";
|
|
613
|
-
import { readFileSync, writeFileSync, existsSync as
|
|
614
|
-
import { join as
|
|
859
|
+
import { readFileSync, writeFileSync, existsSync as existsSync4 } from "fs";
|
|
860
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
615
861
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
616
862
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
617
863
|
var __dirname2 = dirname2(__filename2);
|
|
618
864
|
async function setupCommand() {
|
|
619
865
|
p3.intro(chalk6.bgBlue(" workflow-agent setup "));
|
|
620
866
|
const cwd = process.cwd();
|
|
621
|
-
const packageJsonPath =
|
|
622
|
-
if (!
|
|
867
|
+
const packageJsonPath = join4(cwd, "package.json");
|
|
868
|
+
if (!existsSync4(packageJsonPath)) {
|
|
623
869
|
p3.cancel("No package.json found in current directory");
|
|
624
870
|
process.exit(1);
|
|
625
871
|
}
|
|
@@ -684,8 +930,8 @@ async function setupCommand() {
|
|
|
684
930
|
console.log(chalk6.dim("\nRun them with:"));
|
|
685
931
|
console.log(chalk6.dim(" pnpm run workflow:init"));
|
|
686
932
|
console.log(chalk6.dim(" npm run workflow:init\n"));
|
|
687
|
-
const guidelinesDir =
|
|
688
|
-
if (!
|
|
933
|
+
const guidelinesDir = join4(cwd, "guidelines");
|
|
934
|
+
if (!existsSync4(guidelinesDir)) {
|
|
689
935
|
const templatesDir = findTemplatesDirectory(__dirname2);
|
|
690
936
|
if (templatesDir) {
|
|
691
937
|
const templateResult = installMandatoryTemplates(cwd, templatesDir, {
|
|
@@ -703,7 +949,7 @@ async function setupCommand() {
|
|
|
703
949
|
}
|
|
704
950
|
}
|
|
705
951
|
}
|
|
706
|
-
if (
|
|
952
|
+
if (existsSync4(guidelinesDir)) {
|
|
707
953
|
const result = generateCopilotInstructions(cwd, { silent: false });
|
|
708
954
|
if (result.success) {
|
|
709
955
|
const status = result.isNew ? "Generated" : "Updated";
|
|
@@ -722,14 +968,14 @@ async function setupCommand() {
|
|
|
722
968
|
// src/cli/commands/scope-create.ts
|
|
723
969
|
import * as p4 from "@clack/prompts";
|
|
724
970
|
import chalk7 from "chalk";
|
|
725
|
-
import { existsSync as
|
|
726
|
-
import { writeFile as
|
|
727
|
-
import { join as
|
|
971
|
+
import { existsSync as existsSync5 } from "fs";
|
|
972
|
+
import { writeFile as writeFile3, mkdir as mkdir3, readFile as readFile2 } from "fs/promises";
|
|
973
|
+
import { join as join5 } from "path";
|
|
728
974
|
async function scopeCreateCommand(options) {
|
|
729
975
|
console.log(chalk7.bold.cyan("\n\u{1F3A8} Create Custom Scope Package\n"));
|
|
730
976
|
const cwd = process.cwd();
|
|
731
977
|
const isNonInteractive = !!(options.name && options.scopes && options.presetName);
|
|
732
|
-
const isMonorepo2 =
|
|
978
|
+
const isMonorepo2 = existsSync5(join5(cwd, "pnpm-workspace.yaml"));
|
|
733
979
|
if (isMonorepo2) {
|
|
734
980
|
console.log(chalk7.dim("\u2713 Detected monorepo workspace\n"));
|
|
735
981
|
}
|
|
@@ -875,7 +1121,7 @@ async function scopeCreateCommand(options) {
|
|
|
875
1121
|
if (options.outputDir) {
|
|
876
1122
|
outputDir = options.outputDir;
|
|
877
1123
|
} else if (isMonorepo2) {
|
|
878
|
-
outputDir =
|
|
1124
|
+
outputDir = join5(cwd, "packages", `scopes-${packageName}`);
|
|
879
1125
|
} else {
|
|
880
1126
|
const customDir = await p4.text({
|
|
881
1127
|
message: "Output directory:",
|
|
@@ -886,9 +1132,9 @@ async function scopeCreateCommand(options) {
|
|
|
886
1132
|
p4.cancel("Operation cancelled");
|
|
887
1133
|
process.exit(0);
|
|
888
1134
|
}
|
|
889
|
-
outputDir =
|
|
1135
|
+
outputDir = join5(cwd, customDir);
|
|
890
1136
|
}
|
|
891
|
-
if (
|
|
1137
|
+
if (existsSync5(outputDir)) {
|
|
892
1138
|
const shouldOverwrite = await p4.confirm({
|
|
893
1139
|
message: `Directory ${outputDir} already exists. Overwrite?`,
|
|
894
1140
|
initialValue: false
|
|
@@ -898,10 +1144,10 @@ async function scopeCreateCommand(options) {
|
|
|
898
1144
|
process.exit(0);
|
|
899
1145
|
}
|
|
900
1146
|
}
|
|
901
|
-
const
|
|
902
|
-
|
|
1147
|
+
const spinner10 = p4.spinner();
|
|
1148
|
+
spinner10.start("Creating package structure...");
|
|
903
1149
|
try {
|
|
904
|
-
await
|
|
1150
|
+
await mkdir3(join5(outputDir, "src"), { recursive: true });
|
|
905
1151
|
const packageJson = {
|
|
906
1152
|
name: `@workflow/scopes-${packageName}`,
|
|
907
1153
|
version: "1.0.0",
|
|
@@ -941,8 +1187,8 @@ async function scopeCreateCommand(options) {
|
|
|
941
1187
|
access: "public"
|
|
942
1188
|
}
|
|
943
1189
|
};
|
|
944
|
-
await
|
|
945
|
-
|
|
1190
|
+
await writeFile3(
|
|
1191
|
+
join5(outputDir, "package.json"),
|
|
946
1192
|
JSON.stringify(packageJson, null, 2),
|
|
947
1193
|
"utf-8"
|
|
948
1194
|
);
|
|
@@ -954,8 +1200,8 @@ async function scopeCreateCommand(options) {
|
|
|
954
1200
|
},
|
|
955
1201
|
include: ["src/**/*"]
|
|
956
1202
|
};
|
|
957
|
-
await
|
|
958
|
-
|
|
1203
|
+
await writeFile3(
|
|
1204
|
+
join5(outputDir, "tsconfig.json"),
|
|
959
1205
|
JSON.stringify(tsconfig, null, 2),
|
|
960
1206
|
"utf-8"
|
|
961
1207
|
);
|
|
@@ -969,7 +1215,7 @@ export default defineConfig({
|
|
|
969
1215
|
sourcemap: true,
|
|
970
1216
|
});
|
|
971
1217
|
`;
|
|
972
|
-
await
|
|
1218
|
+
await writeFile3(join5(outputDir, "tsup.config.ts"), tsupConfig, "utf-8");
|
|
973
1219
|
const indexTs = `import type { Scope } from '@hawkinside_out/workflow-agent/config';
|
|
974
1220
|
|
|
975
1221
|
export const scopes: Scope[] = ${JSON.stringify(scopes, null, 2)};
|
|
@@ -983,7 +1229,7 @@ export const preset = {
|
|
|
983
1229
|
|
|
984
1230
|
export default preset;
|
|
985
1231
|
`;
|
|
986
|
-
await
|
|
1232
|
+
await writeFile3(join5(outputDir, "src", "index.ts"), indexTs, "utf-8");
|
|
987
1233
|
if (!options.noTest) {
|
|
988
1234
|
const testFile = `import { describe, it, expect } from 'vitest';
|
|
989
1235
|
import { scopes, preset } from './index.js';
|
|
@@ -1024,16 +1270,16 @@ describe('${presetName} Scope Preset', () => {
|
|
|
1024
1270
|
});
|
|
1025
1271
|
});
|
|
1026
1272
|
`;
|
|
1027
|
-
await
|
|
1028
|
-
|
|
1273
|
+
await writeFile3(
|
|
1274
|
+
join5(outputDir, "src", "index.test.ts"),
|
|
1029
1275
|
testFile,
|
|
1030
1276
|
"utf-8"
|
|
1031
1277
|
);
|
|
1032
1278
|
}
|
|
1033
|
-
|
|
1279
|
+
spinner10.stop("\u2713 Package structure created");
|
|
1034
1280
|
if (isMonorepo2) {
|
|
1035
|
-
const workspaceFile =
|
|
1036
|
-
const workspaceContent = await
|
|
1281
|
+
const workspaceFile = join5(cwd, "pnpm-workspace.yaml");
|
|
1282
|
+
const workspaceContent = await readFile2(workspaceFile, "utf-8");
|
|
1037
1283
|
const packagePath = `packages/scopes-${packageName}`;
|
|
1038
1284
|
if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
|
|
1039
1285
|
console.log(
|
|
@@ -1082,7 +1328,7 @@ describe('${presetName} Scope Preset', () => {
|
|
|
1082
1328
|
);
|
|
1083
1329
|
}
|
|
1084
1330
|
} catch (error) {
|
|
1085
|
-
|
|
1331
|
+
spinner10.stop("\u2717 Failed to create package");
|
|
1086
1332
|
console.error(chalk7.red("\nError:"), error);
|
|
1087
1333
|
process.exit(1);
|
|
1088
1334
|
}
|
|
@@ -1091,9 +1337,9 @@ describe('${presetName} Scope Preset', () => {
|
|
|
1091
1337
|
// src/cli/commands/scope-migrate.ts
|
|
1092
1338
|
import * as p5 from "@clack/prompts";
|
|
1093
1339
|
import chalk8 from "chalk";
|
|
1094
|
-
import { existsSync as
|
|
1095
|
-
import { writeFile as
|
|
1096
|
-
import { join as
|
|
1340
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1341
|
+
import { writeFile as writeFile4, mkdir as mkdir4, readFile as readFile3 } from "fs/promises";
|
|
1342
|
+
import { join as join6 } from "path";
|
|
1097
1343
|
async function scopeMigrateCommand(options) {
|
|
1098
1344
|
console.log(chalk8.bold.cyan("\n\u{1F504} Migrate Scopes to Custom Package\n"));
|
|
1099
1345
|
const cwd = process.cwd();
|
|
@@ -1137,7 +1383,7 @@ async function scopeMigrateCommand(options) {
|
|
|
1137
1383
|
p5.cancel("Migration cancelled");
|
|
1138
1384
|
process.exit(0);
|
|
1139
1385
|
}
|
|
1140
|
-
const isMonorepo2 =
|
|
1386
|
+
const isMonorepo2 = existsSync6(join6(cwd, "pnpm-workspace.yaml"));
|
|
1141
1387
|
if (isMonorepo2) {
|
|
1142
1388
|
console.log(chalk8.dim("\n\u2713 Detected monorepo workspace\n"));
|
|
1143
1389
|
}
|
|
@@ -1187,7 +1433,7 @@ async function scopeMigrateCommand(options) {
|
|
|
1187
1433
|
if (options.outputDir) {
|
|
1188
1434
|
outputDir = options.outputDir;
|
|
1189
1435
|
} else if (isMonorepo2) {
|
|
1190
|
-
outputDir =
|
|
1436
|
+
outputDir = join6(cwd, "packages", `scopes-${packageName}`);
|
|
1191
1437
|
} else {
|
|
1192
1438
|
const customDir = await p5.text({
|
|
1193
1439
|
message: "Output directory:",
|
|
@@ -1198,9 +1444,9 @@ async function scopeMigrateCommand(options) {
|
|
|
1198
1444
|
p5.cancel("Migration cancelled");
|
|
1199
1445
|
process.exit(0);
|
|
1200
1446
|
}
|
|
1201
|
-
outputDir =
|
|
1447
|
+
outputDir = join6(cwd, customDir);
|
|
1202
1448
|
}
|
|
1203
|
-
if (
|
|
1449
|
+
if (existsSync6(outputDir)) {
|
|
1204
1450
|
const shouldOverwrite = await p5.confirm({
|
|
1205
1451
|
message: `Directory ${outputDir} already exists. Overwrite?`,
|
|
1206
1452
|
initialValue: false
|
|
@@ -1210,10 +1456,10 @@ async function scopeMigrateCommand(options) {
|
|
|
1210
1456
|
process.exit(0);
|
|
1211
1457
|
}
|
|
1212
1458
|
}
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1459
|
+
const spinner10 = p5.spinner();
|
|
1460
|
+
spinner10.start("Migrating scopes to package...");
|
|
1215
1461
|
try {
|
|
1216
|
-
await
|
|
1462
|
+
await mkdir4(join6(outputDir, "src"), { recursive: true });
|
|
1217
1463
|
const packageJson = {
|
|
1218
1464
|
name: `@workflow/scopes-${packageName}`,
|
|
1219
1465
|
version: "1.0.0",
|
|
@@ -1253,8 +1499,8 @@ async function scopeMigrateCommand(options) {
|
|
|
1253
1499
|
access: "public"
|
|
1254
1500
|
}
|
|
1255
1501
|
};
|
|
1256
|
-
await
|
|
1257
|
-
|
|
1502
|
+
await writeFile4(
|
|
1503
|
+
join6(outputDir, "package.json"),
|
|
1258
1504
|
JSON.stringify(packageJson, null, 2),
|
|
1259
1505
|
"utf-8"
|
|
1260
1506
|
);
|
|
@@ -1266,8 +1512,8 @@ async function scopeMigrateCommand(options) {
|
|
|
1266
1512
|
},
|
|
1267
1513
|
include: ["src/**/*"]
|
|
1268
1514
|
};
|
|
1269
|
-
await
|
|
1270
|
-
|
|
1515
|
+
await writeFile4(
|
|
1516
|
+
join6(outputDir, "tsconfig.json"),
|
|
1271
1517
|
JSON.stringify(tsconfig, null, 2),
|
|
1272
1518
|
"utf-8"
|
|
1273
1519
|
);
|
|
@@ -1281,7 +1527,7 @@ export default defineConfig({
|
|
|
1281
1527
|
sourcemap: true,
|
|
1282
1528
|
});
|
|
1283
1529
|
`;
|
|
1284
|
-
await
|
|
1530
|
+
await writeFile4(join6(outputDir, "tsup.config.ts"), tsupConfig, "utf-8");
|
|
1285
1531
|
const indexTs = `import type { Scope } from '@hawkinside_out/workflow-agent/config';
|
|
1286
1532
|
|
|
1287
1533
|
export const scopes: Scope[] = ${JSON.stringify(config.scopes, null, 2)};
|
|
@@ -1295,7 +1541,7 @@ export const preset = {
|
|
|
1295
1541
|
|
|
1296
1542
|
export default preset;
|
|
1297
1543
|
`;
|
|
1298
|
-
await
|
|
1544
|
+
await writeFile4(join6(outputDir, "src", "index.ts"), indexTs, "utf-8");
|
|
1299
1545
|
const testFile = `import { describe, it, expect } from 'vitest';
|
|
1300
1546
|
import { scopes, preset } from './index.js';
|
|
1301
1547
|
import { ScopeSchema } from '@hawkinside_out/workflow-agent/config';
|
|
@@ -1338,11 +1584,11 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
1338
1584
|
});
|
|
1339
1585
|
});
|
|
1340
1586
|
`;
|
|
1341
|
-
await
|
|
1342
|
-
|
|
1587
|
+
await writeFile4(join6(outputDir, "src", "index.test.ts"), testFile, "utf-8");
|
|
1588
|
+
spinner10.stop("\u2713 Package created from migrated scopes");
|
|
1343
1589
|
if (isMonorepo2) {
|
|
1344
|
-
const workspaceFile =
|
|
1345
|
-
const workspaceContent = await
|
|
1590
|
+
const workspaceFile = join6(cwd, "pnpm-workspace.yaml");
|
|
1591
|
+
const workspaceContent = await readFile3(workspaceFile, "utf-8");
|
|
1346
1592
|
const packagePath = `packages/scopes-${packageName}`;
|
|
1347
1593
|
if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
|
|
1348
1594
|
console.log(
|
|
@@ -1358,7 +1604,7 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
1358
1604
|
initialValue: false
|
|
1359
1605
|
});
|
|
1360
1606
|
if (!p5.isCancel(keepConfig) && !keepConfig) {
|
|
1361
|
-
const configPath =
|
|
1607
|
+
const configPath = join6(cwd, "workflow.config.json");
|
|
1362
1608
|
const updatedConfig = {
|
|
1363
1609
|
...config,
|
|
1364
1610
|
scopes: [],
|
|
@@ -1366,7 +1612,7 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
1366
1612
|
preset: `scopes-${packageName}`
|
|
1367
1613
|
// Reference the new package
|
|
1368
1614
|
};
|
|
1369
|
-
await
|
|
1615
|
+
await writeFile4(
|
|
1370
1616
|
configPath,
|
|
1371
1617
|
JSON.stringify(updatedConfig, null, 2),
|
|
1372
1618
|
"utf-8"
|
|
@@ -1411,7 +1657,7 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
1411
1657
|
)
|
|
1412
1658
|
);
|
|
1413
1659
|
} catch (error) {
|
|
1414
|
-
|
|
1660
|
+
spinner10.stop("\u2717 Migration failed");
|
|
1415
1661
|
console.error(chalk8.red("\nError:"), error);
|
|
1416
1662
|
process.exit(1);
|
|
1417
1663
|
}
|
|
@@ -1651,14 +1897,14 @@ import chalk10 from "chalk";
|
|
|
1651
1897
|
async function autoSetupCommand(options) {
|
|
1652
1898
|
console.log(chalk10.bold.cyan("\n\u{1F527} Workflow Agent Auto-Setup\n"));
|
|
1653
1899
|
const cwd = process.cwd();
|
|
1654
|
-
const
|
|
1655
|
-
|
|
1900
|
+
const spinner10 = p6.spinner();
|
|
1901
|
+
spinner10.start("Analyzing project...");
|
|
1656
1902
|
let report;
|
|
1657
1903
|
try {
|
|
1658
1904
|
report = await generateAuditReport(cwd);
|
|
1659
|
-
|
|
1905
|
+
spinner10.stop("\u2713 Project analysis complete");
|
|
1660
1906
|
} catch (error) {
|
|
1661
|
-
|
|
1907
|
+
spinner10.stop("\u2717 Failed to analyze project");
|
|
1662
1908
|
console.error(
|
|
1663
1909
|
chalk10.red(
|
|
1664
1910
|
`Error: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -1794,14 +2040,14 @@ function formatAuditReportColored(report) {
|
|
|
1794
2040
|
// src/cli/commands/advisory.ts
|
|
1795
2041
|
import * as p7 from "@clack/prompts";
|
|
1796
2042
|
import chalk11 from "chalk";
|
|
1797
|
-
import { existsSync as
|
|
1798
|
-
import { readFile as
|
|
1799
|
-
import { join as
|
|
2043
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2044
|
+
import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
2045
|
+
import { join as join8 } from "path";
|
|
1800
2046
|
|
|
1801
2047
|
// src/utils/advisory-analyzer.ts
|
|
1802
|
-
import { existsSync as
|
|
1803
|
-
import { readFile as
|
|
1804
|
-
import { join as
|
|
2048
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2049
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
2050
|
+
import { join as join7 } from "path";
|
|
1805
2051
|
import fg from "fast-glob";
|
|
1806
2052
|
var AdvisoryAnalyzer = class {
|
|
1807
2053
|
options;
|
|
@@ -2245,11 +2491,11 @@ var AdvisoryAnalyzer = class {
|
|
|
2245
2491
|
// Helper Methods
|
|
2246
2492
|
// ============================================================================
|
|
2247
2493
|
async readPackageJson() {
|
|
2248
|
-
const pkgPath =
|
|
2249
|
-
if (!
|
|
2494
|
+
const pkgPath = join7(this.options.cwd, "package.json");
|
|
2495
|
+
if (!existsSync7(pkgPath)) {
|
|
2250
2496
|
throw new Error("package.json not found");
|
|
2251
2497
|
}
|
|
2252
|
-
const content = await
|
|
2498
|
+
const content = await readFile4(pkgPath, "utf-8");
|
|
2253
2499
|
return JSON.parse(content);
|
|
2254
2500
|
}
|
|
2255
2501
|
async countFiles() {
|
|
@@ -2834,7 +3080,7 @@ var QuestionGenerator = class {
|
|
|
2834
3080
|
category: "Platform Strategy",
|
|
2835
3081
|
question: `Are our platform choices (${technology.platforms.join(", ")}) aligned with target market and growth plans?`,
|
|
2836
3082
|
context: `Currently deployed on ${technology.platforms.join(" + ")}`,
|
|
2837
|
-
findings: technology.platforms.map((
|
|
3083
|
+
findings: technology.platforms.map((p13) => `Supports ${p13} platform`),
|
|
2838
3084
|
recommendations: [
|
|
2839
3085
|
"Validate platform coverage matches user demographics",
|
|
2840
3086
|
"Assess cross-platform development efficiency",
|
|
@@ -2896,7 +3142,7 @@ var QuestionGenerator = class {
|
|
|
2896
3142
|
category: "Business Alignment",
|
|
2897
3143
|
question: `How is our authentication solution (${authCat.packages.join(", ")}) supporting user onboarding and security requirements?`,
|
|
2898
3144
|
context: `Using ${authCat.packages.join(" + ")} for authentication`,
|
|
2899
|
-
findings: authCat.packages.map((
|
|
3145
|
+
findings: authCat.packages.map((p13) => `Auth provider: ${p13}`),
|
|
2900
3146
|
recommendations: [
|
|
2901
3147
|
"Measure authentication success rates and friction points",
|
|
2902
3148
|
"Ensure compliance with security standards (SOC2, GDPR, etc.)",
|
|
@@ -2948,12 +3194,12 @@ var QuestionGenerator = class {
|
|
|
2948
3194
|
});
|
|
2949
3195
|
}
|
|
2950
3196
|
if (packages.outdated && packages.outdated.length > 10) {
|
|
2951
|
-
const breakingCount = packages.outdated.filter((
|
|
3197
|
+
const breakingCount = packages.outdated.filter((p13) => p13.breaking).length;
|
|
2952
3198
|
questions.push({
|
|
2953
3199
|
category: "Technical Debt",
|
|
2954
3200
|
question: `How should we prioritize updating ${packages.outdated.length} outdated packages${breakingCount > 0 ? ` (${breakingCount} with breaking changes)` : ""}?`,
|
|
2955
3201
|
context: "Dependency audit found outdated packages",
|
|
2956
|
-
findings: packages.outdated.slice(0, 5).map((
|
|
3202
|
+
findings: packages.outdated.slice(0, 5).map((p13) => `${p13.name}: ${p13.current} \u2192 ${p13.latest}`),
|
|
2957
3203
|
recommendations: [
|
|
2958
3204
|
"Create update roadmap starting with non-breaking changes",
|
|
2959
3205
|
"Test breaking changes in feature branches",
|
|
@@ -3263,10 +3509,10 @@ var ReportComparator = class {
|
|
|
3263
3509
|
*/
|
|
3264
3510
|
comparePackages() {
|
|
3265
3511
|
const baselineProduction = new Map(
|
|
3266
|
-
this.baseline.packages.production.map((
|
|
3512
|
+
this.baseline.packages.production.map((p13) => [p13.name, p13])
|
|
3267
3513
|
);
|
|
3268
3514
|
const currentProduction = new Map(
|
|
3269
|
-
this.current.packages.production.map((
|
|
3515
|
+
this.current.packages.production.map((p13) => [p13.name, p13])
|
|
3270
3516
|
);
|
|
3271
3517
|
const added = [];
|
|
3272
3518
|
const removed = [];
|
|
@@ -3298,10 +3544,10 @@ var ReportComparator = class {
|
|
|
3298
3544
|
}
|
|
3299
3545
|
}
|
|
3300
3546
|
const baselineDev = new Map(
|
|
3301
|
-
this.baseline.packages.development.map((
|
|
3547
|
+
this.baseline.packages.development.map((p13) => [p13.name, p13])
|
|
3302
3548
|
);
|
|
3303
3549
|
const currentDev = new Map(
|
|
3304
|
-
this.current.packages.development.map((
|
|
3550
|
+
this.current.packages.development.map((p13) => [p13.name, p13])
|
|
3305
3551
|
);
|
|
3306
3552
|
for (const [name, pkg] of currentDev) {
|
|
3307
3553
|
if (!baselineDev.has(name)) {
|
|
@@ -3589,20 +3835,20 @@ async function advisoryCommand(options) {
|
|
|
3589
3835
|
includeHealth,
|
|
3590
3836
|
excludePatterns: advisoryConfig?.excludePatterns
|
|
3591
3837
|
});
|
|
3592
|
-
const
|
|
3838
|
+
const spinner10 = p7.spinner();
|
|
3593
3839
|
const depthLabels = {
|
|
3594
3840
|
executive: "executive summary",
|
|
3595
3841
|
quick: "quick scan",
|
|
3596
3842
|
standard: "standard analysis",
|
|
3597
3843
|
comprehensive: "comprehensive analysis"
|
|
3598
3844
|
};
|
|
3599
|
-
|
|
3845
|
+
spinner10.start(`Running ${depthLabels[depth]}...`);
|
|
3600
3846
|
let analysis;
|
|
3601
3847
|
try {
|
|
3602
3848
|
analysis = await analyzer.analyze();
|
|
3603
|
-
|
|
3849
|
+
spinner10.stop(`\u2713 Analysis complete`);
|
|
3604
3850
|
} catch (error) {
|
|
3605
|
-
|
|
3851
|
+
spinner10.stop("\u2717 Analysis failed");
|
|
3606
3852
|
console.error(
|
|
3607
3853
|
chalk11.red(
|
|
3608
3854
|
`Error: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -3617,19 +3863,19 @@ async function advisoryCommand(options) {
|
|
|
3617
3863
|
let comparisonReport;
|
|
3618
3864
|
let comparator;
|
|
3619
3865
|
if (options.compare) {
|
|
3620
|
-
const comparisonPath = options.compare.endsWith(".json") ?
|
|
3621
|
-
if (
|
|
3622
|
-
|
|
3866
|
+
const comparisonPath = options.compare.endsWith(".json") ? join8(cwd, options.compare) : join8(cwd, options.compare, "analysis.json");
|
|
3867
|
+
if (existsSync8(comparisonPath)) {
|
|
3868
|
+
spinner10.start("Comparing with previous report...");
|
|
3623
3869
|
try {
|
|
3624
|
-
const previousContent = await
|
|
3870
|
+
const previousContent = await readFile5(comparisonPath, "utf-8");
|
|
3625
3871
|
const previousAnalysis = JSON.parse(previousContent);
|
|
3626
3872
|
comparator = new ReportComparator(previousAnalysis, analysis);
|
|
3627
3873
|
comparisonReport = comparator.compare();
|
|
3628
|
-
|
|
3874
|
+
spinner10.stop("\u2713 Comparison complete");
|
|
3629
3875
|
console.log("");
|
|
3630
3876
|
displayComparisonSummary(comparisonReport);
|
|
3631
3877
|
} catch (error) {
|
|
3632
|
-
|
|
3878
|
+
spinner10.stop("\u26A0 Comparison failed");
|
|
3633
3879
|
console.warn(chalk11.yellow(`Could not compare reports: ${error}`));
|
|
3634
3880
|
}
|
|
3635
3881
|
} else {
|
|
@@ -3646,9 +3892,9 @@ async function advisoryCommand(options) {
|
|
|
3646
3892
|
console.log(chalk11.dim("\n--dry-run mode: No files written.\n"));
|
|
3647
3893
|
return;
|
|
3648
3894
|
}
|
|
3649
|
-
const fullOutputDir =
|
|
3650
|
-
await
|
|
3651
|
-
|
|
3895
|
+
const fullOutputDir = join8(cwd, outputDir);
|
|
3896
|
+
await mkdir5(fullOutputDir, { recursive: true });
|
|
3897
|
+
spinner10.start("Generating reports...");
|
|
3652
3898
|
try {
|
|
3653
3899
|
const timestamp = options.timestamp ? (/* @__PURE__ */ new Date()).toISOString().split("T")[0] : "";
|
|
3654
3900
|
if (options.format === "json") {
|
|
@@ -3662,9 +3908,9 @@ async function advisoryCommand(options) {
|
|
|
3662
3908
|
timestamp
|
|
3663
3909
|
);
|
|
3664
3910
|
}
|
|
3665
|
-
|
|
3911
|
+
spinner10.stop("\u2713 Reports generated");
|
|
3666
3912
|
} catch (error) {
|
|
3667
|
-
|
|
3913
|
+
spinner10.stop("\u2717 Failed to write reports");
|
|
3668
3914
|
console.error(chalk11.red(`Error: ${error}`));
|
|
3669
3915
|
process.exit(1);
|
|
3670
3916
|
}
|
|
@@ -3672,24 +3918,24 @@ async function advisoryCommand(options) {
|
|
|
3672
3918
|
console.log(chalk11.green("\u{1F4DD} Reports written to:"));
|
|
3673
3919
|
const suffix = options.timestamp ? `-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}` : "";
|
|
3674
3920
|
if (options.format === "json") {
|
|
3675
|
-
console.log(chalk11.dim(` ${
|
|
3676
|
-
console.log(chalk11.dim(` ${
|
|
3921
|
+
console.log(chalk11.dim(` ${join8(outputDir, `analysis${suffix}.json`)}`));
|
|
3922
|
+
console.log(chalk11.dim(` ${join8(outputDir, `questions${suffix}.json`)}`));
|
|
3677
3923
|
} else {
|
|
3678
3924
|
console.log(
|
|
3679
|
-
chalk11.dim(` ${
|
|
3925
|
+
chalk11.dim(` ${join8(outputDir, `EXECUTIVE_SUMMARY${suffix}.md`)}`)
|
|
3680
3926
|
);
|
|
3681
3927
|
console.log(
|
|
3682
|
-
chalk11.dim(` ${
|
|
3928
|
+
chalk11.dim(` ${join8(outputDir, `TECHNOLOGY_AUDIT${suffix}.md`)}`)
|
|
3683
3929
|
);
|
|
3684
3930
|
console.log(
|
|
3685
|
-
chalk11.dim(` ${
|
|
3931
|
+
chalk11.dim(` ${join8(outputDir, `STRATEGIC_ROADMAP${suffix}.md`)}`)
|
|
3686
3932
|
);
|
|
3687
3933
|
console.log(
|
|
3688
|
-
chalk11.dim(` ${
|
|
3934
|
+
chalk11.dim(` ${join8(outputDir, `BOARD_QUESTIONS${suffix}.md`)}`)
|
|
3689
3935
|
);
|
|
3690
3936
|
if (comparisonReport) {
|
|
3691
3937
|
console.log(
|
|
3692
|
-
chalk11.dim(` ${
|
|
3938
|
+
chalk11.dim(` ${join8(outputDir, `DIFF_REPORT${suffix}.md`)}`)
|
|
3693
3939
|
);
|
|
3694
3940
|
}
|
|
3695
3941
|
}
|
|
@@ -3782,47 +4028,47 @@ function displayComparisonSummary(comparison) {
|
|
|
3782
4028
|
}
|
|
3783
4029
|
async function writeAnalysisJson(outputDir, analysis, questions, timestamp) {
|
|
3784
4030
|
const suffix = timestamp ? `-${timestamp}` : "";
|
|
3785
|
-
await
|
|
3786
|
-
|
|
4031
|
+
await writeFile5(
|
|
4032
|
+
join8(outputDir, `analysis${suffix}.json`),
|
|
3787
4033
|
JSON.stringify(analysis, null, 2),
|
|
3788
4034
|
"utf-8"
|
|
3789
4035
|
);
|
|
3790
|
-
await
|
|
3791
|
-
|
|
4036
|
+
await writeFile5(
|
|
4037
|
+
join8(outputDir, `questions${suffix}.json`),
|
|
3792
4038
|
JSON.stringify(questions, null, 2),
|
|
3793
4039
|
"utf-8"
|
|
3794
4040
|
);
|
|
3795
4041
|
}
|
|
3796
4042
|
async function writeMarkdownReports(outputDir, analysis, questions, comparator, timestamp) {
|
|
3797
4043
|
const suffix = timestamp ? `-${timestamp}` : "";
|
|
3798
|
-
await
|
|
3799
|
-
|
|
4044
|
+
await writeFile5(
|
|
4045
|
+
join8(outputDir, `analysis.json`),
|
|
3800
4046
|
JSON.stringify(analysis, null, 2),
|
|
3801
4047
|
"utf-8"
|
|
3802
4048
|
);
|
|
3803
|
-
await
|
|
3804
|
-
|
|
4049
|
+
await writeFile5(
|
|
4050
|
+
join8(outputDir, `EXECUTIVE_SUMMARY${suffix}.md`),
|
|
3805
4051
|
generateExecutiveSummary(analysis, questions),
|
|
3806
4052
|
"utf-8"
|
|
3807
4053
|
);
|
|
3808
|
-
await
|
|
3809
|
-
|
|
4054
|
+
await writeFile5(
|
|
4055
|
+
join8(outputDir, `TECHNOLOGY_AUDIT${suffix}.md`),
|
|
3810
4056
|
generateTechnologyAudit(analysis),
|
|
3811
4057
|
"utf-8"
|
|
3812
4058
|
);
|
|
3813
|
-
await
|
|
3814
|
-
|
|
4059
|
+
await writeFile5(
|
|
4060
|
+
join8(outputDir, `STRATEGIC_ROADMAP${suffix}.md`),
|
|
3815
4061
|
generateStrategicRoadmap(analysis, questions),
|
|
3816
4062
|
"utf-8"
|
|
3817
4063
|
);
|
|
3818
|
-
await
|
|
3819
|
-
|
|
4064
|
+
await writeFile5(
|
|
4065
|
+
join8(outputDir, `BOARD_QUESTIONS${suffix}.md`),
|
|
3820
4066
|
generateBoardQuestions(questions),
|
|
3821
4067
|
"utf-8"
|
|
3822
4068
|
);
|
|
3823
4069
|
if (comparator) {
|
|
3824
|
-
await
|
|
3825
|
-
|
|
4070
|
+
await writeFile5(
|
|
4071
|
+
join8(outputDir, `DIFF_REPORT${suffix}.md`),
|
|
3826
4072
|
comparator.generateMarkdownSummary(),
|
|
3827
4073
|
"utf-8"
|
|
3828
4074
|
);
|
|
@@ -4439,20 +4685,20 @@ function checkCIThresholds(analysis, config) {
|
|
|
4439
4685
|
// src/cli/commands/generate-instructions.ts
|
|
4440
4686
|
import * as p8 from "@clack/prompts";
|
|
4441
4687
|
import chalk12 from "chalk";
|
|
4442
|
-
import { existsSync as
|
|
4443
|
-
import { join as
|
|
4688
|
+
import { existsSync as existsSync9 } from "fs";
|
|
4689
|
+
import { join as join9 } from "path";
|
|
4444
4690
|
async function generateInstructionsCommand(options) {
|
|
4445
4691
|
p8.intro(chalk12.bgBlue(" workflow-agent generate-instructions "));
|
|
4446
4692
|
const cwd = process.cwd();
|
|
4447
|
-
const guidelinesDir =
|
|
4448
|
-
const outputPath =
|
|
4449
|
-
if (!
|
|
4693
|
+
const guidelinesDir = join9(cwd, "guidelines");
|
|
4694
|
+
const outputPath = join9(cwd, ".github", "copilot-instructions.md");
|
|
4695
|
+
if (!existsSync9(guidelinesDir)) {
|
|
4450
4696
|
p8.cancel(
|
|
4451
4697
|
"No guidelines directory found. Run 'workflow init' first to generate guidelines."
|
|
4452
4698
|
);
|
|
4453
4699
|
process.exit(1);
|
|
4454
4700
|
}
|
|
4455
|
-
if (
|
|
4701
|
+
if (existsSync9(outputPath) && !options.force) {
|
|
4456
4702
|
const shouldRegenerate = await p8.confirm({
|
|
4457
4703
|
message: ".github/copilot-instructions.md already exists. Regenerate? (Custom content will be preserved)",
|
|
4458
4704
|
initialValue: true
|
|
@@ -4462,8 +4708,8 @@ async function generateInstructionsCommand(options) {
|
|
|
4462
4708
|
process.exit(0);
|
|
4463
4709
|
}
|
|
4464
4710
|
}
|
|
4465
|
-
const
|
|
4466
|
-
|
|
4711
|
+
const spinner10 = p8.spinner();
|
|
4712
|
+
spinner10.start("Generating AI agent instructions from guidelines...");
|
|
4467
4713
|
try {
|
|
4468
4714
|
const result = generateCopilotInstructions(cwd, {
|
|
4469
4715
|
force: true,
|
|
@@ -4471,7 +4717,7 @@ async function generateInstructionsCommand(options) {
|
|
|
4471
4717
|
});
|
|
4472
4718
|
if (result.success) {
|
|
4473
4719
|
const status = result.isNew ? "Generated" : "Regenerated";
|
|
4474
|
-
|
|
4720
|
+
spinner10.stop(
|
|
4475
4721
|
chalk12.green(
|
|
4476
4722
|
`\u2713 ${status} .github/copilot-instructions.md from ${result.guidelinesCount} guidelines`
|
|
4477
4723
|
)
|
|
@@ -4487,12 +4733,12 @@ async function generateInstructionsCommand(options) {
|
|
|
4487
4733
|
)
|
|
4488
4734
|
);
|
|
4489
4735
|
} else {
|
|
4490
|
-
|
|
4736
|
+
spinner10.stop(chalk12.red("\u2717 Failed to generate instructions"));
|
|
4491
4737
|
console.log(chalk12.yellow(`
|
|
4492
4738
|
Reason: ${result.error}`));
|
|
4493
4739
|
}
|
|
4494
4740
|
} catch (error) {
|
|
4495
|
-
|
|
4741
|
+
spinner10.stop(chalk12.red("\u2717 Error generating instructions"));
|
|
4496
4742
|
console.log(
|
|
4497
4743
|
chalk12.yellow(
|
|
4498
4744
|
`
|
|
@@ -4512,8 +4758,8 @@ Reason: ${error instanceof Error ? error.message : String(error)}`
|
|
|
4512
4758
|
// src/cli/commands/update-templates.ts
|
|
4513
4759
|
import * as p9 from "@clack/prompts";
|
|
4514
4760
|
import chalk13 from "chalk";
|
|
4515
|
-
import { existsSync as
|
|
4516
|
-
import { join as
|
|
4761
|
+
import { existsSync as existsSync10 } from "fs";
|
|
4762
|
+
import { join as join10, dirname as dirname3 } from "path";
|
|
4517
4763
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4518
4764
|
var __filename3 = fileURLToPath3(import.meta.url);
|
|
4519
4765
|
var __dirname3 = dirname3(__filename3);
|
|
@@ -4521,13 +4767,13 @@ async function updateTemplatesCommand(options) {
|
|
|
4521
4767
|
const { force = false, skip = false } = options;
|
|
4522
4768
|
p9.intro(chalk13.bgBlue(" workflow-agent update-templates "));
|
|
4523
4769
|
const cwd = process.cwd();
|
|
4524
|
-
const guidelinesDir =
|
|
4770
|
+
const guidelinesDir = join10(cwd, "guidelines");
|
|
4525
4771
|
const templatesDir = findTemplatesDirectory(__dirname3);
|
|
4526
4772
|
if (!templatesDir) {
|
|
4527
4773
|
p9.cancel("Could not find templates directory");
|
|
4528
4774
|
process.exit(1);
|
|
4529
4775
|
}
|
|
4530
|
-
const guidelinesExist =
|
|
4776
|
+
const guidelinesExist = existsSync10(guidelinesDir);
|
|
4531
4777
|
if (!guidelinesExist) {
|
|
4532
4778
|
console.log(chalk13.yellow("\n\u26A0\uFE0F No guidelines directory found."));
|
|
4533
4779
|
console.log(chalk13.dim("Run 'workflow-agent init' to set up guidelines.\n"));
|
|
@@ -4575,8 +4821,8 @@ async function updateTemplatesCommand(options) {
|
|
|
4575
4821
|
process.exit(0);
|
|
4576
4822
|
}
|
|
4577
4823
|
}
|
|
4578
|
-
const
|
|
4579
|
-
|
|
4824
|
+
const spinner10 = p9.spinner();
|
|
4825
|
+
spinner10.start("Updating templates...");
|
|
4580
4826
|
let result;
|
|
4581
4827
|
try {
|
|
4582
4828
|
result = updateTemplates(cwd, templatesDir, {
|
|
@@ -4584,7 +4830,7 @@ async function updateTemplatesCommand(options) {
|
|
|
4584
4830
|
silent: true
|
|
4585
4831
|
});
|
|
4586
4832
|
} catch (error) {
|
|
4587
|
-
|
|
4833
|
+
spinner10.stop("\u274C Failed to update templates");
|
|
4588
4834
|
console.log(
|
|
4589
4835
|
chalk13.red(
|
|
4590
4836
|
`
|
|
@@ -4595,7 +4841,7 @@ Error: ${error instanceof Error ? error.message : String(error)}`
|
|
|
4595
4841
|
}
|
|
4596
4842
|
const totalChanges = result.installed.length + result.updated.length;
|
|
4597
4843
|
if (totalChanges === 0 && result.skipped.length > 0) {
|
|
4598
|
-
|
|
4844
|
+
spinner10.stop("No changes needed");
|
|
4599
4845
|
console.log(
|
|
4600
4846
|
chalk13.dim(
|
|
4601
4847
|
`
|
|
@@ -4603,7 +4849,7 @@ Error: ${error instanceof Error ? error.message : String(error)}`
|
|
|
4603
4849
|
)
|
|
4604
4850
|
);
|
|
4605
4851
|
} else {
|
|
4606
|
-
|
|
4852
|
+
spinner10.stop(`\u2713 Template update complete`);
|
|
4607
4853
|
if (result.installed.length > 0) {
|
|
4608
4854
|
console.log(chalk13.green(`
|
|
4609
4855
|
New templates installed:`));
|
|
@@ -4649,9 +4895,292 @@ Error: ${error instanceof Error ? error.message : String(error)}`
|
|
|
4649
4895
|
p9.outro(chalk13.green("Done!"));
|
|
4650
4896
|
}
|
|
4651
4897
|
|
|
4652
|
-
// src/cli/commands/
|
|
4653
|
-
import chalk14 from "chalk";
|
|
4898
|
+
// src/cli/commands/docs-validate.ts
|
|
4654
4899
|
import * as p10 from "@clack/prompts";
|
|
4900
|
+
import chalk14 from "chalk";
|
|
4901
|
+
import { relative } from "path";
|
|
4902
|
+
async function docsValidateCommand(options) {
|
|
4903
|
+
const { fix = false, patterns, ignore } = options;
|
|
4904
|
+
p10.intro(chalk14.bgBlue(" workflow-agent docs:validate "));
|
|
4905
|
+
const cwd = process.cwd();
|
|
4906
|
+
const spinner10 = p10.spinner();
|
|
4907
|
+
spinner10.start("Scanning markdown files for broken references...");
|
|
4908
|
+
try {
|
|
4909
|
+
const result = await validateDocumentReferences(cwd, {
|
|
4910
|
+
patterns,
|
|
4911
|
+
ignore
|
|
4912
|
+
});
|
|
4913
|
+
spinner10.stop("Scan complete");
|
|
4914
|
+
console.log("");
|
|
4915
|
+
console.log(
|
|
4916
|
+
chalk14.cyan(
|
|
4917
|
+
`\u{1F4C4} Scanned ${result.scannedFiles} file(s), found ${result.totalReferences} reference(s)`
|
|
4918
|
+
)
|
|
4919
|
+
);
|
|
4920
|
+
if (result.errors.length > 0) {
|
|
4921
|
+
console.log("");
|
|
4922
|
+
console.log(chalk14.red("\u274C Errors during validation:"));
|
|
4923
|
+
for (const error of result.errors) {
|
|
4924
|
+
console.log(chalk14.red(` ${error}`));
|
|
4925
|
+
}
|
|
4926
|
+
p10.outro(chalk14.red("Validation failed"));
|
|
4927
|
+
process.exit(1);
|
|
4928
|
+
}
|
|
4929
|
+
if (result.valid) {
|
|
4930
|
+
console.log("");
|
|
4931
|
+
console.log(chalk14.green("\u2705 All document references are valid!"));
|
|
4932
|
+
p10.outro(chalk14.green("No broken links found"));
|
|
4933
|
+
return;
|
|
4934
|
+
}
|
|
4935
|
+
console.log("");
|
|
4936
|
+
console.log(
|
|
4937
|
+
chalk14.yellow(
|
|
4938
|
+
`\u26A0\uFE0F Found ${result.brokenReferences.length} broken reference(s):`
|
|
4939
|
+
)
|
|
4940
|
+
);
|
|
4941
|
+
console.log("");
|
|
4942
|
+
for (const broken of result.brokenReferences) {
|
|
4943
|
+
const relativePath = relative(cwd, broken.file);
|
|
4944
|
+
console.log(
|
|
4945
|
+
chalk14.red(
|
|
4946
|
+
` ${relativePath}:${broken.line}:${broken.column} - ${broken.type}`
|
|
4947
|
+
)
|
|
4948
|
+
);
|
|
4949
|
+
console.log(chalk14.dim(` ${broken.rawLink}`));
|
|
4950
|
+
console.log(chalk14.dim(` Target: ${broken.targetPath}`));
|
|
4951
|
+
if (broken.suggestions.length > 0) {
|
|
4952
|
+
console.log(chalk14.dim(` Suggestions: ${broken.suggestions.slice(0, 3).join(", ")}`));
|
|
4953
|
+
}
|
|
4954
|
+
console.log("");
|
|
4955
|
+
}
|
|
4956
|
+
if (!fix) {
|
|
4957
|
+
console.log(
|
|
4958
|
+
chalk14.yellow("\u{1F4A1} Run with --fix flag to interactively fix broken references")
|
|
4959
|
+
);
|
|
4960
|
+
p10.outro(chalk14.red("Validation failed"));
|
|
4961
|
+
process.exit(1);
|
|
4962
|
+
}
|
|
4963
|
+
console.log(chalk14.cyan("\u{1F527} Interactive fix mode\n"));
|
|
4964
|
+
let fixedCount = 0;
|
|
4965
|
+
let skippedCount = 0;
|
|
4966
|
+
for (const broken of result.brokenReferences) {
|
|
4967
|
+
const relativePath = relative(cwd, broken.file);
|
|
4968
|
+
console.log(chalk14.bold(`
|
|
4969
|
+
${relativePath}:${broken.line}`));
|
|
4970
|
+
console.log(chalk14.dim(` ${broken.rawLink}`));
|
|
4971
|
+
console.log(chalk14.yellow(` \u274C Broken: ${broken.targetPath}
|
|
4972
|
+
`));
|
|
4973
|
+
const options2 = [];
|
|
4974
|
+
if (broken.suggestions.length > 0) {
|
|
4975
|
+
options2.push(
|
|
4976
|
+
...broken.suggestions.slice(0, 8).map((suggestion) => ({
|
|
4977
|
+
value: suggestion,
|
|
4978
|
+
label: `\u{1F4C4} ${suggestion}`
|
|
4979
|
+
}))
|
|
4980
|
+
);
|
|
4981
|
+
}
|
|
4982
|
+
options2.push({
|
|
4983
|
+
value: "__custom__",
|
|
4984
|
+
label: "\u270F\uFE0F Enter custom path"
|
|
4985
|
+
});
|
|
4986
|
+
options2.push({
|
|
4987
|
+
value: "__skip__",
|
|
4988
|
+
label: "\u23ED\uFE0F Skip this reference"
|
|
4989
|
+
});
|
|
4990
|
+
const choice = await p10.select({
|
|
4991
|
+
message: "Choose correct path:",
|
|
4992
|
+
options: options2
|
|
4993
|
+
});
|
|
4994
|
+
if (p10.isCancel(choice)) {
|
|
4995
|
+
console.log("");
|
|
4996
|
+
p10.cancel("Fix operation cancelled");
|
|
4997
|
+
console.log(
|
|
4998
|
+
chalk14.dim(`
|
|
4999
|
+
Fixed: ${fixedCount}, Skipped: ${skippedCount}`)
|
|
5000
|
+
);
|
|
5001
|
+
process.exit(0);
|
|
5002
|
+
}
|
|
5003
|
+
if (choice === "__skip__") {
|
|
5004
|
+
skippedCount++;
|
|
5005
|
+
continue;
|
|
5006
|
+
}
|
|
5007
|
+
let newPath;
|
|
5008
|
+
if (choice === "__custom__") {
|
|
5009
|
+
const customPath = await p10.text({
|
|
5010
|
+
message: "Enter the correct path:",
|
|
5011
|
+
placeholder: broken.targetPath,
|
|
5012
|
+
validate: (value) => {
|
|
5013
|
+
if (!value || value.trim().length === 0) {
|
|
5014
|
+
return "Path cannot be empty";
|
|
5015
|
+
}
|
|
5016
|
+
}
|
|
5017
|
+
});
|
|
5018
|
+
if (p10.isCancel(customPath)) {
|
|
5019
|
+
console.log("");
|
|
5020
|
+
p10.cancel("Fix operation cancelled");
|
|
5021
|
+
console.log(
|
|
5022
|
+
chalk14.dim(`
|
|
5023
|
+
Fixed: ${fixedCount}, Skipped: ${skippedCount}`)
|
|
5024
|
+
);
|
|
5025
|
+
process.exit(0);
|
|
5026
|
+
}
|
|
5027
|
+
newPath = customPath;
|
|
5028
|
+
} else {
|
|
5029
|
+
newPath = choice;
|
|
5030
|
+
}
|
|
5031
|
+
try {
|
|
5032
|
+
await applyReferenceFix(broken.file, broken.rawLink, newPath);
|
|
5033
|
+
console.log(chalk14.green(` \u2705 Fixed: ${broken.targetPath} \u2192 ${newPath}`));
|
|
5034
|
+
fixedCount++;
|
|
5035
|
+
} catch (error) {
|
|
5036
|
+
console.log(
|
|
5037
|
+
chalk14.red(
|
|
5038
|
+
` \u274C Failed to fix: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
5039
|
+
)
|
|
5040
|
+
);
|
|
5041
|
+
skippedCount++;
|
|
5042
|
+
}
|
|
5043
|
+
}
|
|
5044
|
+
console.log("");
|
|
5045
|
+
console.log(chalk14.cyan(`\u{1F4CA} Summary:`));
|
|
5046
|
+
console.log(chalk14.green(` Fixed: ${fixedCount}`));
|
|
5047
|
+
if (skippedCount > 0) {
|
|
5048
|
+
console.log(chalk14.yellow(` Skipped: ${skippedCount}`));
|
|
5049
|
+
}
|
|
5050
|
+
if (fixedCount > 0) {
|
|
5051
|
+
p10.outro(chalk14.green("Document references fixed!"));
|
|
5052
|
+
} else {
|
|
5053
|
+
p10.outro(chalk14.yellow("No references were fixed"));
|
|
5054
|
+
}
|
|
5055
|
+
} catch (error) {
|
|
5056
|
+
spinner10.stop("Scan failed");
|
|
5057
|
+
console.log("");
|
|
5058
|
+
p10.cancel(
|
|
5059
|
+
`Validation error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
5060
|
+
);
|
|
5061
|
+
process.exit(1);
|
|
5062
|
+
}
|
|
5063
|
+
}
|
|
5064
|
+
|
|
5065
|
+
// src/cli/commands/hooks.ts
|
|
5066
|
+
import chalk15 from "chalk";
|
|
5067
|
+
async function hooksCommand(action) {
|
|
5068
|
+
const cwd = process.cwd();
|
|
5069
|
+
switch (action) {
|
|
5070
|
+
case "install":
|
|
5071
|
+
await installHooksAction(cwd);
|
|
5072
|
+
break;
|
|
5073
|
+
case "uninstall":
|
|
5074
|
+
await uninstallHooksAction(cwd);
|
|
5075
|
+
break;
|
|
5076
|
+
case "status":
|
|
5077
|
+
await statusHooksAction(cwd);
|
|
5078
|
+
break;
|
|
5079
|
+
default:
|
|
5080
|
+
console.error(chalk15.red(`Unknown action: ${action}`));
|
|
5081
|
+
console.log(chalk15.dim("Available actions: install, uninstall, status"));
|
|
5082
|
+
process.exit(1);
|
|
5083
|
+
}
|
|
5084
|
+
}
|
|
5085
|
+
async function installHooksAction(cwd) {
|
|
5086
|
+
console.log(chalk15.bold.cyan("\n\u{1F517} Installing Workflow Agent Git Hooks\n"));
|
|
5087
|
+
if (!hasGitRepo(cwd)) {
|
|
5088
|
+
console.error(chalk15.red("\u2717 No git repository found"));
|
|
5089
|
+
console.log(chalk15.yellow(" Run: git init"));
|
|
5090
|
+
process.exit(1);
|
|
5091
|
+
}
|
|
5092
|
+
const config = await loadConfig();
|
|
5093
|
+
const hooksConfig = config?.hooks;
|
|
5094
|
+
const results = await installHooks(hooksConfig, cwd);
|
|
5095
|
+
let hasErrors = false;
|
|
5096
|
+
for (const result of results) {
|
|
5097
|
+
if (result.success) {
|
|
5098
|
+
if (result.wrappedExisting) {
|
|
5099
|
+
console.log(
|
|
5100
|
+
chalk15.green(
|
|
5101
|
+
`\u2713 Installed ${result.hookType} hook (wrapped existing hook)`
|
|
5102
|
+
)
|
|
5103
|
+
);
|
|
5104
|
+
} else {
|
|
5105
|
+
console.log(chalk15.green(`\u2713 Installed ${result.hookType} hook`));
|
|
5106
|
+
}
|
|
5107
|
+
} else {
|
|
5108
|
+
console.error(
|
|
5109
|
+
chalk15.red(`\u2717 Failed to install ${result.hookType}: ${result.error}`)
|
|
5110
|
+
);
|
|
5111
|
+
hasErrors = true;
|
|
5112
|
+
}
|
|
5113
|
+
}
|
|
5114
|
+
if (!hasErrors) {
|
|
5115
|
+
console.log(chalk15.green("\n\u2713 Git hooks installed successfully"));
|
|
5116
|
+
console.log(chalk15.dim("\nHooks will run automatically on commit."));
|
|
5117
|
+
console.log(chalk15.dim("They will be skipped in CI environments."));
|
|
5118
|
+
} else {
|
|
5119
|
+
process.exit(1);
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
async function uninstallHooksAction(cwd) {
|
|
5123
|
+
console.log(chalk15.bold.cyan("\n\u{1F513} Uninstalling Workflow Agent Git Hooks\n"));
|
|
5124
|
+
if (!hasGitRepo(cwd)) {
|
|
5125
|
+
console.error(chalk15.red("\u2717 No git repository found"));
|
|
5126
|
+
process.exit(1);
|
|
5127
|
+
}
|
|
5128
|
+
const results = await uninstallHooks(cwd);
|
|
5129
|
+
let hasErrors = false;
|
|
5130
|
+
for (const result of results) {
|
|
5131
|
+
if (result.success) {
|
|
5132
|
+
if (result.wrappedExisting) {
|
|
5133
|
+
console.log(
|
|
5134
|
+
chalk15.green(`\u2713 Removed ${result.hookType} hook (restored original)`)
|
|
5135
|
+
);
|
|
5136
|
+
} else {
|
|
5137
|
+
console.log(chalk15.green(`\u2713 Removed ${result.hookType} hook`));
|
|
5138
|
+
}
|
|
5139
|
+
} else if (result.error) {
|
|
5140
|
+
console.error(
|
|
5141
|
+
chalk15.red(`\u2717 Failed to remove ${result.hookType}: ${result.error}`)
|
|
5142
|
+
);
|
|
5143
|
+
hasErrors = true;
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
if (!hasErrors) {
|
|
5147
|
+
console.log(chalk15.green("\n\u2713 Git hooks uninstalled successfully"));
|
|
5148
|
+
} else {
|
|
5149
|
+
process.exit(1);
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
async function statusHooksAction(cwd) {
|
|
5153
|
+
console.log(chalk15.bold.cyan("\n\u{1F4CA} Workflow Agent Git Hooks Status\n"));
|
|
5154
|
+
if (!hasGitRepo(cwd)) {
|
|
5155
|
+
console.error(chalk15.red("\u2717 No git repository found"));
|
|
5156
|
+
process.exit(1);
|
|
5157
|
+
}
|
|
5158
|
+
const statuses = await getAllHooksStatus(cwd);
|
|
5159
|
+
for (const status of statuses) {
|
|
5160
|
+
const icon = status.installed ? "\u2713" : "\u2717";
|
|
5161
|
+
const color = status.installed ? chalk15.green : chalk15.yellow;
|
|
5162
|
+
let message = `${icon} ${status.hookType}`;
|
|
5163
|
+
if (status.installed) {
|
|
5164
|
+
message += " - installed";
|
|
5165
|
+
if (status.wrappedOriginal) {
|
|
5166
|
+
message += " (wrapping original hook)";
|
|
5167
|
+
}
|
|
5168
|
+
} else if (status.hasExistingHook) {
|
|
5169
|
+
message += " - existing hook (not managed by Workflow Agent)";
|
|
5170
|
+
} else {
|
|
5171
|
+
message += " - not installed";
|
|
5172
|
+
}
|
|
5173
|
+
console.log(color(message));
|
|
5174
|
+
}
|
|
5175
|
+
const allInstalled = statuses.every((s) => s.installed);
|
|
5176
|
+
if (!allInstalled) {
|
|
5177
|
+
console.log(chalk15.dim("\nTo install hooks: workflow hooks install"));
|
|
5178
|
+
}
|
|
5179
|
+
}
|
|
5180
|
+
|
|
5181
|
+
// src/cli/commands/learn.ts
|
|
5182
|
+
import chalk16 from "chalk";
|
|
5183
|
+
import * as p11 from "@clack/prompts";
|
|
4655
5184
|
import {
|
|
4656
5185
|
PatternStore as PatternStore2,
|
|
4657
5186
|
ContributorManager as ContributorManager2,
|
|
@@ -4674,10 +5203,10 @@ function formatTags(tags) {
|
|
|
4674
5203
|
async function learnRecordCommand(options) {
|
|
4675
5204
|
const cwd = getWorkspacePath();
|
|
4676
5205
|
const store = new PatternStore2(cwd);
|
|
4677
|
-
console.log(
|
|
5206
|
+
console.log(chalk16.cyan("\n\u{1F4DA} Record a Learning Pattern\n"));
|
|
4678
5207
|
let patternType = options.type;
|
|
4679
5208
|
if (!patternType) {
|
|
4680
|
-
const typeChoice = await
|
|
5209
|
+
const typeChoice = await p11.select({
|
|
4681
5210
|
message: "What type of pattern are you recording?",
|
|
4682
5211
|
options: [
|
|
4683
5212
|
{
|
|
@@ -4690,15 +5219,15 @@ async function learnRecordCommand(options) {
|
|
|
4690
5219
|
}
|
|
4691
5220
|
]
|
|
4692
5221
|
});
|
|
4693
|
-
if (
|
|
4694
|
-
|
|
5222
|
+
if (p11.isCancel(typeChoice)) {
|
|
5223
|
+
p11.cancel("Recording cancelled");
|
|
4695
5224
|
process.exit(0);
|
|
4696
5225
|
}
|
|
4697
5226
|
patternType = typeChoice;
|
|
4698
5227
|
}
|
|
4699
5228
|
let name = options.name;
|
|
4700
5229
|
if (!name) {
|
|
4701
|
-
const nameInput = await
|
|
5230
|
+
const nameInput = await p11.text({
|
|
4702
5231
|
message: "Pattern name:",
|
|
4703
5232
|
placeholder: "e.g., Next.js App Router Migration",
|
|
4704
5233
|
validate: (value) => {
|
|
@@ -4708,15 +5237,15 @@ async function learnRecordCommand(options) {
|
|
|
4708
5237
|
return void 0;
|
|
4709
5238
|
}
|
|
4710
5239
|
});
|
|
4711
|
-
if (
|
|
4712
|
-
|
|
5240
|
+
if (p11.isCancel(nameInput)) {
|
|
5241
|
+
p11.cancel("Recording cancelled");
|
|
4713
5242
|
process.exit(0);
|
|
4714
5243
|
}
|
|
4715
5244
|
name = nameInput;
|
|
4716
5245
|
}
|
|
4717
5246
|
let description = options.description;
|
|
4718
5247
|
if (!description) {
|
|
4719
|
-
const descInput = await
|
|
5248
|
+
const descInput = await p11.text({
|
|
4720
5249
|
message: "Description:",
|
|
4721
5250
|
placeholder: "What does this pattern solve?",
|
|
4722
5251
|
validate: (value) => {
|
|
@@ -4727,40 +5256,40 @@ async function learnRecordCommand(options) {
|
|
|
4727
5256
|
return void 0;
|
|
4728
5257
|
}
|
|
4729
5258
|
});
|
|
4730
|
-
if (
|
|
4731
|
-
|
|
5259
|
+
if (p11.isCancel(descInput)) {
|
|
5260
|
+
p11.cancel("Recording cancelled");
|
|
4732
5261
|
process.exit(0);
|
|
4733
5262
|
}
|
|
4734
5263
|
description = descInput;
|
|
4735
5264
|
}
|
|
4736
5265
|
let framework = options.framework;
|
|
4737
5266
|
if (!framework) {
|
|
4738
|
-
const fwInput = await
|
|
5267
|
+
const fwInput = await p11.text({
|
|
4739
5268
|
message: "Framework:",
|
|
4740
5269
|
placeholder: "e.g., next, react, vue, express"
|
|
4741
5270
|
});
|
|
4742
|
-
if (
|
|
4743
|
-
|
|
5271
|
+
if (p11.isCancel(fwInput)) {
|
|
5272
|
+
p11.cancel("Recording cancelled");
|
|
4744
5273
|
process.exit(0);
|
|
4745
5274
|
}
|
|
4746
5275
|
framework = fwInput;
|
|
4747
5276
|
}
|
|
4748
5277
|
let version = options.version;
|
|
4749
5278
|
if (!version) {
|
|
4750
|
-
const versionInput = await
|
|
5279
|
+
const versionInput = await p11.text({
|
|
4751
5280
|
message: "Framework version (semver range):",
|
|
4752
5281
|
placeholder: "e.g., >=14.0.0, ^18.0.0",
|
|
4753
5282
|
initialValue: ">=1.0.0"
|
|
4754
5283
|
});
|
|
4755
|
-
if (
|
|
4756
|
-
|
|
5284
|
+
if (p11.isCancel(versionInput)) {
|
|
5285
|
+
p11.cancel("Recording cancelled");
|
|
4757
5286
|
process.exit(0);
|
|
4758
5287
|
}
|
|
4759
5288
|
version = versionInput;
|
|
4760
5289
|
}
|
|
4761
5290
|
let category = options.category;
|
|
4762
5291
|
if (patternType === "fix" && !category) {
|
|
4763
|
-
const catChoice = await
|
|
5292
|
+
const catChoice = await p11.select({
|
|
4764
5293
|
message: "Category:",
|
|
4765
5294
|
options: [
|
|
4766
5295
|
{ value: "migration", label: "\u{1F504} Migration" },
|
|
@@ -4775,8 +5304,8 @@ async function learnRecordCommand(options) {
|
|
|
4775
5304
|
{ value: "other", label: "\u{1F4E6} Other" }
|
|
4776
5305
|
]
|
|
4777
5306
|
});
|
|
4778
|
-
if (
|
|
4779
|
-
|
|
5307
|
+
if (p11.isCancel(catChoice)) {
|
|
5308
|
+
p11.cancel("Recording cancelled");
|
|
4780
5309
|
process.exit(0);
|
|
4781
5310
|
}
|
|
4782
5311
|
category = catChoice;
|
|
@@ -4839,14 +5368,14 @@ async function learnRecordCommand(options) {
|
|
|
4839
5368
|
};
|
|
4840
5369
|
const result = await store.saveFixPattern(fixPattern);
|
|
4841
5370
|
if (result.success) {
|
|
4842
|
-
console.log(
|
|
4843
|
-
console.log(
|
|
4844
|
-
console.log(
|
|
4845
|
-
console.log(
|
|
4846
|
-
console.log(
|
|
5371
|
+
console.log(chalk16.green("\n\u2705 Fix pattern recorded successfully!\n"));
|
|
5372
|
+
console.log(chalk16.dim(` ID: ${fixPattern.id}`));
|
|
5373
|
+
console.log(chalk16.dim(` Name: ${name}`));
|
|
5374
|
+
console.log(chalk16.dim(` Category: ${category}`));
|
|
5375
|
+
console.log(chalk16.dim(` Framework: ${framework} ${version}`));
|
|
4847
5376
|
} else {
|
|
4848
|
-
console.log(
|
|
4849
|
-
console.log(
|
|
5377
|
+
console.log(chalk16.red("\n\u274C Failed to record pattern"));
|
|
5378
|
+
console.log(chalk16.dim(` Error: ${result.error}`));
|
|
4850
5379
|
process.exit(1);
|
|
4851
5380
|
}
|
|
4852
5381
|
} else {
|
|
@@ -4893,13 +5422,13 @@ async function learnRecordCommand(options) {
|
|
|
4893
5422
|
};
|
|
4894
5423
|
const result = await store.saveBlueprint(blueprint);
|
|
4895
5424
|
if (result.success) {
|
|
4896
|
-
console.log(
|
|
4897
|
-
console.log(
|
|
4898
|
-
console.log(
|
|
4899
|
-
console.log(
|
|
5425
|
+
console.log(chalk16.green("\n\u2705 Blueprint recorded successfully!\n"));
|
|
5426
|
+
console.log(chalk16.dim(` ID: ${blueprint.id}`));
|
|
5427
|
+
console.log(chalk16.dim(` Name: ${name}`));
|
|
5428
|
+
console.log(chalk16.dim(` Framework: ${framework} ${version}`));
|
|
4900
5429
|
} else {
|
|
4901
|
-
console.log(
|
|
4902
|
-
console.log(
|
|
5430
|
+
console.log(chalk16.red("\n\u274C Failed to record blueprint"));
|
|
5431
|
+
console.log(chalk16.dim(` Error: ${result.error}`));
|
|
4903
5432
|
process.exit(1);
|
|
4904
5433
|
}
|
|
4905
5434
|
}
|
|
@@ -4909,7 +5438,7 @@ async function learnListCommand(options) {
|
|
|
4909
5438
|
const store = new PatternStore2(cwd);
|
|
4910
5439
|
const patternType = options.type ?? "all";
|
|
4911
5440
|
const showDeprecated = options.deprecated ?? false;
|
|
4912
|
-
console.log(
|
|
5441
|
+
console.log(chalk16.cyan("\n\u{1F4DA} Recorded Learning Patterns\n"));
|
|
4913
5442
|
if (patternType === "all" || patternType === "fix") {
|
|
4914
5443
|
const fixResult = await store.listFixPatterns({
|
|
4915
5444
|
tags: options.tag ? [{ category: "framework", name: options.tag }] : void 0,
|
|
@@ -4917,29 +5446,29 @@ async function learnListCommand(options) {
|
|
|
4917
5446
|
includeDeprecated: showDeprecated
|
|
4918
5447
|
});
|
|
4919
5448
|
if (fixResult.success && fixResult.data && fixResult.data.length > 0) {
|
|
4920
|
-
console.log(
|
|
5449
|
+
console.log(chalk16.bold.yellow("\u{1F527} Fix Patterns:\n"));
|
|
4921
5450
|
for (const pattern of fixResult.data) {
|
|
4922
5451
|
const isDeprecated = pattern.deprecatedAt !== void 0;
|
|
4923
5452
|
const statusIcon = isDeprecated ? "\u26A0\uFE0F" : "\u2713";
|
|
4924
|
-
const nameColor = isDeprecated ?
|
|
5453
|
+
const nameColor = isDeprecated ? chalk16.dim : chalk16.white;
|
|
4925
5454
|
console.log(` ${statusIcon} ${nameColor(pattern.name)}`);
|
|
4926
|
-
console.log(
|
|
4927
|
-
console.log(
|
|
5455
|
+
console.log(chalk16.dim(` ID: ${pattern.id}`));
|
|
5456
|
+
console.log(chalk16.dim(` Category: ${pattern.category}`));
|
|
4928
5457
|
console.log(
|
|
4929
|
-
|
|
5458
|
+
chalk16.dim(` Created: ${formatDate(pattern.createdAt)}`)
|
|
4930
5459
|
);
|
|
4931
5460
|
console.log(
|
|
4932
|
-
|
|
5461
|
+
chalk16.dim(
|
|
4933
5462
|
` Success Rate: ${(pattern.metrics.successRate * 100).toFixed(0)}% (${pattern.metrics.successes}/${pattern.metrics.applications})`
|
|
4934
5463
|
)
|
|
4935
5464
|
);
|
|
4936
5465
|
if (pattern.tags.length > 0) {
|
|
4937
|
-
console.log(
|
|
5466
|
+
console.log(chalk16.dim(` Tags: ${formatTags(pattern.tags)}`));
|
|
4938
5467
|
}
|
|
4939
5468
|
console.log("");
|
|
4940
5469
|
}
|
|
4941
5470
|
} else if (patternType === "fix") {
|
|
4942
|
-
console.log(
|
|
5471
|
+
console.log(chalk16.dim(" No fix patterns found.\n"));
|
|
4943
5472
|
}
|
|
4944
5473
|
}
|
|
4945
5474
|
if (patternType === "all" || patternType === "blueprint") {
|
|
@@ -4949,46 +5478,46 @@ async function learnListCommand(options) {
|
|
|
4949
5478
|
includeDeprecated: showDeprecated
|
|
4950
5479
|
});
|
|
4951
5480
|
if (bpResult.success && bpResult.data && bpResult.data.length > 0) {
|
|
4952
|
-
console.log(
|
|
5481
|
+
console.log(chalk16.bold.blue("\u{1F4D0} Blueprints:\n"));
|
|
4953
5482
|
for (const blueprint of bpResult.data) {
|
|
4954
5483
|
const isDeprecated = blueprint.deprecatedAt !== void 0;
|
|
4955
5484
|
const statusIcon = isDeprecated ? "\u26A0\uFE0F" : "\u2713";
|
|
4956
|
-
const nameColor = isDeprecated ?
|
|
5485
|
+
const nameColor = isDeprecated ? chalk16.dim : chalk16.white;
|
|
4957
5486
|
console.log(` ${statusIcon} ${nameColor(blueprint.name)}`);
|
|
4958
|
-
console.log(
|
|
4959
|
-
console.log(
|
|
5487
|
+
console.log(chalk16.dim(` ID: ${blueprint.id}`));
|
|
5488
|
+
console.log(chalk16.dim(` Language: ${blueprint.stack.language}`));
|
|
4960
5489
|
console.log(
|
|
4961
|
-
|
|
5490
|
+
chalk16.dim(` Created: ${formatDate(blueprint.createdAt)}`)
|
|
4962
5491
|
);
|
|
4963
5492
|
console.log(
|
|
4964
|
-
|
|
5493
|
+
chalk16.dim(
|
|
4965
5494
|
` Success Rate: ${(blueprint.metrics.successRate * 100).toFixed(0)}% (${blueprint.metrics.successes}/${blueprint.metrics.applications})`
|
|
4966
5495
|
)
|
|
4967
5496
|
);
|
|
4968
5497
|
if (blueprint.tags.length > 0) {
|
|
4969
|
-
console.log(
|
|
5498
|
+
console.log(chalk16.dim(` Tags: ${formatTags(blueprint.tags)}`));
|
|
4970
5499
|
}
|
|
4971
5500
|
console.log("");
|
|
4972
5501
|
}
|
|
4973
5502
|
} else if (patternType === "blueprint") {
|
|
4974
|
-
console.log(
|
|
5503
|
+
console.log(chalk16.dim(" No blueprints found.\n"));
|
|
4975
5504
|
}
|
|
4976
5505
|
}
|
|
4977
5506
|
const stats = await store.getStats();
|
|
4978
5507
|
const totalPatterns = stats.totalFixes + stats.totalBlueprints;
|
|
4979
5508
|
const totalDeprecated = stats.deprecatedFixes + stats.deprecatedBlueprints;
|
|
4980
|
-
console.log(
|
|
4981
|
-
console.log(
|
|
4982
|
-
console.log(
|
|
4983
|
-
console.log(
|
|
4984
|
-
console.log(
|
|
5509
|
+
console.log(chalk16.dim("\u2501".repeat(40)));
|
|
5510
|
+
console.log(chalk16.dim(`Total: ${totalPatterns} patterns`));
|
|
5511
|
+
console.log(chalk16.dim(` Fix Patterns: ${stats.totalFixes}`));
|
|
5512
|
+
console.log(chalk16.dim(` Blueprints: ${stats.totalBlueprints}`));
|
|
5513
|
+
console.log(chalk16.dim(` Deprecated: ${totalDeprecated}`));
|
|
4985
5514
|
console.log("");
|
|
4986
5515
|
}
|
|
4987
5516
|
async function learnApplyCommand(patternId, options) {
|
|
4988
5517
|
const cwd = getWorkspacePath();
|
|
4989
5518
|
const store = new PatternStore2(cwd);
|
|
4990
5519
|
const telemetry = new TelemetryCollector2(cwd);
|
|
4991
|
-
console.log(
|
|
5520
|
+
console.log(chalk16.cyan("\n\u{1F527} Apply Learning Pattern\n"));
|
|
4992
5521
|
let pattern = await store.getFixPattern(patternId);
|
|
4993
5522
|
let patternType = "fix";
|
|
4994
5523
|
if (!pattern.success || !pattern.data) {
|
|
@@ -4997,21 +5526,21 @@ async function learnApplyCommand(patternId, options) {
|
|
|
4997
5526
|
pattern = bpResult;
|
|
4998
5527
|
patternType = "blueprint";
|
|
4999
5528
|
} else {
|
|
5000
|
-
console.log(
|
|
5529
|
+
console.log(chalk16.red(`
|
|
5001
5530
|
\u274C Pattern not found: ${patternId}`));
|
|
5002
5531
|
console.log(
|
|
5003
|
-
|
|
5532
|
+
chalk16.dim(" Use 'workflow learn:list' to see available patterns")
|
|
5004
5533
|
);
|
|
5005
5534
|
process.exit(1);
|
|
5006
5535
|
}
|
|
5007
5536
|
}
|
|
5008
5537
|
const patternData = pattern.data;
|
|
5009
|
-
console.log(
|
|
5010
|
-
console.log(
|
|
5011
|
-
console.log(
|
|
5538
|
+
console.log(chalk16.white(` Pattern: ${patternData.name}`));
|
|
5539
|
+
console.log(chalk16.dim(` Type: ${patternType}`));
|
|
5540
|
+
console.log(chalk16.dim(` Description: ${patternData.description}`));
|
|
5012
5541
|
if (options.dryRun) {
|
|
5013
5542
|
console.log(
|
|
5014
|
-
|
|
5543
|
+
chalk16.yellow("\n\u{1F4CB} DRY-RUN MODE: No changes will be applied\n")
|
|
5015
5544
|
);
|
|
5016
5545
|
}
|
|
5017
5546
|
const framework = options.framework ?? patternData.compatibility.frameworks[0]?.name ?? "unknown";
|
|
@@ -5019,44 +5548,44 @@ async function learnApplyCommand(patternId, options) {
|
|
|
5019
5548
|
await telemetry.recordApplication(patternId, patternType, framework, version);
|
|
5020
5549
|
if (patternType === "fix") {
|
|
5021
5550
|
const fixPattern = patternData;
|
|
5022
|
-
console.log(
|
|
5551
|
+
console.log(chalk16.cyan("\n\u{1F4CB} Solution Steps:\n"));
|
|
5023
5552
|
if (fixPattern.solution.steps) {
|
|
5024
5553
|
for (let i = 0; i < fixPattern.solution.steps.length; i++) {
|
|
5025
5554
|
const step = fixPattern.solution.steps[i];
|
|
5026
5555
|
console.log(
|
|
5027
|
-
|
|
5556
|
+
chalk16.white(` ${i + 1}. [${step.action}] ${step.description}`)
|
|
5028
5557
|
);
|
|
5029
5558
|
if (step.file) {
|
|
5030
|
-
console.log(
|
|
5559
|
+
console.log(chalk16.dim(` File: ${step.file}`));
|
|
5031
5560
|
}
|
|
5032
5561
|
}
|
|
5033
5562
|
}
|
|
5034
5563
|
} else {
|
|
5035
5564
|
const blueprint = patternData;
|
|
5036
|
-
console.log(
|
|
5565
|
+
console.log(chalk16.cyan("\n\u{1F4CB} Setup Steps:\n"));
|
|
5037
5566
|
if (blueprint.setup.steps) {
|
|
5038
5567
|
for (let i = 0; i < blueprint.setup.steps.length; i++) {
|
|
5039
5568
|
const step = blueprint.setup.steps[i];
|
|
5040
|
-
console.log(
|
|
5569
|
+
console.log(chalk16.white(` ${i + 1}. ${step.description}`));
|
|
5041
5570
|
if (step.command) {
|
|
5042
|
-
console.log(
|
|
5571
|
+
console.log(chalk16.dim(` Command: ${step.command}`));
|
|
5043
5572
|
}
|
|
5044
5573
|
}
|
|
5045
5574
|
}
|
|
5046
5575
|
}
|
|
5047
5576
|
if (!options.dryRun) {
|
|
5048
|
-
const confirmed = await
|
|
5577
|
+
const confirmed = await p11.confirm({
|
|
5049
5578
|
message: "Mark this pattern as successfully applied?",
|
|
5050
5579
|
initialValue: true
|
|
5051
5580
|
});
|
|
5052
|
-
if (
|
|
5053
|
-
|
|
5581
|
+
if (p11.isCancel(confirmed)) {
|
|
5582
|
+
p11.cancel("Application cancelled");
|
|
5054
5583
|
process.exit(0);
|
|
5055
5584
|
}
|
|
5056
5585
|
if (confirmed) {
|
|
5057
5586
|
await store.updatePatternMetrics(patternId, patternType, true);
|
|
5058
5587
|
await telemetry.recordSuccess(patternId, patternType, framework, version);
|
|
5059
|
-
console.log(
|
|
5588
|
+
console.log(chalk16.green("\n\u2705 Pattern marked as successfully applied!"));
|
|
5060
5589
|
} else {
|
|
5061
5590
|
await store.updatePatternMetrics(patternId, patternType, false);
|
|
5062
5591
|
await telemetry.recordFailure(
|
|
@@ -5067,7 +5596,7 @@ async function learnApplyCommand(patternId, options) {
|
|
|
5067
5596
|
"unknown"
|
|
5068
5597
|
);
|
|
5069
5598
|
console.log(
|
|
5070
|
-
|
|
5599
|
+
chalk16.yellow("\n\u26A0\uFE0F Pattern application marked as unsuccessful.")
|
|
5071
5600
|
);
|
|
5072
5601
|
}
|
|
5073
5602
|
}
|
|
@@ -5075,32 +5604,32 @@ async function learnApplyCommand(patternId, options) {
|
|
|
5075
5604
|
async function learnSyncCommand(options) {
|
|
5076
5605
|
const cwd = getWorkspacePath();
|
|
5077
5606
|
const contributorManager = new ContributorManager2(cwd);
|
|
5078
|
-
console.log(
|
|
5607
|
+
console.log(chalk16.cyan("\n\u{1F504} Sync Learning Patterns\n"));
|
|
5079
5608
|
const config = await contributorManager.getConfig();
|
|
5080
5609
|
if (!config.success || !config.data?.syncOptIn) {
|
|
5081
|
-
console.log(
|
|
5082
|
-
console.log(
|
|
5083
|
-
console.log(
|
|
5610
|
+
console.log(chalk16.yellow("\u26A0\uFE0F Sync is not enabled.\n"));
|
|
5611
|
+
console.log(chalk16.dim(" To enable sync, run:"));
|
|
5612
|
+
console.log(chalk16.dim(" workflow learn:config --enable-sync\n"));
|
|
5084
5613
|
console.log(
|
|
5085
|
-
|
|
5614
|
+
chalk16.dim(
|
|
5086
5615
|
" This allows you to share anonymized patterns with the community."
|
|
5087
5616
|
)
|
|
5088
5617
|
);
|
|
5089
5618
|
process.exit(0);
|
|
5090
5619
|
}
|
|
5091
5620
|
if (options.dryRun) {
|
|
5092
|
-
console.log(
|
|
5621
|
+
console.log(chalk16.yellow("\u{1F4CB} DRY-RUN MODE: No changes will be synced\n"));
|
|
5093
5622
|
}
|
|
5094
5623
|
const store = new PatternStore2(cwd);
|
|
5095
5624
|
const anonymizer = new PatternAnonymizer();
|
|
5096
5625
|
const { fixes, blueprints } = await store.getPatternsForSync();
|
|
5097
5626
|
console.log(
|
|
5098
|
-
|
|
5627
|
+
chalk16.dim(
|
|
5099
5628
|
` Patterns ready to sync: ${fixes.length} fixes, ${blueprints.length} blueprints`
|
|
5100
5629
|
)
|
|
5101
5630
|
);
|
|
5102
5631
|
if (options.push) {
|
|
5103
|
-
console.log(
|
|
5632
|
+
console.log(chalk16.cyan("\n\u{1F4E4} Pushing patterns...\n"));
|
|
5104
5633
|
let anonymizedFixes = 0;
|
|
5105
5634
|
let anonymizedBlueprints = 0;
|
|
5106
5635
|
for (const fix of fixes) {
|
|
@@ -5108,7 +5637,7 @@ async function learnSyncCommand(options) {
|
|
|
5108
5637
|
if (result.success) {
|
|
5109
5638
|
anonymizedFixes++;
|
|
5110
5639
|
if (!options.dryRun) {
|
|
5111
|
-
console.log(
|
|
5640
|
+
console.log(chalk16.dim(` \u2713 Anonymized: ${fix.name}`));
|
|
5112
5641
|
}
|
|
5113
5642
|
}
|
|
5114
5643
|
}
|
|
@@ -5117,117 +5646,117 @@ async function learnSyncCommand(options) {
|
|
|
5117
5646
|
if (result.success) {
|
|
5118
5647
|
anonymizedBlueprints++;
|
|
5119
5648
|
if (!options.dryRun) {
|
|
5120
|
-
console.log(
|
|
5649
|
+
console.log(chalk16.dim(` \u2713 Anonymized: ${bp.name}`));
|
|
5121
5650
|
}
|
|
5122
5651
|
}
|
|
5123
5652
|
}
|
|
5124
5653
|
console.log(
|
|
5125
|
-
|
|
5654
|
+
chalk16.green(
|
|
5126
5655
|
`
|
|
5127
5656
|
\u2705 Ready to push ${anonymizedFixes} fixes and ${anonymizedBlueprints} blueprints`
|
|
5128
5657
|
)
|
|
5129
5658
|
);
|
|
5130
|
-
console.log(
|
|
5659
|
+
console.log(chalk16.dim(" (Registry push not yet implemented)"));
|
|
5131
5660
|
}
|
|
5132
5661
|
if (options.pull) {
|
|
5133
|
-
console.log(
|
|
5134
|
-
console.log(
|
|
5662
|
+
console.log(chalk16.cyan("\n\u{1F4E5} Pulling patterns from registry...\n"));
|
|
5663
|
+
console.log(chalk16.dim(" (Registry pull not yet implemented)"));
|
|
5135
5664
|
}
|
|
5136
5665
|
if (!options.push && !options.pull) {
|
|
5137
5666
|
console.log(
|
|
5138
|
-
|
|
5667
|
+
chalk16.dim(" Specify --push to upload or --pull to download patterns.\n")
|
|
5139
5668
|
);
|
|
5140
5669
|
}
|
|
5141
5670
|
}
|
|
5142
5671
|
async function learnConfigCommand(options) {
|
|
5143
5672
|
const cwd = getWorkspacePath();
|
|
5144
5673
|
const contributorManager = new ContributorManager2(cwd);
|
|
5145
|
-
console.log(
|
|
5674
|
+
console.log(chalk16.cyan("\n\u2699\uFE0F Learning Configuration\n"));
|
|
5146
5675
|
if (options.enableSync) {
|
|
5147
5676
|
const result = await contributorManager.enableSync();
|
|
5148
5677
|
if (result.success) {
|
|
5149
|
-
console.log(
|
|
5678
|
+
console.log(chalk16.green("\u2705 Sync enabled"));
|
|
5150
5679
|
console.log(
|
|
5151
|
-
|
|
5680
|
+
chalk16.dim(" Your patterns will be anonymized before sharing.")
|
|
5152
5681
|
);
|
|
5153
5682
|
} else {
|
|
5154
|
-
console.log(
|
|
5683
|
+
console.log(chalk16.red(`\u274C Failed: ${result.error}`));
|
|
5155
5684
|
}
|
|
5156
5685
|
return;
|
|
5157
5686
|
}
|
|
5158
5687
|
if (options.disableSync) {
|
|
5159
5688
|
const result = await contributorManager.disableSync();
|
|
5160
5689
|
if (result.success) {
|
|
5161
|
-
console.log(
|
|
5690
|
+
console.log(chalk16.green("\u2705 Sync disabled"));
|
|
5162
5691
|
} else {
|
|
5163
|
-
console.log(
|
|
5692
|
+
console.log(chalk16.red(`\u274C Failed: ${result.error}`));
|
|
5164
5693
|
}
|
|
5165
5694
|
return;
|
|
5166
5695
|
}
|
|
5167
5696
|
if (options.enableTelemetry) {
|
|
5168
5697
|
const result = await contributorManager.enableTelemetry();
|
|
5169
5698
|
if (result.success) {
|
|
5170
|
-
console.log(
|
|
5699
|
+
console.log(chalk16.green("\u2705 Telemetry enabled"));
|
|
5171
5700
|
console.log(
|
|
5172
|
-
|
|
5701
|
+
chalk16.dim(
|
|
5173
5702
|
" Anonymous usage data helps improve pattern recommendations."
|
|
5174
5703
|
)
|
|
5175
5704
|
);
|
|
5176
5705
|
} else {
|
|
5177
|
-
console.log(
|
|
5706
|
+
console.log(chalk16.red(`\u274C Failed: ${result.error}`));
|
|
5178
5707
|
}
|
|
5179
5708
|
return;
|
|
5180
5709
|
}
|
|
5181
5710
|
if (options.disableTelemetry) {
|
|
5182
5711
|
const result = await contributorManager.disableTelemetry();
|
|
5183
5712
|
if (result.success) {
|
|
5184
|
-
console.log(
|
|
5713
|
+
console.log(chalk16.green("\u2705 Telemetry disabled"));
|
|
5185
5714
|
} else {
|
|
5186
|
-
console.log(
|
|
5715
|
+
console.log(chalk16.red(`\u274C Failed: ${result.error}`));
|
|
5187
5716
|
}
|
|
5188
5717
|
return;
|
|
5189
5718
|
}
|
|
5190
5719
|
if (options.resetId) {
|
|
5191
|
-
const confirmed = await
|
|
5720
|
+
const confirmed = await p11.confirm({
|
|
5192
5721
|
message: "Are you sure you want to reset your contributor ID? This cannot be undone.",
|
|
5193
5722
|
initialValue: false
|
|
5194
5723
|
});
|
|
5195
|
-
if (
|
|
5196
|
-
|
|
5724
|
+
if (p11.isCancel(confirmed) || !confirmed) {
|
|
5725
|
+
p11.cancel("Reset cancelled");
|
|
5197
5726
|
return;
|
|
5198
5727
|
}
|
|
5199
5728
|
const result = await contributorManager.resetId();
|
|
5200
5729
|
if (result.success) {
|
|
5201
|
-
console.log(
|
|
5202
|
-
console.log(
|
|
5730
|
+
console.log(chalk16.green("\u2705 Contributor ID reset"));
|
|
5731
|
+
console.log(chalk16.dim(` New ID: ${result.data?.id}`));
|
|
5203
5732
|
} else {
|
|
5204
|
-
console.log(
|
|
5733
|
+
console.log(chalk16.red(`\u274C Failed: ${result.error}`));
|
|
5205
5734
|
}
|
|
5206
5735
|
return;
|
|
5207
5736
|
}
|
|
5208
5737
|
const config = await contributorManager.getConfig();
|
|
5209
5738
|
if (config.success && config.data) {
|
|
5210
|
-
console.log(
|
|
5211
|
-
console.log(
|
|
5212
|
-
console.log(
|
|
5739
|
+
console.log(chalk16.white(" Current Settings:\n"));
|
|
5740
|
+
console.log(chalk16.dim(` Contributor ID: ${config.data.id}`));
|
|
5741
|
+
console.log(chalk16.dim(` Created: ${formatDate(config.data.createdAt)}`));
|
|
5213
5742
|
console.log(
|
|
5214
|
-
|
|
5743
|
+
chalk16.dim(` Sync Enabled: ${config.data.syncOptIn ? "Yes" : "No"}`)
|
|
5215
5744
|
);
|
|
5216
5745
|
console.log(
|
|
5217
|
-
|
|
5746
|
+
chalk16.dim(
|
|
5218
5747
|
` Telemetry Enabled: ${config.data.telemetryEnabled ? "Yes" : "No"}`
|
|
5219
5748
|
)
|
|
5220
5749
|
);
|
|
5221
5750
|
if (config.data.syncEnabledAt) {
|
|
5222
5751
|
console.log(
|
|
5223
|
-
|
|
5752
|
+
chalk16.dim(
|
|
5224
5753
|
` Sync Enabled At: ${formatDate(config.data.syncEnabledAt)}`
|
|
5225
5754
|
)
|
|
5226
5755
|
);
|
|
5227
5756
|
}
|
|
5228
5757
|
} else {
|
|
5229
5758
|
console.log(
|
|
5230
|
-
|
|
5759
|
+
chalk16.dim(
|
|
5231
5760
|
" No configuration found. Settings will be created on first use.\n"
|
|
5232
5761
|
)
|
|
5233
5762
|
);
|
|
@@ -5236,7 +5765,7 @@ async function learnConfigCommand(options) {
|
|
|
5236
5765
|
async function learnDeprecateCommand(patternId, reason) {
|
|
5237
5766
|
const cwd = getWorkspacePath();
|
|
5238
5767
|
const store = new PatternStore2(cwd);
|
|
5239
|
-
console.log(
|
|
5768
|
+
console.log(chalk16.cyan("\n\u26A0\uFE0F Deprecate Pattern\n"));
|
|
5240
5769
|
let patternType = "fix";
|
|
5241
5770
|
let pattern = await store.getFixPattern(patternId);
|
|
5242
5771
|
if (!pattern.success || !pattern.data) {
|
|
@@ -5245,26 +5774,26 @@ async function learnDeprecateCommand(patternId, reason) {
|
|
|
5245
5774
|
pattern = bpResult;
|
|
5246
5775
|
patternType = "blueprint";
|
|
5247
5776
|
} else {
|
|
5248
|
-
console.log(
|
|
5777
|
+
console.log(chalk16.red(`
|
|
5249
5778
|
\u274C Pattern not found: ${patternId}`));
|
|
5250
5779
|
process.exit(1);
|
|
5251
5780
|
}
|
|
5252
5781
|
}
|
|
5253
|
-
console.log(
|
|
5254
|
-
console.log(
|
|
5255
|
-
const confirmed = await
|
|
5782
|
+
console.log(chalk16.white(` Pattern: ${pattern.data.name}`));
|
|
5783
|
+
console.log(chalk16.dim(` Reason: ${reason}`));
|
|
5784
|
+
const confirmed = await p11.confirm({
|
|
5256
5785
|
message: "Are you sure you want to deprecate this pattern?",
|
|
5257
5786
|
initialValue: false
|
|
5258
5787
|
});
|
|
5259
|
-
if (
|
|
5260
|
-
|
|
5788
|
+
if (p11.isCancel(confirmed) || !confirmed) {
|
|
5789
|
+
p11.cancel("Deprecation cancelled");
|
|
5261
5790
|
return;
|
|
5262
5791
|
}
|
|
5263
5792
|
const result = await store.deprecatePattern(patternId, patternType, reason);
|
|
5264
5793
|
if (result.success) {
|
|
5265
|
-
console.log(
|
|
5794
|
+
console.log(chalk16.green("\n\u2705 Pattern deprecated successfully"));
|
|
5266
5795
|
} else {
|
|
5267
|
-
console.log(
|
|
5796
|
+
console.log(chalk16.red(`
|
|
5268
5797
|
\u274C Failed: ${result.error}`));
|
|
5269
5798
|
process.exit(1);
|
|
5270
5799
|
}
|
|
@@ -5273,32 +5802,32 @@ async function learnStatsCommand() {
|
|
|
5273
5802
|
const cwd = getWorkspacePath();
|
|
5274
5803
|
const store = new PatternStore2(cwd);
|
|
5275
5804
|
const telemetry = new TelemetryCollector2(cwd);
|
|
5276
|
-
console.log(
|
|
5805
|
+
console.log(chalk16.cyan("\n\u{1F4CA} Learning Statistics\n"));
|
|
5277
5806
|
const storeStats = await store.getStats();
|
|
5278
5807
|
const totalPatterns = storeStats.totalFixes + storeStats.totalBlueprints;
|
|
5279
5808
|
const totalDeprecated = storeStats.deprecatedFixes + storeStats.deprecatedBlueprints;
|
|
5280
|
-
console.log(
|
|
5281
|
-
console.log(
|
|
5282
|
-
console.log(
|
|
5283
|
-
console.log(
|
|
5284
|
-
console.log(
|
|
5809
|
+
console.log(chalk16.bold.white(" Patterns:\n"));
|
|
5810
|
+
console.log(chalk16.dim(` Total: ${totalPatterns}`));
|
|
5811
|
+
console.log(chalk16.dim(` Fix Patterns: ${storeStats.totalFixes}`));
|
|
5812
|
+
console.log(chalk16.dim(` Blueprints: ${storeStats.totalBlueprints}`));
|
|
5813
|
+
console.log(chalk16.dim(` Deprecated: ${totalDeprecated}`));
|
|
5285
5814
|
const telemetryStats = await telemetry.getStats();
|
|
5286
|
-
console.log(
|
|
5287
|
-
console.log(
|
|
5815
|
+
console.log(chalk16.bold.white("\n Telemetry:\n"));
|
|
5816
|
+
console.log(chalk16.dim(` Pending Events: ${telemetryStats.pendingEvents}`));
|
|
5288
5817
|
console.log(
|
|
5289
|
-
|
|
5818
|
+
chalk16.dim(` Total Events Sent: ${telemetryStats.totalEventsSent}`)
|
|
5290
5819
|
);
|
|
5291
5820
|
if (telemetryStats.lastFlushAt) {
|
|
5292
5821
|
console.log(
|
|
5293
|
-
|
|
5822
|
+
chalk16.dim(` Last Flush: ${formatDate(telemetryStats.lastFlushAt)}`)
|
|
5294
5823
|
);
|
|
5295
5824
|
}
|
|
5296
5825
|
console.log("");
|
|
5297
5826
|
}
|
|
5298
5827
|
|
|
5299
5828
|
// src/cli/commands/solution.ts
|
|
5300
|
-
import
|
|
5301
|
-
import * as
|
|
5829
|
+
import chalk17 from "chalk";
|
|
5830
|
+
import * as p12 from "@clack/prompts";
|
|
5302
5831
|
import * as path2 from "path";
|
|
5303
5832
|
import {
|
|
5304
5833
|
PatternStore as PatternStore3,
|
|
@@ -5340,10 +5869,10 @@ function truncate(str, maxLen) {
|
|
|
5340
5869
|
async function solutionCaptureCommand(options) {
|
|
5341
5870
|
const cwd = getWorkspacePath2();
|
|
5342
5871
|
const store = new PatternStore3(cwd);
|
|
5343
|
-
console.log(
|
|
5872
|
+
console.log(chalk17.cyan("\n\u{1F4E6} Capture Solution Pattern\n"));
|
|
5344
5873
|
let targetPath = options.path;
|
|
5345
5874
|
if (!targetPath) {
|
|
5346
|
-
const pathInput = await
|
|
5875
|
+
const pathInput = await p12.text({
|
|
5347
5876
|
message: "Path to the solution directory:",
|
|
5348
5877
|
placeholder: "./src/auth",
|
|
5349
5878
|
validate: (val) => {
|
|
@@ -5351,8 +5880,8 @@ async function solutionCaptureCommand(options) {
|
|
|
5351
5880
|
return void 0;
|
|
5352
5881
|
}
|
|
5353
5882
|
});
|
|
5354
|
-
if (
|
|
5355
|
-
|
|
5883
|
+
if (p12.isCancel(pathInput)) {
|
|
5884
|
+
p12.cancel("Operation cancelled");
|
|
5356
5885
|
process.exit(0);
|
|
5357
5886
|
}
|
|
5358
5887
|
targetPath = pathInput;
|
|
@@ -5360,7 +5889,7 @@ async function solutionCaptureCommand(options) {
|
|
|
5360
5889
|
const absolutePath = path2.isAbsolute(targetPath) ? targetPath : path2.resolve(cwd, targetPath);
|
|
5361
5890
|
let name = options.name;
|
|
5362
5891
|
if (!name) {
|
|
5363
|
-
const nameInput = await
|
|
5892
|
+
const nameInput = await p12.text({
|
|
5364
5893
|
message: "Solution name:",
|
|
5365
5894
|
placeholder: "JWT Authentication",
|
|
5366
5895
|
validate: (val) => {
|
|
@@ -5368,15 +5897,15 @@ async function solutionCaptureCommand(options) {
|
|
|
5368
5897
|
return void 0;
|
|
5369
5898
|
}
|
|
5370
5899
|
});
|
|
5371
|
-
if (
|
|
5372
|
-
|
|
5900
|
+
if (p12.isCancel(nameInput)) {
|
|
5901
|
+
p12.cancel("Operation cancelled");
|
|
5373
5902
|
process.exit(0);
|
|
5374
5903
|
}
|
|
5375
5904
|
name = nameInput;
|
|
5376
5905
|
}
|
|
5377
5906
|
let description = options.description;
|
|
5378
5907
|
if (!description) {
|
|
5379
|
-
const descInput = await
|
|
5908
|
+
const descInput = await p12.text({
|
|
5380
5909
|
message: "Solution description:",
|
|
5381
5910
|
placeholder: "Complete JWT-based authentication with refresh tokens",
|
|
5382
5911
|
validate: (val) => {
|
|
@@ -5385,15 +5914,15 @@ async function solutionCaptureCommand(options) {
|
|
|
5385
5914
|
return void 0;
|
|
5386
5915
|
}
|
|
5387
5916
|
});
|
|
5388
|
-
if (
|
|
5389
|
-
|
|
5917
|
+
if (p12.isCancel(descInput)) {
|
|
5918
|
+
p12.cancel("Operation cancelled");
|
|
5390
5919
|
process.exit(0);
|
|
5391
5920
|
}
|
|
5392
5921
|
description = descInput;
|
|
5393
5922
|
}
|
|
5394
5923
|
let category = options.category;
|
|
5395
5924
|
if (!category) {
|
|
5396
|
-
const categoryChoice = await
|
|
5925
|
+
const categoryChoice = await p12.select({
|
|
5397
5926
|
message: "Solution category:",
|
|
5398
5927
|
options: [
|
|
5399
5928
|
{ value: "auth", label: "\u{1F510} Authentication" },
|
|
@@ -5412,8 +5941,8 @@ async function solutionCaptureCommand(options) {
|
|
|
5412
5941
|
{ value: "other", label: "\u{1F4E6} Other" }
|
|
5413
5942
|
]
|
|
5414
5943
|
});
|
|
5415
|
-
if (
|
|
5416
|
-
|
|
5944
|
+
if (p12.isCancel(categoryChoice)) {
|
|
5945
|
+
p12.cancel("Operation cancelled");
|
|
5417
5946
|
process.exit(0);
|
|
5418
5947
|
}
|
|
5419
5948
|
category = categoryChoice;
|
|
@@ -5422,20 +5951,20 @@ async function solutionCaptureCommand(options) {
|
|
|
5422
5951
|
if (options.keywords) {
|
|
5423
5952
|
keywords = options.keywords.split(",").map((k) => k.trim());
|
|
5424
5953
|
} else {
|
|
5425
|
-
const keywordsInput = await
|
|
5954
|
+
const keywordsInput = await p12.text({
|
|
5426
5955
|
message: "Keywords (comma-separated):",
|
|
5427
5956
|
placeholder: "jwt, authentication, login, refresh-token"
|
|
5428
5957
|
});
|
|
5429
|
-
if (
|
|
5430
|
-
|
|
5958
|
+
if (p12.isCancel(keywordsInput)) {
|
|
5959
|
+
p12.cancel("Operation cancelled");
|
|
5431
5960
|
process.exit(0);
|
|
5432
5961
|
}
|
|
5433
5962
|
if (keywordsInput) {
|
|
5434
5963
|
keywords = keywordsInput.split(",").map((k) => k.trim());
|
|
5435
5964
|
}
|
|
5436
5965
|
}
|
|
5437
|
-
const
|
|
5438
|
-
|
|
5966
|
+
const spinner10 = p12.spinner();
|
|
5967
|
+
spinner10.start("Analyzing solution...");
|
|
5439
5968
|
const analyzer = new CodeAnalyzer({
|
|
5440
5969
|
anonymize: options.anonymize ?? false
|
|
5441
5970
|
});
|
|
@@ -5447,38 +5976,38 @@ async function solutionCaptureCommand(options) {
|
|
|
5447
5976
|
category,
|
|
5448
5977
|
keywords
|
|
5449
5978
|
);
|
|
5450
|
-
|
|
5451
|
-
console.log(
|
|
5452
|
-
console.log(
|
|
5453
|
-
console.log(`${
|
|
5979
|
+
spinner10.stop("Solution analyzed");
|
|
5980
|
+
console.log(chalk17.green("\n\u2713 Solution captured successfully!\n"));
|
|
5981
|
+
console.log(chalk17.dim("\u2500".repeat(50)));
|
|
5982
|
+
console.log(`${chalk17.bold("Name:")} ${pattern.name}`);
|
|
5454
5983
|
console.log(
|
|
5455
|
-
`${
|
|
5984
|
+
`${chalk17.bold("Category:")} ${formatCategory(pattern.category)}`
|
|
5456
5985
|
);
|
|
5457
5986
|
console.log(
|
|
5458
|
-
`${
|
|
5987
|
+
`${chalk17.bold("Files:")} ${pattern.implementation.files.length}`
|
|
5459
5988
|
);
|
|
5460
5989
|
console.log(
|
|
5461
|
-
`${
|
|
5990
|
+
`${chalk17.bold("Dependencies:")} ${pattern.implementation.dependencies.length}`
|
|
5462
5991
|
);
|
|
5463
5992
|
console.log(
|
|
5464
|
-
`${
|
|
5993
|
+
`${chalk17.bold("Framework:")} ${pattern.compatibility.framework || "generic"}`
|
|
5465
5994
|
);
|
|
5466
|
-
console.log(
|
|
5467
|
-
const confirm10 = await
|
|
5995
|
+
console.log(chalk17.dim("\u2500".repeat(50)));
|
|
5996
|
+
const confirm10 = await p12.confirm({
|
|
5468
5997
|
message: "Save this solution pattern?",
|
|
5469
5998
|
initialValue: true
|
|
5470
5999
|
});
|
|
5471
|
-
if (
|
|
5472
|
-
|
|
6000
|
+
if (p12.isCancel(confirm10) || !confirm10) {
|
|
6001
|
+
p12.cancel("Solution not saved");
|
|
5473
6002
|
process.exit(0);
|
|
5474
6003
|
}
|
|
5475
6004
|
await store.saveSolution(pattern);
|
|
5476
|
-
console.log(
|
|
6005
|
+
console.log(chalk17.green(`
|
|
5477
6006
|
\u2713 Solution saved with ID: ${pattern.id}
|
|
5478
6007
|
`));
|
|
5479
6008
|
} catch (error) {
|
|
5480
|
-
|
|
5481
|
-
console.error(
|
|
6009
|
+
spinner10.stop("Analysis failed");
|
|
6010
|
+
console.error(chalk17.red(`
|
|
5482
6011
|
\u2717 Error: ${error.message}
|
|
5483
6012
|
`));
|
|
5484
6013
|
process.exit(1);
|
|
@@ -5487,7 +6016,7 @@ async function solutionCaptureCommand(options) {
|
|
|
5487
6016
|
async function solutionSearchCommand(query, options) {
|
|
5488
6017
|
const cwd = getWorkspacePath2();
|
|
5489
6018
|
const store = new PatternStore3(cwd);
|
|
5490
|
-
console.log(
|
|
6019
|
+
console.log(chalk17.cyan("\n\u{1F50D} Search Solution Patterns\n"));
|
|
5491
6020
|
const keywords = query.split(/\s+/).filter((k) => k.length > 0);
|
|
5492
6021
|
const result = await store.searchSolutions(keywords, {
|
|
5493
6022
|
category: options.category,
|
|
@@ -5495,39 +6024,39 @@ async function solutionSearchCommand(query, options) {
|
|
|
5495
6024
|
limit: options.limit ?? 10
|
|
5496
6025
|
});
|
|
5497
6026
|
if (!result.success || !result.data) {
|
|
5498
|
-
console.error(
|
|
6027
|
+
console.error(chalk17.red(`
|
|
5499
6028
|
\u2717 Search failed: ${result.error}
|
|
5500
6029
|
`));
|
|
5501
6030
|
return;
|
|
5502
6031
|
}
|
|
5503
6032
|
const solutions = result.data;
|
|
5504
6033
|
if (solutions.length === 0) {
|
|
5505
|
-
console.log(
|
|
5506
|
-
console.log(
|
|
6034
|
+
console.log(chalk17.yellow("No solutions found matching your query.\n"));
|
|
6035
|
+
console.log(chalk17.dim("Try different keywords or fewer filters."));
|
|
5507
6036
|
return;
|
|
5508
6037
|
}
|
|
5509
|
-
console.log(
|
|
6038
|
+
console.log(chalk17.green(`Found ${solutions.length} solution(s):
|
|
5510
6039
|
`));
|
|
5511
|
-
console.log(
|
|
6040
|
+
console.log(chalk17.dim("\u2500".repeat(70)));
|
|
5512
6041
|
for (const solution of solutions) {
|
|
5513
6042
|
console.log(
|
|
5514
|
-
`${
|
|
6043
|
+
`${chalk17.bold(solution.name)} ${chalk17.dim(`(${solution.id.slice(0, 8)})`)}`
|
|
5515
6044
|
);
|
|
5516
6045
|
console.log(` ${formatCategory(solution.category)}`);
|
|
5517
|
-
console.log(` ${
|
|
6046
|
+
console.log(` ${chalk17.dim(truncate(solution.description, 60))}`);
|
|
5518
6047
|
console.log(
|
|
5519
6048
|
` Files: ${solution.implementation.files.length} | Framework: ${solution.compatibility.framework || "generic"} | Uses: ${solution.metrics.applications}`
|
|
5520
6049
|
);
|
|
5521
|
-
console.log(
|
|
6050
|
+
console.log(chalk17.dim("\u2500".repeat(70)));
|
|
5522
6051
|
}
|
|
5523
6052
|
console.log(
|
|
5524
|
-
|
|
6053
|
+
chalk17.dim("\nUse 'workflow solution:apply <id>' to apply a solution.")
|
|
5525
6054
|
);
|
|
5526
6055
|
}
|
|
5527
6056
|
async function solutionListCommand(options) {
|
|
5528
6057
|
const cwd = getWorkspacePath2();
|
|
5529
6058
|
const store = new PatternStore3(cwd);
|
|
5530
|
-
console.log(
|
|
6059
|
+
console.log(chalk17.cyan("\n\u{1F4CB} Solution Patterns\n"));
|
|
5531
6060
|
const result = await store.listSolutions({
|
|
5532
6061
|
category: options.category,
|
|
5533
6062
|
framework: options.framework,
|
|
@@ -5535,20 +6064,20 @@ async function solutionListCommand(options) {
|
|
|
5535
6064
|
limit: options.limit ?? 20
|
|
5536
6065
|
});
|
|
5537
6066
|
if (!result.success || !result.data) {
|
|
5538
|
-
console.error(
|
|
6067
|
+
console.error(chalk17.red(`
|
|
5539
6068
|
\u2717 List failed: ${result.error}
|
|
5540
6069
|
`));
|
|
5541
6070
|
return;
|
|
5542
6071
|
}
|
|
5543
6072
|
const solutions = result.data;
|
|
5544
6073
|
if (solutions.length === 0) {
|
|
5545
|
-
console.log(
|
|
6074
|
+
console.log(chalk17.yellow("No solutions found.\n"));
|
|
5546
6075
|
console.log(
|
|
5547
|
-
|
|
6076
|
+
chalk17.dim("Use 'workflow solution:capture' to capture a solution.")
|
|
5548
6077
|
);
|
|
5549
6078
|
return;
|
|
5550
6079
|
}
|
|
5551
|
-
console.log(
|
|
6080
|
+
console.log(chalk17.green(`${solutions.length} solution(s):
|
|
5552
6081
|
`));
|
|
5553
6082
|
const byCategory = /* @__PURE__ */ new Map();
|
|
5554
6083
|
for (const solution of solutions) {
|
|
@@ -5557,24 +6086,24 @@ async function solutionListCommand(options) {
|
|
|
5557
6086
|
byCategory.set(solution.category, list);
|
|
5558
6087
|
}
|
|
5559
6088
|
for (const [category, items] of byCategory) {
|
|
5560
|
-
console.log(
|
|
6089
|
+
console.log(chalk17.bold(`
|
|
5561
6090
|
${formatCategory(category)}`));
|
|
5562
|
-
console.log(
|
|
6091
|
+
console.log(chalk17.dim("\u2500".repeat(50)));
|
|
5563
6092
|
for (const solution of items) {
|
|
5564
|
-
const deprecated = solution.deprecatedAt ?
|
|
6093
|
+
const deprecated = solution.deprecatedAt ? chalk17.red(" [DEPRECATED]") : "";
|
|
5565
6094
|
console.log(
|
|
5566
|
-
` ${
|
|
6095
|
+
` ${chalk17.cyan(solution.id.slice(0, 8))} ${solution.name}${deprecated}`
|
|
5567
6096
|
);
|
|
5568
|
-
console.log(` ${
|
|
6097
|
+
console.log(` ${chalk17.dim(truncate(solution.description, 50))}`);
|
|
5569
6098
|
console.log(
|
|
5570
|
-
|
|
6099
|
+
chalk17.dim(
|
|
5571
6100
|
` Created: ${formatDate2(solution.createdAt)} | Files: ${solution.implementation.files.length}`
|
|
5572
6101
|
)
|
|
5573
6102
|
);
|
|
5574
6103
|
}
|
|
5575
6104
|
}
|
|
5576
6105
|
console.log(
|
|
5577
|
-
|
|
6106
|
+
chalk17.dim(
|
|
5578
6107
|
"\nUse 'workflow solution:search <query>' to find specific solutions."
|
|
5579
6108
|
)
|
|
5580
6109
|
);
|
|
@@ -5582,10 +6111,10 @@ ${formatCategory(category)}`));
|
|
|
5582
6111
|
async function solutionApplyCommand(solutionId, options) {
|
|
5583
6112
|
const cwd = getWorkspacePath2();
|
|
5584
6113
|
const store = new PatternStore3(cwd);
|
|
5585
|
-
console.log(
|
|
6114
|
+
console.log(chalk17.cyan("\n\u{1F680} Apply Solution Pattern\n"));
|
|
5586
6115
|
const result = await store.getSolution(solutionId);
|
|
5587
6116
|
if (!result.success || !result.data) {
|
|
5588
|
-
console.error(
|
|
6117
|
+
console.error(chalk17.red(`
|
|
5589
6118
|
\u2717 Solution not found: ${solutionId}
|
|
5590
6119
|
`));
|
|
5591
6120
|
process.exit(1);
|
|
@@ -5593,60 +6122,60 @@ async function solutionApplyCommand(solutionId, options) {
|
|
|
5593
6122
|
const solution = result.data;
|
|
5594
6123
|
if (solution.deprecatedAt) {
|
|
5595
6124
|
console.log(
|
|
5596
|
-
|
|
6125
|
+
chalk17.yellow(
|
|
5597
6126
|
`\u26A0\uFE0F This solution is deprecated: ${solution.deprecationReason || "No reason provided"}
|
|
5598
6127
|
`
|
|
5599
6128
|
)
|
|
5600
6129
|
);
|
|
5601
|
-
const proceed = await
|
|
6130
|
+
const proceed = await p12.confirm({
|
|
5602
6131
|
message: "Do you want to continue?",
|
|
5603
6132
|
initialValue: false
|
|
5604
6133
|
});
|
|
5605
|
-
if (
|
|
5606
|
-
|
|
6134
|
+
if (p12.isCancel(proceed) || !proceed) {
|
|
6135
|
+
p12.cancel("Operation cancelled");
|
|
5607
6136
|
process.exit(0);
|
|
5608
6137
|
}
|
|
5609
6138
|
}
|
|
5610
|
-
console.log(
|
|
5611
|
-
console.log(
|
|
6139
|
+
console.log(chalk17.bold(`Solution: ${solution.name}`));
|
|
6140
|
+
console.log(chalk17.dim(solution.description));
|
|
5612
6141
|
console.log();
|
|
5613
|
-
console.log(
|
|
6142
|
+
console.log(chalk17.bold("Files to create:"));
|
|
5614
6143
|
const filesToApply = options.includeTests ? solution.implementation.files : solution.implementation.files.filter(
|
|
5615
6144
|
(f) => f.role !== "test"
|
|
5616
6145
|
);
|
|
5617
6146
|
for (const file of filesToApply) {
|
|
5618
|
-
console.log(
|
|
6147
|
+
console.log(chalk17.dim(` \u2022 ${file.path} (${file.role})`));
|
|
5619
6148
|
}
|
|
5620
6149
|
console.log();
|
|
5621
6150
|
if (solution.implementation.dependencies.length > 0) {
|
|
5622
|
-
console.log(
|
|
6151
|
+
console.log(chalk17.bold("Dependencies to install:"));
|
|
5623
6152
|
for (const dep of solution.implementation.dependencies) {
|
|
5624
|
-
console.log(
|
|
6153
|
+
console.log(chalk17.dim(` \u2022 ${dep.name}@${dep.version}`));
|
|
5625
6154
|
}
|
|
5626
6155
|
console.log();
|
|
5627
6156
|
}
|
|
5628
6157
|
if (solution.implementation.envVars.length > 0) {
|
|
5629
|
-
console.log(
|
|
6158
|
+
console.log(chalk17.bold("Environment variables needed:"));
|
|
5630
6159
|
for (const env of solution.implementation.envVars) {
|
|
5631
|
-
const required = env.required ?
|
|
5632
|
-
console.log(
|
|
6160
|
+
const required = env.required ? chalk17.red("*") : "";
|
|
6161
|
+
console.log(chalk17.dim(` \u2022 ${env.name}${required}`));
|
|
5633
6162
|
}
|
|
5634
6163
|
console.log();
|
|
5635
6164
|
}
|
|
5636
6165
|
if (options.dryRun) {
|
|
5637
|
-
console.log(
|
|
6166
|
+
console.log(chalk17.yellow("Dry run mode - no files were created.\n"));
|
|
5638
6167
|
return;
|
|
5639
6168
|
}
|
|
5640
|
-
const confirm10 = await
|
|
6169
|
+
const confirm10 = await p12.confirm({
|
|
5641
6170
|
message: "Apply this solution?",
|
|
5642
6171
|
initialValue: true
|
|
5643
6172
|
});
|
|
5644
|
-
if (
|
|
5645
|
-
|
|
6173
|
+
if (p12.isCancel(confirm10) || !confirm10) {
|
|
6174
|
+
p12.cancel("Operation cancelled");
|
|
5646
6175
|
process.exit(0);
|
|
5647
6176
|
}
|
|
5648
|
-
const
|
|
5649
|
-
|
|
6177
|
+
const spinner10 = p12.spinner();
|
|
6178
|
+
spinner10.start("Applying solution...");
|
|
5650
6179
|
try {
|
|
5651
6180
|
const outputDir = options.output || cwd;
|
|
5652
6181
|
const fs2 = await import("fs");
|
|
@@ -5658,20 +6187,20 @@ async function solutionApplyCommand(solutionId, options) {
|
|
|
5658
6187
|
await fs2.promises.writeFile(filePath, file.content);
|
|
5659
6188
|
}
|
|
5660
6189
|
await store.updateSolutionMetrics(solution.id, true);
|
|
5661
|
-
|
|
5662
|
-
console.log(
|
|
6190
|
+
spinner10.stop("Solution applied");
|
|
6191
|
+
console.log(chalk17.green(`
|
|
5663
6192
|
\u2713 Solution applied successfully!
|
|
5664
6193
|
`));
|
|
5665
|
-
console.log(
|
|
6194
|
+
console.log(chalk17.dim(`Created ${filesToApply.length} file(s).`));
|
|
5666
6195
|
if (solution.implementation.dependencies.length > 0) {
|
|
5667
|
-
console.log(
|
|
6196
|
+
console.log(chalk17.cyan("\nNext step: Install dependencies with:"));
|
|
5668
6197
|
const deps = solution.implementation.dependencies.map((d) => `${d.name}@${d.version}`).join(" ");
|
|
5669
|
-
console.log(
|
|
6198
|
+
console.log(chalk17.dim(` npm install ${deps}`));
|
|
5670
6199
|
}
|
|
5671
6200
|
} catch (error) {
|
|
5672
|
-
|
|
6201
|
+
spinner10.stop("Application failed");
|
|
5673
6202
|
await store.updateSolutionMetrics(solution.id, false);
|
|
5674
|
-
console.error(
|
|
6203
|
+
console.error(chalk17.red(`
|
|
5675
6204
|
\u2717 Error: ${error.message}
|
|
5676
6205
|
`));
|
|
5677
6206
|
process.exit(1);
|
|
@@ -5680,48 +6209,48 @@ async function solutionApplyCommand(solutionId, options) {
|
|
|
5680
6209
|
async function solutionDeprecateCommand(solutionId, reason) {
|
|
5681
6210
|
const cwd = getWorkspacePath2();
|
|
5682
6211
|
const store = new PatternStore3(cwd);
|
|
5683
|
-
console.log(
|
|
6212
|
+
console.log(chalk17.cyan("\n\u26A0\uFE0F Deprecate Solution Pattern\n"));
|
|
5684
6213
|
const result = await store.getSolution(solutionId);
|
|
5685
6214
|
if (!result.success || !result.data) {
|
|
5686
|
-
console.error(
|
|
6215
|
+
console.error(chalk17.red(`
|
|
5687
6216
|
\u2717 Solution not found: ${solutionId}
|
|
5688
6217
|
`));
|
|
5689
6218
|
process.exit(1);
|
|
5690
6219
|
}
|
|
5691
6220
|
const solution = result.data;
|
|
5692
|
-
console.log(`Solution: ${
|
|
6221
|
+
console.log(`Solution: ${chalk17.bold(solution.name)}`);
|
|
5693
6222
|
console.log(`Reason: ${reason}
|
|
5694
6223
|
`);
|
|
5695
|
-
const confirm10 = await
|
|
6224
|
+
const confirm10 = await p12.confirm({
|
|
5696
6225
|
message: "Deprecate this solution?",
|
|
5697
6226
|
initialValue: false
|
|
5698
6227
|
});
|
|
5699
|
-
if (
|
|
5700
|
-
|
|
6228
|
+
if (p12.isCancel(confirm10) || !confirm10) {
|
|
6229
|
+
p12.cancel("Operation cancelled");
|
|
5701
6230
|
process.exit(0);
|
|
5702
6231
|
}
|
|
5703
6232
|
await store.deprecateSolution(solutionId, reason);
|
|
5704
|
-
console.log(
|
|
6233
|
+
console.log(chalk17.green(`
|
|
5705
6234
|
\u2713 Solution deprecated.
|
|
5706
6235
|
`));
|
|
5707
6236
|
}
|
|
5708
6237
|
async function solutionStatsCommand() {
|
|
5709
6238
|
const cwd = getWorkspacePath2();
|
|
5710
6239
|
const store = new PatternStore3(cwd);
|
|
5711
|
-
console.log(
|
|
6240
|
+
console.log(chalk17.cyan("\n\u{1F4CA} Solution Pattern Statistics\n"));
|
|
5712
6241
|
const stats = await store.getStats();
|
|
5713
|
-
console.log(
|
|
5714
|
-
console.log(`${
|
|
6242
|
+
console.log(chalk17.dim("\u2500".repeat(40)));
|
|
6243
|
+
console.log(`${chalk17.bold("Solutions:")} ${stats.totalSolutions}`);
|
|
5715
6244
|
console.log(` Active: ${stats.totalSolutions - stats.deprecatedSolutions}`);
|
|
5716
6245
|
console.log(` Deprecated: ${stats.deprecatedSolutions}`);
|
|
5717
6246
|
console.log(` Private: ${stats.privateSolutions}`);
|
|
5718
6247
|
console.log(` Synced: ${stats.syncedSolutions}`);
|
|
5719
|
-
console.log(
|
|
5720
|
-
console.log(`${
|
|
5721
|
-
console.log(`${
|
|
5722
|
-
console.log(
|
|
6248
|
+
console.log(chalk17.dim("\u2500".repeat(40)));
|
|
6249
|
+
console.log(`${chalk17.bold("Fixes:")} ${stats.totalFixes}`);
|
|
6250
|
+
console.log(`${chalk17.bold("Blueprints:")} ${stats.totalBlueprints}`);
|
|
6251
|
+
console.log(chalk17.dim("\u2500".repeat(40)));
|
|
5723
6252
|
console.log(`
|
|
5724
|
-
${
|
|
6253
|
+
${chalk17.bold("By Category:")}`);
|
|
5725
6254
|
const listResult = await store.listSolutions({ limit: 1e3 });
|
|
5726
6255
|
if (listResult.success && listResult.data) {
|
|
5727
6256
|
const categories = /* @__PURE__ */ new Map();
|
|
@@ -5757,7 +6286,8 @@ program.command("suggest").description("Submit an improvement suggestion").argum
|
|
|
5757
6286
|
"Category: feature, bug, documentation, performance, other"
|
|
5758
6287
|
).action(suggestCommand);
|
|
5759
6288
|
program.command("setup").description("Add workflow scripts to package.json").action(setupCommand);
|
|
5760
|
-
program.command("doctor").description("Run health check and get optimization suggestions").action(doctorCommand);
|
|
6289
|
+
program.command("doctor").description("Run health check and get optimization suggestions").option("--check-guidelines-only", "Only check guidelines presence").action(doctorCommand);
|
|
6290
|
+
program.command("hooks <action>").description("Manage git hooks").action(hooksCommand);
|
|
5761
6291
|
program.command("scope:create").description("Create a custom scope package").option("--name <name>", 'Package name (e.g., "fintech", "gaming")').option(
|
|
5762
6292
|
"--scopes <scopes>",
|
|
5763
6293
|
"Comma-separated scopes (format: name:description:emoji:category)"
|
|
@@ -5774,6 +6304,15 @@ program.command("advisory").description("Generate advisory board analysis and do
|
|
|
5774
6304
|
).option("--timestamp", "Append timestamp to filenames").option("--include-health", "Include code health metrics from verify/doctor").option("--ci", "CI mode with exit codes on high-risk findings").option("--compare <path>", "Compare with previous report").action(advisoryCommand);
|
|
5775
6305
|
program.command("generate-instructions").description("Generate .github/copilot-instructions.md from guidelines").option("--force", "Regenerate without confirmation").action(generateInstructionsCommand);
|
|
5776
6306
|
program.command("update-templates").description("Update guideline templates from the latest package version").option("--force", "Overwrite existing template files").option("--skip", "Skip the update (useful in CI)").action(updateTemplatesCommand);
|
|
6307
|
+
program.command("docs:validate").description("Validate document references in markdown files").option("--fix", "Interactively fix broken references").option("--patterns <patterns>", "Glob patterns to scan (comma-separated, default: **/*.md)").option("--ignore <patterns>", "Glob patterns to ignore (comma-separated)").action((options) => {
|
|
6308
|
+
const patterns = options.patterns ? options.patterns.split(",").map((p13) => p13.trim()) : void 0;
|
|
6309
|
+
const ignore = options.ignore ? options.ignore.split(",").map((p13) => p13.trim()) : void 0;
|
|
6310
|
+
return docsValidateCommand({
|
|
6311
|
+
fix: options.fix,
|
|
6312
|
+
patterns,
|
|
6313
|
+
ignore
|
|
6314
|
+
});
|
|
6315
|
+
});
|
|
5777
6316
|
program.command("learn:record").description("Record a new pattern from a successful implementation").option("--name <name>", "Pattern name").option("--description <desc>", "Pattern description").option(
|
|
5778
6317
|
"--category <cat>",
|
|
5779
6318
|
"Category (migration, security, performance, etc.)"
|