workflow-agent-cli 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-4BIDFDSR.js → chunk-B27W7GWP.js} +118 -11
- package/dist/chunk-B27W7GWP.js.map +1 -0
- package/dist/cli/index.js +348 -54
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +8 -3
- package/dist/config/index.js +9 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9 -3
- package/dist/schema-C1lmnd7L.d.ts +256 -0
- package/dist/validators/index.d.ts +1 -1
- package/package.json +3 -1
- package/dist/chunk-4BIDFDSR.js.map +0 -1
- package/dist/schema-RkQ91pZW.d.ts +0 -161
package/dist/cli/index.js
CHANGED
|
@@ -5,13 +5,16 @@ import {
|
|
|
5
5
|
validatePRTitle
|
|
6
6
|
} from "../chunk-X2NQJ2ZY.js";
|
|
7
7
|
import {
|
|
8
|
+
DEFAULT_RESERVED_SCOPE_NAMES,
|
|
8
9
|
hasConfig,
|
|
9
10
|
loadConfig,
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
validateConfig,
|
|
12
|
+
validateScopeDefinitions,
|
|
13
|
+
validateScopeName
|
|
14
|
+
} from "../chunk-B27W7GWP.js";
|
|
12
15
|
|
|
13
16
|
// src/cli/index.ts
|
|
14
|
-
import { Command } from "commander";
|
|
17
|
+
import { Command as Command2 } from "commander";
|
|
15
18
|
|
|
16
19
|
// src/cli/commands/init.ts
|
|
17
20
|
import * as p from "@clack/prompts";
|
|
@@ -346,6 +349,8 @@ function generatePreCommitHook(config) {
|
|
|
346
349
|
return " workflow validate commit";
|
|
347
350
|
case "check-guidelines":
|
|
348
351
|
return " workflow doctor --check-guidelines-only 2>/dev/null || true";
|
|
352
|
+
case "validate-scopes":
|
|
353
|
+
return " workflow config validate";
|
|
349
354
|
default:
|
|
350
355
|
return "";
|
|
351
356
|
}
|
|
@@ -924,16 +929,16 @@ async function initCommand(options) {
|
|
|
924
929
|
console.log(chalk.yellow(`
|
|
925
930
|
\u26A0\uFE0F Could not load preset package. Using basic scopes.`));
|
|
926
931
|
scopes = [
|
|
927
|
-
{ name: "feat", description: "New features", emoji: "\u2728" },
|
|
928
|
-
{ name: "fix", description: "Bug fixes", emoji: "\u{1F41B}" },
|
|
929
|
-
{ name: "
|
|
932
|
+
{ name: "feat", description: "New features and enhancements", emoji: "\u2728" },
|
|
933
|
+
{ name: "fix", description: "Bug fixes and patches", emoji: "\u{1F41B}" },
|
|
934
|
+
{ name: "documentation", description: "Documentation updates and improvements", emoji: "\u{1F4DA}" }
|
|
930
935
|
];
|
|
931
936
|
}
|
|
932
937
|
} else {
|
|
933
938
|
scopes = [
|
|
934
|
-
{ name: "feat", description: "New features", emoji: "\u2728" },
|
|
935
|
-
{ name: "fix", description: "Bug fixes", emoji: "\u{1F41B}" },
|
|
936
|
-
{ name: "
|
|
939
|
+
{ name: "feat", description: "New features and enhancements", emoji: "\u2728" },
|
|
940
|
+
{ name: "fix", description: "Bug fixes and patches", emoji: "\u{1F41B}" },
|
|
941
|
+
{ name: "documentation", description: "Documentation updates and improvements", emoji: "\u{1F4DA}" }
|
|
937
942
|
];
|
|
938
943
|
console.log(chalk.dim("\n\u{1F4A1} Tip: Edit workflow.config.json to add your custom scopes"));
|
|
939
944
|
}
|
|
@@ -1141,10 +1146,299 @@ async function validateCommand(type, value, _options = {}) {
|
|
|
1141
1146
|
}
|
|
1142
1147
|
|
|
1143
1148
|
// src/cli/commands/config.ts
|
|
1149
|
+
import { Command } from "commander";
|
|
1150
|
+
import { join as join5 } from "path";
|
|
1151
|
+
import { existsSync as existsSync5, writeFileSync } from "fs";
|
|
1152
|
+
import prompts from "prompts";
|
|
1144
1153
|
import chalk3 from "chalk";
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1154
|
+
function createConfigCommand() {
|
|
1155
|
+
const command = new Command("config").description("Manage workflow configuration").option("-f, --force", "Skip validation checks").option("--cwd <path>", "Working directory", process.cwd());
|
|
1156
|
+
command.command("validate").description("Validate workflow configuration").action(async (options) => {
|
|
1157
|
+
const opts = command.opts();
|
|
1158
|
+
await validateConfigAction(opts);
|
|
1159
|
+
});
|
|
1160
|
+
command.command("add").description("Add configuration items").argument("<type>", "Type to add (scope)").action(async (type, options) => {
|
|
1161
|
+
const opts = command.opts();
|
|
1162
|
+
if (type === "scope") {
|
|
1163
|
+
await addScopeAction(opts);
|
|
1164
|
+
} else {
|
|
1165
|
+
console.error(chalk3.red(`Unknown type: ${type}. Currently only "scope" is supported.`));
|
|
1166
|
+
process.exit(1);
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
command.command("remove").description("Remove configuration items").argument("<type>", "Type to remove (scope)").argument("<name>", "Name of the item to remove").action(async (type, name, options) => {
|
|
1170
|
+
const opts = command.opts();
|
|
1171
|
+
if (type === "scope") {
|
|
1172
|
+
await removeScopeAction(name, opts);
|
|
1173
|
+
} else {
|
|
1174
|
+
console.error(chalk3.red(`Unknown type: ${type}. Currently only "scope" is supported.`));
|
|
1175
|
+
process.exit(1);
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
command.command("list").description("List configuration items").argument("[type]", "Type to list (scopes, reserved, all)", "all").action(async (type, options) => {
|
|
1179
|
+
const opts = command.opts();
|
|
1180
|
+
await listConfigAction(type, opts);
|
|
1181
|
+
});
|
|
1182
|
+
command.command("get").description("Get a configuration value").argument("<path>", "Configuration path (e.g., scopes[0].name)").action(async (path2, options) => {
|
|
1183
|
+
const opts = command.opts();
|
|
1184
|
+
await getConfigValue(path2, opts);
|
|
1185
|
+
});
|
|
1186
|
+
command.command("set").description("Set a configuration value").argument("<path>", "Configuration path (e.g., reservedScopeNames)").argument("<value>", "Value to set").action(async (path2, value, options) => {
|
|
1187
|
+
const opts = command.opts();
|
|
1188
|
+
await setConfigValue(path2, value, opts);
|
|
1189
|
+
});
|
|
1190
|
+
return command;
|
|
1191
|
+
}
|
|
1192
|
+
async function validateConfigAction(opts) {
|
|
1193
|
+
console.log(chalk3.blue("\u{1F50D} Validating workflow configuration..."));
|
|
1194
|
+
const result = await validateConfig(opts.cwd || process.cwd());
|
|
1195
|
+
if (result.valid) {
|
|
1196
|
+
console.log(chalk3.green("\u2713 Configuration is valid"));
|
|
1197
|
+
process.exit(0);
|
|
1198
|
+
} else {
|
|
1199
|
+
console.log(chalk3.red("\u2717 Configuration has errors:\n"));
|
|
1200
|
+
result.errors.forEach((err) => {
|
|
1201
|
+
console.log(chalk3.red(` \u2022 ${err}`));
|
|
1202
|
+
});
|
|
1203
|
+
if (result.warnings.length > 0) {
|
|
1204
|
+
console.log(chalk3.yellow("\n\u26A0 Warnings:\n"));
|
|
1205
|
+
result.warnings.forEach((warn) => {
|
|
1206
|
+
console.log(chalk3.yellow(` \u2022 ${warn}`));
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
console.log(chalk3.gray("\n\u{1F4A1} Fix these issues in workflow.config.json"));
|
|
1210
|
+
process.exit(1);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
async function addScopeAction(opts) {
|
|
1214
|
+
const cwd = opts.cwd || process.cwd();
|
|
1215
|
+
const configPath = join5(cwd, "workflow.config.json");
|
|
1216
|
+
if (!existsSync5(configPath)) {
|
|
1217
|
+
console.error(chalk3.red("No workflow.config.json found. Run: workflow init"));
|
|
1218
|
+
process.exit(1);
|
|
1219
|
+
}
|
|
1220
|
+
const config = await loadConfig(cwd);
|
|
1221
|
+
if (!config) {
|
|
1222
|
+
console.error(chalk3.red("Failed to load configuration"));
|
|
1223
|
+
process.exit(1);
|
|
1224
|
+
}
|
|
1225
|
+
const reservedNames = config.reservedScopeNames || DEFAULT_RESERVED_SCOPE_NAMES;
|
|
1226
|
+
const existingNames = config.scopes.map((s) => s.name);
|
|
1227
|
+
const response = await prompts([
|
|
1228
|
+
{
|
|
1229
|
+
type: "text",
|
|
1230
|
+
name: "name",
|
|
1231
|
+
message: "Scope name:",
|
|
1232
|
+
validate: (value) => {
|
|
1233
|
+
if (!value) return "Name is required";
|
|
1234
|
+
if (existingNames.includes(value)) return `Scope "${value}" already exists`;
|
|
1235
|
+
const validation = validateScopeName(value, reservedNames);
|
|
1236
|
+
if (!validation.valid) {
|
|
1237
|
+
return validation.error + (validation.suggestion ? ` Try: ${validation.suggestion}` : "");
|
|
1238
|
+
}
|
|
1239
|
+
return true;
|
|
1240
|
+
}
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
type: "text",
|
|
1244
|
+
name: "description",
|
|
1245
|
+
message: "Description:",
|
|
1246
|
+
validate: (value) => value ? true : "Description is required"
|
|
1247
|
+
},
|
|
1248
|
+
{
|
|
1249
|
+
type: "multiselect",
|
|
1250
|
+
name: "allowedTypes",
|
|
1251
|
+
message: "Allowed commit types (space to select, enter to continue):",
|
|
1252
|
+
choices: [
|
|
1253
|
+
{ title: "feat", value: "feat", selected: true },
|
|
1254
|
+
{ title: "fix", value: "fix", selected: true },
|
|
1255
|
+
{ title: "docs", value: "docs", selected: false },
|
|
1256
|
+
{ title: "style", value: "style", selected: false },
|
|
1257
|
+
{ title: "refactor", value: "refactor", selected: false },
|
|
1258
|
+
{ title: "perf", value: "perf", selected: false },
|
|
1259
|
+
{ title: "test", value: "test", selected: false },
|
|
1260
|
+
{ title: "build", value: "build", selected: false },
|
|
1261
|
+
{ title: "ci", value: "ci", selected: false },
|
|
1262
|
+
{ title: "chore", value: "chore", selected: false },
|
|
1263
|
+
{ title: "revert", value: "revert", selected: false }
|
|
1264
|
+
],
|
|
1265
|
+
min: 1
|
|
1266
|
+
},
|
|
1267
|
+
{
|
|
1268
|
+
type: "text",
|
|
1269
|
+
name: "mandatoryGuidelines",
|
|
1270
|
+
message: "Mandatory guidelines (comma-separated, or press enter to skip):",
|
|
1271
|
+
initial: ""
|
|
1272
|
+
}
|
|
1273
|
+
]);
|
|
1274
|
+
if (!response.name) {
|
|
1275
|
+
console.log(chalk3.yellow("Cancelled"));
|
|
1276
|
+
process.exit(0);
|
|
1277
|
+
}
|
|
1278
|
+
if (!opts.force) {
|
|
1279
|
+
const validation = validateScopeName(response.name, reservedNames);
|
|
1280
|
+
if (!validation.valid) {
|
|
1281
|
+
console.error(chalk3.red(`
|
|
1282
|
+
\u2717 ${validation.error}`));
|
|
1283
|
+
if (validation.suggestion) {
|
|
1284
|
+
console.log(chalk3.yellow(`\u{1F4A1} Suggestion: ${validation.suggestion}`));
|
|
1285
|
+
}
|
|
1286
|
+
console.log(chalk3.gray("\nUse --force to override this check"));
|
|
1287
|
+
process.exit(1);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
const newScope = {
|
|
1291
|
+
name: response.name,
|
|
1292
|
+
description: response.description,
|
|
1293
|
+
allowedTypes: response.allowedTypes
|
|
1294
|
+
};
|
|
1295
|
+
if (response.mandatoryGuidelines) {
|
|
1296
|
+
const guidelines = response.mandatoryGuidelines.split(",").map((g) => g.trim()).filter((g) => g.length > 0);
|
|
1297
|
+
if (guidelines.length > 0) {
|
|
1298
|
+
newScope.mandatoryGuidelines = guidelines;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
config.scopes.push(newScope);
|
|
1302
|
+
const configContent = JSON.stringify(config, null, 2) + "\n";
|
|
1303
|
+
writeFileSync(configPath, configContent, "utf-8");
|
|
1304
|
+
console.log(chalk3.green(`
|
|
1305
|
+
\u2713 Added scope: ${response.name}`));
|
|
1306
|
+
console.log(chalk3.gray(` Description: ${response.description}`));
|
|
1307
|
+
console.log(chalk3.gray(` Types: ${response.allowedTypes.join(", ")}`));
|
|
1308
|
+
if (newScope.mandatoryGuidelines) {
|
|
1309
|
+
console.log(chalk3.gray(` Guidelines: ${newScope.mandatoryGuidelines.join(", ")}`));
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
async function removeScopeAction(name, opts) {
|
|
1313
|
+
const cwd = opts.cwd || process.cwd();
|
|
1314
|
+
const configPath = join5(cwd, "workflow.config.json");
|
|
1315
|
+
if (!existsSync5(configPath)) {
|
|
1316
|
+
console.error(chalk3.red("No workflow.config.json found"));
|
|
1317
|
+
process.exit(1);
|
|
1318
|
+
}
|
|
1319
|
+
const config = await loadConfig(cwd);
|
|
1320
|
+
if (!config) {
|
|
1321
|
+
console.error(chalk3.red("Failed to load configuration"));
|
|
1322
|
+
process.exit(1);
|
|
1323
|
+
}
|
|
1324
|
+
const scopeIndex = config.scopes.findIndex((s) => s.name === name);
|
|
1325
|
+
if (scopeIndex === -1) {
|
|
1326
|
+
console.error(chalk3.red(`Scope "${name}" not found`));
|
|
1327
|
+
process.exit(1);
|
|
1328
|
+
}
|
|
1329
|
+
const response = await prompts({
|
|
1330
|
+
type: "confirm",
|
|
1331
|
+
name: "confirmed",
|
|
1332
|
+
message: `Remove scope "${name}"?`,
|
|
1333
|
+
initial: false
|
|
1334
|
+
});
|
|
1335
|
+
if (!response.confirmed) {
|
|
1336
|
+
console.log(chalk3.yellow("Cancelled"));
|
|
1337
|
+
process.exit(0);
|
|
1338
|
+
}
|
|
1339
|
+
config.scopes.splice(scopeIndex, 1);
|
|
1340
|
+
const configContent = JSON.stringify(config, null, 2) + "\n";
|
|
1341
|
+
writeFileSync(configPath, configContent, "utf-8");
|
|
1342
|
+
console.log(chalk3.green(`\u2713 Removed scope: ${name}`));
|
|
1343
|
+
}
|
|
1344
|
+
async function listConfigAction(type, opts) {
|
|
1345
|
+
const cwd = opts.cwd || process.cwd();
|
|
1346
|
+
const config = await loadConfig(cwd);
|
|
1347
|
+
if (!config) {
|
|
1348
|
+
console.error(chalk3.red("No configuration found"));
|
|
1349
|
+
process.exit(1);
|
|
1350
|
+
}
|
|
1351
|
+
if (type === "scopes" || type === "all") {
|
|
1352
|
+
console.log(chalk3.blue("\n\u{1F4CB} Scopes:"));
|
|
1353
|
+
if (config.scopes.length === 0) {
|
|
1354
|
+
console.log(chalk3.gray(" (none)"));
|
|
1355
|
+
} else {
|
|
1356
|
+
config.scopes.forEach((scope, index) => {
|
|
1357
|
+
console.log(chalk3.green(`
|
|
1358
|
+
${index + 1}. ${scope.name}`));
|
|
1359
|
+
console.log(chalk3.gray(` ${scope.description}`));
|
|
1360
|
+
console.log(chalk3.gray(` Types: ${scope.allowedTypes.join(", ")}`));
|
|
1361
|
+
if (scope.mandatoryGuidelines && scope.mandatoryGuidelines.length > 0) {
|
|
1362
|
+
console.log(chalk3.gray(` Guidelines: ${scope.mandatoryGuidelines.join(", ")}`));
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
if (type === "reserved" || type === "all") {
|
|
1368
|
+
const reserved = config.reservedScopeNames || DEFAULT_RESERVED_SCOPE_NAMES;
|
|
1369
|
+
console.log(chalk3.blue("\n\u{1F6AB} Reserved Scope Names:"));
|
|
1370
|
+
console.log(chalk3.gray(` ${reserved.join(", ")}`));
|
|
1371
|
+
console.log(chalk3.gray('\n \u{1F4A1} Configure in workflow.config.json: "reservedScopeNames"'));
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
async function getConfigValue(path2, opts) {
|
|
1375
|
+
const cwd = opts.cwd || process.cwd();
|
|
1376
|
+
const config = await loadConfig(cwd);
|
|
1377
|
+
if (!config) {
|
|
1378
|
+
console.error(chalk3.red("No configuration found"));
|
|
1379
|
+
process.exit(1);
|
|
1380
|
+
}
|
|
1381
|
+
const value = resolvePath(config, path2);
|
|
1382
|
+
if (value === void 0) {
|
|
1383
|
+
console.error(chalk3.red(`Path not found: ${path2}`));
|
|
1384
|
+
process.exit(1);
|
|
1385
|
+
}
|
|
1386
|
+
console.log(JSON.stringify(value, null, 2));
|
|
1387
|
+
}
|
|
1388
|
+
async function setConfigValue(path2, value, opts) {
|
|
1389
|
+
const cwd = opts.cwd || process.cwd();
|
|
1390
|
+
const configPath = join5(cwd, "workflow.config.json");
|
|
1391
|
+
if (!existsSync5(configPath)) {
|
|
1392
|
+
console.error(chalk3.red("No workflow.config.json found"));
|
|
1393
|
+
process.exit(1);
|
|
1394
|
+
}
|
|
1395
|
+
const config = await loadConfig(cwd);
|
|
1396
|
+
if (!config) {
|
|
1397
|
+
console.error(chalk3.red("Failed to load configuration"));
|
|
1398
|
+
process.exit(1);
|
|
1399
|
+
}
|
|
1400
|
+
let parsedValue;
|
|
1401
|
+
try {
|
|
1402
|
+
parsedValue = JSON.parse(value);
|
|
1403
|
+
} catch {
|
|
1404
|
+
parsedValue = value;
|
|
1405
|
+
}
|
|
1406
|
+
setPath(config, path2, parsedValue);
|
|
1407
|
+
if (!opts.force) {
|
|
1408
|
+
const validation = await validateConfig(cwd);
|
|
1409
|
+
if (!validation.valid) {
|
|
1410
|
+
console.error(chalk3.red("\u2717 Invalid configuration after change:"));
|
|
1411
|
+
validation.errors.forEach((err) => console.error(chalk3.red(` \u2022 ${err}`)));
|
|
1412
|
+
console.log(chalk3.gray("\nUse --force to skip validation"));
|
|
1413
|
+
process.exit(1);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
const configContent = JSON.stringify(config, null, 2) + "\n";
|
|
1417
|
+
writeFileSync(configPath, configContent, "utf-8");
|
|
1418
|
+
console.log(chalk3.green(`\u2713 Set ${path2} = ${JSON.stringify(parsedValue)}`));
|
|
1419
|
+
}
|
|
1420
|
+
function resolvePath(obj, path2) {
|
|
1421
|
+
const parts = path2.split(/[\.\[\]]+/).filter(Boolean);
|
|
1422
|
+
let current = obj;
|
|
1423
|
+
for (const part of parts) {
|
|
1424
|
+
if (current === void 0 || current === null) {
|
|
1425
|
+
return void 0;
|
|
1426
|
+
}
|
|
1427
|
+
current = current[part];
|
|
1428
|
+
}
|
|
1429
|
+
return current;
|
|
1430
|
+
}
|
|
1431
|
+
function setPath(obj, path2, value) {
|
|
1432
|
+
const parts = path2.split(/[\.\[\]]+/).filter(Boolean);
|
|
1433
|
+
let current = obj;
|
|
1434
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1435
|
+
const part = parts[i];
|
|
1436
|
+
if (current[part] === void 0) {
|
|
1437
|
+
current[part] = {};
|
|
1438
|
+
}
|
|
1439
|
+
current = current[part];
|
|
1440
|
+
}
|
|
1441
|
+
current[parts[parts.length - 1]] = value;
|
|
1148
1442
|
}
|
|
1149
1443
|
|
|
1150
1444
|
// src/cli/commands/suggest.ts
|
|
@@ -1192,9 +1486,9 @@ async function suggestCommand(feedback, options = {}) {
|
|
|
1192
1486
|
import chalk5 from "chalk";
|
|
1193
1487
|
|
|
1194
1488
|
// src/validators/guidelines.ts
|
|
1195
|
-
import { existsSync as
|
|
1489
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1196
1490
|
import { readFile as readFile3, readdir } from "fs/promises";
|
|
1197
|
-
import { join as
|
|
1491
|
+
import { join as join6 } from "path";
|
|
1198
1492
|
function getEffectiveMandatoryTemplates(guidelinesConfig) {
|
|
1199
1493
|
const coreMandatory = getMandatoryTemplateFilenames();
|
|
1200
1494
|
if (!guidelinesConfig) {
|
|
@@ -1214,7 +1508,7 @@ function getEffectiveMandatoryTemplates(guidelinesConfig) {
|
|
|
1214
1508
|
return mandatory;
|
|
1215
1509
|
}
|
|
1216
1510
|
async function validateGuidelinesExist(projectPath = process.cwd(), config) {
|
|
1217
|
-
const guidelinesDir =
|
|
1511
|
+
const guidelinesDir = join6(projectPath, "guidelines");
|
|
1218
1512
|
const result = {
|
|
1219
1513
|
valid: true,
|
|
1220
1514
|
missingMandatory: [],
|
|
@@ -1222,7 +1516,7 @@ async function validateGuidelinesExist(projectPath = process.cwd(), config) {
|
|
|
1222
1516
|
presentOptional: [],
|
|
1223
1517
|
errors: []
|
|
1224
1518
|
};
|
|
1225
|
-
if (!
|
|
1519
|
+
if (!existsSync6(guidelinesDir)) {
|
|
1226
1520
|
const mandatory2 = getEffectiveMandatoryTemplates(config?.guidelines);
|
|
1227
1521
|
result.valid = false;
|
|
1228
1522
|
result.missingMandatory = mandatory2;
|
|
@@ -1260,7 +1554,7 @@ async function validateGuidelinesExist(projectPath = process.cwd(), config) {
|
|
|
1260
1554
|
return result;
|
|
1261
1555
|
}
|
|
1262
1556
|
async function validateGitHubActionsSetup(projectPath = process.cwd()) {
|
|
1263
|
-
const workflowsDir =
|
|
1557
|
+
const workflowsDir = join6(projectPath, ".github", "workflows");
|
|
1264
1558
|
const result = {
|
|
1265
1559
|
valid: true,
|
|
1266
1560
|
hasWorkflowFile: false,
|
|
@@ -1272,7 +1566,7 @@ async function validateGitHubActionsSetup(projectPath = process.cwd()) {
|
|
|
1272
1566
|
errors: [],
|
|
1273
1567
|
warnings: []
|
|
1274
1568
|
};
|
|
1275
|
-
if (!
|
|
1569
|
+
if (!existsSync6(workflowsDir)) {
|
|
1276
1570
|
result.valid = false;
|
|
1277
1571
|
result.errors.push("GitHub Actions workflows directory does not exist. Run: workflow github:setup");
|
|
1278
1572
|
return result;
|
|
@@ -1293,7 +1587,7 @@ async function validateGitHubActionsSetup(projectPath = process.cwd()) {
|
|
|
1293
1587
|
return result;
|
|
1294
1588
|
}
|
|
1295
1589
|
result.hasWorkflowFile = true;
|
|
1296
|
-
const workflowPath =
|
|
1590
|
+
const workflowPath = join6(workflowsDir, ciWorkflows[0]);
|
|
1297
1591
|
let workflowContent = "";
|
|
1298
1592
|
try {
|
|
1299
1593
|
workflowContent = await readFile3(workflowPath, "utf-8");
|
|
@@ -1472,8 +1766,8 @@ async function doctorCommand(options = {}) {
|
|
|
1472
1766
|
// src/cli/commands/setup.ts
|
|
1473
1767
|
import * as p3 from "@clack/prompts";
|
|
1474
1768
|
import chalk6 from "chalk";
|
|
1475
|
-
import { readFileSync, writeFileSync, existsSync as
|
|
1476
|
-
import { join as
|
|
1769
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync7 } from "fs";
|
|
1770
|
+
import { join as join7 } from "path";
|
|
1477
1771
|
var WORKFLOW_SCRIPTS = {
|
|
1478
1772
|
"workflow:init": "workflow-agent init",
|
|
1479
1773
|
"workflow:validate": "workflow-agent validate",
|
|
@@ -1483,12 +1777,12 @@ var WORKFLOW_SCRIPTS = {
|
|
|
1483
1777
|
async function setupCommand() {
|
|
1484
1778
|
p3.intro(chalk6.bgBlue(" workflow-agent setup "));
|
|
1485
1779
|
const cwd = process.cwd();
|
|
1486
|
-
const packageJsonPath =
|
|
1487
|
-
if (!
|
|
1780
|
+
const packageJsonPath = join7(cwd, "package.json");
|
|
1781
|
+
if (!existsSync7(packageJsonPath)) {
|
|
1488
1782
|
p3.cancel("No package.json found in current directory");
|
|
1489
1783
|
process.exit(1);
|
|
1490
1784
|
}
|
|
1491
|
-
const packageJsonContent =
|
|
1785
|
+
const packageJsonContent = readFileSync2(packageJsonPath, "utf-8");
|
|
1492
1786
|
const packageJson = JSON.parse(packageJsonContent);
|
|
1493
1787
|
if (!packageJson.scripts) {
|
|
1494
1788
|
packageJson.scripts = {};
|
|
@@ -1527,7 +1821,7 @@ async function setupCommand() {
|
|
|
1527
1821
|
for (const [scriptName, scriptCommand] of Object.entries(scriptsToAdd)) {
|
|
1528
1822
|
packageJson.scripts[scriptName] = scriptCommand;
|
|
1529
1823
|
}
|
|
1530
|
-
|
|
1824
|
+
writeFileSync2(
|
|
1531
1825
|
packageJsonPath,
|
|
1532
1826
|
JSON.stringify(packageJson, null, 2) + "\n",
|
|
1533
1827
|
"utf-8"
|
|
@@ -1541,14 +1835,14 @@ async function setupCommand() {
|
|
|
1541
1835
|
// src/cli/commands/scope-create.ts
|
|
1542
1836
|
import * as p4 from "@clack/prompts";
|
|
1543
1837
|
import chalk7 from "chalk";
|
|
1544
|
-
import { existsSync as
|
|
1838
|
+
import { existsSync as existsSync8 } from "fs";
|
|
1545
1839
|
import { writeFile as writeFile4, mkdir as mkdir4, readFile as readFile4 } from "fs/promises";
|
|
1546
|
-
import { join as
|
|
1840
|
+
import { join as join8 } from "path";
|
|
1547
1841
|
async function scopeCreateCommand(options) {
|
|
1548
1842
|
console.log(chalk7.bold.cyan("\n\u{1F3A8} Create Custom Scope Package\n"));
|
|
1549
1843
|
const cwd = process.cwd();
|
|
1550
1844
|
const isNonInteractive = !!(options.name && options.scopes && options.presetName);
|
|
1551
|
-
const isMonorepo2 =
|
|
1845
|
+
const isMonorepo2 = existsSync8(join8(cwd, "pnpm-workspace.yaml"));
|
|
1552
1846
|
if (isMonorepo2) {
|
|
1553
1847
|
console.log(chalk7.dim("\u2713 Detected monorepo workspace\n"));
|
|
1554
1848
|
}
|
|
@@ -1683,7 +1977,7 @@ async function scopeCreateCommand(options) {
|
|
|
1683
1977
|
if (options.outputDir) {
|
|
1684
1978
|
outputDir = options.outputDir;
|
|
1685
1979
|
} else if (isMonorepo2) {
|
|
1686
|
-
outputDir =
|
|
1980
|
+
outputDir = join8(cwd, "packages", `scopes-${packageName}`);
|
|
1687
1981
|
} else {
|
|
1688
1982
|
const customDir = await p4.text({
|
|
1689
1983
|
message: "Output directory:",
|
|
@@ -1694,9 +1988,9 @@ async function scopeCreateCommand(options) {
|
|
|
1694
1988
|
p4.cancel("Operation cancelled");
|
|
1695
1989
|
process.exit(0);
|
|
1696
1990
|
}
|
|
1697
|
-
outputDir =
|
|
1991
|
+
outputDir = join8(cwd, customDir);
|
|
1698
1992
|
}
|
|
1699
|
-
if (
|
|
1993
|
+
if (existsSync8(outputDir)) {
|
|
1700
1994
|
const shouldOverwrite = await p4.confirm({
|
|
1701
1995
|
message: `Directory ${outputDir} already exists. Overwrite?`,
|
|
1702
1996
|
initialValue: false
|
|
@@ -1709,7 +2003,7 @@ async function scopeCreateCommand(options) {
|
|
|
1709
2003
|
const spinner5 = p4.spinner();
|
|
1710
2004
|
spinner5.start("Creating package structure...");
|
|
1711
2005
|
try {
|
|
1712
|
-
await mkdir4(
|
|
2006
|
+
await mkdir4(join8(outputDir, "src"), { recursive: true });
|
|
1713
2007
|
const packageJson = {
|
|
1714
2008
|
name: `@workflow/scopes-${packageName}`,
|
|
1715
2009
|
version: "1.0.0",
|
|
@@ -1750,7 +2044,7 @@ async function scopeCreateCommand(options) {
|
|
|
1750
2044
|
}
|
|
1751
2045
|
};
|
|
1752
2046
|
await writeFile4(
|
|
1753
|
-
|
|
2047
|
+
join8(outputDir, "package.json"),
|
|
1754
2048
|
JSON.stringify(packageJson, null, 2),
|
|
1755
2049
|
"utf-8"
|
|
1756
2050
|
);
|
|
@@ -1763,7 +2057,7 @@ async function scopeCreateCommand(options) {
|
|
|
1763
2057
|
include: ["src/**/*"]
|
|
1764
2058
|
};
|
|
1765
2059
|
await writeFile4(
|
|
1766
|
-
|
|
2060
|
+
join8(outputDir, "tsconfig.json"),
|
|
1767
2061
|
JSON.stringify(tsconfig, null, 2),
|
|
1768
2062
|
"utf-8"
|
|
1769
2063
|
);
|
|
@@ -1777,7 +2071,7 @@ export default defineConfig({
|
|
|
1777
2071
|
sourcemap: true,
|
|
1778
2072
|
});
|
|
1779
2073
|
`;
|
|
1780
|
-
await writeFile4(
|
|
2074
|
+
await writeFile4(join8(outputDir, "tsup.config.ts"), tsupConfig, "utf-8");
|
|
1781
2075
|
const indexTs = `import type { Scope } from '@hawkinside_out/workflow-agent/config';
|
|
1782
2076
|
|
|
1783
2077
|
export const scopes: Scope[] = ${JSON.stringify(scopes, null, 2)};
|
|
@@ -1791,7 +2085,7 @@ export const preset = {
|
|
|
1791
2085
|
|
|
1792
2086
|
export default preset;
|
|
1793
2087
|
`;
|
|
1794
|
-
await writeFile4(
|
|
2088
|
+
await writeFile4(join8(outputDir, "src", "index.ts"), indexTs, "utf-8");
|
|
1795
2089
|
if (!options.noTest) {
|
|
1796
2090
|
const testFile = `import { describe, it, expect } from 'vitest';
|
|
1797
2091
|
import { scopes, preset } from './index.js';
|
|
@@ -1832,11 +2126,11 @@ describe('${presetName} Scope Preset', () => {
|
|
|
1832
2126
|
});
|
|
1833
2127
|
});
|
|
1834
2128
|
`;
|
|
1835
|
-
await writeFile4(
|
|
2129
|
+
await writeFile4(join8(outputDir, "src", "index.test.ts"), testFile, "utf-8");
|
|
1836
2130
|
}
|
|
1837
2131
|
spinner5.stop("\u2713 Package structure created");
|
|
1838
2132
|
if (isMonorepo2) {
|
|
1839
|
-
const workspaceFile =
|
|
2133
|
+
const workspaceFile = join8(cwd, "pnpm-workspace.yaml");
|
|
1840
2134
|
const workspaceContent = await readFile4(workspaceFile, "utf-8");
|
|
1841
2135
|
const packagePath = `packages/scopes-${packageName}`;
|
|
1842
2136
|
if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
|
|
@@ -1881,9 +2175,9 @@ describe('${presetName} Scope Preset', () => {
|
|
|
1881
2175
|
// src/cli/commands/scope-migrate.ts
|
|
1882
2176
|
import * as p5 from "@clack/prompts";
|
|
1883
2177
|
import chalk8 from "chalk";
|
|
1884
|
-
import { existsSync as
|
|
2178
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1885
2179
|
import { writeFile as writeFile5, mkdir as mkdir5, readFile as readFile5 } from "fs/promises";
|
|
1886
|
-
import { join as
|
|
2180
|
+
import { join as join9 } from "path";
|
|
1887
2181
|
async function scopeMigrateCommand(options) {
|
|
1888
2182
|
console.log(chalk8.bold.cyan("\n\u{1F504} Migrate Scopes to Custom Package\n"));
|
|
1889
2183
|
const cwd = process.cwd();
|
|
@@ -1921,7 +2215,7 @@ async function scopeMigrateCommand(options) {
|
|
|
1921
2215
|
p5.cancel("Migration cancelled");
|
|
1922
2216
|
process.exit(0);
|
|
1923
2217
|
}
|
|
1924
|
-
const isMonorepo2 =
|
|
2218
|
+
const isMonorepo2 = existsSync9(join9(cwd, "pnpm-workspace.yaml"));
|
|
1925
2219
|
if (isMonorepo2) {
|
|
1926
2220
|
console.log(chalk8.dim("\n\u2713 Detected monorepo workspace\n"));
|
|
1927
2221
|
}
|
|
@@ -1967,7 +2261,7 @@ async function scopeMigrateCommand(options) {
|
|
|
1967
2261
|
if (options.outputDir) {
|
|
1968
2262
|
outputDir = options.outputDir;
|
|
1969
2263
|
} else if (isMonorepo2) {
|
|
1970
|
-
outputDir =
|
|
2264
|
+
outputDir = join9(cwd, "packages", `scopes-${packageName}`);
|
|
1971
2265
|
} else {
|
|
1972
2266
|
const customDir = await p5.text({
|
|
1973
2267
|
message: "Output directory:",
|
|
@@ -1978,9 +2272,9 @@ async function scopeMigrateCommand(options) {
|
|
|
1978
2272
|
p5.cancel("Migration cancelled");
|
|
1979
2273
|
process.exit(0);
|
|
1980
2274
|
}
|
|
1981
|
-
outputDir =
|
|
2275
|
+
outputDir = join9(cwd, customDir);
|
|
1982
2276
|
}
|
|
1983
|
-
if (
|
|
2277
|
+
if (existsSync9(outputDir)) {
|
|
1984
2278
|
const shouldOverwrite = await p5.confirm({
|
|
1985
2279
|
message: `Directory ${outputDir} already exists. Overwrite?`,
|
|
1986
2280
|
initialValue: false
|
|
@@ -1993,7 +2287,7 @@ async function scopeMigrateCommand(options) {
|
|
|
1993
2287
|
const spinner5 = p5.spinner();
|
|
1994
2288
|
spinner5.start("Migrating scopes to package...");
|
|
1995
2289
|
try {
|
|
1996
|
-
await mkdir5(
|
|
2290
|
+
await mkdir5(join9(outputDir, "src"), { recursive: true });
|
|
1997
2291
|
const packageJson = {
|
|
1998
2292
|
name: `@workflow/scopes-${packageName}`,
|
|
1999
2293
|
version: "1.0.0",
|
|
@@ -2034,7 +2328,7 @@ async function scopeMigrateCommand(options) {
|
|
|
2034
2328
|
}
|
|
2035
2329
|
};
|
|
2036
2330
|
await writeFile5(
|
|
2037
|
-
|
|
2331
|
+
join9(outputDir, "package.json"),
|
|
2038
2332
|
JSON.stringify(packageJson, null, 2),
|
|
2039
2333
|
"utf-8"
|
|
2040
2334
|
);
|
|
@@ -2047,7 +2341,7 @@ async function scopeMigrateCommand(options) {
|
|
|
2047
2341
|
include: ["src/**/*"]
|
|
2048
2342
|
};
|
|
2049
2343
|
await writeFile5(
|
|
2050
|
-
|
|
2344
|
+
join9(outputDir, "tsconfig.json"),
|
|
2051
2345
|
JSON.stringify(tsconfig, null, 2),
|
|
2052
2346
|
"utf-8"
|
|
2053
2347
|
);
|
|
@@ -2061,7 +2355,7 @@ export default defineConfig({
|
|
|
2061
2355
|
sourcemap: true,
|
|
2062
2356
|
});
|
|
2063
2357
|
`;
|
|
2064
|
-
await writeFile5(
|
|
2358
|
+
await writeFile5(join9(outputDir, "tsup.config.ts"), tsupConfig, "utf-8");
|
|
2065
2359
|
const indexTs = `import type { Scope } from '@hawkinside_out/workflow-agent/config';
|
|
2066
2360
|
|
|
2067
2361
|
export const scopes: Scope[] = ${JSON.stringify(config.scopes, null, 2)};
|
|
@@ -2075,7 +2369,7 @@ export const preset = {
|
|
|
2075
2369
|
|
|
2076
2370
|
export default preset;
|
|
2077
2371
|
`;
|
|
2078
|
-
await writeFile5(
|
|
2372
|
+
await writeFile5(join9(outputDir, "src", "index.ts"), indexTs, "utf-8");
|
|
2079
2373
|
const testFile = `import { describe, it, expect } from 'vitest';
|
|
2080
2374
|
import { scopes, preset } from './index.js';
|
|
2081
2375
|
import { ScopeSchema } from '@hawkinside_out/workflow-agent/config';
|
|
@@ -2118,10 +2412,10 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
2118
2412
|
});
|
|
2119
2413
|
});
|
|
2120
2414
|
`;
|
|
2121
|
-
await writeFile5(
|
|
2415
|
+
await writeFile5(join9(outputDir, "src", "index.test.ts"), testFile, "utf-8");
|
|
2122
2416
|
spinner5.stop("\u2713 Package created from migrated scopes");
|
|
2123
2417
|
if (isMonorepo2) {
|
|
2124
|
-
const workspaceFile =
|
|
2418
|
+
const workspaceFile = join9(cwd, "pnpm-workspace.yaml");
|
|
2125
2419
|
const workspaceContent = await readFile5(workspaceFile, "utf-8");
|
|
2126
2420
|
const packagePath = `packages/scopes-${packageName}`;
|
|
2127
2421
|
if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
|
|
@@ -2136,7 +2430,7 @@ describe('${presetName} Scope Preset (Migrated)', () => {
|
|
|
2136
2430
|
initialValue: false
|
|
2137
2431
|
});
|
|
2138
2432
|
if (!p5.isCancel(keepConfig) && !keepConfig) {
|
|
2139
|
-
const configPath =
|
|
2433
|
+
const configPath = join9(cwd, "workflow.config.json");
|
|
2140
2434
|
const updatedConfig = {
|
|
2141
2435
|
...config,
|
|
2142
2436
|
scopes: [],
|
|
@@ -2415,11 +2709,11 @@ async function checkAction(cwd) {
|
|
|
2415
2709
|
}
|
|
2416
2710
|
|
|
2417
2711
|
// src/cli/index.ts
|
|
2418
|
-
var program = new
|
|
2712
|
+
var program = new Command2();
|
|
2419
2713
|
program.name("workflow").description("A self-evolving workflow management system for AI agent development").version("1.0.0");
|
|
2420
2714
|
program.command("init").description("Initialize workflow in current project").option("--migrate", "Auto-detect existing patterns and migrate").option("--workspace", "Initialize for multiple repositories").option("--preset <preset>", "Preset to use (saas, library, api, ecommerce, cms, custom)").option("--name <name>", "Project name").option("-y, --yes", "Skip confirmation prompts").action(initCommand);
|
|
2421
2715
|
program.command("validate <type>").description("Validate branch name, commit message, or PR title").argument("<type>", "What to validate: branch, commit, or pr").argument("[value]", "Value to validate (defaults to current branch/HEAD commit)").option("--suggest-on-error", "Offer improvement suggestions on validation errors").action(validateCommand);
|
|
2422
|
-
program.
|
|
2716
|
+
program.addCommand(createConfigCommand());
|
|
2423
2717
|
program.command("suggest").description("Submit an improvement suggestion").argument("<feedback>", "Your improvement suggestion").option("--author <author>", "Your name or username").option("--category <category>", "Category: feature, bug, documentation, performance, other").action(suggestCommand);
|
|
2424
2718
|
program.command("setup").description("Add workflow scripts to package.json").action(setupCommand);
|
|
2425
2719
|
program.command("doctor").description("Run health check and get optimization suggestions").option("--check-guidelines-only", "Only check mandatory guidelines exist (exits 0 or 1)").action(doctorCommand);
|