workflow-agent-cli 2.20.1 → 2.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-KVM6A42U.js +321 -0
- package/dist/chunk-KVM6A42U.js.map +1 -0
- package/dist/chunk-OMHCXETM.js +238 -0
- package/dist/chunk-OMHCXETM.js.map +1 -0
- package/dist/{chunk-6NWQLGHI.js → chunk-XGS2VFBP.js} +5 -323
- package/dist/chunk-XGS2VFBP.js.map +1 -0
- package/dist/{chunk-CIGGRLZU.js → chunk-YR2X64TH.js} +74 -21
- package/dist/chunk-YR2X64TH.js.map +1 -0
- package/dist/cli/index.js +1414 -603
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +10 -8
- package/dist/scripts/postinstall.js +23 -2
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/verify-2PDVNYWV.js +8 -0
- package/dist/verify-2PDVNYWV.js.map +1 -0
- package/package.json +33 -28
- package/dist/chunk-6NWQLGHI.js.map +0 -1
- package/dist/chunk-CIGGRLZU.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -3,12 +3,9 @@ import {
|
|
|
3
3
|
analyzeProject,
|
|
4
4
|
detectPackageManager,
|
|
5
5
|
generateAuditReport,
|
|
6
|
-
hasUncommittedChanges,
|
|
7
6
|
isMonorepo,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
stageAllChanges
|
|
11
|
-
} from "../chunk-6NWQLGHI.js";
|
|
7
|
+
runAllSetups
|
|
8
|
+
} from "../chunk-XGS2VFBP.js";
|
|
12
9
|
import {
|
|
13
10
|
applyReferenceFix,
|
|
14
11
|
validateBranchName,
|
|
@@ -33,17 +30,21 @@ import {
|
|
|
33
30
|
installMandatoryTemplates,
|
|
34
31
|
templateMetadata,
|
|
35
32
|
updateTemplates
|
|
36
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-YR2X64TH.js";
|
|
37
34
|
import {
|
|
38
35
|
autoFixConfigFile,
|
|
39
36
|
validateScopeDefinitions
|
|
40
37
|
} from "../chunk-YELUGXOM.js";
|
|
38
|
+
import {
|
|
39
|
+
verifyCommand
|
|
40
|
+
} from "../chunk-OMHCXETM.js";
|
|
41
|
+
import "../chunk-KVM6A42U.js";
|
|
41
42
|
import {
|
|
42
43
|
syncCommand
|
|
43
44
|
} from "../chunk-WXHRDBAB.js";
|
|
44
45
|
|
|
45
46
|
// src/cli/index.ts
|
|
46
|
-
import { Command as
|
|
47
|
+
import { Command as Command7 } from "commander";
|
|
47
48
|
import chalk23 from "chalk";
|
|
48
49
|
|
|
49
50
|
// src/cli/commands/init.ts
|
|
@@ -904,6 +905,9 @@ async function doctorCommand(options) {
|
|
|
904
905
|
}
|
|
905
906
|
}
|
|
906
907
|
|
|
908
|
+
// src/cli/commands/setup/index.ts
|
|
909
|
+
import { Command } from "commander";
|
|
910
|
+
|
|
907
911
|
// src/cli/commands/setup.ts
|
|
908
912
|
import * as p3 from "@clack/prompts";
|
|
909
913
|
import chalk6 from "chalk";
|
|
@@ -1041,21 +1045,176 @@ async function setupCommand() {
|
|
|
1041
1045
|
}
|
|
1042
1046
|
}
|
|
1043
1047
|
|
|
1044
|
-
// src/cli/commands/
|
|
1048
|
+
// src/cli/commands/auto-setup-command.ts
|
|
1045
1049
|
import * as p4 from "@clack/prompts";
|
|
1046
1050
|
import chalk7 from "chalk";
|
|
1051
|
+
async function autoSetupCommand(options) {
|
|
1052
|
+
console.log(chalk7.bold.cyan("\n\u{1F527} Workflow Agent Auto-Setup\n"));
|
|
1053
|
+
const cwd = process.cwd();
|
|
1054
|
+
const spinner10 = p4.spinner();
|
|
1055
|
+
spinner10.start("Analyzing project...");
|
|
1056
|
+
let report;
|
|
1057
|
+
try {
|
|
1058
|
+
report = await generateAuditReport(cwd);
|
|
1059
|
+
spinner10.stop("\u2713 Project analysis complete");
|
|
1060
|
+
} catch (error) {
|
|
1061
|
+
spinner10.stop("\u2717 Failed to analyze project");
|
|
1062
|
+
console.error(
|
|
1063
|
+
chalk7.red(
|
|
1064
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`
|
|
1065
|
+
)
|
|
1066
|
+
);
|
|
1067
|
+
process.exit(1);
|
|
1068
|
+
}
|
|
1069
|
+
console.log("\n" + formatAuditReportColored(report));
|
|
1070
|
+
if (options.audit) {
|
|
1071
|
+
console.log(chalk7.dim("\n--audit mode: No changes applied.\n"));
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
if (report.totalChanges === 0 && report.allDevDependencies.length === 0) {
|
|
1075
|
+
p4.outro(chalk7.green("\u2713 Project is already fully configured!"));
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
if (!options.yes) {
|
|
1079
|
+
const shouldProceed = await p4.confirm({
|
|
1080
|
+
message: `Apply ${report.totalChanges} changes and install ${report.allDevDependencies.length} packages?`,
|
|
1081
|
+
initialValue: true
|
|
1082
|
+
});
|
|
1083
|
+
if (p4.isCancel(shouldProceed) || !shouldProceed) {
|
|
1084
|
+
p4.cancel("Setup cancelled");
|
|
1085
|
+
process.exit(0);
|
|
1086
|
+
}
|
|
1087
|
+
} else {
|
|
1088
|
+
console.log(chalk7.dim("\n--yes mode: Auto-approving all changes.\n"));
|
|
1089
|
+
}
|
|
1090
|
+
console.log("");
|
|
1091
|
+
const setupSpinner = p4.spinner();
|
|
1092
|
+
const stepMessages = [];
|
|
1093
|
+
const results = await runAllSetups(cwd, (step, status) => {
|
|
1094
|
+
if (status === "start") {
|
|
1095
|
+
setupSpinner.start(step);
|
|
1096
|
+
} else if (status === "done") {
|
|
1097
|
+
setupSpinner.stop(`\u2713 ${step}`);
|
|
1098
|
+
stepMessages.push(`\u2713 ${step}`);
|
|
1099
|
+
} else {
|
|
1100
|
+
setupSpinner.stop(`\u2717 ${step}`);
|
|
1101
|
+
stepMessages.push(`\u2717 ${step}`);
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
const successCount = results.filter((r) => r.success).length;
|
|
1105
|
+
const failCount = results.filter((r) => !r.success).length;
|
|
1106
|
+
console.log("");
|
|
1107
|
+
if (failCount === 0) {
|
|
1108
|
+
p4.outro(
|
|
1109
|
+
chalk7.green(
|
|
1110
|
+
`\u2713 Auto-setup complete! (${successCount} configurations applied)`
|
|
1111
|
+
)
|
|
1112
|
+
);
|
|
1113
|
+
} else {
|
|
1114
|
+
p4.outro(
|
|
1115
|
+
chalk7.yellow(
|
|
1116
|
+
`\u26A0 Setup completed with issues: ${successCount} succeeded, ${failCount} failed`
|
|
1117
|
+
)
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
console.log(chalk7.dim("\nNext steps:"));
|
|
1121
|
+
console.log(chalk7.dim(" 1. Review the generated configuration files"));
|
|
1122
|
+
console.log(chalk7.dim(" 2. Run: pnpm verify (or npm/yarn)"));
|
|
1123
|
+
console.log(chalk7.dim(" 3. Commit your changes\n"));
|
|
1124
|
+
}
|
|
1125
|
+
function formatAuditReportColored(report) {
|
|
1126
|
+
const lines = [];
|
|
1127
|
+
lines.push(chalk7.bold("\u{1F4CB} Audit Report\n"));
|
|
1128
|
+
lines.push(chalk7.dim(`Framework: ${report.analysis.framework}`));
|
|
1129
|
+
lines.push(chalk7.dim(`Package Manager: ${report.analysis.packageManager}`));
|
|
1130
|
+
lines.push(
|
|
1131
|
+
chalk7.dim(`TypeScript: ${report.analysis.isTypeScript ? "Yes" : "No"}`)
|
|
1132
|
+
);
|
|
1133
|
+
lines.push(
|
|
1134
|
+
chalk7.dim(`Monorepo: ${report.analysis.isMonorepo ? "Yes" : "No"}`)
|
|
1135
|
+
);
|
|
1136
|
+
lines.push("");
|
|
1137
|
+
for (const plan of report.plans) {
|
|
1138
|
+
const hasChanges = plan.changes.some((c) => c.type !== "unchanged");
|
|
1139
|
+
const icon = hasChanges ? "\u{1F527}" : "\u2713";
|
|
1140
|
+
const titleColor = hasChanges ? chalk7.yellow : chalk7.green;
|
|
1141
|
+
lines.push(
|
|
1142
|
+
titleColor(
|
|
1143
|
+
`${icon} ${plan.name.charAt(0).toUpperCase() + plan.name.slice(1)} - ${plan.description}`
|
|
1144
|
+
)
|
|
1145
|
+
);
|
|
1146
|
+
for (const change of plan.changes) {
|
|
1147
|
+
let symbol;
|
|
1148
|
+
let line;
|
|
1149
|
+
switch (change.type) {
|
|
1150
|
+
case "add":
|
|
1151
|
+
symbol = chalk7.green("+");
|
|
1152
|
+
line = chalk7.green(change.description);
|
|
1153
|
+
break;
|
|
1154
|
+
case "modify":
|
|
1155
|
+
symbol = chalk7.yellow("~");
|
|
1156
|
+
line = chalk7.yellow(change.description);
|
|
1157
|
+
if (change.key && change.oldValue !== void 0 && change.newValue !== void 0) {
|
|
1158
|
+
line += chalk7.dim(
|
|
1159
|
+
` (${String(change.oldValue)} \u2192 ${String(change.newValue)})`
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
break;
|
|
1163
|
+
case "unchanged":
|
|
1164
|
+
default:
|
|
1165
|
+
symbol = chalk7.dim("=");
|
|
1166
|
+
line = chalk7.dim(change.description);
|
|
1167
|
+
}
|
|
1168
|
+
lines.push(` ${symbol} ${line}`);
|
|
1169
|
+
}
|
|
1170
|
+
if (plan.devDependencies.length > 0) {
|
|
1171
|
+
lines.push(
|
|
1172
|
+
chalk7.blue(` \u{1F4E6} Install: ${plan.devDependencies.join(", ")}`)
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
lines.push("");
|
|
1176
|
+
}
|
|
1177
|
+
if (report.allDevDependencies.length > 0) {
|
|
1178
|
+
lines.push(chalk7.bold("Dependencies to install (batched):"));
|
|
1179
|
+
const pm = report.analysis.packageManager;
|
|
1180
|
+
const cmd = pm === "npm" ? "npm install" : pm === "yarn" ? "yarn add" : `${pm} add`;
|
|
1181
|
+
lines.push(
|
|
1182
|
+
chalk7.cyan(` ${cmd} -D ${report.allDevDependencies.join(" ")}`)
|
|
1183
|
+
);
|
|
1184
|
+
lines.push("");
|
|
1185
|
+
}
|
|
1186
|
+
lines.push(
|
|
1187
|
+
chalk7.bold(
|
|
1188
|
+
`Total: ${report.totalChanges} changes, ${report.allDevDependencies.length} packages`
|
|
1189
|
+
)
|
|
1190
|
+
);
|
|
1191
|
+
return lines.join("\n");
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// src/cli/commands/setup/index.ts
|
|
1195
|
+
function createSetupCommand() {
|
|
1196
|
+
const setupCmd = new Command("setup").description("Setup and configuration commands");
|
|
1197
|
+
setupCmd.action(setupCommand);
|
|
1198
|
+
setupCmd.command("scripts").description("Add workflow scripts to package.json").action(setupCommand);
|
|
1199
|
+
setupCmd.command("auto").description("Automatically configure linting, formatting, testing, and CI").option("-y, --yes", "Auto-approve all prompts").option("--audit", "Show audit report without applying changes").action(autoSetupCommand);
|
|
1200
|
+
return setupCmd;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// src/cli/commands/scope-create.ts
|
|
1204
|
+
import * as p5 from "@clack/prompts";
|
|
1205
|
+
import chalk8 from "chalk";
|
|
1047
1206
|
import { existsSync as existsSync5 } from "fs";
|
|
1048
1207
|
import { writeFile as writeFile3, mkdir as mkdir3, readFile as readFile2 } from "fs/promises";
|
|
1049
1208
|
import { join as join5 } from "path";
|
|
1050
1209
|
async function scopeCreateCommand(options) {
|
|
1051
|
-
console.log(
|
|
1210
|
+
console.log(chalk8.bold.cyan("\n\u{1F3A8} Create Custom Scope Package\n"));
|
|
1052
1211
|
const cwd = process.cwd();
|
|
1053
1212
|
const isNonInteractive = !!(options.name && options.scopes && options.presetName);
|
|
1054
1213
|
const isMonorepo2 = existsSync5(join5(cwd, "pnpm-workspace.yaml"));
|
|
1055
1214
|
if (isMonorepo2) {
|
|
1056
|
-
console.log(
|
|
1215
|
+
console.log(chalk8.dim("\u2713 Detected monorepo workspace\n"));
|
|
1057
1216
|
}
|
|
1058
|
-
const packageNameInput = isNonInteractive ? options.name : await
|
|
1217
|
+
const packageNameInput = isNonInteractive ? options.name : await p5.text({
|
|
1059
1218
|
message: 'What is the package name? (e.g., "fintech", "gaming", "healthcare")',
|
|
1060
1219
|
placeholder: "my-custom-scope",
|
|
1061
1220
|
validate: (value) => {
|
|
@@ -1067,12 +1226,12 @@ async function scopeCreateCommand(options) {
|
|
|
1067
1226
|
return void 0;
|
|
1068
1227
|
}
|
|
1069
1228
|
});
|
|
1070
|
-
if (!isNonInteractive &&
|
|
1071
|
-
|
|
1229
|
+
if (!isNonInteractive && p5.isCancel(packageNameInput)) {
|
|
1230
|
+
p5.cancel("Operation cancelled");
|
|
1072
1231
|
process.exit(0);
|
|
1073
1232
|
}
|
|
1074
1233
|
const packageName = packageNameInput;
|
|
1075
|
-
const presetNameInput = isNonInteractive ? options.presetName : await
|
|
1234
|
+
const presetNameInput = isNonInteractive ? options.presetName : await p5.text({
|
|
1076
1235
|
message: 'What is the preset display name? (e.g., "FinTech Application", "Gaming Platform")',
|
|
1077
1236
|
placeholder: "My Custom Preset",
|
|
1078
1237
|
validate: (value) => {
|
|
@@ -1080,8 +1239,8 @@ async function scopeCreateCommand(options) {
|
|
|
1080
1239
|
return void 0;
|
|
1081
1240
|
}
|
|
1082
1241
|
});
|
|
1083
|
-
if (!isNonInteractive &&
|
|
1084
|
-
|
|
1242
|
+
if (!isNonInteractive && p5.isCancel(presetNameInput)) {
|
|
1243
|
+
p5.cancel("Operation cancelled");
|
|
1085
1244
|
process.exit(0);
|
|
1086
1245
|
}
|
|
1087
1246
|
const presetName = presetNameInput;
|
|
@@ -1099,11 +1258,11 @@ async function scopeCreateCommand(options) {
|
|
|
1099
1258
|
}
|
|
1100
1259
|
} else {
|
|
1101
1260
|
console.log(
|
|
1102
|
-
|
|
1261
|
+
chalk8.dim("\nAdd scopes to your preset (aim for 8-15 scopes):\n")
|
|
1103
1262
|
);
|
|
1104
1263
|
let addMore = true;
|
|
1105
1264
|
while (addMore) {
|
|
1106
|
-
const scopeName = await
|
|
1265
|
+
const scopeName = await p5.text({
|
|
1107
1266
|
message: `Scope #${scopes.length + 1} - Name:`,
|
|
1108
1267
|
placeholder: "auth",
|
|
1109
1268
|
validate: (value) => {
|
|
@@ -1116,10 +1275,10 @@ async function scopeCreateCommand(options) {
|
|
|
1116
1275
|
return void 0;
|
|
1117
1276
|
}
|
|
1118
1277
|
});
|
|
1119
|
-
if (
|
|
1278
|
+
if (p5.isCancel(scopeName)) {
|
|
1120
1279
|
break;
|
|
1121
1280
|
}
|
|
1122
|
-
const scopeDescription = await
|
|
1281
|
+
const scopeDescription = await p5.text({
|
|
1123
1282
|
message: "Description:",
|
|
1124
1283
|
placeholder: "Authentication and authorization",
|
|
1125
1284
|
validate: (value) => {
|
|
@@ -1128,17 +1287,17 @@ async function scopeCreateCommand(options) {
|
|
|
1128
1287
|
return void 0;
|
|
1129
1288
|
}
|
|
1130
1289
|
});
|
|
1131
|
-
if (
|
|
1290
|
+
if (p5.isCancel(scopeDescription)) {
|
|
1132
1291
|
break;
|
|
1133
1292
|
}
|
|
1134
|
-
const scopeEmoji = await
|
|
1293
|
+
const scopeEmoji = await p5.text({
|
|
1135
1294
|
message: "Emoji (optional):",
|
|
1136
1295
|
placeholder: "\u{1F510}"
|
|
1137
1296
|
});
|
|
1138
|
-
if (
|
|
1297
|
+
if (p5.isCancel(scopeEmoji)) {
|
|
1139
1298
|
break;
|
|
1140
1299
|
}
|
|
1141
|
-
const scopeCategory = await
|
|
1300
|
+
const scopeCategory = await p5.select({
|
|
1142
1301
|
message: "Category (optional):",
|
|
1143
1302
|
options: [
|
|
1144
1303
|
{ value: "auth", label: "Authentication & Authorization" },
|
|
@@ -1151,7 +1310,7 @@ async function scopeCreateCommand(options) {
|
|
|
1151
1310
|
{ value: "", label: "None" }
|
|
1152
1311
|
]
|
|
1153
1312
|
});
|
|
1154
|
-
if (
|
|
1313
|
+
if (p5.isCancel(scopeCategory)) {
|
|
1155
1314
|
break;
|
|
1156
1315
|
}
|
|
1157
1316
|
scopes.push({
|
|
@@ -1160,15 +1319,15 @@ async function scopeCreateCommand(options) {
|
|
|
1160
1319
|
emoji: scopeEmoji ? scopeEmoji : void 0,
|
|
1161
1320
|
category: scopeCategory ? scopeCategory : void 0
|
|
1162
1321
|
});
|
|
1163
|
-
console.log(
|
|
1322
|
+
console.log(chalk8.green(`
|
|
1164
1323
|
\u2713 Added scope: ${scopeName}
|
|
1165
1324
|
`));
|
|
1166
1325
|
if (scopes.length >= 3) {
|
|
1167
|
-
addMore = await
|
|
1326
|
+
addMore = await p5.confirm({
|
|
1168
1327
|
message: `You have ${scopes.length} scopes. Add another?`,
|
|
1169
1328
|
initialValue: scopes.length < 10
|
|
1170
1329
|
});
|
|
1171
|
-
if (
|
|
1330
|
+
if (p5.isCancel(addMore)) {
|
|
1172
1331
|
break;
|
|
1173
1332
|
}
|
|
1174
1333
|
if (!addMore) break;
|
|
@@ -1176,20 +1335,20 @@ async function scopeCreateCommand(options) {
|
|
|
1176
1335
|
}
|
|
1177
1336
|
}
|
|
1178
1337
|
if (scopes.length === 0) {
|
|
1179
|
-
|
|
1338
|
+
p5.cancel("No scopes defined. Operation cancelled.");
|
|
1180
1339
|
process.exit(1);
|
|
1181
1340
|
}
|
|
1182
1341
|
const validation = validateScopeDefinitions(scopes);
|
|
1183
1342
|
if (!validation.valid) {
|
|
1184
|
-
console.log(
|
|
1343
|
+
console.log(chalk8.red("\n\u2717 Scope validation failed:\n"));
|
|
1185
1344
|
validation.errors.forEach(
|
|
1186
|
-
(error) => console.log(
|
|
1345
|
+
(error) => console.log(chalk8.red(` \u2022 ${error}`))
|
|
1187
1346
|
);
|
|
1188
|
-
|
|
1347
|
+
p5.cancel("Operation cancelled");
|
|
1189
1348
|
process.exit(1);
|
|
1190
1349
|
}
|
|
1191
1350
|
console.log(
|
|
1192
|
-
|
|
1351
|
+
chalk8.green(`
|
|
1193
1352
|
\u2713 ${scopes.length} scopes validated successfully
|
|
1194
1353
|
`)
|
|
1195
1354
|
);
|
|
@@ -1199,28 +1358,28 @@ async function scopeCreateCommand(options) {
|
|
|
1199
1358
|
} else if (isMonorepo2) {
|
|
1200
1359
|
outputDir = join5(cwd, "packages", `scopes-${packageName}`);
|
|
1201
1360
|
} else {
|
|
1202
|
-
const customDir = await
|
|
1361
|
+
const customDir = await p5.text({
|
|
1203
1362
|
message: "Output directory:",
|
|
1204
1363
|
placeholder: `./scopes-${packageName}`,
|
|
1205
1364
|
defaultValue: `./scopes-${packageName}`
|
|
1206
1365
|
});
|
|
1207
|
-
if (
|
|
1208
|
-
|
|
1366
|
+
if (p5.isCancel(customDir)) {
|
|
1367
|
+
p5.cancel("Operation cancelled");
|
|
1209
1368
|
process.exit(0);
|
|
1210
1369
|
}
|
|
1211
1370
|
outputDir = join5(cwd, customDir);
|
|
1212
1371
|
}
|
|
1213
1372
|
if (existsSync5(outputDir)) {
|
|
1214
|
-
const shouldOverwrite = await
|
|
1373
|
+
const shouldOverwrite = await p5.confirm({
|
|
1215
1374
|
message: `Directory ${outputDir} already exists. Overwrite?`,
|
|
1216
1375
|
initialValue: false
|
|
1217
1376
|
});
|
|
1218
|
-
if (
|
|
1219
|
-
|
|
1377
|
+
if (p5.isCancel(shouldOverwrite) || !shouldOverwrite) {
|
|
1378
|
+
p5.cancel("Operation cancelled");
|
|
1220
1379
|
process.exit(0);
|
|
1221
1380
|
}
|
|
1222
1381
|
}
|
|
1223
|
-
const spinner10 =
|
|
1382
|
+
const spinner10 = p5.spinner();
|
|
1224
1383
|
spinner10.start("Creating package structure...");
|
|
1225
1384
|
try {
|
|
1226
1385
|
await mkdir3(join5(outputDir, "src"), { recursive: true });
|
|
@@ -1359,111 +1518,111 @@ describe('${presetName} Scope Preset', () => {
|
|
|
1359
1518
|
const packagePath = `packages/scopes-${packageName}`;
|
|
1360
1519
|
if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
|
|
1361
1520
|
console.log(
|
|
1362
|
-
|
|
1521
|
+
chalk8.yellow("\n\u26A0\uFE0F Add the following to pnpm-workspace.yaml:")
|
|
1363
1522
|
);
|
|
1364
|
-
console.log(
|
|
1523
|
+
console.log(chalk8.dim(` - '${packagePath}'`));
|
|
1365
1524
|
} else {
|
|
1366
|
-
console.log(
|
|
1525
|
+
console.log(chalk8.green("\n\u2713 Package will be included in workspace"));
|
|
1367
1526
|
}
|
|
1368
1527
|
}
|
|
1369
1528
|
console.log(
|
|
1370
|
-
|
|
1529
|
+
chalk8.green.bold("\n\u2728 Custom scope package created successfully!\n")
|
|
1371
1530
|
);
|
|
1372
|
-
console.log(
|
|
1373
|
-
console.log(
|
|
1374
|
-
console.log(
|
|
1375
|
-
console.log(
|
|
1531
|
+
console.log(chalk8.bold("Package details:"));
|
|
1532
|
+
console.log(chalk8.dim(` Location: ${outputDir}`));
|
|
1533
|
+
console.log(chalk8.dim(` Package: @workflow/scopes-${packageName}`));
|
|
1534
|
+
console.log(chalk8.dim(` Scopes: ${scopes.length} defined
|
|
1376
1535
|
`));
|
|
1377
|
-
console.log(
|
|
1378
|
-
console.log(
|
|
1379
|
-
console.log(
|
|
1380
|
-
console.log(
|
|
1536
|
+
console.log(chalk8.bold("Next steps:\n"));
|
|
1537
|
+
console.log(chalk8.dim(` 1. cd ${outputDir}`));
|
|
1538
|
+
console.log(chalk8.dim(` 2. pnpm install`));
|
|
1539
|
+
console.log(chalk8.dim(` 3. pnpm build`));
|
|
1381
1540
|
if (!options.noTest) {
|
|
1382
|
-
console.log(
|
|
1541
|
+
console.log(chalk8.dim(` 4. pnpm test`));
|
|
1383
1542
|
}
|
|
1384
1543
|
console.log(
|
|
1385
|
-
|
|
1544
|
+
chalk8.dim(
|
|
1386
1545
|
` ${!options.noTest ? "5" : "4"}. Update repository URL in package.json`
|
|
1387
1546
|
)
|
|
1388
1547
|
);
|
|
1389
|
-
const shouldPublish = isNonInteractive ? false : await
|
|
1548
|
+
const shouldPublish = isNonInteractive ? false : await p5.confirm({
|
|
1390
1549
|
message: "\nWould you like instructions for publishing to npm?",
|
|
1391
1550
|
initialValue: false
|
|
1392
1551
|
});
|
|
1393
|
-
if (shouldPublish && !
|
|
1394
|
-
console.log(
|
|
1552
|
+
if (shouldPublish && !p5.isCancel(shouldPublish)) {
|
|
1553
|
+
console.log(chalk8.bold("\n\u{1F4E6} Publishing instructions:\n"));
|
|
1395
1554
|
console.log(
|
|
1396
|
-
|
|
1555
|
+
chalk8.dim(" 1. npm login (or configure .npmrc with your registry)")
|
|
1397
1556
|
);
|
|
1398
|
-
console.log(
|
|
1399
|
-
console.log(
|
|
1557
|
+
console.log(chalk8.dim(" 2. Update version in package.json as needed"));
|
|
1558
|
+
console.log(chalk8.dim(" 3. pnpm publish --access public"));
|
|
1400
1559
|
console.log(
|
|
1401
|
-
|
|
1560
|
+
chalk8.dim(
|
|
1402
1561
|
" 4. Use in other projects: pnpm add @workflow/scopes-" + packageName + "\n"
|
|
1403
1562
|
)
|
|
1404
1563
|
);
|
|
1405
1564
|
}
|
|
1406
1565
|
} catch (error) {
|
|
1407
1566
|
spinner10.stop("\u2717 Failed to create package");
|
|
1408
|
-
console.error(
|
|
1567
|
+
console.error(chalk8.red("\nError:"), error);
|
|
1409
1568
|
process.exit(1);
|
|
1410
1569
|
}
|
|
1411
1570
|
}
|
|
1412
1571
|
|
|
1413
1572
|
// src/cli/commands/scope-migrate.ts
|
|
1414
|
-
import * as
|
|
1415
|
-
import
|
|
1573
|
+
import * as p6 from "@clack/prompts";
|
|
1574
|
+
import chalk9 from "chalk";
|
|
1416
1575
|
import { existsSync as existsSync6 } from "fs";
|
|
1417
1576
|
import { writeFile as writeFile4, mkdir as mkdir4, readFile as readFile3 } from "fs/promises";
|
|
1418
1577
|
import { join as join6 } from "path";
|
|
1419
1578
|
async function scopeMigrateCommand(options) {
|
|
1420
|
-
console.log(
|
|
1579
|
+
console.log(chalk9.bold.cyan("\n\u{1F504} Migrate Scopes to Custom Package\n"));
|
|
1421
1580
|
const cwd = process.cwd();
|
|
1422
1581
|
if (!hasConfig(cwd)) {
|
|
1423
|
-
|
|
1582
|
+
p6.cancel("No workflow.config.json found in current directory");
|
|
1424
1583
|
process.exit(1);
|
|
1425
1584
|
}
|
|
1426
1585
|
let config = null;
|
|
1427
1586
|
try {
|
|
1428
1587
|
config = await loadConfig(cwd);
|
|
1429
1588
|
} catch (error) {
|
|
1430
|
-
console.error(
|
|
1589
|
+
console.error(chalk9.red("Failed to load config:"), error);
|
|
1431
1590
|
process.exit(1);
|
|
1432
1591
|
}
|
|
1433
1592
|
if (!config) {
|
|
1434
|
-
|
|
1593
|
+
p6.cancel("Failed to load configuration");
|
|
1435
1594
|
process.exit(1);
|
|
1436
1595
|
}
|
|
1437
1596
|
if (!config.scopes || config.scopes.length === 0) {
|
|
1438
|
-
|
|
1597
|
+
p6.cancel("No scopes found in workflow.config.json");
|
|
1439
1598
|
process.exit(1);
|
|
1440
1599
|
}
|
|
1441
1600
|
console.log(
|
|
1442
|
-
|
|
1601
|
+
chalk9.dim(`Found ${config.scopes.length} scopes in workflow.config.json
|
|
1443
1602
|
`)
|
|
1444
1603
|
);
|
|
1445
|
-
console.log(
|
|
1604
|
+
console.log(chalk9.bold("Current scopes:"));
|
|
1446
1605
|
config.scopes.forEach((scope, i) => {
|
|
1447
1606
|
console.log(
|
|
1448
|
-
|
|
1607
|
+
chalk9.dim(
|
|
1449
1608
|
` ${i + 1}. ${scope.emoji || "\u2022"} ${scope.name} - ${scope.description}`
|
|
1450
1609
|
)
|
|
1451
1610
|
);
|
|
1452
1611
|
});
|
|
1453
1612
|
console.log();
|
|
1454
|
-
const shouldContinue = await
|
|
1613
|
+
const shouldContinue = await p6.confirm({
|
|
1455
1614
|
message: "Migrate these scopes to a custom package?",
|
|
1456
1615
|
initialValue: true
|
|
1457
1616
|
});
|
|
1458
|
-
if (
|
|
1459
|
-
|
|
1617
|
+
if (p6.isCancel(shouldContinue) || !shouldContinue) {
|
|
1618
|
+
p6.cancel("Migration cancelled");
|
|
1460
1619
|
process.exit(0);
|
|
1461
1620
|
}
|
|
1462
1621
|
const isMonorepo2 = existsSync6(join6(cwd, "pnpm-workspace.yaml"));
|
|
1463
1622
|
if (isMonorepo2) {
|
|
1464
|
-
console.log(
|
|
1623
|
+
console.log(chalk9.dim("\n\u2713 Detected monorepo workspace\n"));
|
|
1465
1624
|
}
|
|
1466
|
-
const packageNameInput = options.name || await
|
|
1625
|
+
const packageNameInput = options.name || await p6.text({
|
|
1467
1626
|
message: "Package name for the scope preset:",
|
|
1468
1627
|
placeholder: config.projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-"),
|
|
1469
1628
|
validate: (value) => {
|
|
@@ -1475,33 +1634,33 @@ async function scopeMigrateCommand(options) {
|
|
|
1475
1634
|
return void 0;
|
|
1476
1635
|
}
|
|
1477
1636
|
});
|
|
1478
|
-
if (
|
|
1479
|
-
|
|
1637
|
+
if (p6.isCancel(packageNameInput)) {
|
|
1638
|
+
p6.cancel("Migration cancelled");
|
|
1480
1639
|
process.exit(0);
|
|
1481
1640
|
}
|
|
1482
1641
|
const packageName = packageNameInput;
|
|
1483
|
-
const presetNameInput = await
|
|
1642
|
+
const presetNameInput = await p6.text({
|
|
1484
1643
|
message: "Preset display name:",
|
|
1485
1644
|
placeholder: config.projectName,
|
|
1486
1645
|
defaultValue: config.projectName
|
|
1487
1646
|
});
|
|
1488
|
-
if (
|
|
1489
|
-
|
|
1647
|
+
if (p6.isCancel(presetNameInput)) {
|
|
1648
|
+
p6.cancel("Migration cancelled");
|
|
1490
1649
|
process.exit(0);
|
|
1491
1650
|
}
|
|
1492
1651
|
const presetName = presetNameInput;
|
|
1493
1652
|
const validation = validateScopeDefinitions(config.scopes);
|
|
1494
1653
|
if (!validation.valid) {
|
|
1495
|
-
console.log(
|
|
1654
|
+
console.log(chalk9.yellow("\n\u26A0\uFE0F Scope validation warnings:\n"));
|
|
1496
1655
|
validation.errors.forEach(
|
|
1497
|
-
(error) => console.log(
|
|
1656
|
+
(error) => console.log(chalk9.yellow(` \u2022 ${error}`))
|
|
1498
1657
|
);
|
|
1499
|
-
const shouldFix = await
|
|
1658
|
+
const shouldFix = await p6.confirm({
|
|
1500
1659
|
message: "Some scopes have validation issues. Continue anyway?",
|
|
1501
1660
|
initialValue: false
|
|
1502
1661
|
});
|
|
1503
|
-
if (
|
|
1504
|
-
|
|
1662
|
+
if (p6.isCancel(shouldFix) || !shouldFix) {
|
|
1663
|
+
p6.cancel("Migration cancelled. Please fix validation errors first.");
|
|
1505
1664
|
process.exit(1);
|
|
1506
1665
|
}
|
|
1507
1666
|
}
|
|
@@ -1511,28 +1670,28 @@ async function scopeMigrateCommand(options) {
|
|
|
1511
1670
|
} else if (isMonorepo2) {
|
|
1512
1671
|
outputDir = join6(cwd, "packages", `scopes-${packageName}`);
|
|
1513
1672
|
} else {
|
|
1514
|
-
const customDir = await
|
|
1673
|
+
const customDir = await p6.text({
|
|
1515
1674
|
message: "Output directory:",
|
|
1516
1675
|
placeholder: `./scopes-${packageName}`,
|
|
1517
1676
|
defaultValue: `./scopes-${packageName}`
|
|
1518
1677
|
});
|
|
1519
|
-
if (
|
|
1520
|
-
|
|
1678
|
+
if (p6.isCancel(customDir)) {
|
|
1679
|
+
p6.cancel("Migration cancelled");
|
|
1521
1680
|
process.exit(0);
|
|
1522
1681
|
}
|
|
1523
1682
|
outputDir = join6(cwd, customDir);
|
|
1524
1683
|
}
|
|
1525
1684
|
if (existsSync6(outputDir)) {
|
|
1526
|
-
const shouldOverwrite = await
|
|
1685
|
+
const shouldOverwrite = await p6.confirm({
|
|
1527
1686
|
message: `Directory ${outputDir} already exists. Overwrite?`,
|
|
1528
1687
|
initialValue: false
|
|
1529
1688
|
});
|
|
1530
|
-
if (
|
|
1531
|
-
|
|
1689
|
+
if (p6.isCancel(shouldOverwrite) || !shouldOverwrite) {
|
|
1690
|
+
p6.cancel("Migration cancelled");
|
|
1532
1691
|
process.exit(0);
|
|
1533
1692
|
}
|
|
1534
1693
|
}
|
|
1535
|
-
const spinner10 =
|
|
1694
|
+
const spinner10 = p6.spinner();
|
|
1536
1695
|
spinner10.start("Migrating scopes to package...");
|
|
1537
1696
|
try {
|
|
1538
1697
|
await mkdir4(join6(outputDir, "src"), { recursive: true });
|
|
@@ -1668,18 +1827,18 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
1668
1827
|
const packagePath = `packages/scopes-${packageName}`;
|
|
1669
1828
|
if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
|
|
1670
1829
|
console.log(
|
|
1671
|
-
|
|
1830
|
+
chalk9.yellow("\n\u26A0\uFE0F Add the following to pnpm-workspace.yaml:")
|
|
1672
1831
|
);
|
|
1673
|
-
console.log(
|
|
1832
|
+
console.log(chalk9.dim(` - '${packagePath}'`));
|
|
1674
1833
|
} else {
|
|
1675
|
-
console.log(
|
|
1834
|
+
console.log(chalk9.green("\n\u2713 Package will be included in workspace"));
|
|
1676
1835
|
}
|
|
1677
1836
|
}
|
|
1678
|
-
const keepConfig = options.keepConfig ?? await
|
|
1837
|
+
const keepConfig = options.keepConfig ?? await p6.confirm({
|
|
1679
1838
|
message: "Remove migrated scopes from workflow.config.json?",
|
|
1680
1839
|
initialValue: false
|
|
1681
1840
|
});
|
|
1682
|
-
if (!
|
|
1841
|
+
if (!p6.isCancel(keepConfig) && !keepConfig) {
|
|
1683
1842
|
const configPath = join6(cwd, "workflow.config.json");
|
|
1684
1843
|
const updatedConfig = {
|
|
1685
1844
|
...config,
|
|
@@ -1693,428 +1852,78 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
1693
1852
|
JSON.stringify(updatedConfig, null, 2),
|
|
1694
1853
|
"utf-8"
|
|
1695
1854
|
);
|
|
1696
|
-
console.log(
|
|
1697
|
-
console.log(
|
|
1855
|
+
console.log(chalk9.green("\u2713 Updated workflow.config.json"));
|
|
1856
|
+
console.log(chalk9.dim(" \u2022 Cleared inline scopes"));
|
|
1698
1857
|
console.log(
|
|
1699
|
-
|
|
1858
|
+
chalk9.dim(` \u2022 Added preset reference: scopes-${packageName}
|
|
1700
1859
|
`)
|
|
1701
1860
|
);
|
|
1702
1861
|
}
|
|
1703
|
-
console.log(
|
|
1704
|
-
console.log(
|
|
1705
|
-
console.log(
|
|
1706
|
-
console.log(
|
|
1707
|
-
console.log(
|
|
1862
|
+
console.log(chalk9.green.bold("\n\u2728 Migration completed successfully!\n"));
|
|
1863
|
+
console.log(chalk9.bold("Package details:"));
|
|
1864
|
+
console.log(chalk9.dim(` Location: ${outputDir}`));
|
|
1865
|
+
console.log(chalk9.dim(` Package: @workflow/scopes-${packageName}`));
|
|
1866
|
+
console.log(chalk9.dim(` Scopes: ${config.scopes.length} migrated
|
|
1708
1867
|
`));
|
|
1709
|
-
console.log(
|
|
1710
|
-
console.log(
|
|
1711
|
-
console.log(
|
|
1712
|
-
console.log(
|
|
1713
|
-
console.log(
|
|
1714
|
-
console.log(
|
|
1868
|
+
console.log(chalk9.bold("Next steps:\n"));
|
|
1869
|
+
console.log(chalk9.dim(` 1. cd ${outputDir}`));
|
|
1870
|
+
console.log(chalk9.dim(` 2. pnpm install`));
|
|
1871
|
+
console.log(chalk9.dim(` 3. pnpm build`));
|
|
1872
|
+
console.log(chalk9.dim(` 4. pnpm test`));
|
|
1873
|
+
console.log(chalk9.dim(` 5. Update repository URL in package.json
|
|
1715
1874
|
`));
|
|
1716
1875
|
if (!keepConfig) {
|
|
1717
|
-
console.log(
|
|
1876
|
+
console.log(chalk9.bold("To use the migrated scopes:\n"));
|
|
1718
1877
|
console.log(
|
|
1719
|
-
|
|
1878
|
+
chalk9.dim(
|
|
1720
1879
|
` 1. Install the package: pnpm add -w @workflow/scopes-${packageName}`
|
|
1721
1880
|
)
|
|
1722
1881
|
);
|
|
1723
|
-
console.log(
|
|
1724
|
-
|
|
1725
|
-
` 2. The preset is already referenced in workflow.config.json
|
|
1726
|
-
`
|
|
1727
|
-
)
|
|
1728
|
-
);
|
|
1729
|
-
}
|
|
1730
|
-
console.log(
|
|
1731
|
-
chalk8.dim(
|
|
1732
|
-
"\u{1F4A1} Tip: You can now reuse this scope package across multiple projects!\n"
|
|
1733
|
-
)
|
|
1734
|
-
);
|
|
1735
|
-
} catch (error) {
|
|
1736
|
-
spinner10.stop("\u2717 Migration failed");
|
|
1737
|
-
console.error(chalk8.red("\nError:"), error);
|
|
1738
|
-
process.exit(1);
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
|
-
// src/cli/commands/verify.ts
|
|
1743
|
-
import chalk9 from "chalk";
|
|
1744
|
-
import { execa as execa2 } from "execa";
|
|
1745
|
-
import {
|
|
1746
|
-
PatternStore,
|
|
1747
|
-
TelemetryCollector,
|
|
1748
|
-
ContributorManager
|
|
1749
|
-
} from "@hawkinside_out/workflow-improvement-tracker";
|
|
1750
|
-
async function verifyCommand(options) {
|
|
1751
|
-
const cwd = process.cwd();
|
|
1752
|
-
const maxRetries = options.maxRetries ? parseInt(options.maxRetries, 10) : 10;
|
|
1753
|
-
const autoFix = options.fix ?? false;
|
|
1754
|
-
const shouldCommit = options.commit ?? false;
|
|
1755
|
-
const dryRun = options.dryRun ?? false;
|
|
1756
|
-
const learnFromFixes = options.learn ?? false;
|
|
1757
|
-
console.log(chalk9.bold.cyan("\n\u{1F50D} Workflow Agent Quality Verification\n"));
|
|
1758
|
-
if (dryRun) {
|
|
1759
|
-
console.log(chalk9.yellow("\u{1F4CB} DRY-RUN MODE: No changes will be applied\n"));
|
|
1760
|
-
}
|
|
1761
|
-
console.log(chalk9.dim(` Auto-fix: ${autoFix ? "enabled" : "disabled"}`));
|
|
1762
|
-
console.log(chalk9.dim(` Max retries: ${maxRetries}`));
|
|
1763
|
-
console.log(chalk9.dim(` Commit on success: ${shouldCommit ? "yes" : "no"}`));
|
|
1764
|
-
console.log(chalk9.dim(` Dry-run: ${dryRun ? "yes" : "no"}`));
|
|
1765
|
-
console.log(
|
|
1766
|
-
chalk9.dim(` Learn from fixes: ${learnFromFixes ? "yes" : "no"}`)
|
|
1767
|
-
);
|
|
1768
|
-
const startTime = Date.now();
|
|
1769
|
-
const result = await runAllChecks(cwd, {
|
|
1770
|
-
maxRetries,
|
|
1771
|
-
autoFix,
|
|
1772
|
-
dryRun
|
|
1773
|
-
});
|
|
1774
|
-
const totalTime = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
1775
|
-
console.log(`
|
|
1776
|
-
${"\u2501".repeat(50)}`);
|
|
1777
|
-
if (result.success) {
|
|
1778
|
-
console.log(chalk9.bold.green("\n\u2705 ALL QUALITY CHECKS PASSED!\n"));
|
|
1779
|
-
console.log(chalk9.dim(` Total time: ${totalTime}s`));
|
|
1780
|
-
console.log(chalk9.dim(` Validation cycles: ${result.totalAttempts}`));
|
|
1781
|
-
console.log(chalk9.dim(` Fixes applied: ${result.fixesApplied}`));
|
|
1782
|
-
if (learnFromFixes && result.fixesApplied > 0 && !dryRun) {
|
|
1783
|
-
await recordSuccessfulFixes(cwd, result);
|
|
1784
|
-
}
|
|
1785
|
-
if (shouldCommit) {
|
|
1786
|
-
const hasChanges = await hasUncommittedChanges(cwd);
|
|
1787
|
-
if (hasChanges) {
|
|
1788
|
-
console.log(chalk9.cyan("\n\u{1F4E6} Staging and committing changes...\n"));
|
|
1789
|
-
const staged = await stageAllChanges(cwd);
|
|
1790
|
-
if (!staged) {
|
|
1791
|
-
console.log(chalk9.red("\u274C Failed to stage changes"));
|
|
1792
|
-
process.exit(1);
|
|
1793
|
-
}
|
|
1794
|
-
try {
|
|
1795
|
-
await execa2(
|
|
1796
|
-
"git",
|
|
1797
|
-
["commit", "-m", "chore: auto-fix quality issues"],
|
|
1798
|
-
{ cwd }
|
|
1799
|
-
);
|
|
1800
|
-
console.log(chalk9.green("\u2705 Changes committed successfully"));
|
|
1801
|
-
} catch (error) {
|
|
1802
|
-
console.log(chalk9.red("\u274C Failed to commit changes"));
|
|
1803
|
-
console.log(chalk9.dim(error.message));
|
|
1804
|
-
process.exit(1);
|
|
1805
|
-
}
|
|
1806
|
-
} else {
|
|
1807
|
-
console.log(chalk9.dim("\n No changes to commit."));
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
console.log(chalk9.cyan("\n\u{1F4A1} Next steps:\n"));
|
|
1811
|
-
console.log(chalk9.dim(" 1. git add ."));
|
|
1812
|
-
console.log(
|
|
1813
|
-
chalk9.dim(' 2. git commit -m "<type>(<scope>): <description>"')
|
|
1814
|
-
);
|
|
1815
|
-
console.log(chalk9.dim(" 3. git push origin <branch-name>"));
|
|
1816
|
-
console.log("");
|
|
1817
|
-
process.exit(0);
|
|
1818
|
-
} else {
|
|
1819
|
-
console.log(chalk9.bold.red("\n\u274C QUALITY CHECKS FAILED\n"));
|
|
1820
|
-
console.log(chalk9.dim(` Total time: ${totalTime}s`));
|
|
1821
|
-
console.log(chalk9.dim(` Validation cycles: ${result.totalAttempts}`));
|
|
1822
|
-
console.log(chalk9.dim(` Fixes applied: ${result.fixesApplied}`));
|
|
1823
|
-
if (result.pendingFixes && result.pendingFixes.length > 0) {
|
|
1824
|
-
console.log(chalk9.yellow("\n\u{1F4CB} Pending fixes (dry-run):"));
|
|
1825
|
-
for (const fix of result.pendingFixes) {
|
|
1826
|
-
console.log(chalk9.dim(` \u2022 ${fix.check.displayName}: ${fix.command}`));
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
console.log(
|
|
1830
|
-
chalk9.yellow("\n\u26A0\uFE0F Please fix the errors above and run again.")
|
|
1831
|
-
);
|
|
1832
|
-
console.log(
|
|
1833
|
-
chalk9.dim(" Run with --fix to auto-fix lint and format issues.")
|
|
1834
|
-
);
|
|
1835
|
-
console.log("");
|
|
1836
|
-
process.exit(1);
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
async function recordSuccessfulFixes(cwd, result) {
|
|
1840
|
-
try {
|
|
1841
|
-
const contributorManager = new ContributorManager(cwd);
|
|
1842
|
-
const telemetryEnabled = await contributorManager.isTelemetryEnabled();
|
|
1843
|
-
if (!telemetryEnabled) {
|
|
1844
|
-
return;
|
|
1845
|
-
}
|
|
1846
|
-
const store = new PatternStore(cwd);
|
|
1847
|
-
const telemetry = new TelemetryCollector(cwd);
|
|
1848
|
-
let framework = "unknown";
|
|
1849
|
-
let frameworkVersion = "0.0.0";
|
|
1850
|
-
try {
|
|
1851
|
-
const fs3 = await import("fs");
|
|
1852
|
-
const path4 = await import("path");
|
|
1853
|
-
const packageJsonPath = path4.join(cwd, "package.json");
|
|
1854
|
-
const packageJson = JSON.parse(
|
|
1855
|
-
await fs3.promises.readFile(packageJsonPath, "utf-8")
|
|
1856
|
-
);
|
|
1857
|
-
const deps = {
|
|
1858
|
-
...packageJson.dependencies,
|
|
1859
|
-
...packageJson.devDependencies
|
|
1860
|
-
};
|
|
1861
|
-
if (deps["next"]) {
|
|
1862
|
-
framework = "next";
|
|
1863
|
-
frameworkVersion = deps["next"].replace(/[\^~]/, "");
|
|
1864
|
-
} else if (deps["react"]) {
|
|
1865
|
-
framework = "react";
|
|
1866
|
-
frameworkVersion = deps["react"].replace(/[\^~]/, "");
|
|
1867
|
-
} else if (deps["vue"]) {
|
|
1868
|
-
framework = "vue";
|
|
1869
|
-
frameworkVersion = deps["vue"].replace(/[\^~]/, "");
|
|
1870
|
-
} else if (deps["express"]) {
|
|
1871
|
-
framework = "express";
|
|
1872
|
-
frameworkVersion = deps["express"].replace(/[\^~]/, "");
|
|
1873
|
-
}
|
|
1874
|
-
} catch {
|
|
1875
|
-
}
|
|
1876
|
-
if (result.appliedFixes && result.appliedFixes.length > 0) {
|
|
1877
|
-
console.log(
|
|
1878
|
-
chalk9.cyan("\n\u{1F4DA} Recording successful fixes for learning...\n")
|
|
1879
|
-
);
|
|
1880
|
-
for (const fix of result.appliedFixes) {
|
|
1881
|
-
const patternName = `Auto-fix: ${fix.displayName}`;
|
|
1882
|
-
const patternId = crypto.randomUUID();
|
|
1883
|
-
const existingPatterns = await store.listFixPatterns({
|
|
1884
|
-
tags: [{ category: "tool", name: fix.checkName }]
|
|
1885
|
-
});
|
|
1886
|
-
if (existingPatterns.success && existingPatterns.data && existingPatterns.data.length > 0) {
|
|
1887
|
-
const existingPattern = existingPatterns.data[0];
|
|
1888
|
-
await store.updateFixMetrics(existingPattern.id, true);
|
|
1889
|
-
await telemetry.recordSuccess(
|
|
1890
|
-
existingPattern.id,
|
|
1891
|
-
"fix",
|
|
1892
|
-
framework,
|
|
1893
|
-
frameworkVersion
|
|
1894
|
-
);
|
|
1895
|
-
console.log(chalk9.dim(` \u2713 Updated: ${existingPattern.name}`));
|
|
1896
|
-
} else {
|
|
1897
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1898
|
-
const newPattern = {
|
|
1899
|
-
id: patternId,
|
|
1900
|
-
name: patternName,
|
|
1901
|
-
description: `Auto-fix pattern for ${fix.displayName} using command: ${fix.command}`,
|
|
1902
|
-
category: "config",
|
|
1903
|
-
tags: [
|
|
1904
|
-
{ category: "tool", name: fix.checkName },
|
|
1905
|
-
{ category: "framework", name: framework }
|
|
1906
|
-
],
|
|
1907
|
-
trigger: {
|
|
1908
|
-
errorPattern: fix.checkName,
|
|
1909
|
-
errorMessage: `${fix.checkName} check failed`,
|
|
1910
|
-
filePattern: "**/*"
|
|
1911
|
-
},
|
|
1912
|
-
solution: {
|
|
1913
|
-
type: "command",
|
|
1914
|
-
steps: [
|
|
1915
|
-
{
|
|
1916
|
-
order: 1,
|
|
1917
|
-
action: "run",
|
|
1918
|
-
target: fix.command,
|
|
1919
|
-
description: `Run ${fix.command}`
|
|
1920
|
-
}
|
|
1921
|
-
]
|
|
1922
|
-
},
|
|
1923
|
-
compatibility: {
|
|
1924
|
-
framework,
|
|
1925
|
-
frameworkVersion: `>=${frameworkVersion}`,
|
|
1926
|
-
runtime: "node",
|
|
1927
|
-
runtimeVersion: ">=18.0.0",
|
|
1928
|
-
dependencies: []
|
|
1929
|
-
},
|
|
1930
|
-
metrics: {
|
|
1931
|
-
applications: 1,
|
|
1932
|
-
successes: 1,
|
|
1933
|
-
failures: 0,
|
|
1934
|
-
successRate: 100,
|
|
1935
|
-
lastUsed: now,
|
|
1936
|
-
lastSuccessful: now
|
|
1937
|
-
},
|
|
1938
|
-
source: "verify-fix",
|
|
1939
|
-
isPrivate: true,
|
|
1940
|
-
createdAt: now,
|
|
1941
|
-
updatedAt: now
|
|
1942
|
-
};
|
|
1943
|
-
const saveResult = await store.saveFixPattern(newPattern);
|
|
1944
|
-
if (saveResult.success) {
|
|
1945
|
-
await telemetry.recordSuccess(
|
|
1946
|
-
patternId,
|
|
1947
|
-
"fix",
|
|
1948
|
-
framework,
|
|
1949
|
-
frameworkVersion
|
|
1950
|
-
);
|
|
1951
|
-
console.log(chalk9.dim(` \u2713 Recorded: ${patternName}`));
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
console.log(
|
|
1956
|
-
chalk9.dim(`
|
|
1957
|
-
Use 'workflow learn:list' to see recorded patterns.`)
|
|
1958
|
-
);
|
|
1959
|
-
}
|
|
1960
|
-
} catch (error) {
|
|
1961
|
-
console.log(
|
|
1962
|
-
chalk9.dim(
|
|
1963
|
-
`
|
|
1964
|
-
Note: Could not record learning patterns: ${error.message}`
|
|
1965
|
-
)
|
|
1966
|
-
);
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
|
|
1970
|
-
// src/cli/commands/auto-setup-command.ts
|
|
1971
|
-
import * as p6 from "@clack/prompts";
|
|
1972
|
-
import chalk10 from "chalk";
|
|
1973
|
-
async function autoSetupCommand(options) {
|
|
1974
|
-
console.log(chalk10.bold.cyan("\n\u{1F527} Workflow Agent Auto-Setup\n"));
|
|
1975
|
-
const cwd = process.cwd();
|
|
1976
|
-
const spinner10 = p6.spinner();
|
|
1977
|
-
spinner10.start("Analyzing project...");
|
|
1978
|
-
let report;
|
|
1979
|
-
try {
|
|
1980
|
-
report = await generateAuditReport(cwd);
|
|
1981
|
-
spinner10.stop("\u2713 Project analysis complete");
|
|
1982
|
-
} catch (error) {
|
|
1983
|
-
spinner10.stop("\u2717 Failed to analyze project");
|
|
1984
|
-
console.error(
|
|
1985
|
-
chalk10.red(
|
|
1986
|
-
`Error: ${error instanceof Error ? error.message : String(error)}`
|
|
1987
|
-
)
|
|
1988
|
-
);
|
|
1989
|
-
process.exit(1);
|
|
1990
|
-
}
|
|
1991
|
-
console.log("\n" + formatAuditReportColored(report));
|
|
1992
|
-
if (options.audit) {
|
|
1993
|
-
console.log(chalk10.dim("\n--audit mode: No changes applied.\n"));
|
|
1994
|
-
return;
|
|
1995
|
-
}
|
|
1996
|
-
if (report.totalChanges === 0 && report.allDevDependencies.length === 0) {
|
|
1997
|
-
p6.outro(chalk10.green("\u2713 Project is already fully configured!"));
|
|
1998
|
-
return;
|
|
1999
|
-
}
|
|
2000
|
-
if (!options.yes) {
|
|
2001
|
-
const shouldProceed = await p6.confirm({
|
|
2002
|
-
message: `Apply ${report.totalChanges} changes and install ${report.allDevDependencies.length} packages?`,
|
|
2003
|
-
initialValue: true
|
|
2004
|
-
});
|
|
2005
|
-
if (p6.isCancel(shouldProceed) || !shouldProceed) {
|
|
2006
|
-
p6.cancel("Setup cancelled");
|
|
2007
|
-
process.exit(0);
|
|
2008
|
-
}
|
|
2009
|
-
} else {
|
|
2010
|
-
console.log(chalk10.dim("\n--yes mode: Auto-approving all changes.\n"));
|
|
2011
|
-
}
|
|
2012
|
-
console.log("");
|
|
2013
|
-
const setupSpinner = p6.spinner();
|
|
2014
|
-
const stepMessages = [];
|
|
2015
|
-
const results = await runAllSetups(cwd, (step, status) => {
|
|
2016
|
-
if (status === "start") {
|
|
2017
|
-
setupSpinner.start(step);
|
|
2018
|
-
} else if (status === "done") {
|
|
2019
|
-
setupSpinner.stop(`\u2713 ${step}`);
|
|
2020
|
-
stepMessages.push(`\u2713 ${step}`);
|
|
2021
|
-
} else {
|
|
2022
|
-
setupSpinner.stop(`\u2717 ${step}`);
|
|
2023
|
-
stepMessages.push(`\u2717 ${step}`);
|
|
2024
|
-
}
|
|
2025
|
-
});
|
|
2026
|
-
const successCount = results.filter((r) => r.success).length;
|
|
2027
|
-
const failCount = results.filter((r) => !r.success).length;
|
|
2028
|
-
console.log("");
|
|
2029
|
-
if (failCount === 0) {
|
|
2030
|
-
p6.outro(
|
|
2031
|
-
chalk10.green(
|
|
2032
|
-
`\u2713 Auto-setup complete! (${successCount} configurations applied)`
|
|
2033
|
-
)
|
|
2034
|
-
);
|
|
2035
|
-
} else {
|
|
2036
|
-
p6.outro(
|
|
2037
|
-
chalk10.yellow(
|
|
2038
|
-
`\u26A0 Setup completed with issues: ${successCount} succeeded, ${failCount} failed`
|
|
2039
|
-
)
|
|
2040
|
-
);
|
|
2041
|
-
}
|
|
2042
|
-
console.log(chalk10.dim("\nNext steps:"));
|
|
2043
|
-
console.log(chalk10.dim(" 1. Review the generated configuration files"));
|
|
2044
|
-
console.log(chalk10.dim(" 2. Run: pnpm verify (or npm/yarn)"));
|
|
2045
|
-
console.log(chalk10.dim(" 3. Commit your changes\n"));
|
|
2046
|
-
}
|
|
2047
|
-
function formatAuditReportColored(report) {
|
|
2048
|
-
const lines = [];
|
|
2049
|
-
lines.push(chalk10.bold("\u{1F4CB} Audit Report\n"));
|
|
2050
|
-
lines.push(chalk10.dim(`Framework: ${report.analysis.framework}`));
|
|
2051
|
-
lines.push(chalk10.dim(`Package Manager: ${report.analysis.packageManager}`));
|
|
2052
|
-
lines.push(
|
|
2053
|
-
chalk10.dim(`TypeScript: ${report.analysis.isTypeScript ? "Yes" : "No"}`)
|
|
2054
|
-
);
|
|
2055
|
-
lines.push(
|
|
2056
|
-
chalk10.dim(`Monorepo: ${report.analysis.isMonorepo ? "Yes" : "No"}`)
|
|
2057
|
-
);
|
|
2058
|
-
lines.push("");
|
|
2059
|
-
for (const plan of report.plans) {
|
|
2060
|
-
const hasChanges = plan.changes.some((c) => c.type !== "unchanged");
|
|
2061
|
-
const icon = hasChanges ? "\u{1F527}" : "\u2713";
|
|
2062
|
-
const titleColor = hasChanges ? chalk10.yellow : chalk10.green;
|
|
2063
|
-
lines.push(
|
|
2064
|
-
titleColor(
|
|
2065
|
-
`${icon} ${plan.name.charAt(0).toUpperCase() + plan.name.slice(1)} - ${plan.description}`
|
|
2066
|
-
)
|
|
2067
|
-
);
|
|
2068
|
-
for (const change of plan.changes) {
|
|
2069
|
-
let symbol;
|
|
2070
|
-
let line;
|
|
2071
|
-
switch (change.type) {
|
|
2072
|
-
case "add":
|
|
2073
|
-
symbol = chalk10.green("+");
|
|
2074
|
-
line = chalk10.green(change.description);
|
|
2075
|
-
break;
|
|
2076
|
-
case "modify":
|
|
2077
|
-
symbol = chalk10.yellow("~");
|
|
2078
|
-
line = chalk10.yellow(change.description);
|
|
2079
|
-
if (change.key && change.oldValue !== void 0 && change.newValue !== void 0) {
|
|
2080
|
-
line += chalk10.dim(
|
|
2081
|
-
` (${String(change.oldValue)} \u2192 ${String(change.newValue)})`
|
|
2082
|
-
);
|
|
2083
|
-
}
|
|
2084
|
-
break;
|
|
2085
|
-
case "unchanged":
|
|
2086
|
-
default:
|
|
2087
|
-
symbol = chalk10.dim("=");
|
|
2088
|
-
line = chalk10.dim(change.description);
|
|
2089
|
-
}
|
|
2090
|
-
lines.push(` ${symbol} ${line}`);
|
|
2091
|
-
}
|
|
2092
|
-
if (plan.devDependencies.length > 0) {
|
|
2093
|
-
lines.push(
|
|
2094
|
-
chalk10.blue(` \u{1F4E6} Install: ${plan.devDependencies.join(", ")}`)
|
|
2095
|
-
);
|
|
1882
|
+
console.log(
|
|
1883
|
+
chalk9.dim(
|
|
1884
|
+
` 2. The preset is already referenced in workflow.config.json
|
|
1885
|
+
`
|
|
1886
|
+
)
|
|
1887
|
+
);
|
|
2096
1888
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
const pm = report.analysis.packageManager;
|
|
2102
|
-
const cmd = pm === "npm" ? "npm install" : pm === "yarn" ? "yarn add" : `${pm} add`;
|
|
2103
|
-
lines.push(
|
|
2104
|
-
chalk10.cyan(` ${cmd} -D ${report.allDevDependencies.join(" ")}`)
|
|
1889
|
+
console.log(
|
|
1890
|
+
chalk9.dim(
|
|
1891
|
+
"\u{1F4A1} Tip: You can now reuse this scope package across multiple projects!\n"
|
|
1892
|
+
)
|
|
2105
1893
|
);
|
|
2106
|
-
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
spinner10.stop("\u2717 Migration failed");
|
|
1896
|
+
console.error(chalk9.red("\nError:"), error);
|
|
1897
|
+
process.exit(1);
|
|
2107
1898
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// src/cli/commands/pre-commit.ts
|
|
1902
|
+
import chalk10 from "chalk";
|
|
1903
|
+
async function preCommitCommand(options) {
|
|
1904
|
+
const stagedOnly = options.stagedOnly ?? true;
|
|
1905
|
+
const dryRun = options.dryRun ?? false;
|
|
1906
|
+
const maxRetries = options.maxRetries ?? "5";
|
|
1907
|
+
console.log(chalk10.bold.cyan("\n\u{1F512} Pre-Commit Quality Check\n"));
|
|
1908
|
+
if (dryRun) {
|
|
1909
|
+
console.log(chalk10.yellow("\u{1F4CB} DRY-RUN MODE: No changes will be applied\n"));
|
|
1910
|
+
}
|
|
1911
|
+
if (stagedOnly) {
|
|
1912
|
+
console.log(chalk10.dim(" Checking staged files only...\n"));
|
|
1913
|
+
}
|
|
1914
|
+
await verifyCommand({
|
|
1915
|
+
fix: true,
|
|
1916
|
+
maxRetries,
|
|
1917
|
+
commit: false,
|
|
1918
|
+
// Never auto-commit in pre-commit
|
|
1919
|
+
dryRun,
|
|
1920
|
+
learn: false
|
|
1921
|
+
// Skip learning in pre-commit for speed
|
|
1922
|
+
});
|
|
2114
1923
|
}
|
|
2115
1924
|
|
|
2116
1925
|
// src/cli/commands/docs/index.ts
|
|
2117
|
-
import { Command } from "commander";
|
|
1926
|
+
import { Command as Command2 } from "commander";
|
|
2118
1927
|
import chalk15 from "chalk";
|
|
2119
1928
|
|
|
2120
1929
|
// src/cli/commands/docs-validate.ts
|
|
@@ -5145,7 +4954,7 @@ function checkCIThresholds(analysis, config) {
|
|
|
5145
4954
|
|
|
5146
4955
|
// src/cli/commands/docs/index.ts
|
|
5147
4956
|
function createDocsCommand() {
|
|
5148
|
-
const docsCmd = new
|
|
4957
|
+
const docsCmd = new Command2("docs").description("Manage documentation and guidelines").addHelpText(
|
|
5149
4958
|
"after",
|
|
5150
4959
|
`
|
|
5151
4960
|
${chalk15.bold("Examples:")}
|
|
@@ -5218,7 +5027,7 @@ ${chalk15.bold("Examples:")}
|
|
|
5218
5027
|
}
|
|
5219
5028
|
|
|
5220
5029
|
// src/cli/commands/hooks/index.ts
|
|
5221
|
-
import { Command as
|
|
5030
|
+
import { Command as Command3 } from "commander";
|
|
5222
5031
|
import chalk17 from "chalk";
|
|
5223
5032
|
|
|
5224
5033
|
// src/cli/commands/hooks.ts
|
|
@@ -5337,62 +5146,8 @@ async function statusHooksAction(cwd) {
|
|
|
5337
5146
|
}
|
|
5338
5147
|
}
|
|
5339
5148
|
|
|
5340
|
-
// src/cli/commands/hooks/index.ts
|
|
5341
|
-
async function installAction() {
|
|
5342
|
-
return hooksCommand("install");
|
|
5343
|
-
}
|
|
5344
|
-
async function uninstallAction() {
|
|
5345
|
-
return hooksCommand("uninstall");
|
|
5346
|
-
}
|
|
5347
|
-
async function statusAction() {
|
|
5348
|
-
return hooksCommand("status");
|
|
5349
|
-
}
|
|
5350
|
-
function createHooksCommand() {
|
|
5351
|
-
const hooksCmd = new Command2("hooks").description("Manage git hooks for the project").addHelpText(
|
|
5352
|
-
"after",
|
|
5353
|
-
`
|
|
5354
|
-
${chalk17.bold("Examples:")}
|
|
5355
|
-
$ workflow hooks install ${chalk17.dim("# Install git hooks")}
|
|
5356
|
-
$ workflow hooks uninstall ${chalk17.dim("# Remove git hooks")}
|
|
5357
|
-
$ workflow hooks status ${chalk17.dim("# Check hooks status")}
|
|
5358
|
-
`
|
|
5359
|
-
).action(() => {
|
|
5360
|
-
hooksCmd.help();
|
|
5361
|
-
});
|
|
5362
|
-
hooksCmd.command("install").description("Install git hooks for the project").addHelpText(
|
|
5363
|
-
"after",
|
|
5364
|
-
`
|
|
5365
|
-
${chalk17.bold("Details:")}
|
|
5366
|
-
Installs pre-commit and commit-msg hooks that:
|
|
5367
|
-
- Validate branch names
|
|
5368
|
-
- Validate commit message format
|
|
5369
|
-
- Run quality checks before commit
|
|
5370
|
-
|
|
5371
|
-
If existing hooks are found, they will be wrapped
|
|
5372
|
-
so both the original and workflow hooks run.
|
|
5373
|
-
`
|
|
5374
|
-
).action(installAction);
|
|
5375
|
-
hooksCmd.command("uninstall").description("Remove installed git hooks").addHelpText(
|
|
5376
|
-
"after",
|
|
5377
|
-
`
|
|
5378
|
-
${chalk17.bold("Details:")}
|
|
5379
|
-
Removes workflow agent hooks from the project.
|
|
5380
|
-
If original hooks were wrapped, they will be restored.
|
|
5381
|
-
`
|
|
5382
|
-
).action(uninstallAction);
|
|
5383
|
-
hooksCmd.command("status").description("Show current hooks installation status").addHelpText(
|
|
5384
|
-
"after",
|
|
5385
|
-
`
|
|
5386
|
-
${chalk17.bold("Details:")}
|
|
5387
|
-
Shows which git hooks are installed and whether
|
|
5388
|
-
they are managed by workflow agent.
|
|
5389
|
-
`
|
|
5390
|
-
).action(statusAction);
|
|
5391
|
-
return hooksCmd;
|
|
5392
|
-
}
|
|
5393
|
-
|
|
5394
5149
|
// src/cli/commands/solution/index.ts
|
|
5395
|
-
import { Command as
|
|
5150
|
+
import { Command as Command4 } from "commander";
|
|
5396
5151
|
import chalk19 from "chalk";
|
|
5397
5152
|
|
|
5398
5153
|
// src/cli/commands/solution.ts
|
|
@@ -5400,7 +5155,7 @@ import chalk18 from "chalk";
|
|
|
5400
5155
|
import * as p11 from "@clack/prompts";
|
|
5401
5156
|
import * as path2 from "path";
|
|
5402
5157
|
import {
|
|
5403
|
-
PatternStore
|
|
5158
|
+
PatternStore,
|
|
5404
5159
|
CodeAnalyzer
|
|
5405
5160
|
} from "@hawkinside_out/workflow-improvement-tracker";
|
|
5406
5161
|
function getWorkspacePath() {
|
|
@@ -5438,7 +5193,8 @@ function truncate(str, maxLen) {
|
|
|
5438
5193
|
}
|
|
5439
5194
|
async function solutionCaptureCommand(options) {
|
|
5440
5195
|
const cwd = getWorkspacePath();
|
|
5441
|
-
const store = new
|
|
5196
|
+
const store = new PatternStore(cwd);
|
|
5197
|
+
await store.initialize();
|
|
5442
5198
|
console.log(chalk18.cyan("\n\u{1F4E6} Capture Solution Pattern\n"));
|
|
5443
5199
|
let targetPath = options.path;
|
|
5444
5200
|
if (!targetPath) {
|
|
@@ -5586,7 +5342,8 @@ async function solutionCaptureCommand(options) {
|
|
|
5586
5342
|
}
|
|
5587
5343
|
async function solutionSearchCommand(query, options) {
|
|
5588
5344
|
const cwd = getWorkspacePath();
|
|
5589
|
-
const store = new
|
|
5345
|
+
const store = new PatternStore(cwd);
|
|
5346
|
+
await store.initialize();
|
|
5590
5347
|
console.log(chalk18.cyan("\n\u{1F50D} Search Solution Patterns\n"));
|
|
5591
5348
|
const keywords = query.split(/\s+/).filter((k) => k.length > 0);
|
|
5592
5349
|
const result = await store.searchSolutions(keywords, {
|
|
@@ -5626,7 +5383,8 @@ async function solutionSearchCommand(query, options) {
|
|
|
5626
5383
|
}
|
|
5627
5384
|
async function solutionListCommand(options) {
|
|
5628
5385
|
const cwd = getWorkspacePath();
|
|
5629
|
-
const store = new
|
|
5386
|
+
const store = new PatternStore(cwd);
|
|
5387
|
+
await store.initialize();
|
|
5630
5388
|
console.log(chalk18.cyan("\n\u{1F4CB} Solution Patterns\n"));
|
|
5631
5389
|
const result = await store.listSolutions({
|
|
5632
5390
|
category: options.category,
|
|
@@ -5681,7 +5439,8 @@ ${formatCategory(category)}`));
|
|
|
5681
5439
|
}
|
|
5682
5440
|
async function solutionApplyCommand(solutionId, options) {
|
|
5683
5441
|
const cwd = getWorkspacePath();
|
|
5684
|
-
const store = new
|
|
5442
|
+
const store = new PatternStore(cwd);
|
|
5443
|
+
await store.initialize();
|
|
5685
5444
|
console.log(chalk18.cyan("\n\u{1F680} Apply Solution Pattern\n"));
|
|
5686
5445
|
const result = await store.getSolution(solutionId);
|
|
5687
5446
|
if (!result.success || !result.data) {
|
|
@@ -5779,7 +5538,8 @@ async function solutionApplyCommand(solutionId, options) {
|
|
|
5779
5538
|
}
|
|
5780
5539
|
async function solutionDeprecateCommand(solutionId, reason) {
|
|
5781
5540
|
const cwd = getWorkspacePath();
|
|
5782
|
-
const store = new
|
|
5541
|
+
const store = new PatternStore(cwd);
|
|
5542
|
+
await store.initialize();
|
|
5783
5543
|
console.log(chalk18.cyan("\n\u26A0\uFE0F Deprecate Solution Pattern\n"));
|
|
5784
5544
|
const result = await store.getSolution(solutionId);
|
|
5785
5545
|
if (!result.success || !result.data) {
|
|
@@ -5807,7 +5567,8 @@ async function solutionDeprecateCommand(solutionId, reason) {
|
|
|
5807
5567
|
}
|
|
5808
5568
|
async function solutionStatsCommand() {
|
|
5809
5569
|
const cwd = getWorkspacePath();
|
|
5810
|
-
const store = new
|
|
5570
|
+
const store = new PatternStore(cwd);
|
|
5571
|
+
await store.initialize();
|
|
5811
5572
|
console.log(chalk18.cyan("\n\u{1F4CA} Solution Pattern Statistics\n"));
|
|
5812
5573
|
const stats = await store.getStats();
|
|
5813
5574
|
console.log(chalk18.dim("\u2500".repeat(40)));
|
|
@@ -5834,20 +5595,363 @@ ${chalk18.bold("By Category:")}`);
|
|
|
5834
5595
|
}
|
|
5835
5596
|
console.log();
|
|
5836
5597
|
}
|
|
5598
|
+
async function solutionCreateCommand(options) {
|
|
5599
|
+
const cwd = getWorkspacePath();
|
|
5600
|
+
const store = new PatternStore(cwd);
|
|
5601
|
+
await store.initialize();
|
|
5602
|
+
console.log(chalk18.cyan("\n\u2728 Create Solution Pattern\n"));
|
|
5603
|
+
let name = options.name;
|
|
5604
|
+
if (!name) {
|
|
5605
|
+
const nameInput = await p11.text({
|
|
5606
|
+
message: "Solution name:",
|
|
5607
|
+
placeholder: "My Custom Solution",
|
|
5608
|
+
validate: (val) => {
|
|
5609
|
+
if (!val || val.length < 3) return "Name must be at least 3 characters";
|
|
5610
|
+
return void 0;
|
|
5611
|
+
}
|
|
5612
|
+
});
|
|
5613
|
+
if (p11.isCancel(nameInput)) {
|
|
5614
|
+
p11.cancel("Operation cancelled");
|
|
5615
|
+
process.exit(0);
|
|
5616
|
+
}
|
|
5617
|
+
name = nameInput;
|
|
5618
|
+
}
|
|
5619
|
+
let description = options.description;
|
|
5620
|
+
if (!description) {
|
|
5621
|
+
const descInput = await p11.text({
|
|
5622
|
+
message: "Solution description:",
|
|
5623
|
+
placeholder: "A description of what this solution does",
|
|
5624
|
+
validate: (val) => {
|
|
5625
|
+
if (!val || val.length < 10)
|
|
5626
|
+
return "Description must be at least 10 characters";
|
|
5627
|
+
return void 0;
|
|
5628
|
+
}
|
|
5629
|
+
});
|
|
5630
|
+
if (p11.isCancel(descInput)) {
|
|
5631
|
+
p11.cancel("Operation cancelled");
|
|
5632
|
+
process.exit(0);
|
|
5633
|
+
}
|
|
5634
|
+
description = descInput;
|
|
5635
|
+
}
|
|
5636
|
+
let category = options.category;
|
|
5637
|
+
if (!category) {
|
|
5638
|
+
const categoryChoice = await p11.select({
|
|
5639
|
+
message: "Solution category:",
|
|
5640
|
+
options: [
|
|
5641
|
+
{ value: "auth", label: "\u{1F510} Authentication" },
|
|
5642
|
+
{ value: "api", label: "\u{1F310} API" },
|
|
5643
|
+
{ value: "database", label: "\u{1F4BE} Database" },
|
|
5644
|
+
{ value: "ui", label: "\u{1F3A8} UI/Components" },
|
|
5645
|
+
{ value: "testing", label: "\u{1F9EA} Testing" },
|
|
5646
|
+
{ value: "deployment", label: "\u{1F680} Deployment" },
|
|
5647
|
+
{ value: "integrations", label: "\u{1F517} Integrations" },
|
|
5648
|
+
{ value: "performance", label: "\u26A1 Performance" },
|
|
5649
|
+
{ value: "security", label: "\u{1F6E1}\uFE0F Security" },
|
|
5650
|
+
{ value: "other", label: "\u{1F4E6} Other" }
|
|
5651
|
+
]
|
|
5652
|
+
});
|
|
5653
|
+
if (p11.isCancel(categoryChoice)) {
|
|
5654
|
+
p11.cancel("Operation cancelled");
|
|
5655
|
+
process.exit(0);
|
|
5656
|
+
}
|
|
5657
|
+
category = categoryChoice;
|
|
5658
|
+
}
|
|
5659
|
+
let keywords = [];
|
|
5660
|
+
if (options.keywords) {
|
|
5661
|
+
keywords = options.keywords.split(",").map((k) => k.trim());
|
|
5662
|
+
} else {
|
|
5663
|
+
const keywordsInput = await p11.text({
|
|
5664
|
+
message: "Keywords (comma-separated):",
|
|
5665
|
+
placeholder: "auth, jwt, login"
|
|
5666
|
+
});
|
|
5667
|
+
if (p11.isCancel(keywordsInput)) {
|
|
5668
|
+
p11.cancel("Operation cancelled");
|
|
5669
|
+
process.exit(0);
|
|
5670
|
+
}
|
|
5671
|
+
if (keywordsInput) {
|
|
5672
|
+
keywords = keywordsInput.split(",").map((k) => k.trim());
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
5675
|
+
const framework = options.framework || "generic";
|
|
5676
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5677
|
+
const solution = {
|
|
5678
|
+
id: crypto.randomUUID(),
|
|
5679
|
+
name,
|
|
5680
|
+
description,
|
|
5681
|
+
category,
|
|
5682
|
+
keywords,
|
|
5683
|
+
implementation: {
|
|
5684
|
+
files: [],
|
|
5685
|
+
dependencies: [],
|
|
5686
|
+
devDependencies: [],
|
|
5687
|
+
envVars: []
|
|
5688
|
+
},
|
|
5689
|
+
compatibility: {
|
|
5690
|
+
framework,
|
|
5691
|
+
frameworkVersion: ">=1.0.0",
|
|
5692
|
+
runtime: "node",
|
|
5693
|
+
runtimeVersion: ">=18.0.0",
|
|
5694
|
+
dependencies: []
|
|
5695
|
+
},
|
|
5696
|
+
metrics: {
|
|
5697
|
+
applications: 0,
|
|
5698
|
+
successes: 0,
|
|
5699
|
+
failures: 0,
|
|
5700
|
+
successRate: 0
|
|
5701
|
+
},
|
|
5702
|
+
isPrivate: true,
|
|
5703
|
+
createdAt: now,
|
|
5704
|
+
updatedAt: now
|
|
5705
|
+
};
|
|
5706
|
+
await store.saveSolution(solution);
|
|
5707
|
+
console.log(chalk18.green("\n\u2713 Solution pattern created!\n"));
|
|
5708
|
+
console.log(chalk18.dim(` ID: ${solution.id}`));
|
|
5709
|
+
console.log(chalk18.dim(` Name: ${name}`));
|
|
5710
|
+
console.log(chalk18.dim(` Category: ${category}`));
|
|
5711
|
+
console.log(chalk18.dim(`
|
|
5712
|
+
Add files using 'workflow solution capture --path <dir>'`));
|
|
5713
|
+
}
|
|
5714
|
+
async function solutionShowCommand(solutionId) {
|
|
5715
|
+
const cwd = getWorkspacePath();
|
|
5716
|
+
const store = new PatternStore(cwd);
|
|
5717
|
+
await store.initialize();
|
|
5718
|
+
console.log(chalk18.cyan("\n\u{1F4CB} Solution Details\n"));
|
|
5719
|
+
const result = await store.getSolution(solutionId);
|
|
5720
|
+
if (!result.success || !result.data) {
|
|
5721
|
+
console.error(chalk18.red(`
|
|
5722
|
+
\u2717 Solution not found: ${solutionId}
|
|
5723
|
+
`));
|
|
5724
|
+
process.exit(1);
|
|
5725
|
+
}
|
|
5726
|
+
const solution = result.data;
|
|
5727
|
+
console.log(chalk18.dim("\u2500".repeat(60)));
|
|
5728
|
+
console.log(chalk18.bold(`Name: ${solution.name}`));
|
|
5729
|
+
console.log(`ID: ${chalk18.dim(solution.id)}`);
|
|
5730
|
+
console.log(`Category: ${formatCategory(solution.category)}`);
|
|
5731
|
+
console.log(`Description: ${solution.description}`);
|
|
5732
|
+
console.log(chalk18.dim("\u2500".repeat(60)));
|
|
5733
|
+
console.log(chalk18.bold("\nCompatibility:"));
|
|
5734
|
+
console.log(` Framework: ${solution.compatibility.framework || "generic"}`);
|
|
5735
|
+
console.log(` Version: ${solution.compatibility.frameworkVersion}`);
|
|
5736
|
+
console.log(` Runtime: ${solution.compatibility.runtime} ${solution.compatibility.runtimeVersion}`);
|
|
5737
|
+
console.log(chalk18.bold("\nImplementation:"));
|
|
5738
|
+
console.log(` Files: ${solution.implementation.files.length}`);
|
|
5739
|
+
for (const file of solution.implementation.files) {
|
|
5740
|
+
console.log(chalk18.dim(` \u2022 ${file.path} (${file.role})`));
|
|
5741
|
+
}
|
|
5742
|
+
if (solution.implementation.dependencies.length > 0) {
|
|
5743
|
+
console.log(` Dependencies: ${solution.implementation.dependencies.length}`);
|
|
5744
|
+
for (const dep of solution.implementation.dependencies) {
|
|
5745
|
+
console.log(chalk18.dim(` \u2022 ${dep.name}@${dep.version}`));
|
|
5746
|
+
}
|
|
5747
|
+
}
|
|
5748
|
+
if (solution.implementation.envVars.length > 0) {
|
|
5749
|
+
console.log(` Environment Variables: ${solution.implementation.envVars.length}`);
|
|
5750
|
+
for (const env of solution.implementation.envVars) {
|
|
5751
|
+
const required = env.required ? chalk18.red("*") : "";
|
|
5752
|
+
console.log(chalk18.dim(` \u2022 ${env.name}${required}`));
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
console.log(chalk18.bold("\nMetrics:"));
|
|
5756
|
+
console.log(` Applications: ${solution.metrics.applications}`);
|
|
5757
|
+
console.log(` Success Rate: ${(solution.metrics.successRate * 100).toFixed(1)}%`);
|
|
5758
|
+
console.log(chalk18.bold("\nMetadata:"));
|
|
5759
|
+
console.log(` Created: ${formatDate(solution.createdAt)}`);
|
|
5760
|
+
console.log(` Updated: ${formatDate(solution.updatedAt)}`);
|
|
5761
|
+
console.log(` Private: ${solution.isPrivate ? "Yes" : "No"}`);
|
|
5762
|
+
if (solution.deprecatedAt) {
|
|
5763
|
+
console.log(chalk18.red(` Deprecated: ${formatDate(solution.deprecatedAt)}`));
|
|
5764
|
+
console.log(chalk18.dim(` Reason: ${solution.deprecationReason || "No reason provided"}`));
|
|
5765
|
+
}
|
|
5766
|
+
console.log();
|
|
5767
|
+
}
|
|
5768
|
+
async function solutionExportCommand(options) {
|
|
5769
|
+
const cwd = getWorkspacePath();
|
|
5770
|
+
const store = new PatternStore(cwd);
|
|
5771
|
+
await store.initialize();
|
|
5772
|
+
const format = options.format ?? "json";
|
|
5773
|
+
const outputPath = options.output ?? `solutions-export.${format}`;
|
|
5774
|
+
console.log(chalk18.cyan("\n\u{1F4E4} Exporting Solution Patterns\n"));
|
|
5775
|
+
const result = await store.listSolutions({
|
|
5776
|
+
solutionCategory: options.category,
|
|
5777
|
+
limit: 1e3
|
|
5778
|
+
});
|
|
5779
|
+
if (!result.success || !result.data) {
|
|
5780
|
+
console.error(chalk18.red(`
|
|
5781
|
+
\u2717 Export failed: ${result.error}
|
|
5782
|
+
`));
|
|
5783
|
+
process.exit(1);
|
|
5784
|
+
}
|
|
5785
|
+
const solutions = result.data;
|
|
5786
|
+
if (solutions.length === 0) {
|
|
5787
|
+
console.log(chalk18.yellow(" No solutions to export"));
|
|
5788
|
+
return;
|
|
5789
|
+
}
|
|
5790
|
+
const fs3 = await import("fs");
|
|
5791
|
+
const pathModule = await import("path");
|
|
5792
|
+
let output;
|
|
5793
|
+
if (format === "yaml") {
|
|
5794
|
+
output = `# Workflow Agent Solutions Export
|
|
5795
|
+
# Exported: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
5796
|
+
|
|
5797
|
+
solutions:
|
|
5798
|
+
`;
|
|
5799
|
+
for (const solution of solutions) {
|
|
5800
|
+
output += ` - id: ${solution.id}
|
|
5801
|
+
`;
|
|
5802
|
+
output += ` name: "${solution.name}"
|
|
5803
|
+
`;
|
|
5804
|
+
output += ` category: ${solution.category}
|
|
5805
|
+
`;
|
|
5806
|
+
output += ` description: "${solution.description}"
|
|
5807
|
+
|
|
5808
|
+
`;
|
|
5809
|
+
}
|
|
5810
|
+
} else {
|
|
5811
|
+
output = JSON.stringify(
|
|
5812
|
+
{
|
|
5813
|
+
version: "1.0",
|
|
5814
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5815
|
+
solutions
|
|
5816
|
+
},
|
|
5817
|
+
null,
|
|
5818
|
+
2
|
|
5819
|
+
);
|
|
5820
|
+
}
|
|
5821
|
+
const fullOutputPath = pathModule.default.isAbsolute(outputPath) ? outputPath : pathModule.default.join(cwd, outputPath);
|
|
5822
|
+
await fs3.promises.writeFile(fullOutputPath, output, "utf-8");
|
|
5823
|
+
console.log(chalk18.green(` \u2713 Exported ${solutions.length} solutions
|
|
5824
|
+
`));
|
|
5825
|
+
console.log(chalk18.dim(` Output: ${fullOutputPath}`));
|
|
5826
|
+
console.log(chalk18.dim(` Format: ${format.toUpperCase()}`));
|
|
5827
|
+
}
|
|
5828
|
+
async function solutionImportCommand(file, options) {
|
|
5829
|
+
const cwd = getWorkspacePath();
|
|
5830
|
+
const store = new PatternStore(cwd);
|
|
5831
|
+
await store.initialize();
|
|
5832
|
+
const dryRun = options.dryRun ?? false;
|
|
5833
|
+
const merge = options.merge ?? true;
|
|
5834
|
+
console.log(chalk18.cyan("\n\u{1F4E5} Importing Solution Patterns\n"));
|
|
5835
|
+
const fs3 = await import("fs");
|
|
5836
|
+
const pathModule = await import("path");
|
|
5837
|
+
const filePath = pathModule.default.isAbsolute(file) ? file : pathModule.default.join(cwd, file);
|
|
5838
|
+
if (!fs3.existsSync(filePath)) {
|
|
5839
|
+
console.log(chalk18.red(` \u2717 File not found: ${filePath}`));
|
|
5840
|
+
process.exit(1);
|
|
5841
|
+
}
|
|
5842
|
+
const content = await fs3.promises.readFile(filePath, "utf-8");
|
|
5843
|
+
let importData;
|
|
5844
|
+
try {
|
|
5845
|
+
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
5846
|
+
console.log(chalk18.yellow(" YAML import not fully supported, treating as JSON"));
|
|
5847
|
+
}
|
|
5848
|
+
importData = JSON.parse(content);
|
|
5849
|
+
} catch {
|
|
5850
|
+
console.log(chalk18.red(" \u2717 Failed to parse import file"));
|
|
5851
|
+
process.exit(1);
|
|
5852
|
+
}
|
|
5853
|
+
const solutions = importData.solutions || [];
|
|
5854
|
+
if (solutions.length === 0) {
|
|
5855
|
+
console.log(chalk18.yellow(" No solutions found in import file"));
|
|
5856
|
+
return;
|
|
5857
|
+
}
|
|
5858
|
+
console.log(chalk18.dim(` Found ${solutions.length} solutions
|
|
5859
|
+
`));
|
|
5860
|
+
if (dryRun) {
|
|
5861
|
+
console.log(chalk18.yellow(" \u{1F50D} Dry run - no changes will be made\n"));
|
|
5862
|
+
for (const solution of solutions) {
|
|
5863
|
+
console.log(chalk18.dim(` Would import: ${solution.name} (${solution.id})`));
|
|
5864
|
+
}
|
|
5865
|
+
return;
|
|
5866
|
+
}
|
|
5867
|
+
let imported = 0;
|
|
5868
|
+
let skipped = 0;
|
|
5869
|
+
for (const solution of solutions) {
|
|
5870
|
+
const existing = await store.getSolution(solution.id);
|
|
5871
|
+
if (existing.success && existing.data && !merge) {
|
|
5872
|
+
console.log(chalk18.yellow(` Skipped (exists): ${solution.name}`));
|
|
5873
|
+
skipped++;
|
|
5874
|
+
continue;
|
|
5875
|
+
}
|
|
5876
|
+
await store.saveSolution(solution);
|
|
5877
|
+
console.log(chalk18.green(` \u2713 Imported: ${solution.name}`));
|
|
5878
|
+
imported++;
|
|
5879
|
+
}
|
|
5880
|
+
console.log(chalk18.green(`
|
|
5881
|
+
\u2713 Import complete`));
|
|
5882
|
+
console.log(chalk18.dim(` Imported: ${imported}`));
|
|
5883
|
+
console.log(chalk18.dim(` Skipped: ${skipped}`));
|
|
5884
|
+
}
|
|
5885
|
+
async function solutionAnalyzeCommand() {
|
|
5886
|
+
const cwd = getWorkspacePath();
|
|
5887
|
+
const store = new PatternStore(cwd);
|
|
5888
|
+
await store.initialize();
|
|
5889
|
+
const fs3 = await import("fs");
|
|
5890
|
+
const pathModule = await import("path");
|
|
5891
|
+
console.log(chalk18.cyan("\n\u{1F50D} Analyzing Codebase for Solution Patterns\n"));
|
|
5892
|
+
const existingResult = await store.listSolutions({ limit: 1e3 });
|
|
5893
|
+
const existingNames = (existingResult.data || []).map((s) => s.name.toLowerCase());
|
|
5894
|
+
const opportunities = [];
|
|
5895
|
+
const patterns = [
|
|
5896
|
+
{ path: "src/auth", name: "Authentication Module", category: "auth", desc: "Authentication implementation" },
|
|
5897
|
+
{ path: "src/lib/auth", name: "Auth Library", category: "auth", desc: "Authentication utilities" },
|
|
5898
|
+
{ path: "src/api", name: "API Layer", category: "api", desc: "API routing structure" },
|
|
5899
|
+
{ path: "app/api", name: "Next.js API Routes", category: "api", desc: "Next.js API implementation" },
|
|
5900
|
+
{ path: "src/db", name: "Database Layer", category: "database", desc: "Database connection and queries" },
|
|
5901
|
+
{ path: "src/lib/db", name: "Database Utilities", category: "database", desc: "Database helper functions" },
|
|
5902
|
+
{ path: "src/components/ui", name: "UI Components", category: "ui", desc: "Reusable UI components" },
|
|
5903
|
+
{ path: "src/hooks", name: "Custom Hooks", category: "ui", desc: "React custom hooks" },
|
|
5904
|
+
{ path: "__tests__", name: "Testing Setup", category: "testing", desc: "Test configuration and utilities" },
|
|
5905
|
+
{ path: ".github/workflows", name: "CI/CD Pipeline", category: "deployment", desc: "GitHub Actions workflows" },
|
|
5906
|
+
{ path: "src/integrations", name: "Integrations", category: "integrations", desc: "Third-party integrations" },
|
|
5907
|
+
{ path: "src/middleware", name: "Middleware", category: "security", desc: "Request middleware and guards" }
|
|
5908
|
+
];
|
|
5909
|
+
for (const pattern of patterns) {
|
|
5910
|
+
const fullPath = pathModule.default.join(cwd, pattern.path);
|
|
5911
|
+
if (fs3.existsSync(fullPath) && !existingNames.includes(pattern.name.toLowerCase())) {
|
|
5912
|
+
opportunities.push({
|
|
5913
|
+
name: pattern.name,
|
|
5914
|
+
category: pattern.category,
|
|
5915
|
+
description: pattern.desc,
|
|
5916
|
+
path: pattern.path
|
|
5917
|
+
});
|
|
5918
|
+
}
|
|
5919
|
+
}
|
|
5920
|
+
if (opportunities.length === 0) {
|
|
5921
|
+
console.log(chalk18.green(" \u2713 No new solution opportunities found"));
|
|
5922
|
+
console.log(chalk18.dim("\n Your solutions seem well-captured!"));
|
|
5923
|
+
return;
|
|
5924
|
+
}
|
|
5925
|
+
console.log(chalk18.bold(` Found ${opportunities.length} potential solutions:
|
|
5926
|
+
`));
|
|
5927
|
+
for (const opp of opportunities) {
|
|
5928
|
+
console.log(` ${formatCategory(opp.category)}`);
|
|
5929
|
+
console.log(chalk18.bold(` ${opp.name}`));
|
|
5930
|
+
console.log(chalk18.dim(` ${opp.description}`));
|
|
5931
|
+
console.log(chalk18.dim(` Path: ${opp.path}
|
|
5932
|
+
`));
|
|
5933
|
+
}
|
|
5934
|
+
console.log(chalk18.dim(" To capture a solution:"));
|
|
5935
|
+
console.log(chalk18.cyan(" workflow solution capture --path <path> --name <name>"));
|
|
5936
|
+
}
|
|
5837
5937
|
|
|
5838
5938
|
// src/cli/commands/solution/index.ts
|
|
5839
5939
|
function createSolutionCommand() {
|
|
5840
|
-
const solutionCmd = new
|
|
5940
|
+
const solutionCmd = new Command4("solution").description("Manage solution patterns for code reuse").addHelpText(
|
|
5841
5941
|
"after",
|
|
5842
5942
|
`
|
|
5843
5943
|
${chalk19.bold("Examples:")}
|
|
5844
|
-
$ workflow solution capture
|
|
5845
|
-
$ workflow solution
|
|
5944
|
+
$ workflow solution capture --path ./src/auth ${chalk19.dim("# Capture from path")}
|
|
5945
|
+
$ workflow solution create --name "My Auth" ${chalk19.dim("# Create manually")}
|
|
5946
|
+
$ workflow solution show abc123 ${chalk19.dim("# Show solution details")}
|
|
5846
5947
|
$ workflow solution search "jwt auth" ${chalk19.dim("# Search solutions")}
|
|
5847
5948
|
$ workflow solution list ${chalk19.dim("# List all solutions")}
|
|
5848
5949
|
$ workflow solution list --category auth ${chalk19.dim("# List by category")}
|
|
5849
5950
|
$ workflow solution apply abc123 ${chalk19.dim("# Apply a solution")}
|
|
5850
5951
|
$ workflow solution apply abc123 --dry-run ${chalk19.dim("# Preview application")}
|
|
5952
|
+
$ workflow solution export --format json ${chalk19.dim("# Export solutions")}
|
|
5953
|
+
$ workflow solution import solutions.json ${chalk19.dim("# Import solutions")}
|
|
5954
|
+
$ workflow solution analyze ${chalk19.dim("# Find opportunities")}
|
|
5851
5955
|
$ workflow solution stats ${chalk19.dim("# Show statistics")}
|
|
5852
5956
|
`
|
|
5853
5957
|
).action(() => {
|
|
@@ -5867,7 +5971,22 @@ ${chalk19.bold("Examples:")}
|
|
|
5867
5971
|
$ workflow solution capture --anonymize ${chalk19.dim("# Anonymize secrets")}
|
|
5868
5972
|
$ workflow solution capture --private ${chalk19.dim("# Keep private")}
|
|
5869
5973
|
`
|
|
5870
|
-
).action(solutionCaptureCommand);
|
|
5974
|
+
).action(solutionCaptureCommand);
|
|
5975
|
+
solutionCmd.command("create").description("Create a new solution pattern manually").option("--name <name>", "Solution name").option("--description <desc>", "Solution description").option("--category <cat>", "Category").option("--keywords <kw>", "Comma-separated keywords").option("--framework <fw>", "Target framework").addHelpText(
|
|
5976
|
+
"after",
|
|
5977
|
+
`
|
|
5978
|
+
${chalk19.bold("Examples:")}
|
|
5979
|
+
$ workflow solution create ${chalk19.dim("# Interactive mode")}
|
|
5980
|
+
$ workflow solution create --name "Custom Auth" ${chalk19.dim("# With name")}
|
|
5981
|
+
`
|
|
5982
|
+
).action(solutionCreateCommand);
|
|
5983
|
+
solutionCmd.command("show <solutionId>").description("Display details of a specific solution pattern").addHelpText(
|
|
5984
|
+
"after",
|
|
5985
|
+
`
|
|
5986
|
+
${chalk19.bold("Examples:")}
|
|
5987
|
+
$ workflow solution show abc123 ${chalk19.dim("# Show by ID")}
|
|
5988
|
+
`
|
|
5989
|
+
).action(solutionShowCommand);
|
|
5871
5990
|
solutionCmd.command("search <query>").description("Search for solution patterns").option("--category <cat>", "Filter by category").option("--framework <fw>", "Filter by framework").option("--limit <n>", "Maximum results", "10").addHelpText(
|
|
5872
5991
|
"after",
|
|
5873
5992
|
`
|
|
@@ -5898,6 +6017,36 @@ ${chalk19.bold("Examples:")}
|
|
|
5898
6017
|
$ workflow solution apply abc123 --include-tests ${chalk19.dim("# Include test files")}
|
|
5899
6018
|
`
|
|
5900
6019
|
).action(solutionApplyCommand);
|
|
6020
|
+
solutionCmd.command("export").description("Export solution patterns to a file").option("-o, --output <path>", "Output file path", "solutions-export.json").option("-f, --format <format>", "Output format (json, yaml)", "json").option("--category <cat>", "Filter by category").addHelpText(
|
|
6021
|
+
"after",
|
|
6022
|
+
`
|
|
6023
|
+
${chalk19.bold("Examples:")}
|
|
6024
|
+
$ workflow solution export ${chalk19.dim("# Export all as JSON")}
|
|
6025
|
+
$ workflow solution export --format yaml ${chalk19.dim("# Export as YAML")}
|
|
6026
|
+
$ workflow solution export --category auth ${chalk19.dim("# Export auth only")}
|
|
6027
|
+
$ workflow solution export -o backup.json ${chalk19.dim("# Custom output path")}
|
|
6028
|
+
`
|
|
6029
|
+
).action(solutionExportCommand);
|
|
6030
|
+
solutionCmd.command("import <file>").description("Import solution patterns from a file").option("-f, --format <format>", "Input format (json, yaml)", "json").option("--dry-run", "Preview import without making changes").option("--no-merge", "Skip existing solutions instead of merging").addHelpText(
|
|
6031
|
+
"after",
|
|
6032
|
+
`
|
|
6033
|
+
${chalk19.bold("Examples:")}
|
|
6034
|
+
$ workflow solution import solutions.json ${chalk19.dim("# Import from JSON")}
|
|
6035
|
+
$ workflow solution import backup.json --dry-run ${chalk19.dim("# Preview import")}
|
|
6036
|
+
`
|
|
6037
|
+
).action(solutionImportCommand);
|
|
6038
|
+
solutionCmd.command("analyze").description("Analyze codebase for potential solution patterns").addHelpText(
|
|
6039
|
+
"after",
|
|
6040
|
+
`
|
|
6041
|
+
${chalk19.bold("Details:")}
|
|
6042
|
+
Scans your codebase for common patterns that could be
|
|
6043
|
+
captured as reusable solutions, such as:
|
|
6044
|
+
- Authentication modules
|
|
6045
|
+
- API layers
|
|
6046
|
+
- Database utilities
|
|
6047
|
+
- UI component libraries
|
|
6048
|
+
`
|
|
6049
|
+
).action(solutionAnalyzeCommand);
|
|
5901
6050
|
solutionCmd.command("deprecate <solutionId> <reason>").description("Deprecate a solution pattern").addHelpText(
|
|
5902
6051
|
"after",
|
|
5903
6052
|
`
|
|
@@ -5917,7 +6066,7 @@ ${chalk19.bold("Examples:")}
|
|
|
5917
6066
|
}
|
|
5918
6067
|
|
|
5919
6068
|
// src/cli/commands/learn/index.ts
|
|
5920
|
-
import { Command as
|
|
6069
|
+
import { Command as Command5 } from "commander";
|
|
5921
6070
|
import chalk21 from "chalk";
|
|
5922
6071
|
|
|
5923
6072
|
// src/cli/commands/learn.ts
|
|
@@ -5926,10 +6075,10 @@ import * as p12 from "@clack/prompts";
|
|
|
5926
6075
|
import * as fs2 from "fs";
|
|
5927
6076
|
import * as path3 from "path";
|
|
5928
6077
|
import {
|
|
5929
|
-
PatternStore as
|
|
5930
|
-
ContributorManager
|
|
6078
|
+
PatternStore as PatternStore2,
|
|
6079
|
+
ContributorManager,
|
|
5931
6080
|
PatternAnonymizer,
|
|
5932
|
-
TelemetryCollector
|
|
6081
|
+
TelemetryCollector,
|
|
5933
6082
|
FixPatternSchema,
|
|
5934
6083
|
BlueprintSchema,
|
|
5935
6084
|
SolutionPatternSchema
|
|
@@ -5949,7 +6098,8 @@ function formatTags(tags) {
|
|
|
5949
6098
|
}
|
|
5950
6099
|
async function learnRecordCommand(options) {
|
|
5951
6100
|
const cwd = getWorkspacePath2();
|
|
5952
|
-
const store = new
|
|
6101
|
+
const store = new PatternStore2(cwd);
|
|
6102
|
+
await store.initialize();
|
|
5953
6103
|
console.log(chalk20.cyan("\n\u{1F4DA} Record a Learning Pattern\n"));
|
|
5954
6104
|
let patternType = options.type;
|
|
5955
6105
|
if (!patternType) {
|
|
@@ -6182,7 +6332,8 @@ async function learnRecordCommand(options) {
|
|
|
6182
6332
|
}
|
|
6183
6333
|
async function learnListCommand(options) {
|
|
6184
6334
|
const cwd = getWorkspacePath2();
|
|
6185
|
-
const store = new
|
|
6335
|
+
const store = new PatternStore2(cwd);
|
|
6336
|
+
await store.initialize();
|
|
6186
6337
|
const patternType = options.type ?? "all";
|
|
6187
6338
|
const showDeprecated = options.deprecated ?? false;
|
|
6188
6339
|
console.log(chalk20.cyan("\n\u{1F4DA} Recorded Learning Patterns\n"));
|
|
@@ -6314,8 +6465,9 @@ async function learnListCommand(options) {
|
|
|
6314
6465
|
}
|
|
6315
6466
|
async function learnApplyCommand(patternId, options) {
|
|
6316
6467
|
const cwd = getWorkspacePath2();
|
|
6317
|
-
const store = new
|
|
6318
|
-
|
|
6468
|
+
const store = new PatternStore2(cwd);
|
|
6469
|
+
await store.initialize();
|
|
6470
|
+
const telemetry = new TelemetryCollector(cwd);
|
|
6319
6471
|
console.log(chalk20.cyan("\n\u{1F527} Apply Learning Pattern\n"));
|
|
6320
6472
|
let pattern = await store.getFixPattern(patternId);
|
|
6321
6473
|
let patternType = "fix";
|
|
@@ -6402,7 +6554,7 @@ async function learnApplyCommand(patternId, options) {
|
|
|
6402
6554
|
}
|
|
6403
6555
|
async function learnConfigCommand(options) {
|
|
6404
6556
|
const cwd = getWorkspacePath2();
|
|
6405
|
-
const contributorManager = new
|
|
6557
|
+
const contributorManager = new ContributorManager(cwd);
|
|
6406
6558
|
console.log(chalk20.cyan("\n\u2699\uFE0F Learning Configuration\n"));
|
|
6407
6559
|
if (options.enableSync) {
|
|
6408
6560
|
const result = await contributorManager.enableSync();
|
|
@@ -6496,7 +6648,8 @@ async function learnConfigCommand(options) {
|
|
|
6496
6648
|
}
|
|
6497
6649
|
async function learnPublishCommand(patternId, options) {
|
|
6498
6650
|
const cwd = getWorkspacePath2();
|
|
6499
|
-
const store = new
|
|
6651
|
+
const store = new PatternStore2(cwd);
|
|
6652
|
+
await store.initialize();
|
|
6500
6653
|
const makePrivate = options.private ?? false;
|
|
6501
6654
|
const actionWord = makePrivate ? "private" : "public";
|
|
6502
6655
|
const emoji = makePrivate ? "\u{1F512}" : "\u{1F310}";
|
|
@@ -6645,7 +6798,8 @@ ${emoji} Mark Pattern(s) ${actionWord}
|
|
|
6645
6798
|
}
|
|
6646
6799
|
async function learnDeprecateCommand(patternId, reason) {
|
|
6647
6800
|
const cwd = getWorkspacePath2();
|
|
6648
|
-
const store = new
|
|
6801
|
+
const store = new PatternStore2(cwd);
|
|
6802
|
+
await store.initialize();
|
|
6649
6803
|
console.log(chalk20.cyan("\n\u26A0\uFE0F Deprecate Pattern\n"));
|
|
6650
6804
|
let patternType = "fix";
|
|
6651
6805
|
let pattern = await store.getFixPattern(patternId);
|
|
@@ -6681,8 +6835,9 @@ async function learnDeprecateCommand(patternId, reason) {
|
|
|
6681
6835
|
}
|
|
6682
6836
|
async function learnStatsCommand() {
|
|
6683
6837
|
const cwd = getWorkspacePath2();
|
|
6684
|
-
const store = new
|
|
6685
|
-
|
|
6838
|
+
const store = new PatternStore2(cwd);
|
|
6839
|
+
await store.initialize();
|
|
6840
|
+
const telemetry = new TelemetryCollector(cwd);
|
|
6686
6841
|
console.log(chalk20.cyan("\n\u{1F4CA} Learning Statistics\n"));
|
|
6687
6842
|
const storeStats = await store.getStats();
|
|
6688
6843
|
const totalPatterns = storeStats.totalFixes + storeStats.totalBlueprints;
|
|
@@ -7195,7 +7350,8 @@ function inferTagsFromContent(filePaths) {
|
|
|
7195
7350
|
}
|
|
7196
7351
|
async function learnCaptureCommand(paths, options) {
|
|
7197
7352
|
const cwd = getWorkspacePath2();
|
|
7198
|
-
const store = new
|
|
7353
|
+
const store = new PatternStore2(cwd);
|
|
7354
|
+
await store.initialize();
|
|
7199
7355
|
console.log(chalk20.cyan("\n\u{1F4F8} Capture Files as Blueprint\n"));
|
|
7200
7356
|
const resolvedPaths = [];
|
|
7201
7357
|
const relativePaths = [];
|
|
@@ -7345,7 +7501,7 @@ async function learnCaptureCommand(paths, options) {
|
|
|
7345
7501
|
}
|
|
7346
7502
|
const primaryLanguage = Object.entries(languageCounts).sort((a, b) => b[1] - a[1])[0]?.[0] || "typescript";
|
|
7347
7503
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7348
|
-
const contributorManager = new
|
|
7504
|
+
const contributorManager = new ContributorManager(cwd);
|
|
7349
7505
|
const contributorResult = await contributorManager.getOrCreateId();
|
|
7350
7506
|
const contributorId = contributorResult.success && contributorResult.data ? contributorResult.data : void 0;
|
|
7351
7507
|
const keyFiles = files.map((f) => ({
|
|
@@ -7439,10 +7595,340 @@ function getAllFilesInDir(dirPath) {
|
|
|
7439
7595
|
}
|
|
7440
7596
|
return files;
|
|
7441
7597
|
}
|
|
7598
|
+
async function learnAnalyzeCommand(options) {
|
|
7599
|
+
const cwd = getWorkspacePath2();
|
|
7600
|
+
const store = new PatternStore2(cwd);
|
|
7601
|
+
await store.initialize();
|
|
7602
|
+
const verbose = options.verbose ?? false;
|
|
7603
|
+
console.log(chalk20.cyan("\n\u{1F50D} Analyzing Codebase for Learning Opportunities\n"));
|
|
7604
|
+
const fixResult = await store.listFixPatterns({});
|
|
7605
|
+
const bpResult = await store.listBlueprints({});
|
|
7606
|
+
const existingPatterns = [
|
|
7607
|
+
...(fixResult.data || []).map((p13) => p13.name.toLowerCase()),
|
|
7608
|
+
...(bpResult.data || []).map((p13) => p13.name.toLowerCase())
|
|
7609
|
+
];
|
|
7610
|
+
const opportunities = [];
|
|
7611
|
+
const authPaths = ["src/auth", "src/lib/auth", "lib/auth", "app/api/auth"];
|
|
7612
|
+
for (const authPath of authPaths) {
|
|
7613
|
+
if (fs2.existsSync(path3.join(cwd, authPath))) {
|
|
7614
|
+
if (!existingPatterns.some((p13) => p13.includes("auth"))) {
|
|
7615
|
+
opportunities.push({
|
|
7616
|
+
type: "blueprint",
|
|
7617
|
+
name: "Authentication Module",
|
|
7618
|
+
description: "Capture your authentication implementation as a reusable pattern",
|
|
7619
|
+
path: authPath
|
|
7620
|
+
});
|
|
7621
|
+
}
|
|
7622
|
+
}
|
|
7623
|
+
}
|
|
7624
|
+
const apiPaths = ["src/api", "app/api", "pages/api", "src/routes"];
|
|
7625
|
+
for (const apiPath of apiPaths) {
|
|
7626
|
+
if (fs2.existsSync(path3.join(cwd, apiPath))) {
|
|
7627
|
+
if (!existingPatterns.some((p13) => p13.includes("api"))) {
|
|
7628
|
+
opportunities.push({
|
|
7629
|
+
type: "blueprint",
|
|
7630
|
+
name: "API Structure",
|
|
7631
|
+
description: "Capture your API routing structure as a blueprint",
|
|
7632
|
+
path: apiPath
|
|
7633
|
+
});
|
|
7634
|
+
}
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
const componentPaths = ["src/components", "components", "src/ui"];
|
|
7638
|
+
for (const compPath of componentPaths) {
|
|
7639
|
+
if (fs2.existsSync(path3.join(cwd, compPath))) {
|
|
7640
|
+
if (!existingPatterns.some((p13) => p13.includes("component"))) {
|
|
7641
|
+
opportunities.push({
|
|
7642
|
+
type: "blueprint",
|
|
7643
|
+
name: "Component Library",
|
|
7644
|
+
description: "Capture your component structure as a reusable pattern",
|
|
7645
|
+
path: compPath
|
|
7646
|
+
});
|
|
7647
|
+
}
|
|
7648
|
+
}
|
|
7649
|
+
}
|
|
7650
|
+
const testPaths = ["__tests__", "test", "tests", "src/__tests__"];
|
|
7651
|
+
for (const testPath of testPaths) {
|
|
7652
|
+
if (fs2.existsSync(path3.join(cwd, testPath))) {
|
|
7653
|
+
if (!existingPatterns.some((p13) => p13.includes("test"))) {
|
|
7654
|
+
opportunities.push({
|
|
7655
|
+
type: "blueprint",
|
|
7656
|
+
name: "Testing Structure",
|
|
7657
|
+
description: "Capture your testing setup as a blueprint",
|
|
7658
|
+
path: testPath
|
|
7659
|
+
});
|
|
7660
|
+
}
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
if (opportunities.length === 0) {
|
|
7664
|
+
console.log(chalk20.green(" \u2713 No new learning opportunities identified"));
|
|
7665
|
+
console.log(chalk20.dim("\n Your patterns seem well-captured!"));
|
|
7666
|
+
return;
|
|
7667
|
+
}
|
|
7668
|
+
console.log(chalk20.bold(` Found ${opportunities.length} potential learning opportunities:
|
|
7669
|
+
`));
|
|
7670
|
+
for (const opp of opportunities) {
|
|
7671
|
+
const icon = opp.type === "blueprint" ? "\u{1F4D0}" : "\u{1F527}";
|
|
7672
|
+
console.log(` ${icon} ${chalk20.green(opp.name)}`);
|
|
7673
|
+
console.log(chalk20.dim(` ${opp.description}`));
|
|
7674
|
+
if (opp.path && verbose) {
|
|
7675
|
+
console.log(chalk20.dim(` Path: ${opp.path}`));
|
|
7676
|
+
}
|
|
7677
|
+
console.log("");
|
|
7678
|
+
}
|
|
7679
|
+
console.log(chalk20.dim(" To capture a pattern:"));
|
|
7680
|
+
console.log(chalk20.cyan(" workflow learn capture <path> --name <name>"));
|
|
7681
|
+
}
|
|
7682
|
+
async function learnExportCommand(options) {
|
|
7683
|
+
const cwd = getWorkspacePath2();
|
|
7684
|
+
const store = new PatternStore2(cwd);
|
|
7685
|
+
await store.initialize();
|
|
7686
|
+
const format = options.format ?? "json";
|
|
7687
|
+
const patternType = options.type ?? "all";
|
|
7688
|
+
const outputPath = options.output ?? `patterns-export.${format}`;
|
|
7689
|
+
console.log(chalk20.cyan("\n\u{1F4E4} Exporting Learning Patterns\n"));
|
|
7690
|
+
const exportData = {
|
|
7691
|
+
fixes: [],
|
|
7692
|
+
blueprints: []
|
|
7693
|
+
};
|
|
7694
|
+
if (patternType === "all" || patternType === "fix") {
|
|
7695
|
+
const fixResult = await store.listFixPatterns({});
|
|
7696
|
+
if (fixResult.success && fixResult.data) {
|
|
7697
|
+
exportData.fixes = fixResult.data;
|
|
7698
|
+
}
|
|
7699
|
+
}
|
|
7700
|
+
if (patternType === "all" || patternType === "blueprint") {
|
|
7701
|
+
const bpResult = await store.listBlueprints({});
|
|
7702
|
+
if (bpResult.success && bpResult.data) {
|
|
7703
|
+
exportData.blueprints = bpResult.data;
|
|
7704
|
+
}
|
|
7705
|
+
}
|
|
7706
|
+
const totalCount = exportData.fixes.length + exportData.blueprints.length;
|
|
7707
|
+
if (totalCount === 0) {
|
|
7708
|
+
console.log(chalk20.yellow(" No patterns to export"));
|
|
7709
|
+
return;
|
|
7710
|
+
}
|
|
7711
|
+
let output;
|
|
7712
|
+
if (format === "yaml") {
|
|
7713
|
+
output = `# Workflow Agent Patterns Export
|
|
7714
|
+
# Exported: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
7715
|
+
|
|
7716
|
+
`;
|
|
7717
|
+
output += `fixes:
|
|
7718
|
+
`;
|
|
7719
|
+
for (const fix of exportData.fixes) {
|
|
7720
|
+
output += ` - id: ${fix.id}
|
|
7721
|
+
`;
|
|
7722
|
+
output += ` name: "${fix.name}"
|
|
7723
|
+
`;
|
|
7724
|
+
output += ` category: ${fix.category}
|
|
7725
|
+
`;
|
|
7726
|
+
output += ` description: "${fix.description}"
|
|
7727
|
+
|
|
7728
|
+
`;
|
|
7729
|
+
}
|
|
7730
|
+
output += `blueprints:
|
|
7731
|
+
`;
|
|
7732
|
+
for (const bp of exportData.blueprints) {
|
|
7733
|
+
output += ` - id: ${bp.id}
|
|
7734
|
+
`;
|
|
7735
|
+
output += ` name: "${bp.name}"
|
|
7736
|
+
`;
|
|
7737
|
+
output += ` description: "${bp.description}"
|
|
7738
|
+
|
|
7739
|
+
`;
|
|
7740
|
+
}
|
|
7741
|
+
} else {
|
|
7742
|
+
output = JSON.stringify(
|
|
7743
|
+
{
|
|
7744
|
+
version: "1.0",
|
|
7745
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7746
|
+
...exportData
|
|
7747
|
+
},
|
|
7748
|
+
null,
|
|
7749
|
+
2
|
|
7750
|
+
);
|
|
7751
|
+
}
|
|
7752
|
+
const fullOutputPath = path3.isAbsolute(outputPath) ? outputPath : path3.join(cwd, outputPath);
|
|
7753
|
+
await fs2.promises.writeFile(fullOutputPath, output, "utf-8");
|
|
7754
|
+
console.log(chalk20.green(` \u2713 Exported ${totalCount} patterns
|
|
7755
|
+
`));
|
|
7756
|
+
console.log(chalk20.dim(` Fix patterns: ${exportData.fixes.length}`));
|
|
7757
|
+
console.log(chalk20.dim(` Blueprints: ${exportData.blueprints.length}`));
|
|
7758
|
+
console.log(chalk20.dim(` Output: ${fullOutputPath}`));
|
|
7759
|
+
console.log(chalk20.dim(` Format: ${format.toUpperCase()}`));
|
|
7760
|
+
}
|
|
7761
|
+
async function learnImportCommand(file, options) {
|
|
7762
|
+
const cwd = getWorkspacePath2();
|
|
7763
|
+
const store = new PatternStore2(cwd);
|
|
7764
|
+
await store.initialize();
|
|
7765
|
+
const dryRun = options.dryRun ?? false;
|
|
7766
|
+
const merge = options.merge ?? true;
|
|
7767
|
+
console.log(chalk20.cyan("\n\u{1F4E5} Importing Learning Patterns\n"));
|
|
7768
|
+
const filePath = path3.isAbsolute(file) ? file : path3.join(cwd, file);
|
|
7769
|
+
if (!fs2.existsSync(filePath)) {
|
|
7770
|
+
console.log(chalk20.red(` \u2717 File not found: ${filePath}`));
|
|
7771
|
+
process.exit(1);
|
|
7772
|
+
}
|
|
7773
|
+
const content = await fs2.promises.readFile(filePath, "utf-8");
|
|
7774
|
+
let importData;
|
|
7775
|
+
try {
|
|
7776
|
+
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
7777
|
+
console.log(chalk20.yellow(" YAML import not fully supported, treating as JSON"));
|
|
7778
|
+
}
|
|
7779
|
+
importData = JSON.parse(content);
|
|
7780
|
+
} catch {
|
|
7781
|
+
console.log(chalk20.red(" \u2717 Failed to parse import file"));
|
|
7782
|
+
process.exit(1);
|
|
7783
|
+
}
|
|
7784
|
+
const fixes = importData.fixes || [];
|
|
7785
|
+
const blueprints = importData.blueprints || [];
|
|
7786
|
+
const totalCount = fixes.length + blueprints.length;
|
|
7787
|
+
if (totalCount === 0) {
|
|
7788
|
+
console.log(chalk20.yellow(" No patterns found in import file"));
|
|
7789
|
+
return;
|
|
7790
|
+
}
|
|
7791
|
+
console.log(chalk20.dim(` Found ${fixes.length} fix patterns`));
|
|
7792
|
+
console.log(chalk20.dim(` Found ${blueprints.length} blueprints
|
|
7793
|
+
`));
|
|
7794
|
+
if (dryRun) {
|
|
7795
|
+
console.log(chalk20.yellow(" \u{1F50D} Dry run - no changes will be made\n"));
|
|
7796
|
+
for (const fix of fixes) {
|
|
7797
|
+
console.log(chalk20.dim(` Would import fix: ${fix.name} (${fix.id})`));
|
|
7798
|
+
}
|
|
7799
|
+
for (const bp of blueprints) {
|
|
7800
|
+
console.log(chalk20.dim(` Would import blueprint: ${bp.name} (${bp.id})`));
|
|
7801
|
+
}
|
|
7802
|
+
return;
|
|
7803
|
+
}
|
|
7804
|
+
let imported = 0;
|
|
7805
|
+
let skipped = 0;
|
|
7806
|
+
for (const fix of fixes) {
|
|
7807
|
+
const existing = await store.getFixPattern(fix.id);
|
|
7808
|
+
if (existing.success && existing.data && !merge) {
|
|
7809
|
+
console.log(chalk20.yellow(` Skipped (exists): ${fix.name}`));
|
|
7810
|
+
skipped++;
|
|
7811
|
+
continue;
|
|
7812
|
+
}
|
|
7813
|
+
const result = await store.saveFixPattern(fix);
|
|
7814
|
+
if (result.success) {
|
|
7815
|
+
console.log(chalk20.green(` \u2713 Imported: ${fix.name}`));
|
|
7816
|
+
imported++;
|
|
7817
|
+
} else {
|
|
7818
|
+
console.log(chalk20.red(` \u2717 Failed: ${fix.name}`));
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7821
|
+
for (const bp of blueprints) {
|
|
7822
|
+
const existing = await store.getBlueprint(bp.id);
|
|
7823
|
+
if (existing.success && existing.data && !merge) {
|
|
7824
|
+
console.log(chalk20.yellow(` Skipped (exists): ${bp.name}`));
|
|
7825
|
+
skipped++;
|
|
7826
|
+
continue;
|
|
7827
|
+
}
|
|
7828
|
+
const result = await store.saveBlueprint(bp);
|
|
7829
|
+
if (result.success) {
|
|
7830
|
+
console.log(chalk20.green(` \u2713 Imported: ${bp.name}`));
|
|
7831
|
+
imported++;
|
|
7832
|
+
} else {
|
|
7833
|
+
console.log(chalk20.red(` \u2717 Failed: ${bp.name}`));
|
|
7834
|
+
}
|
|
7835
|
+
}
|
|
7836
|
+
console.log(chalk20.green(`
|
|
7837
|
+
\u2713 Import complete`));
|
|
7838
|
+
console.log(chalk20.dim(` Imported: ${imported}`));
|
|
7839
|
+
console.log(chalk20.dim(` Skipped: ${skipped}`));
|
|
7840
|
+
}
|
|
7841
|
+
async function learnCleanCommand(options) {
|
|
7842
|
+
const cwd = getWorkspacePath2();
|
|
7843
|
+
const store = new PatternStore2(cwd);
|
|
7844
|
+
await store.initialize();
|
|
7845
|
+
const dryRun = options.dryRun ?? false;
|
|
7846
|
+
const cleanDeprecated = options.deprecated ?? false;
|
|
7847
|
+
const cleanStale = options.stale ?? false;
|
|
7848
|
+
const cleanAll = options.all ?? false;
|
|
7849
|
+
console.log(chalk20.cyan("\n\u{1F9F9} Cleaning Learning Patterns\n"));
|
|
7850
|
+
if (!cleanDeprecated && !cleanStale && !cleanAll) {
|
|
7851
|
+
console.log(chalk20.yellow(" Specify what to clean:"));
|
|
7852
|
+
console.log(chalk20.dim(" --deprecated Remove deprecated patterns"));
|
|
7853
|
+
console.log(chalk20.dim(" --stale Remove patterns not used in 90+ days"));
|
|
7854
|
+
console.log(chalk20.dim(" --all Remove all patterns (use with caution!)"));
|
|
7855
|
+
return;
|
|
7856
|
+
}
|
|
7857
|
+
const toRemove = [];
|
|
7858
|
+
const fixResult = await store.listFixPatterns({ includeDeprecated: true });
|
|
7859
|
+
const bpResult = await store.listBlueprints({ includeDeprecated: true });
|
|
7860
|
+
const fixes = fixResult.data || [];
|
|
7861
|
+
const blueprints = bpResult.data || [];
|
|
7862
|
+
const now = Date.now();
|
|
7863
|
+
const staleDays = 90;
|
|
7864
|
+
const staleThreshold = now - staleDays * 24 * 60 * 60 * 1e3;
|
|
7865
|
+
for (const fix of fixes) {
|
|
7866
|
+
if (cleanAll) {
|
|
7867
|
+
toRemove.push({ id: fix.id, name: fix.name, type: "fix", reason: "all" });
|
|
7868
|
+
} else if (cleanDeprecated && fix.deprecatedAt) {
|
|
7869
|
+
toRemove.push({ id: fix.id, name: fix.name, type: "fix", reason: "deprecated" });
|
|
7870
|
+
} else if (cleanStale) {
|
|
7871
|
+
const lastUsed = new Date(fix.updatedAt).getTime();
|
|
7872
|
+
if (lastUsed < staleThreshold) {
|
|
7873
|
+
toRemove.push({ id: fix.id, name: fix.name, type: "fix", reason: "stale" });
|
|
7874
|
+
}
|
|
7875
|
+
}
|
|
7876
|
+
}
|
|
7877
|
+
for (const bp of blueprints) {
|
|
7878
|
+
if (cleanAll) {
|
|
7879
|
+
toRemove.push({ id: bp.id, name: bp.name, type: "blueprint", reason: "all" });
|
|
7880
|
+
} else if (cleanDeprecated && bp.deprecatedAt) {
|
|
7881
|
+
toRemove.push({ id: bp.id, name: bp.name, type: "blueprint", reason: "deprecated" });
|
|
7882
|
+
} else if (cleanStale) {
|
|
7883
|
+
const lastUsed = new Date(bp.updatedAt).getTime();
|
|
7884
|
+
if (lastUsed < staleThreshold) {
|
|
7885
|
+
toRemove.push({ id: bp.id, name: bp.name, type: "blueprint", reason: "stale" });
|
|
7886
|
+
}
|
|
7887
|
+
}
|
|
7888
|
+
}
|
|
7889
|
+
if (toRemove.length === 0) {
|
|
7890
|
+
console.log(chalk20.green(" \u2713 Nothing to clean"));
|
|
7891
|
+
return;
|
|
7892
|
+
}
|
|
7893
|
+
console.log(chalk20.bold(` Found ${toRemove.length} patterns to remove:
|
|
7894
|
+
`));
|
|
7895
|
+
for (const item of toRemove) {
|
|
7896
|
+
const icon = item.type === "fix" ? "\u{1F527}" : "\u{1F4D0}";
|
|
7897
|
+
console.log(` ${icon} ${item.name} (${item.reason})`);
|
|
7898
|
+
}
|
|
7899
|
+
if (dryRun) {
|
|
7900
|
+
console.log(chalk20.yellow("\n \u{1F50D} Dry run - no changes made"));
|
|
7901
|
+
return;
|
|
7902
|
+
}
|
|
7903
|
+
const confirmed = await p12.confirm({
|
|
7904
|
+
message: `Remove ${toRemove.length} patterns? This cannot be undone.`,
|
|
7905
|
+
initialValue: false
|
|
7906
|
+
});
|
|
7907
|
+
if (p12.isCancel(confirmed) || !confirmed) {
|
|
7908
|
+
p12.cancel("Clean cancelled");
|
|
7909
|
+
return;
|
|
7910
|
+
}
|
|
7911
|
+
let removed = 0;
|
|
7912
|
+
const patternsPath = path3.join(cwd, ".workflow", "patterns");
|
|
7913
|
+
for (const item of toRemove) {
|
|
7914
|
+
const dir = item.type === "fix" ? "fixes" : "blueprints";
|
|
7915
|
+
const filePath = path3.join(patternsPath, dir, `${item.id}.json`);
|
|
7916
|
+
try {
|
|
7917
|
+
if (fs2.existsSync(filePath)) {
|
|
7918
|
+
await fs2.promises.unlink(filePath);
|
|
7919
|
+
removed++;
|
|
7920
|
+
}
|
|
7921
|
+
} catch {
|
|
7922
|
+
console.log(chalk20.red(` \u2717 Failed to remove: ${item.name}`));
|
|
7923
|
+
}
|
|
7924
|
+
}
|
|
7925
|
+
console.log(chalk20.green(`
|
|
7926
|
+
\u2713 Removed ${removed} patterns`));
|
|
7927
|
+
}
|
|
7442
7928
|
|
|
7443
7929
|
// src/cli/commands/learn/index.ts
|
|
7444
7930
|
function createLearnCommand() {
|
|
7445
|
-
const learnCmd = new
|
|
7931
|
+
const learnCmd = new Command5("learn").description("Manage learning patterns for AI-assisted development").addHelpText(
|
|
7446
7932
|
"after",
|
|
7447
7933
|
`
|
|
7448
7934
|
${chalk21.bold("Examples:")}
|
|
@@ -7450,9 +7936,13 @@ ${chalk21.bold("Examples:")}
|
|
|
7450
7936
|
$ workflow learn list --type blueprint ${chalk21.dim("# List blueprints only")}
|
|
7451
7937
|
$ workflow learn apply abc123 --dry-run ${chalk21.dim("# Preview pattern application")}
|
|
7452
7938
|
$ workflow learn capture ./src/auth --name auth ${chalk21.dim("# Capture as blueprint")}
|
|
7939
|
+
$ workflow learn analyze ${chalk21.dim("# Find learning opportunities")}
|
|
7940
|
+
$ workflow learn export --format json ${chalk21.dim("# Export patterns")}
|
|
7941
|
+
$ workflow learn import patterns.json ${chalk21.dim("# Import patterns")}
|
|
7453
7942
|
$ workflow learn sync --push ${chalk21.dim("# Push patterns to registry")}
|
|
7454
7943
|
$ workflow learn config --show ${chalk21.dim("# Show current configuration")}
|
|
7455
7944
|
$ workflow learn stats ${chalk21.dim("# Show learning statistics")}
|
|
7945
|
+
$ workflow learn clean --deprecated ${chalk21.dim("# Clean deprecated patterns")}
|
|
7456
7946
|
$ workflow learn validate --fix ${chalk21.dim("# Auto-fix pattern issues")}
|
|
7457
7947
|
`
|
|
7458
7948
|
).action(() => {
|
|
@@ -7550,6 +8040,42 @@ ${chalk21.bold("Examples:")}
|
|
|
7550
8040
|
$ workflow learn stats ${chalk21.dim("# Show all statistics")}
|
|
7551
8041
|
`
|
|
7552
8042
|
).action(learnStatsCommand);
|
|
8043
|
+
learnCmd.command("analyze").description("Analyze codebase for learning opportunities").option("-v, --verbose", "Show detailed output including paths").addHelpText(
|
|
8044
|
+
"after",
|
|
8045
|
+
`
|
|
8046
|
+
${chalk21.bold("Examples:")}
|
|
8047
|
+
$ workflow learn analyze ${chalk21.dim("# Find learning opportunities")}
|
|
8048
|
+
$ workflow learn analyze --verbose ${chalk21.dim("# Show paths and details")}
|
|
8049
|
+
`
|
|
8050
|
+
).action(learnAnalyzeCommand);
|
|
8051
|
+
learnCmd.command("export").description("Export learning patterns to a file").option("-o, --output <path>", "Output file path", "patterns-export.json").option("-f, --format <format>", "Output format (json, yaml)", "json").option("-t, --type <type>", "Pattern type to export (fix, blueprint, all)", "all").addHelpText(
|
|
8052
|
+
"after",
|
|
8053
|
+
`
|
|
8054
|
+
${chalk21.bold("Examples:")}
|
|
8055
|
+
$ workflow learn export ${chalk21.dim("# Export all as JSON")}
|
|
8056
|
+
$ workflow learn export --format yaml ${chalk21.dim("# Export as YAML")}
|
|
8057
|
+
$ workflow learn export --type fix ${chalk21.dim("# Export only fixes")}
|
|
8058
|
+
$ workflow learn export -o backup.json ${chalk21.dim("# Custom output path")}
|
|
8059
|
+
`
|
|
8060
|
+
).action(learnExportCommand);
|
|
8061
|
+
learnCmd.command("import <file>").description("Import learning patterns from a file").option("-f, --format <format>", "Input format (json, yaml)", "json").option("--dry-run", "Preview import without making changes").option("--no-merge", "Skip existing patterns instead of merging").addHelpText(
|
|
8062
|
+
"after",
|
|
8063
|
+
`
|
|
8064
|
+
${chalk21.bold("Examples:")}
|
|
8065
|
+
$ workflow learn import patterns.json ${chalk21.dim("# Import from JSON")}
|
|
8066
|
+
$ workflow learn import backup.json --dry-run ${chalk21.dim("# Preview import")}
|
|
8067
|
+
$ workflow learn import patterns.yaml --format yaml ${chalk21.dim("# Import from YAML")}
|
|
8068
|
+
`
|
|
8069
|
+
).action(learnImportCommand);
|
|
8070
|
+
learnCmd.command("clean").description("Clean old or stale learning patterns").option("--deprecated", "Remove deprecated patterns").option("--stale", "Remove patterns not used in 90+ days").option("--all", "Remove all patterns (use with caution!)").option("--dry-run", "Preview what would be removed").addHelpText(
|
|
8071
|
+
"after",
|
|
8072
|
+
`
|
|
8073
|
+
${chalk21.bold("Examples:")}
|
|
8074
|
+
$ workflow learn clean --deprecated ${chalk21.dim("# Remove deprecated")}
|
|
8075
|
+
$ workflow learn clean --stale ${chalk21.dim("# Remove stale patterns")}
|
|
8076
|
+
$ workflow learn clean --all --dry-run ${chalk21.dim("# Preview full clean")}
|
|
8077
|
+
`
|
|
8078
|
+
).action(learnCleanCommand);
|
|
7553
8079
|
learnCmd.command("validate").description("Validate pattern files and optionally auto-fix common issues").option("-t, --type <type>", "Pattern type to validate (fix, blueprint, solution, all)", "all").option("-f, --file <path>", "Validate a specific file by path").option("--fix", "Automatically fix common issues").option("-v, --verbose", "Show detailed validation output").addHelpText(
|
|
7554
8080
|
"after",
|
|
7555
8081
|
`
|
|
@@ -7565,19 +8091,250 @@ ${chalk21.bold("Examples:")}
|
|
|
7565
8091
|
}
|
|
7566
8092
|
|
|
7567
8093
|
// src/cli/commands/scope/index.ts
|
|
7568
|
-
import { Command as
|
|
8094
|
+
import { Command as Command6 } from "commander";
|
|
7569
8095
|
import chalk22 from "chalk";
|
|
8096
|
+
async function scopeListCommand() {
|
|
8097
|
+
console.log(chalk22.bold.cyan("\n\u{1F4CB} Available Scopes\n"));
|
|
8098
|
+
const config = await loadConfig();
|
|
8099
|
+
const scopes = config?.scopes || [];
|
|
8100
|
+
if (scopes.length === 0) {
|
|
8101
|
+
console.log(chalk22.yellow(" No scopes configured."));
|
|
8102
|
+
console.log(chalk22.dim("\n Add scopes with: workflow scope add <name>"));
|
|
8103
|
+
console.log(chalk22.dim(" Or create a custom scope: workflow scope create"));
|
|
8104
|
+
return;
|
|
8105
|
+
}
|
|
8106
|
+
const byCategory = {};
|
|
8107
|
+
for (const scope of scopes) {
|
|
8108
|
+
const cat = scope.category || "other";
|
|
8109
|
+
if (!byCategory[cat]) byCategory[cat] = [];
|
|
8110
|
+
byCategory[cat].push(scope);
|
|
8111
|
+
}
|
|
8112
|
+
for (const [category, categoryScopes] of Object.entries(byCategory)) {
|
|
8113
|
+
console.log(chalk22.bold(` ${category.charAt(0).toUpperCase() + category.slice(1)}:`));
|
|
8114
|
+
for (const scope of categoryScopes) {
|
|
8115
|
+
const emoji = scope.emoji || "\u{1F4E6}";
|
|
8116
|
+
console.log(` ${emoji} ${chalk22.green(scope.name)} - ${scope.description || "No description"}`);
|
|
8117
|
+
}
|
|
8118
|
+
console.log("");
|
|
8119
|
+
}
|
|
8120
|
+
console.log(chalk22.dim(` Total: ${scopes.length} scopes`));
|
|
8121
|
+
}
|
|
8122
|
+
async function scopeAddCommand(name, options) {
|
|
8123
|
+
console.log(chalk22.bold.cyan(`
|
|
8124
|
+
\u2795 Adding Scope: ${name}
|
|
8125
|
+
`));
|
|
8126
|
+
const fs3 = await import("fs");
|
|
8127
|
+
const path4 = await import("path");
|
|
8128
|
+
const cwd = process.cwd();
|
|
8129
|
+
const configFiles = ["workflow.config.json", "workflow.config.js", ".workflowrc.json"];
|
|
8130
|
+
let configPath = null;
|
|
8131
|
+
for (const file of configFiles) {
|
|
8132
|
+
const fullPath = path4.join(cwd, file);
|
|
8133
|
+
if (fs3.existsSync(fullPath)) {
|
|
8134
|
+
configPath = fullPath;
|
|
8135
|
+
break;
|
|
8136
|
+
}
|
|
8137
|
+
}
|
|
8138
|
+
if (!configPath) {
|
|
8139
|
+
console.log(chalk22.red("\u2717 No workflow configuration file found"));
|
|
8140
|
+
console.log(chalk22.yellow(" Run: workflow init"));
|
|
8141
|
+
process.exit(1);
|
|
8142
|
+
}
|
|
8143
|
+
const configContent = fs3.readFileSync(configPath, "utf-8");
|
|
8144
|
+
const config = JSON.parse(configContent);
|
|
8145
|
+
if (!config.scopes) {
|
|
8146
|
+
config.scopes = [];
|
|
8147
|
+
}
|
|
8148
|
+
const existing = config.scopes.find((s) => s.name === name);
|
|
8149
|
+
if (existing) {
|
|
8150
|
+
console.log(chalk22.yellow(` Scope "${name}" already exists`));
|
|
8151
|
+
process.exit(1);
|
|
8152
|
+
}
|
|
8153
|
+
const newScope = {
|
|
8154
|
+
name,
|
|
8155
|
+
description: options.description || `${name} related changes`,
|
|
8156
|
+
emoji: options.emoji || "\u{1F4E6}",
|
|
8157
|
+
category: options.category || "feature"
|
|
8158
|
+
};
|
|
8159
|
+
config.scopes.push(newScope);
|
|
8160
|
+
fs3.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
8161
|
+
console.log(chalk22.green(`\u2713 Added scope: ${newScope.emoji} ${name}`));
|
|
8162
|
+
console.log(chalk22.dim(` Description: ${newScope.description}`));
|
|
8163
|
+
console.log(chalk22.dim(` Category: ${newScope.category}`));
|
|
8164
|
+
}
|
|
8165
|
+
async function scopeRemoveCommand(name) {
|
|
8166
|
+
console.log(chalk22.bold.cyan(`
|
|
8167
|
+
\u2796 Removing Scope: ${name}
|
|
8168
|
+
`));
|
|
8169
|
+
const fs3 = await import("fs");
|
|
8170
|
+
const path4 = await import("path");
|
|
8171
|
+
const cwd = process.cwd();
|
|
8172
|
+
const configFiles = ["workflow.config.json", "workflow.config.js", ".workflowrc.json"];
|
|
8173
|
+
let configPath = null;
|
|
8174
|
+
for (const file of configFiles) {
|
|
8175
|
+
const fullPath = path4.join(cwd, file);
|
|
8176
|
+
if (fs3.existsSync(fullPath)) {
|
|
8177
|
+
configPath = fullPath;
|
|
8178
|
+
break;
|
|
8179
|
+
}
|
|
8180
|
+
}
|
|
8181
|
+
if (!configPath) {
|
|
8182
|
+
console.log(chalk22.red("\u2717 No workflow configuration file found"));
|
|
8183
|
+
process.exit(1);
|
|
8184
|
+
}
|
|
8185
|
+
const configContent = fs3.readFileSync(configPath, "utf-8");
|
|
8186
|
+
const config = JSON.parse(configContent);
|
|
8187
|
+
if (!config.scopes || config.scopes.length === 0) {
|
|
8188
|
+
console.log(chalk22.yellow(" No scopes configured"));
|
|
8189
|
+
process.exit(1);
|
|
8190
|
+
}
|
|
8191
|
+
const index = config.scopes.findIndex((s) => s.name === name);
|
|
8192
|
+
if (index === -1) {
|
|
8193
|
+
console.log(chalk22.yellow(` Scope "${name}" not found`));
|
|
8194
|
+
process.exit(1);
|
|
8195
|
+
}
|
|
8196
|
+
const removed = config.scopes.splice(index, 1)[0];
|
|
8197
|
+
fs3.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
8198
|
+
console.log(chalk22.green(`\u2713 Removed scope: ${removed.emoji || "\u{1F4E6}"} ${name}`));
|
|
8199
|
+
}
|
|
8200
|
+
async function scopeSyncCommand(options) {
|
|
8201
|
+
console.log(chalk22.bold.cyan("\n\u{1F504} Syncing Scopes\n"));
|
|
8202
|
+
const { syncCommand: syncCommand2 } = await import("../sync-MNHQ6AIQ.js");
|
|
8203
|
+
await syncCommand2({
|
|
8204
|
+
...options,
|
|
8205
|
+
scopes: true,
|
|
8206
|
+
learn: false,
|
|
8207
|
+
solutions: false
|
|
8208
|
+
});
|
|
8209
|
+
}
|
|
8210
|
+
async function scopeAnalyzeCommand() {
|
|
8211
|
+
console.log(chalk22.bold.cyan("\n\u{1F50D} Analyzing Scope Usage\n"));
|
|
8212
|
+
const { execa: execa2 } = await import("execa");
|
|
8213
|
+
const cwd = process.cwd();
|
|
8214
|
+
try {
|
|
8215
|
+
const { stdout } = await execa2("git", ["log", "--oneline", "-50", "--format=%s"], { cwd });
|
|
8216
|
+
const commits = stdout.split("\n").filter(Boolean);
|
|
8217
|
+
const config = await loadConfig();
|
|
8218
|
+
const scopes = config?.scopes || [];
|
|
8219
|
+
const scopeNames = scopes.map((s) => s.name);
|
|
8220
|
+
const usage = {};
|
|
8221
|
+
let unscoped = 0;
|
|
8222
|
+
let invalidScopes = [];
|
|
8223
|
+
for (const commit of commits) {
|
|
8224
|
+
const match = commit.match(/^\w+\(([^)]+)\):/);
|
|
8225
|
+
if (match) {
|
|
8226
|
+
const scope = match[1];
|
|
8227
|
+
if (scopeNames.includes(scope)) {
|
|
8228
|
+
usage[scope] = (usage[scope] || 0) + 1;
|
|
8229
|
+
} else {
|
|
8230
|
+
if (!invalidScopes.includes(scope)) {
|
|
8231
|
+
invalidScopes.push(scope);
|
|
8232
|
+
}
|
|
8233
|
+
}
|
|
8234
|
+
} else if (commit.match(/^\w+:/)) {
|
|
8235
|
+
unscoped++;
|
|
8236
|
+
}
|
|
8237
|
+
}
|
|
8238
|
+
console.log(chalk22.bold(" Scope Usage (last 50 commits):"));
|
|
8239
|
+
console.log("");
|
|
8240
|
+
const sortedUsage = Object.entries(usage).sort((a, b) => b[1] - a[1]);
|
|
8241
|
+
for (const [scope, count] of sortedUsage) {
|
|
8242
|
+
const scopeConfig = scopes.find((s) => s.name === scope);
|
|
8243
|
+
const emoji = scopeConfig?.emoji || "\u{1F4E6}";
|
|
8244
|
+
const bar = "\u2588".repeat(Math.min(count, 20));
|
|
8245
|
+
console.log(` ${emoji} ${chalk22.green(scope.padEnd(15))} ${bar} ${count}`);
|
|
8246
|
+
}
|
|
8247
|
+
if (unscoped > 0) {
|
|
8248
|
+
console.log(` ${chalk22.yellow("(unscoped)".padEnd(17))} ${"\u2591".repeat(Math.min(unscoped, 20))} ${unscoped}`);
|
|
8249
|
+
}
|
|
8250
|
+
const unusedScopes = scopeNames.filter((name) => !usage[name]);
|
|
8251
|
+
if (unusedScopes.length > 0) {
|
|
8252
|
+
console.log(chalk22.yellow("\n Unused scopes (consider removing):"));
|
|
8253
|
+
for (const name of unusedScopes) {
|
|
8254
|
+
console.log(chalk22.dim(` \u2022 ${name}`));
|
|
8255
|
+
}
|
|
8256
|
+
}
|
|
8257
|
+
if (invalidScopes.length > 0) {
|
|
8258
|
+
console.log(chalk22.yellow("\n Unknown scopes (consider adding):"));
|
|
8259
|
+
for (const name of invalidScopes) {
|
|
8260
|
+
console.log(chalk22.dim(` \u2022 ${name}`));
|
|
8261
|
+
}
|
|
8262
|
+
}
|
|
8263
|
+
console.log("");
|
|
8264
|
+
} catch {
|
|
8265
|
+
console.log(chalk22.yellow(" Unable to analyze git history"));
|
|
8266
|
+
console.log(chalk22.dim(" Make sure you're in a git repository with commit history"));
|
|
8267
|
+
}
|
|
8268
|
+
}
|
|
8269
|
+
async function hooksTestCommand(options) {
|
|
8270
|
+
console.log(chalk22.bold.cyan("\n\u{1F9EA} Testing Git Hooks\n"));
|
|
8271
|
+
const fs3 = await import("fs");
|
|
8272
|
+
const path4 = await import("path");
|
|
8273
|
+
const cwd = process.cwd();
|
|
8274
|
+
const gitDir = path4.join(cwd, ".git");
|
|
8275
|
+
const hooksDir = path4.join(gitDir, "hooks");
|
|
8276
|
+
if (!fs3.existsSync(gitDir)) {
|
|
8277
|
+
console.log(chalk22.red("\u2717 Not a git repository"));
|
|
8278
|
+
process.exit(1);
|
|
8279
|
+
}
|
|
8280
|
+
if (!fs3.existsSync(hooksDir)) {
|
|
8281
|
+
console.log(chalk22.yellow(" No hooks directory found"));
|
|
8282
|
+
console.log(chalk22.dim(" Run: workflow scope hooks install"));
|
|
8283
|
+
process.exit(1);
|
|
8284
|
+
}
|
|
8285
|
+
const hookTypes = ["pre-commit", "commit-msg"];
|
|
8286
|
+
let allInstalled = true;
|
|
8287
|
+
for (const hookType of hookTypes) {
|
|
8288
|
+
const hookPath = path4.join(hooksDir, hookType);
|
|
8289
|
+
const exists = fs3.existsSync(hookPath);
|
|
8290
|
+
const isExecutable = exists && (fs3.statSync(hookPath).mode & 73) !== 0;
|
|
8291
|
+
const isWorkflowHook2 = exists && fs3.readFileSync(hookPath, "utf-8").includes("workflow-agent");
|
|
8292
|
+
if (exists && isExecutable && isWorkflowHook2) {
|
|
8293
|
+
console.log(chalk22.green(` \u2713 ${hookType} - installed and executable`));
|
|
8294
|
+
} else if (exists && !isWorkflowHook2) {
|
|
8295
|
+
console.log(chalk22.yellow(` \u26A0 ${hookType} - exists but not managed by workflow-agent`));
|
|
8296
|
+
allInstalled = false;
|
|
8297
|
+
} else if (exists && !isExecutable) {
|
|
8298
|
+
console.log(chalk22.red(` \u2717 ${hookType} - exists but not executable`));
|
|
8299
|
+
allInstalled = false;
|
|
8300
|
+
} else {
|
|
8301
|
+
console.log(chalk22.red(` \u2717 ${hookType} - not installed`));
|
|
8302
|
+
allInstalled = false;
|
|
8303
|
+
}
|
|
8304
|
+
}
|
|
8305
|
+
if (options.dryRun) {
|
|
8306
|
+
console.log(chalk22.bold.cyan("\n Dry-run hook simulation:\n"));
|
|
8307
|
+
console.log(chalk22.dim(" Simulating pre-commit hook..."));
|
|
8308
|
+
const { verifyCommand: verifyCommand2 } = await import("../verify-2PDVNYWV.js");
|
|
8309
|
+
try {
|
|
8310
|
+
await verifyCommand2({ fix: false, dryRun: true, maxRetries: "1" });
|
|
8311
|
+
} catch {
|
|
8312
|
+
}
|
|
8313
|
+
}
|
|
8314
|
+
if (!allInstalled) {
|
|
8315
|
+
console.log(chalk22.yellow("\n Some hooks are not properly installed"));
|
|
8316
|
+
console.log(chalk22.dim(" Run: workflow scope hooks install"));
|
|
8317
|
+
process.exit(1);
|
|
8318
|
+
}
|
|
8319
|
+
console.log(chalk22.green("\n\u2713 All hooks are properly installed"));
|
|
8320
|
+
}
|
|
7570
8321
|
function createScopeCommand() {
|
|
7571
|
-
const scopeCmd = new
|
|
8322
|
+
const scopeCmd = new Command6("scope").description("Manage custom scope packages and git hooks").addHelpText(
|
|
7572
8323
|
"after",
|
|
7573
8324
|
`
|
|
7574
8325
|
${chalk22.bold("Examples:")}
|
|
7575
|
-
$ workflow scope
|
|
7576
|
-
$ workflow scope
|
|
8326
|
+
$ workflow scope list ${chalk22.dim("# List available scopes")}
|
|
8327
|
+
$ workflow scope create --name fintech ${chalk22.dim("# Create fintech scope package")}
|
|
8328
|
+
$ workflow scope migrate --name my-scopes ${chalk22.dim("# Migrate inline to package")}
|
|
8329
|
+
$ workflow scope add auth ${chalk22.dim("# Add auth scope")}
|
|
8330
|
+
$ workflow scope remove legacy ${chalk22.dim("# Remove legacy scope")}
|
|
8331
|
+
$ workflow scope analyze ${chalk22.dim("# Analyze scope usage")}
|
|
8332
|
+
$ workflow scope hooks install ${chalk22.dim("# Install git hooks")}
|
|
7577
8333
|
`
|
|
7578
8334
|
).action(() => {
|
|
7579
|
-
|
|
8335
|
+
scopeListCommand();
|
|
7580
8336
|
});
|
|
8337
|
+
scopeCmd.command("list").description("List available scopes").action(scopeListCommand);
|
|
7581
8338
|
scopeCmd.command("create").description("Create a custom scope package").option("--name <name>", 'Package name (e.g., "fintech", "gaming")').option(
|
|
7582
8339
|
"--scopes <scopes>",
|
|
7583
8340
|
"Comma-separated scopes (format: name:description:emoji:category)"
|
|
@@ -7601,6 +8358,57 @@ ${chalk22.bold("Examples:")}
|
|
|
7601
8358
|
$ workflow scope migrate --keep-config ${chalk22.dim("# Keep inline copy")}
|
|
7602
8359
|
`
|
|
7603
8360
|
).action(scopeMigrateCommand);
|
|
8361
|
+
scopeCmd.command("add <name>").description("Add a scope to the project configuration").option("--description <desc>", "Scope description").option("--emoji <emoji>", "Scope emoji").option("--category <cat>", "Scope category (feature, fix, core, etc.)").addHelpText(
|
|
8362
|
+
"after",
|
|
8363
|
+
`
|
|
8364
|
+
${chalk22.bold("Examples:")}
|
|
8365
|
+
$ workflow scope add auth ${chalk22.dim("# Add auth scope")}
|
|
8366
|
+
$ workflow scope add payments --emoji \u{1F4B3} ${chalk22.dim("# With emoji")}
|
|
8367
|
+
$ workflow scope add api --category core ${chalk22.dim("# With category")}
|
|
8368
|
+
`
|
|
8369
|
+
).action(scopeAddCommand);
|
|
8370
|
+
scopeCmd.command("remove <name>").description("Remove a scope from the project configuration").addHelpText(
|
|
8371
|
+
"after",
|
|
8372
|
+
`
|
|
8373
|
+
${chalk22.bold("Examples:")}
|
|
8374
|
+
$ workflow scope remove legacy ${chalk22.dim("# Remove scope")}
|
|
8375
|
+
`
|
|
8376
|
+
).action(scopeRemoveCommand);
|
|
8377
|
+
scopeCmd.command("sync").description("Sync scopes with the community registry").option("--push", "Push local scopes to registry").option("--pull", "Pull scopes from registry").option("--dry-run", "Preview without syncing").addHelpText(
|
|
8378
|
+
"after",
|
|
8379
|
+
`
|
|
8380
|
+
${chalk22.bold("Examples:")}
|
|
8381
|
+
$ workflow scope sync --push ${chalk22.dim("# Push to registry")}
|
|
8382
|
+
$ workflow scope sync --pull ${chalk22.dim("# Pull from registry")}
|
|
8383
|
+
$ workflow scope sync --dry-run ${chalk22.dim("# Preview changes")}
|
|
8384
|
+
`
|
|
8385
|
+
).action(scopeSyncCommand);
|
|
8386
|
+
scopeCmd.command("analyze").description("Analyze scope usage in the project").addHelpText(
|
|
8387
|
+
"after",
|
|
8388
|
+
`
|
|
8389
|
+
${chalk22.bold("Details:")}
|
|
8390
|
+
Analyzes recent git commits to show:
|
|
8391
|
+
- Which scopes are used most frequently
|
|
8392
|
+
- Unused scopes that could be removed
|
|
8393
|
+
- Unknown scopes that could be added
|
|
8394
|
+
`
|
|
8395
|
+
).action(scopeAnalyzeCommand);
|
|
8396
|
+
const hooksCmd = scopeCmd.command("hooks").description("Manage git hooks for the project").addHelpText(
|
|
8397
|
+
"after",
|
|
8398
|
+
`
|
|
8399
|
+
${chalk22.bold("Examples:")}
|
|
8400
|
+
$ workflow scope hooks install ${chalk22.dim("# Install git hooks")}
|
|
8401
|
+
$ workflow scope hooks uninstall ${chalk22.dim("# Remove git hooks")}
|
|
8402
|
+
$ workflow scope hooks test ${chalk22.dim("# Verify installation")}
|
|
8403
|
+
$ workflow scope hooks test --dry-run ${chalk22.dim("# Test with simulation")}
|
|
8404
|
+
`
|
|
8405
|
+
).action(() => {
|
|
8406
|
+
hooksCommand("status");
|
|
8407
|
+
});
|
|
8408
|
+
hooksCmd.command("install").description("Install git hooks for the project").action(() => hooksCommand("install"));
|
|
8409
|
+
hooksCmd.command("uninstall").description("Remove installed git hooks").action(() => hooksCommand("uninstall"));
|
|
8410
|
+
hooksCmd.command("status").description("Show current hooks installation status").action(() => hooksCommand("status"));
|
|
8411
|
+
hooksCmd.command("test").description("Test that hooks are properly installed").option("--dry-run", "Simulate hook execution without making changes").action(hooksTestCommand);
|
|
7604
8412
|
return scopeCmd;
|
|
7605
8413
|
}
|
|
7606
8414
|
|
|
@@ -7610,7 +8418,7 @@ function deprecationWarning(oldCmd, newCmd) {
|
|
|
7610
8418
|
console.warn(chalk23.yellow(` Use: ${newCmd}
|
|
7611
8419
|
`));
|
|
7612
8420
|
}
|
|
7613
|
-
var program = new
|
|
8421
|
+
var program = new Command7();
|
|
7614
8422
|
program.name("workflow").description(
|
|
7615
8423
|
"A self-evolving workflow management system for AI agent development"
|
|
7616
8424
|
).version("1.0.0");
|
|
@@ -7618,7 +8426,6 @@ program.addCommand(createDocsCommand());
|
|
|
7618
8426
|
program.addCommand(createSolutionCommand());
|
|
7619
8427
|
program.addCommand(createLearnCommand());
|
|
7620
8428
|
program.addCommand(createScopeCommand());
|
|
7621
|
-
program.addCommand(createHooksCommand());
|
|
7622
8429
|
program.command("sync").description("Sync patterns and solutions with the community registry").option("--push", "Push local patterns to registry").option("--pull", "Pull patterns from registry").option("--solutions", "Include solution patterns").option("--learn", "Include learning patterns (default)").option("--scopes", "Sync custom scope packages").option("--all", "Sync everything").option("--dry-run", "Preview without syncing").addHelpText(
|
|
7623
8430
|
"after",
|
|
7624
8431
|
`
|
|
@@ -7679,18 +8486,18 @@ program.command("suggest").description("Submit an improvement suggestion").argum
|
|
|
7679
8486
|
"--category <category>",
|
|
7680
8487
|
"Category: feature, bug, documentation, performance, other"
|
|
7681
8488
|
).action(suggestCommand);
|
|
7682
|
-
program.
|
|
8489
|
+
program.addCommand(createSetupCommand());
|
|
7683
8490
|
program.command("doctor").description("Run health check and get optimization suggestions").option("--check-guidelines-only", "Only check guidelines presence").option("--fix", "Automatically fix validation issues in configuration").action(doctorCommand);
|
|
7684
|
-
program.command("hooks:install", { hidden: true }).description("[DEPRECATED] Use: workflow hooks install").action(async () => {
|
|
7685
|
-
deprecationWarning("workflow hooks:install", "workflow hooks install");
|
|
8491
|
+
program.command("hooks:install", { hidden: true }).description("[DEPRECATED] Use: workflow scope hooks install").action(async () => {
|
|
8492
|
+
deprecationWarning("workflow hooks:install", "workflow scope hooks install");
|
|
7686
8493
|
return hooksCommand("install");
|
|
7687
8494
|
});
|
|
7688
|
-
program.command("hooks:uninstall", { hidden: true }).description("[DEPRECATED] Use: workflow hooks uninstall").action(async () => {
|
|
7689
|
-
deprecationWarning("workflow hooks:uninstall", "workflow hooks uninstall");
|
|
8495
|
+
program.command("hooks:uninstall", { hidden: true }).description("[DEPRECATED] Use: workflow scope hooks uninstall").action(async () => {
|
|
8496
|
+
deprecationWarning("workflow hooks:uninstall", "workflow scope hooks uninstall");
|
|
7690
8497
|
return hooksCommand("uninstall");
|
|
7691
8498
|
});
|
|
7692
|
-
program.command("hooks:status", { hidden: true }).description("[DEPRECATED] Use: workflow hooks status").action(async () => {
|
|
7693
|
-
deprecationWarning("workflow hooks:status", "workflow hooks status");
|
|
8499
|
+
program.command("hooks:status", { hidden: true }).description("[DEPRECATED] Use: workflow scope hooks status").action(async () => {
|
|
8500
|
+
deprecationWarning("workflow hooks:status", "workflow scope hooks status");
|
|
7694
8501
|
return hooksCommand("status");
|
|
7695
8502
|
});
|
|
7696
8503
|
program.command("scope:create", { hidden: true }).description("[DEPRECATED] Use: workflow scope create").option("--name <name>", 'Package name (e.g., "fintech", "gaming")').option(
|
|
@@ -7705,7 +8512,11 @@ program.command("scope:migrate", { hidden: true }).description("[DEPRECATED] Use
|
|
|
7705
8512
|
return scopeMigrateCommand(options);
|
|
7706
8513
|
});
|
|
7707
8514
|
program.command("verify").description("Run all quality checks with fix-and-revalidate pattern").option("--fix", "Enable auto-fix for lint and format issues").option("--max-retries <n>", "Maximum retry cycles (default: 10)", "10").option("--commit", "Commit changes if all checks pass").option("--dry-run", "Preview fixes without applying them").option("--learn", "Record successful fixes as learning patterns").action(verifyCommand);
|
|
7708
|
-
program.command("
|
|
8515
|
+
program.command("pre-commit").description("Run pre-commit checks (alias for verify --fix --staged)").option("--dry-run", "Preview fixes without applying them").action(preCommitCommand);
|
|
8516
|
+
program.command("auto-setup", { hidden: true }).description("[DEPRECATED] Use: workflow setup auto").option("-y, --yes", "Auto-approve all prompts").option("--audit", "Show audit report without applying changes").action(async (options) => {
|
|
8517
|
+
deprecationWarning("workflow auto-setup", "workflow setup auto");
|
|
8518
|
+
return autoSetupCommand(options);
|
|
8519
|
+
});
|
|
7709
8520
|
program.command("advisory", { hidden: true }).description("[DEPRECATED] Use: workflow docs advisory").option("--depth <level>", "Analysis depth").option("--output <path>", "Output directory").option("--interactive", "Enable interactive mode").option("--dry-run", "Preview analysis without writing files").option("--format <type>", "Output format").option("--timestamp", "Append timestamp to filenames").option("--include-health", "Include code health metrics").option("--ci", "CI mode with exit codes").option("--compare <path>", "Compare with previous report").action(async (options) => {
|
|
7710
8521
|
deprecationWarning("workflow advisory", "workflow docs advisory");
|
|
7711
8522
|
return advisoryCommand(options);
|