workflow-agent-cli 2.14.1 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cli/index.js +370 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/scripts/postinstall.js +0 -0
- package/package.json +30 -31
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Workflow Agent Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/cli/index.js
CHANGED
|
@@ -58,8 +58,8 @@ var adapters = {
|
|
|
58
58
|
name: "Next.js App Router",
|
|
59
59
|
description: "Next.js 13+ with app directory",
|
|
60
60
|
detect: async () => {
|
|
61
|
-
const
|
|
62
|
-
return
|
|
61
|
+
const fs3 = await import("fs");
|
|
62
|
+
return fs3.existsSync("app") && fs3.existsSync("next.config.ts") || fs3.existsSync("next.config.js");
|
|
63
63
|
},
|
|
64
64
|
paths: {
|
|
65
65
|
actions: "app/actions",
|
|
@@ -75,8 +75,8 @@ var adapters = {
|
|
|
75
75
|
name: "Next.js Pages Router",
|
|
76
76
|
description: "Next.js with pages directory",
|
|
77
77
|
detect: async () => {
|
|
78
|
-
const
|
|
79
|
-
return
|
|
78
|
+
const fs3 = await import("fs");
|
|
79
|
+
return fs3.existsSync("pages") && (fs3.existsSync("next.config.ts") || fs3.existsSync("next.config.js"));
|
|
80
80
|
},
|
|
81
81
|
paths: {
|
|
82
82
|
components: "components",
|
|
@@ -91,8 +91,8 @@ var adapters = {
|
|
|
91
91
|
name: "Vite + React",
|
|
92
92
|
description: "Vite-powered React application",
|
|
93
93
|
detect: async () => {
|
|
94
|
-
const
|
|
95
|
-
return
|
|
94
|
+
const fs3 = await import("fs");
|
|
95
|
+
return fs3.existsSync("vite.config.ts") || fs3.existsSync("vite.config.js");
|
|
96
96
|
},
|
|
97
97
|
paths: {
|
|
98
98
|
components: "src/components",
|
|
@@ -107,8 +107,8 @@ var adapters = {
|
|
|
107
107
|
name: "Remix",
|
|
108
108
|
description: "Remix full-stack framework",
|
|
109
109
|
detect: async () => {
|
|
110
|
-
const
|
|
111
|
-
return
|
|
110
|
+
const fs3 = await import("fs");
|
|
111
|
+
return fs3.existsSync("app/routes") && (fs3.existsSync("remix.config.js") || fs3.existsSync("package.json"));
|
|
112
112
|
},
|
|
113
113
|
paths: {
|
|
114
114
|
components: "app/components",
|
|
@@ -122,8 +122,8 @@ var adapters = {
|
|
|
122
122
|
name: "Astro",
|
|
123
123
|
description: "Astro static site framework",
|
|
124
124
|
detect: async () => {
|
|
125
|
-
const
|
|
126
|
-
return
|
|
125
|
+
const fs3 = await import("fs");
|
|
126
|
+
return fs3.existsSync("astro.config.mjs") || fs3.existsSync("astro.config.ts");
|
|
127
127
|
},
|
|
128
128
|
paths: {
|
|
129
129
|
components: "src/components",
|
|
@@ -137,8 +137,8 @@ var adapters = {
|
|
|
137
137
|
name: "SvelteKit",
|
|
138
138
|
description: "SvelteKit full-stack framework",
|
|
139
139
|
detect: async () => {
|
|
140
|
-
const
|
|
141
|
-
return
|
|
140
|
+
const fs3 = await import("fs");
|
|
141
|
+
return fs3.existsSync("svelte.config.js") || fs3.existsSync("src/routes");
|
|
142
142
|
},
|
|
143
143
|
paths: {
|
|
144
144
|
components: "src/lib/components",
|
|
@@ -1817,11 +1817,11 @@ async function recordSuccessfulFixes(cwd, result) {
|
|
|
1817
1817
|
let framework = "unknown";
|
|
1818
1818
|
let frameworkVersion = "0.0.0";
|
|
1819
1819
|
try {
|
|
1820
|
-
const
|
|
1821
|
-
const
|
|
1822
|
-
const packageJsonPath =
|
|
1820
|
+
const fs3 = await import("fs");
|
|
1821
|
+
const path4 = await import("path");
|
|
1822
|
+
const packageJsonPath = path4.join(cwd, "package.json");
|
|
1823
1823
|
const packageJson = JSON.parse(
|
|
1824
|
-
await
|
|
1824
|
+
await fs3.promises.readFile(packageJsonPath, "utf-8")
|
|
1825
1825
|
);
|
|
1826
1826
|
const deps = {
|
|
1827
1827
|
...packageJson.dependencies,
|
|
@@ -5226,11 +5226,17 @@ async function statusHooksAction(cwd) {
|
|
|
5226
5226
|
// src/cli/commands/learn.ts
|
|
5227
5227
|
import chalk16 from "chalk";
|
|
5228
5228
|
import * as p11 from "@clack/prompts";
|
|
5229
|
+
import * as fs2 from "fs";
|
|
5230
|
+
import * as path2 from "path";
|
|
5229
5231
|
import {
|
|
5230
5232
|
PatternStore as PatternStore2,
|
|
5231
5233
|
ContributorManager as ContributorManager2,
|
|
5232
5234
|
PatternAnonymizer,
|
|
5233
|
-
TelemetryCollector as TelemetryCollector2
|
|
5235
|
+
TelemetryCollector as TelemetryCollector2,
|
|
5236
|
+
FixPatternSchema,
|
|
5237
|
+
BlueprintSchema,
|
|
5238
|
+
SolutionPatternSchema,
|
|
5239
|
+
createDefaultMetrics
|
|
5234
5240
|
} from "@hawkinside_out/workflow-improvement-tracker";
|
|
5235
5241
|
|
|
5236
5242
|
// src/sync/registry-client.ts
|
|
@@ -5335,8 +5341,8 @@ var RegistryClient = class {
|
|
|
5335
5341
|
/**
|
|
5336
5342
|
* Make an HTTP request to the registry
|
|
5337
5343
|
*/
|
|
5338
|
-
async request(
|
|
5339
|
-
const url = `${this.baseUrl}${
|
|
5344
|
+
async request(path4, options) {
|
|
5345
|
+
const url = `${this.baseUrl}${path4}`;
|
|
5340
5346
|
let lastError = null;
|
|
5341
5347
|
for (let attempt = 1; attempt <= this.retries; attempt++) {
|
|
5342
5348
|
try {
|
|
@@ -5739,11 +5745,63 @@ async function learnListCommand(options) {
|
|
|
5739
5745
|
const stats = await store.getStats();
|
|
5740
5746
|
const totalPatterns = stats.totalFixes + stats.totalBlueprints;
|
|
5741
5747
|
const totalDeprecated = stats.deprecatedFixes + stats.deprecatedBlueprints;
|
|
5748
|
+
const totalInvalid = stats.invalidFixes + stats.invalidBlueprints + stats.invalidSolutions;
|
|
5742
5749
|
console.log(chalk16.dim("\u2501".repeat(40)));
|
|
5743
5750
|
console.log(chalk16.dim(`Total: ${totalPatterns} patterns`));
|
|
5744
5751
|
console.log(chalk16.dim(` Fix Patterns: ${stats.totalFixes}`));
|
|
5745
5752
|
console.log(chalk16.dim(` Blueprints: ${stats.totalBlueprints}`));
|
|
5746
5753
|
console.log(chalk16.dim(` Deprecated: ${totalDeprecated}`));
|
|
5754
|
+
if (totalInvalid > 0) {
|
|
5755
|
+
console.log(
|
|
5756
|
+
chalk16.yellow(
|
|
5757
|
+
`
|
|
5758
|
+
\u26A0\uFE0F ${totalInvalid} pattern(s) failed schema validation and were skipped:`
|
|
5759
|
+
)
|
|
5760
|
+
);
|
|
5761
|
+
console.log(
|
|
5762
|
+
chalk16.dim(` Fix patterns: ${stats.invalidFixes} invalid`)
|
|
5763
|
+
);
|
|
5764
|
+
console.log(
|
|
5765
|
+
chalk16.dim(` Blueprints: ${stats.invalidBlueprints} invalid`)
|
|
5766
|
+
);
|
|
5767
|
+
console.log(
|
|
5768
|
+
chalk16.dim(` Solutions: ${stats.invalidSolutions} invalid`)
|
|
5769
|
+
);
|
|
5770
|
+
const validationErrors = store.getValidationErrors();
|
|
5771
|
+
if (validationErrors.length > 0) {
|
|
5772
|
+
console.log(chalk16.yellow("\n Validation errors:"));
|
|
5773
|
+
for (const err of validationErrors.slice(0, 5)) {
|
|
5774
|
+
console.log(chalk16.dim(` \u2022 ${err.file}: ${err.error}`));
|
|
5775
|
+
if (err.details && err.details.length > 0) {
|
|
5776
|
+
for (const detail of err.details.slice(0, 3)) {
|
|
5777
|
+
console.log(chalk16.dim(` - ${detail}`));
|
|
5778
|
+
}
|
|
5779
|
+
if (err.details.length > 3) {
|
|
5780
|
+
console.log(
|
|
5781
|
+
chalk16.dim(` ... and ${err.details.length - 3} more`)
|
|
5782
|
+
);
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5785
|
+
}
|
|
5786
|
+
if (validationErrors.length > 5) {
|
|
5787
|
+
console.log(
|
|
5788
|
+
chalk16.dim(
|
|
5789
|
+
` ... and ${validationErrors.length - 5} more errors`
|
|
5790
|
+
)
|
|
5791
|
+
);
|
|
5792
|
+
}
|
|
5793
|
+
}
|
|
5794
|
+
console.log(
|
|
5795
|
+
chalk16.dim(
|
|
5796
|
+
"\n Tip: Invalid patterns may be missing required fields. Use the PatternStore API"
|
|
5797
|
+
)
|
|
5798
|
+
);
|
|
5799
|
+
console.log(
|
|
5800
|
+
chalk16.dim(
|
|
5801
|
+
" to create patterns instead of writing JSON files directly."
|
|
5802
|
+
)
|
|
5803
|
+
);
|
|
5804
|
+
}
|
|
5747
5805
|
console.log("");
|
|
5748
5806
|
}
|
|
5749
5807
|
async function learnApplyCommand(patternId, options) {
|
|
@@ -6382,11 +6440,294 @@ async function learnStatsCommand() {
|
|
|
6382
6440
|
}
|
|
6383
6441
|
console.log("");
|
|
6384
6442
|
}
|
|
6443
|
+
async function learnValidateCommand(options) {
|
|
6444
|
+
const cwd = getWorkspacePath();
|
|
6445
|
+
const patternsPath = path2.join(cwd, ".workflow", "patterns");
|
|
6446
|
+
const patternType = options.type ?? "all";
|
|
6447
|
+
const shouldFix = options.fix ?? false;
|
|
6448
|
+
const verbose = options.verbose ?? false;
|
|
6449
|
+
const specificFile = options.file;
|
|
6450
|
+
console.log(chalk16.cyan("\n\u{1F50D} Validating Pattern Files\n"));
|
|
6451
|
+
const results = [];
|
|
6452
|
+
if (specificFile) {
|
|
6453
|
+
const fileResult = await validateSingleFile(specificFile, verbose);
|
|
6454
|
+
if (fileResult) {
|
|
6455
|
+
results.push(fileResult);
|
|
6456
|
+
}
|
|
6457
|
+
} else {
|
|
6458
|
+
if (patternType === "all" || patternType === "fix") {
|
|
6459
|
+
const fixesPath = path2.join(patternsPath, "fixes");
|
|
6460
|
+
const fixResults = await validatePatternDirectory(
|
|
6461
|
+
fixesPath,
|
|
6462
|
+
"fix",
|
|
6463
|
+
FixPatternSchema,
|
|
6464
|
+
verbose
|
|
6465
|
+
);
|
|
6466
|
+
results.push(...fixResults);
|
|
6467
|
+
}
|
|
6468
|
+
if (patternType === "all" || patternType === "blueprint") {
|
|
6469
|
+
const blueprintsPath = path2.join(patternsPath, "blueprints");
|
|
6470
|
+
const bpResults = await validatePatternDirectory(
|
|
6471
|
+
blueprintsPath,
|
|
6472
|
+
"blueprint",
|
|
6473
|
+
BlueprintSchema,
|
|
6474
|
+
verbose
|
|
6475
|
+
);
|
|
6476
|
+
results.push(...bpResults);
|
|
6477
|
+
}
|
|
6478
|
+
if (patternType === "all" || patternType === "solution") {
|
|
6479
|
+
const solutionsPath = path2.join(patternsPath, "solutions");
|
|
6480
|
+
const solResults = await validatePatternDirectory(
|
|
6481
|
+
solutionsPath,
|
|
6482
|
+
"solution",
|
|
6483
|
+
SolutionPatternSchema,
|
|
6484
|
+
verbose
|
|
6485
|
+
);
|
|
6486
|
+
results.push(...solResults);
|
|
6487
|
+
}
|
|
6488
|
+
}
|
|
6489
|
+
const valid = results.filter((r) => r.valid);
|
|
6490
|
+
const invalid = results.filter((r) => !r.valid);
|
|
6491
|
+
const fixable = invalid.filter((r) => r.fixable);
|
|
6492
|
+
console.log(chalk16.dim("\u2501".repeat(50)));
|
|
6493
|
+
console.log(chalk16.bold(`
|
|
6494
|
+
\u{1F4CA} Validation Summary
|
|
6495
|
+
`));
|
|
6496
|
+
console.log(chalk16.green(` \u2713 Valid: ${valid.length}`));
|
|
6497
|
+
if (invalid.length > 0) {
|
|
6498
|
+
console.log(chalk16.red(` \u2717 Invalid: ${invalid.length}`));
|
|
6499
|
+
console.log(chalk16.yellow(` \u{1F527} Auto-fixable: ${fixable.length}`));
|
|
6500
|
+
}
|
|
6501
|
+
if (invalid.length > 0) {
|
|
6502
|
+
console.log(chalk16.red(`
|
|
6503
|
+
\u274C Invalid Patterns:
|
|
6504
|
+
`));
|
|
6505
|
+
for (const result of invalid) {
|
|
6506
|
+
console.log(chalk16.white(` ${result.file} (${result.type})`));
|
|
6507
|
+
for (const err of result.errors.slice(0, 5)) {
|
|
6508
|
+
console.log(chalk16.dim(` - ${err}`));
|
|
6509
|
+
}
|
|
6510
|
+
if (result.errors.length > 5) {
|
|
6511
|
+
console.log(chalk16.dim(` ... and ${result.errors.length - 5} more`));
|
|
6512
|
+
}
|
|
6513
|
+
if (result.fixable) {
|
|
6514
|
+
console.log(chalk16.yellow(` \u2192 Can be auto-fixed`));
|
|
6515
|
+
}
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6518
|
+
if (shouldFix && fixable.length > 0) {
|
|
6519
|
+
console.log(chalk16.cyan(`
|
|
6520
|
+
\u{1F527} Auto-fixing ${fixable.length} patterns...
|
|
6521
|
+
`));
|
|
6522
|
+
let fixed = 0;
|
|
6523
|
+
for (const result of fixable) {
|
|
6524
|
+
if (result.fixedData) {
|
|
6525
|
+
const filePath = path2.join(
|
|
6526
|
+
patternsPath,
|
|
6527
|
+
result.type === "fix" ? "fixes" : result.type === "blueprint" ? "blueprints" : "solutions",
|
|
6528
|
+
result.file
|
|
6529
|
+
);
|
|
6530
|
+
try {
|
|
6531
|
+
await fs2.promises.writeFile(
|
|
6532
|
+
filePath,
|
|
6533
|
+
JSON.stringify(result.fixedData, null, 2)
|
|
6534
|
+
);
|
|
6535
|
+
console.log(chalk16.green(` \u2713 Fixed: ${result.file}`));
|
|
6536
|
+
fixed++;
|
|
6537
|
+
} catch (error) {
|
|
6538
|
+
console.log(
|
|
6539
|
+
chalk16.red(
|
|
6540
|
+
` \u2717 Failed to fix: ${result.file} - ${error instanceof Error ? error.message : "Unknown error"}`
|
|
6541
|
+
)
|
|
6542
|
+
);
|
|
6543
|
+
}
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
console.log(chalk16.green(`
|
|
6547
|
+
\u2705 Fixed ${fixed}/${fixable.length} patterns`));
|
|
6548
|
+
} else if (fixable.length > 0 && !shouldFix) {
|
|
6549
|
+
console.log(
|
|
6550
|
+
chalk16.yellow(
|
|
6551
|
+
`
|
|
6552
|
+
\u{1F4A1} Run with --fix to auto-fix ${fixable.length} patterns`
|
|
6553
|
+
)
|
|
6554
|
+
);
|
|
6555
|
+
}
|
|
6556
|
+
console.log("");
|
|
6557
|
+
const unfixable = invalid.filter((r) => !r.fixable);
|
|
6558
|
+
if (unfixable.length > 0 && !shouldFix) {
|
|
6559
|
+
process.exit(1);
|
|
6560
|
+
}
|
|
6561
|
+
if (invalid.length > 0 && !shouldFix) {
|
|
6562
|
+
process.exit(1);
|
|
6563
|
+
}
|
|
6564
|
+
}
|
|
6565
|
+
async function validatePatternDirectory(dirPath, type, schema, verbose) {
|
|
6566
|
+
const results = [];
|
|
6567
|
+
try {
|
|
6568
|
+
const files = await fs2.promises.readdir(dirPath);
|
|
6569
|
+
for (const file of files) {
|
|
6570
|
+
if (!file.endsWith(".json")) continue;
|
|
6571
|
+
const filePath = path2.join(dirPath, file);
|
|
6572
|
+
const result = await validatePatternFile(filePath, file, type, schema, verbose);
|
|
6573
|
+
results.push(result);
|
|
6574
|
+
if (verbose) {
|
|
6575
|
+
if (result.valid) {
|
|
6576
|
+
console.log(chalk16.green(` \u2713 ${file}`));
|
|
6577
|
+
} else {
|
|
6578
|
+
console.log(chalk16.red(` \u2717 ${file}`));
|
|
6579
|
+
}
|
|
6580
|
+
}
|
|
6581
|
+
}
|
|
6582
|
+
} catch (error) {
|
|
6583
|
+
if (error.code !== "ENOENT") {
|
|
6584
|
+
console.log(
|
|
6585
|
+
chalk16.yellow(` \u26A0 Could not read ${type} directory: ${dirPath}`)
|
|
6586
|
+
);
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
return results;
|
|
6590
|
+
}
|
|
6591
|
+
async function validateSingleFile(filePath, verbose) {
|
|
6592
|
+
const fileName = path2.basename(filePath);
|
|
6593
|
+
let type;
|
|
6594
|
+
let schema;
|
|
6595
|
+
if (filePath.includes("/fixes/") || filePath.includes("\\fixes\\")) {
|
|
6596
|
+
type = "fix";
|
|
6597
|
+
schema = FixPatternSchema;
|
|
6598
|
+
} else if (filePath.includes("/blueprints/") || filePath.includes("\\blueprints\\")) {
|
|
6599
|
+
type = "blueprint";
|
|
6600
|
+
schema = BlueprintSchema;
|
|
6601
|
+
} else if (filePath.includes("/solutions/") || filePath.includes("\\solutions\\")) {
|
|
6602
|
+
type = "solution";
|
|
6603
|
+
schema = SolutionPatternSchema;
|
|
6604
|
+
} else {
|
|
6605
|
+
try {
|
|
6606
|
+
const content = await fs2.promises.readFile(filePath, "utf-8");
|
|
6607
|
+
const data = JSON.parse(content);
|
|
6608
|
+
if (data.trigger && data.solution) {
|
|
6609
|
+
type = "fix";
|
|
6610
|
+
schema = FixPatternSchema;
|
|
6611
|
+
} else if (data.stack && data.structure) {
|
|
6612
|
+
type = "blueprint";
|
|
6613
|
+
schema = BlueprintSchema;
|
|
6614
|
+
} else if (data.context && data.approach) {
|
|
6615
|
+
type = "solution";
|
|
6616
|
+
schema = SolutionPatternSchema;
|
|
6617
|
+
} else {
|
|
6618
|
+
type = "blueprint";
|
|
6619
|
+
schema = BlueprintSchema;
|
|
6620
|
+
}
|
|
6621
|
+
} catch {
|
|
6622
|
+
type = "blueprint";
|
|
6623
|
+
schema = BlueprintSchema;
|
|
6624
|
+
}
|
|
6625
|
+
}
|
|
6626
|
+
return validatePatternFile(filePath, fileName, type, schema, verbose);
|
|
6627
|
+
}
|
|
6628
|
+
async function validatePatternFile(filePath, fileName, type, schema, verbose) {
|
|
6629
|
+
try {
|
|
6630
|
+
const content = await fs2.promises.readFile(filePath, "utf-8");
|
|
6631
|
+
const data = JSON.parse(content);
|
|
6632
|
+
const validation = schema.safeParse(data);
|
|
6633
|
+
if (validation.success) {
|
|
6634
|
+
return {
|
|
6635
|
+
file: fileName,
|
|
6636
|
+
type,
|
|
6637
|
+
valid: true,
|
|
6638
|
+
errors: [],
|
|
6639
|
+
fixable: false
|
|
6640
|
+
};
|
|
6641
|
+
}
|
|
6642
|
+
const errors = validation.error.issues.map(
|
|
6643
|
+
(i) => `${i.path.join(".")}: ${i.message}`
|
|
6644
|
+
);
|
|
6645
|
+
const { fixable, fixedData } = tryAutoFix(data, type, validation.error.issues);
|
|
6646
|
+
return {
|
|
6647
|
+
file: fileName,
|
|
6648
|
+
type,
|
|
6649
|
+
valid: false,
|
|
6650
|
+
errors,
|
|
6651
|
+
fixable,
|
|
6652
|
+
fixedData
|
|
6653
|
+
};
|
|
6654
|
+
} catch (error) {
|
|
6655
|
+
return {
|
|
6656
|
+
file: fileName,
|
|
6657
|
+
type,
|
|
6658
|
+
valid: false,
|
|
6659
|
+
errors: [
|
|
6660
|
+
error instanceof Error ? error.message : "Failed to parse JSON"
|
|
6661
|
+
],
|
|
6662
|
+
fixable: false
|
|
6663
|
+
};
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
function tryAutoFix(data, type, issues) {
|
|
6667
|
+
const fixedData = { ...data };
|
|
6668
|
+
let allFixable = true;
|
|
6669
|
+
for (const issue of issues) {
|
|
6670
|
+
const pathStr = issue.path.join(".");
|
|
6671
|
+
if (pathStr === "metrics" && issue.code === "invalid_type") {
|
|
6672
|
+
fixedData.metrics = createDefaultMetrics();
|
|
6673
|
+
continue;
|
|
6674
|
+
}
|
|
6675
|
+
if (pathStr === "setup" && issue.code === "invalid_type" && type === "blueprint") {
|
|
6676
|
+
fixedData.setup = {
|
|
6677
|
+
commands: [],
|
|
6678
|
+
envVars: [],
|
|
6679
|
+
dependencies: []
|
|
6680
|
+
};
|
|
6681
|
+
continue;
|
|
6682
|
+
}
|
|
6683
|
+
if (pathStr === "relatedPatterns" && issue.code === "invalid_type") {
|
|
6684
|
+
fixedData.relatedPatterns = [];
|
|
6685
|
+
continue;
|
|
6686
|
+
}
|
|
6687
|
+
if (pathStr === "tags" && issue.code === "invalid_type") {
|
|
6688
|
+
fixedData.tags = [];
|
|
6689
|
+
continue;
|
|
6690
|
+
}
|
|
6691
|
+
if (pathStr === "errorSignatures" && issue.code === "invalid_type" && type === "fix") {
|
|
6692
|
+
fixedData.errorSignatures = [];
|
|
6693
|
+
continue;
|
|
6694
|
+
}
|
|
6695
|
+
if (pathStr === "codeChanges" && issue.code === "invalid_type" && type === "fix") {
|
|
6696
|
+
fixedData.codeChanges = [];
|
|
6697
|
+
continue;
|
|
6698
|
+
}
|
|
6699
|
+
if (pathStr === "problemKeywords" && issue.code === "invalid_type" && type === "solution") {
|
|
6700
|
+
fixedData.problemKeywords = [];
|
|
6701
|
+
continue;
|
|
6702
|
+
}
|
|
6703
|
+
if (pathStr === "implementations" && issue.code === "invalid_type" && type === "solution") {
|
|
6704
|
+
fixedData.implementations = [];
|
|
6705
|
+
continue;
|
|
6706
|
+
}
|
|
6707
|
+
allFixable = false;
|
|
6708
|
+
}
|
|
6709
|
+
let schema;
|
|
6710
|
+
if (type === "fix") {
|
|
6711
|
+
schema = FixPatternSchema;
|
|
6712
|
+
} else if (type === "blueprint") {
|
|
6713
|
+
schema = BlueprintSchema;
|
|
6714
|
+
} else {
|
|
6715
|
+
schema = SolutionPatternSchema;
|
|
6716
|
+
}
|
|
6717
|
+
const revalidation = schema.safeParse(fixedData);
|
|
6718
|
+
if (revalidation.success) {
|
|
6719
|
+
return { fixable: true, fixedData };
|
|
6720
|
+
}
|
|
6721
|
+
if (allFixable) {
|
|
6722
|
+
return { fixable: true, fixedData };
|
|
6723
|
+
}
|
|
6724
|
+
return { fixable: false };
|
|
6725
|
+
}
|
|
6385
6726
|
|
|
6386
6727
|
// src/cli/commands/solution.ts
|
|
6387
6728
|
import chalk17 from "chalk";
|
|
6388
6729
|
import * as p12 from "@clack/prompts";
|
|
6389
|
-
import * as
|
|
6730
|
+
import * as path3 from "path";
|
|
6390
6731
|
import {
|
|
6391
6732
|
PatternStore as PatternStore3,
|
|
6392
6733
|
CodeAnalyzer
|
|
@@ -6444,7 +6785,7 @@ async function solutionCaptureCommand(options) {
|
|
|
6444
6785
|
}
|
|
6445
6786
|
targetPath = pathInput;
|
|
6446
6787
|
}
|
|
6447
|
-
const absolutePath =
|
|
6788
|
+
const absolutePath = path3.isAbsolute(targetPath) ? targetPath : path3.resolve(cwd, targetPath);
|
|
6448
6789
|
let name = options.name;
|
|
6449
6790
|
if (!name) {
|
|
6450
6791
|
const nameInput = await p12.text({
|
|
@@ -6736,13 +7077,13 @@ async function solutionApplyCommand(solutionId, options) {
|
|
|
6736
7077
|
spinner10.start("Applying solution...");
|
|
6737
7078
|
try {
|
|
6738
7079
|
const outputDir = options.output || cwd;
|
|
6739
|
-
const
|
|
7080
|
+
const fs3 = await import("fs");
|
|
6740
7081
|
const pathModule = await import("path");
|
|
6741
7082
|
for (const file of filesToApply) {
|
|
6742
7083
|
const filePath = pathModule.join(outputDir, file.path);
|
|
6743
7084
|
const dir = pathModule.dirname(filePath);
|
|
6744
|
-
await
|
|
6745
|
-
await
|
|
7085
|
+
await fs3.promises.mkdir(dir, { recursive: true });
|
|
7086
|
+
await fs3.promises.writeFile(filePath, file.content);
|
|
6746
7087
|
}
|
|
6747
7088
|
await store.updateSolutionMetrics(solution.id, true);
|
|
6748
7089
|
spinner10.stop("Solution applied");
|
|
@@ -6909,6 +7250,11 @@ program.command("learn:config").description("Configure learning settings").optio
|
|
|
6909
7250
|
program.command("learn:deprecate <patternId> <reason>").description("Deprecate an outdated pattern").argument("<patternId>", "Pattern ID to deprecate").argument("<reason>", "Reason for deprecation").action(learnDeprecateCommand);
|
|
6910
7251
|
program.command("learn:publish [patternId]").description("Mark pattern(s) as public for syncing").option("--private", "Mark as private instead of public").option("--all", "Apply to all patterns").option("-y, --yes", "Skip confirmation prompts").action(learnPublishCommand);
|
|
6911
7252
|
program.command("learn:stats").description("Show learning statistics").action(learnStatsCommand);
|
|
7253
|
+
program.command("learn:validate").description("Validate pattern files and optionally auto-fix common issues").option(
|
|
7254
|
+
"-t, --type <type>",
|
|
7255
|
+
"Pattern type to validate (fix, blueprint, solution, all)",
|
|
7256
|
+
"all"
|
|
7257
|
+
).option("-f, --file <path>", "Validate a specific file by path").option("--fix", "Automatically fix common issues (missing metrics, setup, etc.)").option("-v, --verbose", "Show detailed validation output").action(learnValidateCommand);
|
|
6912
7258
|
program.command("solution:capture").description("Capture a solution pattern from working code").option("--name <name>", "Solution name").option("--description <desc>", "Solution description").option(
|
|
6913
7259
|
"--category <cat>",
|
|
6914
7260
|
"Category (auth, api, database, ui, testing, deployment, integration, performance, security, other)"
|