workflow-agent-cli 2.1.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  validateBranchName,
4
4
  validateCommitMessage,
5
5
  validatePRTitle
6
- } from "../chunk-X2NQJ2ZY.js";
6
+ } from "../chunk-NMHWD2GA.js";
7
7
  import {
8
8
  DEFAULT_RESERVED_SCOPE_NAMES,
9
9
  hasConfig,
@@ -11,7 +11,7 @@ import {
11
11
  validateConfig,
12
12
  validateScopeDefinitions,
13
13
  validateScopeName
14
- } from "../chunk-B27W7GWP.js";
14
+ } from "../chunk-JCDT4363.js";
15
15
 
16
16
  // src/cli/index.ts
17
17
  import { Command as Command2 } from "commander";
@@ -79,7 +79,7 @@ var adapters = {
79
79
  config: "src"
80
80
  }
81
81
  },
82
- "remix": {
82
+ remix: {
83
83
  name: "Remix",
84
84
  description: "Remix full-stack framework",
85
85
  detect: async () => {
@@ -94,7 +94,7 @@ var adapters = {
94
94
  config: "app/root.tsx"
95
95
  }
96
96
  },
97
- "astro": {
97
+ astro: {
98
98
  name: "Astro",
99
99
  description: "Astro static site framework",
100
100
  detect: async () => {
@@ -109,7 +109,7 @@ var adapters = {
109
109
  config: "src/pages"
110
110
  }
111
111
  },
112
- "sveltekit": {
112
+ sveltekit: {
113
113
  name: "SvelteKit",
114
114
  description: "SvelteKit full-stack framework",
115
115
  detect: async () => {
@@ -124,7 +124,7 @@ var adapters = {
124
124
  config: "src/routes"
125
125
  }
126
126
  },
127
- "generic": {
127
+ generic: {
128
128
  name: "Generic Project",
129
129
  description: "Standard project structure",
130
130
  detect: async () => true,
@@ -210,7 +210,9 @@ async function validateTemplateDirectory(templateDir) {
210
210
  const files = await fs.readdir(templateDir);
211
211
  const templateFiles = files.filter((f) => f.match(/\.(md|ts|json)$/));
212
212
  if (templateFiles.length === 0) {
213
- throw new Error(`No template files found in template directory: ${templateDir}`);
213
+ throw new Error(
214
+ `No template files found in template directory: ${templateDir}`
215
+ );
214
216
  }
215
217
  } catch (error) {
216
218
  if (error.code === "ENOENT") {
@@ -470,12 +472,14 @@ async function installSingleHook(hookType, config, projectPath = process.cwd())
470
472
  }
471
473
  async function installHooks(config, projectPath = process.cwd()) {
472
474
  if (!hasGitRepo(projectPath)) {
473
- return [{
474
- success: false,
475
- hookType: "pre-commit",
476
- wrappedExisting: false,
477
- error: "No git repository found. Run git init first."
478
- }];
475
+ return [
476
+ {
477
+ success: false,
478
+ hookType: "pre-commit",
479
+ wrappedExisting: false,
480
+ error: "No git repository found. Run git init first."
481
+ }
482
+ ];
479
483
  }
480
484
  const results = await Promise.all([
481
485
  installSingleHook("pre-commit", config, projectPath),
@@ -535,7 +539,9 @@ async function isGitRepo(projectPath = process.cwd()) {
535
539
  }
536
540
  async function getGitRemoteUrl(projectPath = process.cwd()) {
537
541
  try {
538
- const { stdout } = await execa("git", ["remote", "get-url", "origin"], { cwd: projectPath });
542
+ const { stdout } = await execa("git", ["remote", "get-url", "origin"], {
543
+ cwd: projectPath
544
+ });
539
545
  return stdout.trim() || null;
540
546
  } catch {
541
547
  return null;
@@ -558,15 +564,23 @@ function parseGitHubUrl(remoteUrl) {
558
564
  }
559
565
  async function getDefaultBranch(projectPath = process.cwd()) {
560
566
  try {
561
- const { stdout } = await execa("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
562
- cwd: projectPath
563
- });
567
+ const { stdout } = await execa(
568
+ "git",
569
+ ["symbolic-ref", "refs/remotes/origin/HEAD"],
570
+ {
571
+ cwd: projectPath
572
+ }
573
+ );
564
574
  return stdout.trim().replace("refs/remotes/origin/", "") || "main";
565
575
  } catch {
566
576
  try {
567
- const { stdout } = await execa("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
568
- cwd: projectPath
569
- });
577
+ const { stdout } = await execa(
578
+ "git",
579
+ ["rev-parse", "--abbrev-ref", "HEAD"],
580
+ {
581
+ cwd: projectPath
582
+ }
583
+ );
570
584
  return stdout.trim() || "main";
571
585
  } catch {
572
586
  return "main";
@@ -758,7 +772,11 @@ function generateCIWorkflowContent(options) {
758
772
  }
759
773
  if (checks.includes("typecheck")) {
760
774
  if (hasTypecheckScript) {
761
- const typecheckCmd = getRunCommand(packageManager, "typecheck", isMonorepo2);
775
+ const typecheckCmd = getRunCommand(
776
+ packageManager,
777
+ "typecheck",
778
+ isMonorepo2
779
+ );
762
780
  steps.push(`
763
781
  - name: Type check
764
782
  run: ${typecheckCmd}`);
@@ -770,7 +788,11 @@ function generateCIWorkflowContent(options) {
770
788
  }
771
789
  if (checks.includes("format")) {
772
790
  if (hasFormatScript) {
773
- const formatCmd = getRunCommand(packageManager, "format:check", isMonorepo2);
791
+ const formatCmd = getRunCommand(
792
+ packageManager,
793
+ "format:check",
794
+ isMonorepo2
795
+ );
774
796
  steps.push(`
775
797
  - name: Format check
776
798
  run: ${formatCmd} || npx prettier --check "**/*.{ts,tsx,js,jsx,json,md}"`);
@@ -844,7 +866,13 @@ async function createCIWorkflow(options = {}) {
844
866
  const projectInfo = await getProjectInfo(projectPath);
845
867
  const packageManager = options.packageManager || projectInfo.packageManager;
846
868
  const isMonorepo2 = options.isMonorepo ?? projectInfo.isMonorepo;
847
- const checks = options.ciConfig?.checks || ["lint", "typecheck", "format", "build", "test"];
869
+ const checks = options.ciConfig?.checks || [
870
+ "lint",
871
+ "typecheck",
872
+ "format",
873
+ "build",
874
+ "test"
875
+ ];
848
876
  const nodeVersions = options.nodeVersions || ["20"];
849
877
  const defaultBranch = options.defaultBranch || "main";
850
878
  if (!existsSync3(workflowsDir)) {
@@ -904,12 +932,30 @@ async function initCommand(options) {
904
932
  const preset = isNonInteractive ? options.preset : await p.select({
905
933
  message: "Choose a scope preset for your project:",
906
934
  options: [
907
- { value: "saas", label: "\u{1F4E6} SaaS Application - 17 scopes (auth, tasks, boards, sprints, etc.)" },
908
- { value: "library", label: "\u{1F4DA} Library/Package - 10 scopes (types, build, docs, examples, etc.)" },
909
- { value: "api", label: "\u{1F50C} API/Backend - 13 scopes (auth, endpoints, models, services, etc.)" },
910
- { value: "ecommerce", label: "\u{1F6D2} E-commerce - 12 scopes (cart, products, payments, orders, etc.)" },
911
- { value: "cms", label: "\u{1F4DD} CMS - 13 scopes (content, pages, media, editor, etc.)" },
912
- { value: "custom", label: "\u2728 Custom (define your own scopes manually)" }
935
+ {
936
+ value: "saas",
937
+ label: "\u{1F4E6} SaaS Application - 17 scopes (auth, tasks, boards, sprints, etc.)"
938
+ },
939
+ {
940
+ value: "library",
941
+ label: "\u{1F4DA} Library/Package - 10 scopes (types, build, docs, examples, etc.)"
942
+ },
943
+ {
944
+ value: "api",
945
+ label: "\u{1F50C} API/Backend - 13 scopes (auth, endpoints, models, services, etc.)"
946
+ },
947
+ {
948
+ value: "ecommerce",
949
+ label: "\u{1F6D2} E-commerce - 12 scopes (cart, products, payments, orders, etc.)"
950
+ },
951
+ {
952
+ value: "cms",
953
+ label: "\u{1F4DD} CMS - 13 scopes (content, pages, media, editor, etc.)"
954
+ },
955
+ {
956
+ value: "custom",
957
+ label: "\u2728 Custom (define your own scopes manually)"
958
+ }
913
959
  ]
914
960
  });
915
961
  if (!isNonInteractive && p.isCancel(preset)) {
@@ -926,27 +972,62 @@ async function initCommand(options) {
926
972
  await new Promise((resolve) => setTimeout(resolve, 500));
927
973
  spinner5.stop(`\u2713 Loaded ${scopes.length} scopes from preset`);
928
974
  } catch (error) {
929
- console.log(chalk.yellow(`
930
- \u26A0\uFE0F Could not load preset package. Using basic scopes.`));
975
+ console.log(
976
+ chalk.yellow(
977
+ `
978
+ \u26A0\uFE0F Could not load preset package. Using basic scopes.`
979
+ )
980
+ );
931
981
  scopes = [
932
- { name: "feat", description: "New features and enhancements", emoji: "\u2728" },
982
+ {
983
+ name: "feat",
984
+ description: "New features and enhancements",
985
+ emoji: "\u2728"
986
+ },
933
987
  { name: "fix", description: "Bug fixes and patches", emoji: "\u{1F41B}" },
934
- { name: "documentation", description: "Documentation updates and improvements", emoji: "\u{1F4DA}" }
988
+ {
989
+ name: "documentation",
990
+ description: "Documentation updates and improvements",
991
+ emoji: "\u{1F4DA}"
992
+ }
935
993
  ];
936
994
  }
937
995
  } else {
938
996
  scopes = [
939
- { name: "feat", description: "New features and enhancements", emoji: "\u2728" },
997
+ {
998
+ name: "feat",
999
+ description: "New features and enhancements",
1000
+ emoji: "\u2728"
1001
+ },
940
1002
  { name: "fix", description: "Bug fixes and patches", emoji: "\u{1F41B}" },
941
- { name: "documentation", description: "Documentation updates and improvements", emoji: "\u{1F4DA}" }
1003
+ {
1004
+ name: "documentation",
1005
+ description: "Documentation updates and improvements",
1006
+ emoji: "\u{1F4DA}"
1007
+ }
942
1008
  ];
943
- console.log(chalk.dim("\n\u{1F4A1} Tip: Edit workflow.config.json to add your custom scopes"));
1009
+ console.log(
1010
+ chalk.dim(
1011
+ "\n\u{1F4A1} Tip: Edit workflow.config.json to add your custom scopes"
1012
+ )
1013
+ );
944
1014
  }
945
1015
  const config = {
946
1016
  projectName,
947
1017
  scopes,
948
1018
  enforcement: "strict",
949
- language: "en"
1019
+ language: "en",
1020
+ hooks: {
1021
+ enabled: true,
1022
+ preCommit: ["validate-branch", "check-guidelines"],
1023
+ commitMsg: ["validate-commit"]
1024
+ },
1025
+ ci: {
1026
+ enabled: true,
1027
+ provider: "github",
1028
+ checks: ["lint", "typecheck", "format", "build", "test"]
1029
+ },
1030
+ reservedScopeNames: DEFAULT_RESERVED_SCOPE_NAMES
950
1031
  };
951
1032
  const configPath = join4(cwd, "workflow.config.json");
952
1033
  await writeFile3(configPath, JSON.stringify(config, null, 2));
@@ -958,8 +1039,12 @@ async function initCommand(options) {
958
1039
  const projectInfo = await getProjectInfo(cwd);
959
1040
  const mandatoryTemplates = getMandatoryTemplates();
960
1041
  const optionalTemplates = getOptionalTemplates();
961
- console.log(chalk.dim(`
962
- \u{1F4CB} Generating ${mandatoryTemplates.length} mandatory guidelines...`));
1042
+ console.log(
1043
+ chalk.dim(
1044
+ `
1045
+ \u{1F4CB} Generating ${mandatoryTemplates.length} mandatory guidelines...`
1046
+ )
1047
+ );
963
1048
  const guidelinesDir = join4(cwd, "guidelines");
964
1049
  const templatesDir = join4(__dirname, "../../templates");
965
1050
  let mandatoryGenerated = 0;
@@ -972,13 +1057,20 @@ async function initCommand(options) {
972
1057
  try {
973
1058
  const templatePath = join4(templatesDir, template.filename);
974
1059
  const outputPath = join4(guidelinesDir, template.filename);
975
- await renderTemplateFile(templatePath, outputPath, context);
1060
+ await renderTemplateFile(templatePath, outputPath, {
1061
+ ...context,
1062
+ reservedScopeNames: (config.reservedScopeNames || []).join(", ")
1063
+ });
976
1064
  mandatoryGenerated++;
977
1065
  } catch (error) {
978
- console.log(chalk.yellow(` \u26A0\uFE0F Could not generate ${template.filename}`));
1066
+ console.log(
1067
+ chalk.yellow(` \u26A0\uFE0F Could not generate ${template.filename}`)
1068
+ );
979
1069
  }
980
1070
  }
981
- console.log(chalk.green(`\u2713 Generated ${mandatoryGenerated} mandatory guidelines`));
1071
+ console.log(
1072
+ chalk.green(`\u2713 Generated ${mandatoryGenerated} mandatory guidelines`)
1073
+ );
982
1074
  let shouldGenerateOptional = isNonInteractive;
983
1075
  if (!isNonInteractive) {
984
1076
  const response = await p.confirm({
@@ -997,11 +1089,17 @@ async function initCommand(options) {
997
1089
  } catch {
998
1090
  }
999
1091
  }
1000
- console.log(chalk.green(`\u2713 Generated ${optionalGenerated} optional guidelines`));
1092
+ console.log(
1093
+ chalk.green(`\u2713 Generated ${optionalGenerated} optional guidelines`)
1094
+ );
1001
1095
  }
1002
1096
  } catch (error) {
1003
- console.log(chalk.yellow(`
1004
- \u26A0\uFE0F Could not generate guidelines: ${error instanceof Error ? error.message : String(error)}`));
1097
+ console.log(
1098
+ chalk.yellow(
1099
+ `
1100
+ \u26A0\uFE0F Could not generate guidelines: ${error instanceof Error ? error.message : String(error)}`
1101
+ )
1102
+ );
1005
1103
  console.log(chalk.dim("You can manually copy guidelines later if needed."));
1006
1104
  }
1007
1105
  if (hasGitRepo(cwd)) {
@@ -1016,7 +1114,14 @@ async function initCommand(options) {
1016
1114
  if (shouldInstallHooks) {
1017
1115
  const hookSpinner = p.spinner();
1018
1116
  hookSpinner.start("Installing git hooks...");
1019
- const hookResults = await installHooks(config.hooks, cwd);
1117
+ const hookResults = await installHooks(
1118
+ config.hooks || {
1119
+ enabled: true,
1120
+ preCommit: ["validate-branch", "check-guidelines"],
1121
+ commitMsg: ["validate-commit"]
1122
+ },
1123
+ cwd
1124
+ );
1020
1125
  const allSuccess = hookResults.every((r) => r.success);
1021
1126
  if (allSuccess) {
1022
1127
  hookSpinner.stop("\u2713 Installed git hooks");
@@ -1028,19 +1133,29 @@ async function initCommand(options) {
1028
1133
  if (repoInfo.isGitHub) {
1029
1134
  const existingCI = hasCIWorkflow(cwd);
1030
1135
  if (!existingCI) {
1031
- console.log(chalk.dim("\n\u{1F527} Setting up GitHub Actions CI (mandatory for GitHub repos)..."));
1136
+ console.log(
1137
+ chalk.dim(
1138
+ "\n\u{1F527} Setting up GitHub Actions CI (mandatory for GitHub repos)..."
1139
+ )
1140
+ );
1032
1141
  const ciResult = await createCIWorkflow({
1033
1142
  projectPath: cwd,
1034
1143
  packageManager: projectInfo.packageManager,
1035
1144
  isMonorepo: projectInfo.isMonorepo,
1036
- ciConfig: config.ci,
1145
+ ciConfig: config.ci || {
1146
+ enabled: true,
1147
+ provider: "github",
1148
+ checks: ["lint", "typecheck", "format", "build", "test"]
1149
+ },
1037
1150
  defaultBranch: repoInfo.defaultBranch || "main"
1038
1151
  });
1039
1152
  if (ciResult.success) {
1040
1153
  console.log(chalk.green("\u2713 Created GitHub Actions CI workflow"));
1041
1154
  console.log(chalk.dim(` File: .github/workflows/ci.yml`));
1042
1155
  } else {
1043
- console.log(chalk.yellow(`\u26A0\uFE0F Could not create CI workflow: ${ciResult.error}`));
1156
+ console.log(
1157
+ chalk.yellow(`\u26A0\uFE0F Could not create CI workflow: ${ciResult.error}`)
1158
+ );
1044
1159
  }
1045
1160
  } else {
1046
1161
  console.log(chalk.dim("\n\u2713 GitHub Actions CI workflow already exists"));
@@ -1068,13 +1183,21 @@ async function initCommand(options) {
1068
1183
  }
1069
1184
  p.outro(chalk.green("\u2713 Workflow Agent initialized successfully!"));
1070
1185
  console.log(chalk.dim("\nNext steps:"));
1071
- console.log(chalk.dim(" 1. Review your configuration in workflow.config.json"));
1072
- console.log(chalk.dim(" 2. Review generated guidelines in guidelines/ directory"));
1186
+ console.log(
1187
+ chalk.dim(" 1. Review your configuration in workflow.config.json")
1188
+ );
1189
+ console.log(
1190
+ chalk.dim(" 2. Review generated guidelines in guidelines/ directory")
1191
+ );
1073
1192
  console.log(chalk.dim(" 3. Run: workflow validate branch"));
1074
1193
  console.log(chalk.dim(" 4. Run: workflow doctor (for health check)\n"));
1075
1194
  if (repoInfo.isGitHub) {
1076
- console.log(chalk.cyan("\u{1F4A1} Recommended: Enable branch protection on GitHub"));
1077
- console.log(chalk.dim(" Settings \u2192 Branches \u2192 Add rule \u2192 Require status checks\n"));
1195
+ console.log(
1196
+ chalk.cyan("\u{1F4A1} Recommended: Enable branch protection on GitHub")
1197
+ );
1198
+ console.log(
1199
+ chalk.dim(" Settings \u2192 Branches \u2192 Add rule \u2192 Require status checks\n")
1200
+ );
1078
1201
  }
1079
1202
  }
1080
1203
 
@@ -1084,7 +1207,9 @@ import { execa as execa2 } from "execa";
1084
1207
  async function validateCommand(type, value, _options = {}) {
1085
1208
  const config = await loadConfig();
1086
1209
  if (!config) {
1087
- console.error(chalk2.red("\u2717 No workflow configuration found. Run: workflow init"));
1210
+ console.error(
1211
+ chalk2.red("\u2717 No workflow configuration found. Run: workflow init")
1212
+ );
1088
1213
  process.exit(1);
1089
1214
  }
1090
1215
  let targetValue = value;
@@ -1134,8 +1259,12 @@ async function validateCommand(type, value, _options = {}) {
1134
1259
  if (enforcementLevel === "strict") {
1135
1260
  process.exit(1);
1136
1261
  } else {
1137
- console.log(chalk2.yellow(`
1138
- \u26A0\uFE0F Advisory mode: validation failed but not blocking`));
1262
+ console.log(
1263
+ chalk2.yellow(
1264
+ `
1265
+ \u26A0\uFE0F Advisory mode: validation failed but not blocking`
1266
+ )
1267
+ );
1139
1268
  process.exit(0);
1140
1269
  }
1141
1270
  }
@@ -1153,37 +1282,45 @@ import prompts from "prompts";
1153
1282
  import chalk3 from "chalk";
1154
1283
  function createConfigCommand() {
1155
1284
  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) => {
1285
+ command.command("validate").description("Validate workflow configuration").action(async () => {
1157
1286
  const opts = command.opts();
1158
1287
  await validateConfigAction(opts);
1159
1288
  });
1160
- command.command("add").description("Add configuration items").argument("<type>", "Type to add (scope)").action(async (type, options) => {
1289
+ command.command("add").description("Add configuration items").argument("<type>", "Type to add (scope)").action(async (type) => {
1161
1290
  const opts = command.opts();
1162
1291
  if (type === "scope") {
1163
1292
  await addScopeAction(opts);
1164
1293
  } else {
1165
- console.error(chalk3.red(`Unknown type: ${type}. Currently only "scope" is supported.`));
1294
+ console.error(
1295
+ chalk3.red(
1296
+ `Unknown type: ${type}. Currently only "scope" is supported.`
1297
+ )
1298
+ );
1166
1299
  process.exit(1);
1167
1300
  }
1168
1301
  });
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) => {
1302
+ 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) => {
1170
1303
  const opts = command.opts();
1171
1304
  if (type === "scope") {
1172
1305
  await removeScopeAction(name, opts);
1173
1306
  } else {
1174
- console.error(chalk3.red(`Unknown type: ${type}. Currently only "scope" is supported.`));
1307
+ console.error(
1308
+ chalk3.red(
1309
+ `Unknown type: ${type}. Currently only "scope" is supported.`
1310
+ )
1311
+ );
1175
1312
  process.exit(1);
1176
1313
  }
1177
1314
  });
1178
- command.command("list").description("List configuration items").argument("[type]", "Type to list (scopes, reserved, all)", "all").action(async (type, options) => {
1315
+ command.command("list").description("List configuration items").argument("[type]", "Type to list (scopes, reserved, all)", "all").action(async (type) => {
1179
1316
  const opts = command.opts();
1180
1317
  await listConfigAction(type, opts);
1181
1318
  });
1182
- command.command("get").description("Get a configuration value").argument("<path>", "Configuration path (e.g., scopes[0].name)").action(async (path2, options) => {
1319
+ command.command("get").description("Get a configuration value").argument("<path>", "Configuration path (e.g., scopes[0].name)").action(async (path2) => {
1183
1320
  const opts = command.opts();
1184
1321
  await getConfigValue(path2, opts);
1185
1322
  });
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) => {
1323
+ command.command("set").description("Set a configuration value").argument("<path>", "Configuration path (e.g., reservedScopeNames)").argument("<value>", "Value to set").action(async (path2, value) => {
1187
1324
  const opts = command.opts();
1188
1325
  await setConfigValue(path2, value, opts);
1189
1326
  });
@@ -1214,7 +1351,9 @@ async function addScopeAction(opts) {
1214
1351
  const cwd = opts.cwd || process.cwd();
1215
1352
  const configPath = join5(cwd, "workflow.config.json");
1216
1353
  if (!existsSync5(configPath)) {
1217
- console.error(chalk3.red("No workflow.config.json found. Run: workflow init"));
1354
+ console.error(
1355
+ chalk3.red("No workflow.config.json found. Run: workflow init")
1356
+ );
1218
1357
  process.exit(1);
1219
1358
  }
1220
1359
  const config = await loadConfig(cwd);
@@ -1231,7 +1370,8 @@ async function addScopeAction(opts) {
1231
1370
  message: "Scope name:",
1232
1371
  validate: (value) => {
1233
1372
  if (!value) return "Name is required";
1234
- if (existingNames.includes(value)) return `Scope "${value}" already exists`;
1373
+ if (existingNames.includes(value))
1374
+ return `Scope "${value}" already exists`;
1235
1375
  const validation = validateScopeName(value, reservedNames);
1236
1376
  if (!validation.valid) {
1237
1377
  return validation.error + (validation.suggestion ? ` Try: ${validation.suggestion}` : "");
@@ -1306,7 +1446,9 @@ async function addScopeAction(opts) {
1306
1446
  console.log(chalk3.gray(` Description: ${response.description}`));
1307
1447
  console.log(chalk3.gray(` Types: ${response.allowedTypes.join(", ")}`));
1308
1448
  if (newScope.mandatoryGuidelines) {
1309
- console.log(chalk3.gray(` Guidelines: ${newScope.mandatoryGuidelines.join(", ")}`));
1449
+ console.log(
1450
+ chalk3.gray(` Guidelines: ${newScope.mandatoryGuidelines.join(", ")}`)
1451
+ );
1310
1452
  }
1311
1453
  }
1312
1454
  async function removeScopeAction(name, opts) {
@@ -1357,9 +1499,15 @@ async function listConfigAction(type, opts) {
1357
1499
  console.log(chalk3.green(`
1358
1500
  ${index + 1}. ${scope.name}`));
1359
1501
  console.log(chalk3.gray(` ${scope.description}`));
1360
- console.log(chalk3.gray(` Types: ${scope.allowedTypes.join(", ")}`));
1502
+ console.log(
1503
+ chalk3.gray(` Types: ${scope.allowedTypes?.join(", ") || "all"}`)
1504
+ );
1361
1505
  if (scope.mandatoryGuidelines && scope.mandatoryGuidelines.length > 0) {
1362
- console.log(chalk3.gray(` Guidelines: ${scope.mandatoryGuidelines.join(", ")}`));
1506
+ console.log(
1507
+ chalk3.gray(
1508
+ ` Guidelines: ${scope.mandatoryGuidelines.join(", ")}`
1509
+ )
1510
+ );
1363
1511
  }
1364
1512
  });
1365
1513
  }
@@ -1368,7 +1516,11 @@ async function listConfigAction(type, opts) {
1368
1516
  const reserved = config.reservedScopeNames || DEFAULT_RESERVED_SCOPE_NAMES;
1369
1517
  console.log(chalk3.blue("\n\u{1F6AB} Reserved Scope Names:"));
1370
1518
  console.log(chalk3.gray(` ${reserved.join(", ")}`));
1371
- console.log(chalk3.gray('\n \u{1F4A1} Configure in workflow.config.json: "reservedScopeNames"'));
1519
+ console.log(
1520
+ chalk3.gray(
1521
+ '\n \u{1F4A1} Configure in workflow.config.json: "reservedScopeNames"'
1522
+ )
1523
+ );
1372
1524
  }
1373
1525
  }
1374
1526
  async function getConfigValue(path2, opts) {
@@ -1408,7 +1560,9 @@ async function setConfigValue(path2, value, opts) {
1408
1560
  const validation = await validateConfig(cwd);
1409
1561
  if (!validation.valid) {
1410
1562
  console.error(chalk3.red("\u2717 Invalid configuration after change:"));
1411
- validation.errors.forEach((err) => console.error(chalk3.red(` \u2022 ${err}`)));
1563
+ validation.errors.forEach(
1564
+ (err) => console.error(chalk3.red(` \u2022 ${err}`))
1565
+ );
1412
1566
  console.log(chalk3.gray("\nUse --force to skip validation"));
1413
1567
  process.exit(1);
1414
1568
  }
@@ -1479,7 +1633,9 @@ async function suggestCommand(feedback, options = {}) {
1479
1633
  console.log(chalk4.dim("\nYour suggestion will be:"));
1480
1634
  console.log(chalk4.dim(" 1. Reviewed by the community"));
1481
1635
  console.log(chalk4.dim(" 2. Prioritized based on impact"));
1482
- console.log(chalk4.dim(" 3. Incorporated into future releases if approved\n"));
1636
+ console.log(
1637
+ chalk4.dim(" 3. Incorporated into future releases if approved\n")
1638
+ );
1483
1639
  }
1484
1640
 
1485
1641
  // src/cli/commands/doctor.ts
@@ -1503,7 +1659,9 @@ function getEffectiveMandatoryTemplates(guidelinesConfig) {
1503
1659
  }
1504
1660
  }
1505
1661
  if (guidelinesConfig.optionalOverrides) {
1506
- mandatory = mandatory.filter((t) => !guidelinesConfig.optionalOverrides.includes(t));
1662
+ mandatory = mandatory.filter(
1663
+ (t) => !guidelinesConfig.optionalOverrides.includes(t)
1664
+ );
1507
1665
  }
1508
1666
  return mandatory;
1509
1667
  }
@@ -1520,7 +1678,9 @@ async function validateGuidelinesExist(projectPath = process.cwd(), config) {
1520
1678
  const mandatory2 = getEffectiveMandatoryTemplates(config?.guidelines);
1521
1679
  result.valid = false;
1522
1680
  result.missingMandatory = mandatory2;
1523
- result.errors.push("Guidelines directory does not exist. Run: workflow init");
1681
+ result.errors.push(
1682
+ "Guidelines directory does not exist. Run: workflow init"
1683
+ );
1524
1684
  return result;
1525
1685
  }
1526
1686
  let existingFiles = [];
@@ -1528,7 +1688,9 @@ async function validateGuidelinesExist(projectPath = process.cwd(), config) {
1528
1688
  existingFiles = await readdir(guidelinesDir);
1529
1689
  } catch (error) {
1530
1690
  result.valid = false;
1531
- result.errors.push(`Cannot read guidelines directory: ${error instanceof Error ? error.message : String(error)}`);
1691
+ result.errors.push(
1692
+ `Cannot read guidelines directory: ${error instanceof Error ? error.message : String(error)}`
1693
+ );
1532
1694
  return result;
1533
1695
  }
1534
1696
  const mandatory = getEffectiveMandatoryTemplates(config?.guidelines);
@@ -1568,7 +1730,9 @@ async function validateGitHubActionsSetup(projectPath = process.cwd()) {
1568
1730
  };
1569
1731
  if (!existsSync6(workflowsDir)) {
1570
1732
  result.valid = false;
1571
- result.errors.push("GitHub Actions workflows directory does not exist. Run: workflow github:setup");
1733
+ result.errors.push(
1734
+ "GitHub Actions workflows directory does not exist. Run: workflow github:setup"
1735
+ );
1572
1736
  return result;
1573
1737
  }
1574
1738
  let workflowFiles = [];
@@ -1576,11 +1740,24 @@ async function validateGitHubActionsSetup(projectPath = process.cwd()) {
1576
1740
  workflowFiles = await readdir(workflowsDir);
1577
1741
  } catch (error) {
1578
1742
  result.valid = false;
1579
- result.errors.push(`Cannot read workflows directory: ${error instanceof Error ? error.message : String(error)}`);
1743
+ result.errors.push(
1744
+ `Cannot read workflows directory: ${error instanceof Error ? error.message : String(error)}`
1745
+ );
1580
1746
  return result;
1581
1747
  }
1582
- const ciWorkflowNames = ["ci.yml", "ci.yaml", "main.yml", "main.yaml", "build.yml", "build.yaml", "test.yml", "test.yaml"];
1583
- const ciWorkflows = workflowFiles.filter((f) => ciWorkflowNames.includes(f.toLowerCase()));
1748
+ const ciWorkflowNames = [
1749
+ "ci.yml",
1750
+ "ci.yaml",
1751
+ "main.yml",
1752
+ "main.yaml",
1753
+ "build.yml",
1754
+ "build.yaml",
1755
+ "test.yml",
1756
+ "test.yaml"
1757
+ ];
1758
+ const ciWorkflows = workflowFiles.filter(
1759
+ (f) => ciWorkflowNames.includes(f.toLowerCase())
1760
+ );
1584
1761
  if (ciWorkflows.length === 0) {
1585
1762
  result.valid = false;
1586
1763
  result.errors.push("No CI workflow file found. Run: workflow github:setup");
@@ -1592,7 +1769,9 @@ async function validateGitHubActionsSetup(projectPath = process.cwd()) {
1592
1769
  try {
1593
1770
  workflowContent = await readFile3(workflowPath, "utf-8");
1594
1771
  } catch (error) {
1595
- result.warnings.push(`Cannot read workflow file: ${error instanceof Error ? error.message : String(error)}`);
1772
+ result.warnings.push(
1773
+ `Cannot read workflow file: ${error instanceof Error ? error.message : String(error)}`
1774
+ );
1596
1775
  return result;
1597
1776
  }
1598
1777
  const contentLower = workflowContent.toLowerCase();
@@ -1621,10 +1800,16 @@ async function validateGitHubActionsSetup(projectPath = process.cwd()) {
1621
1800
  } else {
1622
1801
  result.warnings.push("CI workflow may be missing test step");
1623
1802
  }
1624
- const mandatoryChecks = [result.hasLintCheck, result.hasTypecheckCheck, result.hasFormatCheck];
1803
+ const mandatoryChecks = [
1804
+ result.hasLintCheck,
1805
+ result.hasTypecheckCheck,
1806
+ result.hasFormatCheck
1807
+ ];
1625
1808
  if (!mandatoryChecks.every(Boolean)) {
1626
1809
  result.valid = false;
1627
- result.errors.push("CI workflow is missing mandatory checks (lint, typecheck, format)");
1810
+ result.errors.push(
1811
+ "CI workflow is missing mandatory checks (lint, typecheck, format)"
1812
+ );
1628
1813
  }
1629
1814
  return result;
1630
1815
  }
@@ -1661,13 +1846,25 @@ async function doctorCommand(options = {}) {
1661
1846
  console.log(chalk5.bold("\n\u{1F4DA} Guidelines"));
1662
1847
  const guidelinesResult = await validateGuidelinesExist(cwd, config);
1663
1848
  if (guidelinesResult.valid) {
1664
- console.log(chalk5.green(` \u2713 All ${guidelinesResult.presentMandatory.length} mandatory guidelines present`));
1849
+ console.log(
1850
+ chalk5.green(
1851
+ ` \u2713 All ${guidelinesResult.presentMandatory.length} mandatory guidelines present`
1852
+ )
1853
+ );
1665
1854
  if (guidelinesResult.presentOptional.length > 0) {
1666
- console.log(chalk5.dim(` + ${guidelinesResult.presentOptional.length} optional guidelines`));
1855
+ console.log(
1856
+ chalk5.dim(
1857
+ ` + ${guidelinesResult.presentOptional.length} optional guidelines`
1858
+ )
1859
+ );
1667
1860
  }
1668
1861
  } else {
1669
1862
  hasErrors = true;
1670
- console.log(chalk5.red(` \u2717 Missing ${guidelinesResult.missingMandatory.length} mandatory guidelines:`));
1863
+ console.log(
1864
+ chalk5.red(
1865
+ ` \u2717 Missing ${guidelinesResult.missingMandatory.length} mandatory guidelines:`
1866
+ )
1867
+ );
1671
1868
  for (const missing of guidelinesResult.missingMandatory) {
1672
1869
  console.log(chalk5.red(` \u2022 ${missing}`));
1673
1870
  }
@@ -1681,14 +1878,20 @@ async function doctorCommand(options = {}) {
1681
1878
  const hookStatuses = await getAllHooksStatus(cwd);
1682
1879
  const installedHooks = hookStatuses.filter((h) => h.installed);
1683
1880
  if (installedHooks.length === hookStatuses.length) {
1684
- console.log(chalk5.green(` \u2713 All ${installedHooks.length} hooks installed`));
1881
+ console.log(
1882
+ chalk5.green(` \u2713 All ${installedHooks.length} hooks installed`)
1883
+ );
1685
1884
  for (const hook of hookStatuses) {
1686
1885
  const extra = hook.wrappedOriginal ? " (wrapping original)" : "";
1687
1886
  console.log(chalk5.dim(` \u2022 ${hook.hookType}${extra}`));
1688
1887
  }
1689
1888
  } else if (installedHooks.length > 0) {
1690
1889
  hasWarnings = true;
1691
- console.log(chalk5.yellow(` \u26A0 ${installedHooks.length}/${hookStatuses.length} hooks installed`));
1890
+ console.log(
1891
+ chalk5.yellow(
1892
+ ` \u26A0 ${installedHooks.length}/${hookStatuses.length} hooks installed`
1893
+ )
1894
+ );
1692
1895
  for (const hook of hookStatuses) {
1693
1896
  if (hook.installed) {
1694
1897
  console.log(chalk5.green(` \u2713 ${hook.hookType}`));
@@ -1711,7 +1914,11 @@ async function doctorCommand(options = {}) {
1711
1914
  console.log(chalk5.dim(" \u25CB Not a GitHub repository (CI check skipped)"));
1712
1915
  console.log(chalk5.dim(` Remote: ${repoInfo.remoteUrl || "none"}`));
1713
1916
  } else {
1714
- console.log(chalk5.dim(` Repository: ${repoInfo.github?.owner}/${repoInfo.github?.repo}`));
1917
+ console.log(
1918
+ chalk5.dim(
1919
+ ` Repository: ${repoInfo.github?.owner}/${repoInfo.github?.repo}`
1920
+ )
1921
+ );
1715
1922
  const ciResult = await validateGitHubActionsSetup(cwd);
1716
1923
  if (ciResult.valid) {
1717
1924
  console.log(chalk5.green(" \u2713 GitHub Actions CI configured correctly"));
@@ -1740,15 +1947,21 @@ async function doctorCommand(options = {}) {
1740
1947
  if (repoInfo.isGitHub && hasCIWorkflow(cwd)) {
1741
1948
  console.log(chalk5.cyan(" \u2192 Enable branch protection on GitHub"));
1742
1949
  console.log(chalk5.dim(" Settings \u2192 Branches \u2192 Add rule"));
1743
- console.log(chalk5.dim(" \u2611 Require status checks to pass before merging"));
1744
- console.log(chalk5.dim(" \u2611 Require branches to be up to date before merging"));
1950
+ console.log(
1951
+ chalk5.dim(" \u2611 Require status checks to pass before merging")
1952
+ );
1953
+ console.log(
1954
+ chalk5.dim(" \u2611 Require branches to be up to date before merging")
1955
+ );
1745
1956
  }
1746
1957
  if (config.enforcement !== "strict") {
1747
1958
  console.log(chalk5.cyan(` \u2192 Consider switching to 'strict' enforcement`));
1748
1959
  console.log(chalk5.dim(` Current: ${config.enforcement}`));
1749
1960
  }
1750
1961
  if (config.scopes.length < 5) {
1751
- console.log(chalk5.cyan(" \u2192 Consider adding more scopes for better organization"));
1962
+ console.log(
1963
+ chalk5.cyan(" \u2192 Consider adding more scopes for better organization")
1964
+ );
1752
1965
  console.log(chalk5.dim(" Run: workflow config add scope <name>"));
1753
1966
  }
1754
1967
  console.log(chalk5.bold("\n\u{1F4CA} Summary"));
@@ -1766,7 +1979,7 @@ async function doctorCommand(options = {}) {
1766
1979
  // src/cli/commands/setup.ts
1767
1980
  import * as p3 from "@clack/prompts";
1768
1981
  import chalk6 from "chalk";
1769
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync7 } from "fs";
1982
+ import { readFileSync, writeFileSync as writeFileSync2, existsSync as existsSync7 } from "fs";
1770
1983
  import { join as join7 } from "path";
1771
1984
  var WORKFLOW_SCRIPTS = {
1772
1985
  "workflow:init": "workflow-agent init",
@@ -1782,7 +1995,7 @@ async function setupCommand() {
1782
1995
  p3.cancel("No package.json found in current directory");
1783
1996
  process.exit(1);
1784
1997
  }
1785
- const packageJsonContent = readFileSync2(packageJsonPath, "utf-8");
1998
+ const packageJsonContent = readFileSync(packageJsonPath, "utf-8");
1786
1999
  const packageJson = JSON.parse(packageJsonContent);
1787
2000
  if (!packageJson.scripts) {
1788
2001
  packageJson.scripts = {};
@@ -1826,7 +2039,11 @@ async function setupCommand() {
1826
2039
  JSON.stringify(packageJson, null, 2) + "\n",
1827
2040
  "utf-8"
1828
2041
  );
1829
- p3.outro(chalk6.green(`\u2713 Added ${Object.keys(scriptsToAdd).length} workflow scripts to package.json!`));
2042
+ p3.outro(
2043
+ chalk6.green(
2044
+ `\u2713 Added ${Object.keys(scriptsToAdd).length} workflow scripts to package.json!`
2045
+ )
2046
+ );
1830
2047
  console.log(chalk6.dim("\nRun them with:"));
1831
2048
  console.log(chalk6.dim(" pnpm run workflow:init"));
1832
2049
  console.log(chalk6.dim(" npm run workflow:init\n"));
@@ -1851,8 +2068,10 @@ async function scopeCreateCommand(options) {
1851
2068
  placeholder: "my-custom-scope",
1852
2069
  validate: (value) => {
1853
2070
  if (!value || value.length === 0) return "Package name is required";
1854
- if (!/^[a-z0-9-]+$/.test(value)) return "Package name must be lowercase alphanumeric with hyphens";
1855
- if (value.length > 32) return "Package name must be 32 characters or less";
2071
+ if (!/^[a-z0-9-]+$/.test(value))
2072
+ return "Package name must be lowercase alphanumeric with hyphens";
2073
+ if (value.length > 32)
2074
+ return "Package name must be 32 characters or less";
1856
2075
  return void 0;
1857
2076
  }
1858
2077
  });
@@ -1887,7 +2106,9 @@ async function scopeCreateCommand(options) {
1887
2106
  });
1888
2107
  }
1889
2108
  } else {
1890
- console.log(chalk7.dim("\nAdd scopes to your preset (aim for 8-15 scopes):\n"));
2109
+ console.log(
2110
+ chalk7.dim("\nAdd scopes to your preset (aim for 8-15 scopes):\n")
2111
+ );
1891
2112
  let addMore = true;
1892
2113
  while (addMore) {
1893
2114
  const scopeName = await p4.text({
@@ -1895,9 +2116,11 @@ async function scopeCreateCommand(options) {
1895
2116
  placeholder: "auth",
1896
2117
  validate: (value) => {
1897
2118
  if (!value || value.length === 0) return "Scope name is required";
1898
- if (!/^[a-z0-9-]+$/.test(value)) return "Must be lowercase alphanumeric with hyphens";
2119
+ if (!/^[a-z0-9-]+$/.test(value))
2120
+ return "Must be lowercase alphanumeric with hyphens";
1899
2121
  if (value.length > 32) return "Must be 32 characters or less";
1900
- if (scopes.some((s) => s.name === value)) return "Scope name already exists";
2122
+ if (scopes.some((s) => s.name === value))
2123
+ return "Scope name already exists";
1901
2124
  return void 0;
1902
2125
  }
1903
2126
  });
@@ -1908,7 +2131,8 @@ async function scopeCreateCommand(options) {
1908
2131
  message: "Description:",
1909
2132
  placeholder: "Authentication and authorization",
1910
2133
  validate: (value) => {
1911
- if (!value || value.length < 10) return "Description must be at least 10 characters";
2134
+ if (!value || value.length < 10)
2135
+ return "Description must be at least 10 characters";
1912
2136
  return void 0;
1913
2137
  }
1914
2138
  });
@@ -1966,13 +2190,17 @@ async function scopeCreateCommand(options) {
1966
2190
  const validation = validateScopeDefinitions(scopes);
1967
2191
  if (!validation.valid) {
1968
2192
  console.log(chalk7.red("\n\u2717 Scope validation failed:\n"));
1969
- validation.errors.forEach((error) => console.log(chalk7.red(` \u2022 ${error}`)));
2193
+ validation.errors.forEach(
2194
+ (error) => console.log(chalk7.red(` \u2022 ${error}`))
2195
+ );
1970
2196
  p4.cancel("Operation cancelled");
1971
2197
  process.exit(1);
1972
2198
  }
1973
- console.log(chalk7.green(`
2199
+ console.log(
2200
+ chalk7.green(`
1974
2201
  \u2713 ${scopes.length} scopes validated successfully
1975
- `));
2202
+ `)
2203
+ );
1976
2204
  let outputDir;
1977
2205
  if (options.outputDir) {
1978
2206
  outputDir = options.outputDir;
@@ -2126,7 +2354,11 @@ describe('${presetName} Scope Preset', () => {
2126
2354
  });
2127
2355
  });
2128
2356
  `;
2129
- await writeFile4(join8(outputDir, "src", "index.test.ts"), testFile, "utf-8");
2357
+ await writeFile4(
2358
+ join8(outputDir, "src", "index.test.ts"),
2359
+ testFile,
2360
+ "utf-8"
2361
+ );
2130
2362
  }
2131
2363
  spinner5.stop("\u2713 Package structure created");
2132
2364
  if (isMonorepo2) {
@@ -2134,13 +2366,17 @@ describe('${presetName} Scope Preset', () => {
2134
2366
  const workspaceContent = await readFile4(workspaceFile, "utf-8");
2135
2367
  const packagePath = `packages/scopes-${packageName}`;
2136
2368
  if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
2137
- console.log(chalk7.yellow("\n\u26A0\uFE0F Add the following to pnpm-workspace.yaml:"));
2369
+ console.log(
2370
+ chalk7.yellow("\n\u26A0\uFE0F Add the following to pnpm-workspace.yaml:")
2371
+ );
2138
2372
  console.log(chalk7.dim(` - '${packagePath}'`));
2139
2373
  } else {
2140
2374
  console.log(chalk7.green("\n\u2713 Package will be included in workspace"));
2141
2375
  }
2142
2376
  }
2143
- console.log(chalk7.green.bold("\n\u2728 Custom scope package created successfully!\n"));
2377
+ console.log(
2378
+ chalk7.green.bold("\n\u2728 Custom scope package created successfully!\n")
2379
+ );
2144
2380
  console.log(chalk7.bold("Package details:"));
2145
2381
  console.log(chalk7.dim(` Location: ${outputDir}`));
2146
2382
  console.log(chalk7.dim(` Package: @workflow/scopes-${packageName}`));
@@ -2153,17 +2389,27 @@ describe('${presetName} Scope Preset', () => {
2153
2389
  if (!options.noTest) {
2154
2390
  console.log(chalk7.dim(` 4. pnpm test`));
2155
2391
  }
2156
- console.log(chalk7.dim(` ${!options.noTest ? "5" : "4"}. Update repository URL in package.json`));
2392
+ console.log(
2393
+ chalk7.dim(
2394
+ ` ${!options.noTest ? "5" : "4"}. Update repository URL in package.json`
2395
+ )
2396
+ );
2157
2397
  const shouldPublish = isNonInteractive ? false : await p4.confirm({
2158
2398
  message: "\nWould you like instructions for publishing to npm?",
2159
2399
  initialValue: false
2160
2400
  });
2161
2401
  if (shouldPublish && !p4.isCancel(shouldPublish)) {
2162
2402
  console.log(chalk7.bold("\n\u{1F4E6} Publishing instructions:\n"));
2163
- console.log(chalk7.dim(" 1. npm login (or configure .npmrc with your registry)"));
2403
+ console.log(
2404
+ chalk7.dim(" 1. npm login (or configure .npmrc with your registry)")
2405
+ );
2164
2406
  console.log(chalk7.dim(" 2. Update version in package.json as needed"));
2165
2407
  console.log(chalk7.dim(" 3. pnpm publish --access public"));
2166
- console.log(chalk7.dim(" 4. Use in other projects: pnpm add @workflow/scopes-" + packageName + "\n"));
2408
+ console.log(
2409
+ chalk7.dim(
2410
+ " 4. Use in other projects: pnpm add @workflow/scopes-" + packageName + "\n"
2411
+ )
2412
+ );
2167
2413
  }
2168
2414
  } catch (error) {
2169
2415
  spinner5.stop("\u2717 Failed to create package");
@@ -2200,11 +2446,17 @@ async function scopeMigrateCommand(options) {
2200
2446
  p5.cancel("No scopes found in workflow.config.json");
2201
2447
  process.exit(1);
2202
2448
  }
2203
- console.log(chalk8.dim(`Found ${config.scopes.length} scopes in workflow.config.json
2204
- `));
2449
+ console.log(
2450
+ chalk8.dim(`Found ${config.scopes.length} scopes in workflow.config.json
2451
+ `)
2452
+ );
2205
2453
  console.log(chalk8.bold("Current scopes:"));
2206
2454
  config.scopes.forEach((scope, i) => {
2207
- console.log(chalk8.dim(` ${i + 1}. ${scope.emoji || "\u2022"} ${scope.name} - ${scope.description}`));
2455
+ console.log(
2456
+ chalk8.dim(
2457
+ ` ${i + 1}. ${scope.emoji || "\u2022"} ${scope.name} - ${scope.description}`
2458
+ )
2459
+ );
2208
2460
  });
2209
2461
  console.log();
2210
2462
  const shouldContinue = await p5.confirm({
@@ -2224,8 +2476,10 @@ async function scopeMigrateCommand(options) {
2224
2476
  placeholder: config.projectName.toLowerCase().replace(/[^a-z0-9-]/g, "-"),
2225
2477
  validate: (value) => {
2226
2478
  if (!value || value.length === 0) return "Package name is required";
2227
- if (!/^[a-z0-9-]+$/.test(value)) return "Package name must be lowercase alphanumeric with hyphens";
2228
- if (value.length > 32) return "Package name must be 32 characters or less";
2479
+ if (!/^[a-z0-9-]+$/.test(value))
2480
+ return "Package name must be lowercase alphanumeric with hyphens";
2481
+ if (value.length > 32)
2482
+ return "Package name must be 32 characters or less";
2229
2483
  return void 0;
2230
2484
  }
2231
2485
  });
@@ -2247,7 +2501,9 @@ async function scopeMigrateCommand(options) {
2247
2501
  const validation = validateScopeDefinitions(config.scopes);
2248
2502
  if (!validation.valid) {
2249
2503
  console.log(chalk8.yellow("\n\u26A0\uFE0F Scope validation warnings:\n"));
2250
- validation.errors.forEach((error) => console.log(chalk8.yellow(` \u2022 ${error}`)));
2504
+ validation.errors.forEach(
2505
+ (error) => console.log(chalk8.yellow(` \u2022 ${error}`))
2506
+ );
2251
2507
  const shouldFix = await p5.confirm({
2252
2508
  message: "Some scopes have validation issues. Continue anyway?",
2253
2509
  initialValue: false
@@ -2419,7 +2675,9 @@ describe('${presetName} Scope Preset (Migrated)', () => {
2419
2675
  const workspaceContent = await readFile5(workspaceFile, "utf-8");
2420
2676
  const packagePath = `packages/scopes-${packageName}`;
2421
2677
  if (!workspaceContent.includes(packagePath) && !workspaceContent.includes("packages/*")) {
2422
- console.log(chalk8.yellow("\n\u26A0\uFE0F Add the following to pnpm-workspace.yaml:"));
2678
+ console.log(
2679
+ chalk8.yellow("\n\u26A0\uFE0F Add the following to pnpm-workspace.yaml:")
2680
+ );
2423
2681
  console.log(chalk8.dim(` - '${packagePath}'`));
2424
2682
  } else {
2425
2683
  console.log(chalk8.green("\n\u2713 Package will be included in workspace"));
@@ -2438,11 +2696,17 @@ describe('${presetName} Scope Preset (Migrated)', () => {
2438
2696
  preset: `scopes-${packageName}`
2439
2697
  // Reference the new package
2440
2698
  };
2441
- await writeFile5(configPath, JSON.stringify(updatedConfig, null, 2), "utf-8");
2699
+ await writeFile5(
2700
+ configPath,
2701
+ JSON.stringify(updatedConfig, null, 2),
2702
+ "utf-8"
2703
+ );
2442
2704
  console.log(chalk8.green("\u2713 Updated workflow.config.json"));
2443
2705
  console.log(chalk8.dim(" \u2022 Cleared inline scopes"));
2444
- console.log(chalk8.dim(` \u2022 Added preset reference: scopes-${packageName}
2445
- `));
2706
+ console.log(
2707
+ chalk8.dim(` \u2022 Added preset reference: scopes-${packageName}
2708
+ `)
2709
+ );
2446
2710
  }
2447
2711
  console.log(chalk8.green.bold("\n\u2728 Migration completed successfully!\n"));
2448
2712
  console.log(chalk8.bold("Package details:"));
@@ -2459,11 +2723,23 @@ describe('${presetName} Scope Preset (Migrated)', () => {
2459
2723
  `));
2460
2724
  if (!keepConfig) {
2461
2725
  console.log(chalk8.bold("To use the migrated scopes:\n"));
2462
- console.log(chalk8.dim(` 1. Install the package: pnpm add -w @workflow/scopes-${packageName}`));
2463
- console.log(chalk8.dim(` 2. The preset is already referenced in workflow.config.json
2464
- `));
2465
- }
2466
- console.log(chalk8.dim("\u{1F4A1} Tip: You can now reuse this scope package across multiple projects!\n"));
2726
+ console.log(
2727
+ chalk8.dim(
2728
+ ` 1. Install the package: pnpm add -w @workflow/scopes-${packageName}`
2729
+ )
2730
+ );
2731
+ console.log(
2732
+ chalk8.dim(
2733
+ ` 2. The preset is already referenced in workflow.config.json
2734
+ `
2735
+ )
2736
+ );
2737
+ }
2738
+ console.log(
2739
+ chalk8.dim(
2740
+ "\u{1F4A1} Tip: You can now reuse this scope package across multiple projects!\n"
2741
+ )
2742
+ );
2467
2743
  } catch (error) {
2468
2744
  spinner5.stop("\u2717 Migration failed");
2469
2745
  console.error(chalk8.red("\nError:"), error);
@@ -2505,12 +2781,18 @@ async function installHooksAction(cwd) {
2505
2781
  for (const result of results) {
2506
2782
  if (result.success) {
2507
2783
  if (result.wrappedExisting) {
2508
- console.log(chalk9.green(`\u2713 Installed ${result.hookType} hook (wrapped existing hook)`));
2784
+ console.log(
2785
+ chalk9.green(
2786
+ `\u2713 Installed ${result.hookType} hook (wrapped existing hook)`
2787
+ )
2788
+ );
2509
2789
  } else {
2510
2790
  console.log(chalk9.green(`\u2713 Installed ${result.hookType} hook`));
2511
2791
  }
2512
2792
  } else {
2513
- console.error(chalk9.red(`\u2717 Failed to install ${result.hookType}: ${result.error}`));
2793
+ console.error(
2794
+ chalk9.red(`\u2717 Failed to install ${result.hookType}: ${result.error}`)
2795
+ );
2514
2796
  hasErrors = true;
2515
2797
  }
2516
2798
  }
@@ -2533,12 +2815,16 @@ async function uninstallHooksAction(cwd) {
2533
2815
  for (const result of results) {
2534
2816
  if (result.success) {
2535
2817
  if (result.wrappedExisting) {
2536
- console.log(chalk9.green(`\u2713 Removed ${result.hookType} hook (restored original)`));
2818
+ console.log(
2819
+ chalk9.green(`\u2713 Removed ${result.hookType} hook (restored original)`)
2820
+ );
2537
2821
  } else {
2538
2822
  console.log(chalk9.green(`\u2713 Removed ${result.hookType} hook`));
2539
2823
  }
2540
2824
  } else if (result.error) {
2541
- console.error(chalk9.red(`\u2717 Failed to remove ${result.hookType}: ${result.error}`));
2825
+ console.error(
2826
+ chalk9.red(`\u2717 Failed to remove ${result.hookType}: ${result.error}`)
2827
+ );
2542
2828
  hasErrors = true;
2543
2829
  }
2544
2830
  }
@@ -2614,7 +2900,11 @@ async function setupAction(cwd) {
2614
2900
  process.exit(0);
2615
2901
  }
2616
2902
  } else {
2617
- console.log(chalk10.dim(`Repository: ${repoInfo.github?.owner}/${repoInfo.github?.repo}`));
2903
+ console.log(
2904
+ chalk10.dim(
2905
+ `Repository: ${repoInfo.github?.owner}/${repoInfo.github?.repo}`
2906
+ )
2907
+ );
2618
2908
  }
2619
2909
  if (hasCIWorkflow(cwd)) {
2620
2910
  const shouldOverwrite = await p6.confirm({
@@ -2648,7 +2938,13 @@ async function setupAction(cwd) {
2648
2938
  console.log(chalk10.dim(" \u2022 Push to main/develop branches"));
2649
2939
  console.log(chalk10.dim(" \u2022 Pull requests to main/develop branches"));
2650
2940
  console.log(chalk10.dim("\nChecks included:"));
2651
- const checks = ciConfig?.checks || ["lint", "typecheck", "format", "build", "test"];
2941
+ const checks = ciConfig?.checks || [
2942
+ "lint",
2943
+ "typecheck",
2944
+ "format",
2945
+ "build",
2946
+ "test"
2947
+ ];
2652
2948
  for (const check of checks) {
2653
2949
  const hasScript = check === "lint" ? projectInfo.hasLintScript : check === "typecheck" ? projectInfo.hasTypecheckScript : check === "format" ? projectInfo.hasFormatScript : check === "test" ? projectInfo.hasTestScript : check === "build" ? projectInfo.hasBuildScript : false;
2654
2950
  const status = hasScript ? chalk10.green("\u2713") : chalk10.yellow("\u26A0");
@@ -2657,7 +2953,9 @@ async function setupAction(cwd) {
2657
2953
  }
2658
2954
  console.log(chalk10.cyan("\n\u{1F4A1} Recommended: Enable branch protection"));
2659
2955
  console.log(chalk10.dim(" Go to GitHub \u2192 Settings \u2192 Branches \u2192 Add rule"));
2660
- console.log(chalk10.dim(' Enable "Require status checks to pass before merging"'));
2956
+ console.log(
2957
+ chalk10.dim(' Enable "Require status checks to pass before merging"')
2958
+ );
2661
2959
  console.log(chalk10.dim(' Select the "ci" status check'));
2662
2960
  } else {
2663
2961
  spinner5.stop(chalk10.red("\u2717 Failed to create CI workflow"));
@@ -2708,18 +3006,496 @@ async function checkAction(cwd) {
2708
3006
  }
2709
3007
  }
2710
3008
 
3009
+ // src/cli/commands/fix.ts
3010
+ import { existsSync as existsSync10, readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync } from "fs";
3011
+ import { dirname as dirname2, join as join10, relative } from "path";
3012
+ import { execa as execa3 } from "execa";
3013
+ import * as p7 from "@clack/prompts";
3014
+ import pc from "picocolors";
3015
+ function extractFilePaths(errorMessage, cwd) {
3016
+ const paths = /* @__PURE__ */ new Set();
3017
+ const patterns = [
3018
+ /(?:at\s+)?([\/\w\.\-]+\.(?:ts|js|tsx|jsx|mjs|cjs|vue|svelte))(?::\d+(?::\d+)?)?/g,
3019
+ /(?:Error in |from )\.?([\/\w\.\-]+\.(?:ts|js|tsx|jsx|mjs|cjs|vue|svelte))/g,
3020
+ /['"]([\/\w\.\-]+\.(?:ts|js|tsx|jsx|mjs|cjs|vue|svelte))['"]/g
3021
+ ];
3022
+ for (const pattern of patterns) {
3023
+ let match;
3024
+ while ((match = pattern.exec(errorMessage)) !== null) {
3025
+ let filePath = match[1];
3026
+ if (!filePath.startsWith("/")) {
3027
+ filePath = join10(cwd, filePath);
3028
+ }
3029
+ if (existsSync10(filePath)) {
3030
+ paths.add(filePath);
3031
+ }
3032
+ }
3033
+ }
3034
+ return Array.from(paths);
3035
+ }
3036
+ function readFileContents(paths) {
3037
+ const contents = {};
3038
+ for (const filePath of paths) {
3039
+ try {
3040
+ if (existsSync10(filePath)) {
3041
+ contents[filePath] = readFileSync2(filePath, "utf-8");
3042
+ }
3043
+ } catch {
3044
+ }
3045
+ }
3046
+ return contents;
3047
+ }
3048
+ async function generateFixWithLLM(errorMessage, _fileContents, _context) {
3049
+ console.log(pc.dim(" Analyzing error with LLM..."));
3050
+ return {
3051
+ analysis: `Error analysis for: ${errorMessage.slice(0, 100)}...`,
3052
+ rootCause: "Unable to determine root cause without LLM API access",
3053
+ suggestedFix: {
3054
+ description: "Manual intervention required - LLM API not configured",
3055
+ files: []
3056
+ },
3057
+ confidence: 0
3058
+ };
3059
+ }
3060
+ async function applyChanges(changes, dryRun) {
3061
+ for (const change of changes) {
3062
+ const actionColor = change.action === "create" ? pc.green : change.action === "delete" ? pc.red : pc.yellow;
3063
+ console.log(` ${actionColor(change.action.toUpperCase())} ${change.path}`);
3064
+ if (dryRun) {
3065
+ console.log(pc.dim(" (dry run - no changes made)"));
3066
+ continue;
3067
+ }
3068
+ switch (change.action) {
3069
+ case "create":
3070
+ case "modify":
3071
+ if (change.content) {
3072
+ const dir = dirname2(change.path);
3073
+ if (!existsSync10(dir)) {
3074
+ mkdirSync(dir, { recursive: true });
3075
+ }
3076
+ writeFileSync3(change.path, change.content);
3077
+ }
3078
+ break;
3079
+ case "delete":
3080
+ console.log(pc.dim(" (delete skipped for safety)"));
3081
+ break;
3082
+ }
3083
+ }
3084
+ }
3085
+ async function commitAndPush(message, cwd) {
3086
+ try {
3087
+ await execa3("git", ["add", "-A"], { cwd });
3088
+ const { stdout: status } = await execa3(
3089
+ "git",
3090
+ ["status", "--porcelain"],
3091
+ { cwd }
3092
+ );
3093
+ if (!status.trim()) {
3094
+ return { success: true };
3095
+ }
3096
+ await execa3("git", ["commit", "-m", message], { cwd });
3097
+ await execa3("git", ["push"], { cwd });
3098
+ return { success: true };
3099
+ } catch (error) {
3100
+ return {
3101
+ success: false,
3102
+ error: error instanceof Error ? error.message : String(error)
3103
+ };
3104
+ }
3105
+ }
3106
+ async function fixCommand(options) {
3107
+ const cwd = process.cwd();
3108
+ console.log(pc.cyan("\n\u{1F527} Auto-Heal: Fixing Pipeline Error\n"));
3109
+ if (!options.error) {
3110
+ console.error(pc.red("Error: --error flag is required"));
3111
+ process.exit(1);
3112
+ }
3113
+ console.log(pc.bold("Error Message:"));
3114
+ console.log(pc.dim(options.error.slice(0, 500)));
3115
+ if (options.error.length > 500) {
3116
+ console.log(pc.dim(`... (${options.error.length - 500} more characters)`));
3117
+ }
3118
+ console.log("");
3119
+ let filePaths = options.files || [];
3120
+ if (filePaths.length === 0) {
3121
+ console.log(pc.dim("Extracting file paths from error..."));
3122
+ filePaths = extractFilePaths(options.error, cwd);
3123
+ }
3124
+ if (filePaths.length > 0) {
3125
+ console.log(pc.bold("\nRelevant Files:"));
3126
+ for (const path2 of filePaths) {
3127
+ console.log(` \u{1F4C4} ${relative(cwd, path2)}`);
3128
+ }
3129
+ console.log("");
3130
+ }
3131
+ const fileContents = readFileContents(filePaths);
3132
+ let context;
3133
+ if (options.context) {
3134
+ try {
3135
+ context = JSON.parse(options.context);
3136
+ } catch {
3137
+ context = options.context;
3138
+ }
3139
+ }
3140
+ console.log(pc.bold("Generating Fix...\n"));
3141
+ const fix = await generateFixWithLLM(options.error, fileContents, context);
3142
+ console.log(pc.bold("Analysis:"));
3143
+ console.log(` ${fix.analysis}`);
3144
+ console.log("");
3145
+ console.log(pc.bold("Root Cause:"));
3146
+ console.log(` ${fix.rootCause}`);
3147
+ console.log("");
3148
+ console.log(pc.bold("Suggested Fix:"));
3149
+ console.log(` ${fix.suggestedFix.description}`);
3150
+ console.log(` Confidence: ${Math.round(fix.confidence * 100)}%`);
3151
+ console.log("");
3152
+ if (fix.suggestedFix.files.length === 0) {
3153
+ console.log(
3154
+ pc.yellow("\u26A0\uFE0F No automatic fix available. Manual intervention required.")
3155
+ );
3156
+ process.exit(1);
3157
+ }
3158
+ if (fix.confidence < 0.5) {
3159
+ console.log(
3160
+ pc.yellow(
3161
+ `\u26A0\uFE0F Low confidence (${Math.round(fix.confidence * 100)}%). Skipping automatic fix.`
3162
+ )
3163
+ );
3164
+ process.exit(1);
3165
+ }
3166
+ if (!options.auto) {
3167
+ const shouldApply = await p7.confirm({
3168
+ message: "Apply suggested changes?",
3169
+ initialValue: false
3170
+ });
3171
+ if (p7.isCancel(shouldApply) || !shouldApply) {
3172
+ console.log(pc.dim("Fix cancelled."));
3173
+ process.exit(0);
3174
+ }
3175
+ }
3176
+ console.log(pc.bold("\nApplying Changes...\n"));
3177
+ await applyChanges(fix.suggestedFix.files, options.dryRun || false);
3178
+ if (options.dryRun) {
3179
+ console.log(pc.yellow("\n\u26A0\uFE0F Dry run complete. No changes were made."));
3180
+ process.exit(0);
3181
+ }
3182
+ if (options.auto) {
3183
+ console.log(pc.bold("\nCommitting and Pushing...\n"));
3184
+ const scope = filePaths.length > 0 ? dirname2(relative(cwd, filePaths[0])).split("/")[0] || "core" : "core";
3185
+ const commitMessage = `fix(${scope}): auto-heal pipeline failure
3186
+
3187
+ ${fix.rootCause}
3188
+
3189
+ Auto-generated fix with ${Math.round(fix.confidence * 100)}% confidence.
3190
+ `;
3191
+ const result = await commitAndPush(commitMessage, cwd);
3192
+ if (result.success) {
3193
+ console.log(pc.green("\u2705 Fix applied, committed, and pushed!"));
3194
+ } else {
3195
+ console.log(pc.red(`\u274C Failed to commit/push: ${result.error}`));
3196
+ process.exit(1);
3197
+ }
3198
+ } else {
3199
+ console.log(pc.green("\n\u2705 Fix applied! Don't forget to commit and push."));
3200
+ }
3201
+ }
3202
+
3203
+ // src/cli/commands/visual.ts
3204
+ import { existsSync as existsSync11, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "fs";
3205
+ import { dirname as dirname3, join as join11 } from "path";
3206
+ import * as p8 from "@clack/prompts";
3207
+ import pc2 from "picocolors";
3208
+ function getBaselinesDir() {
3209
+ const cwd = process.cwd();
3210
+ return join11(cwd, ".visual-baselines");
3211
+ }
3212
+ function getMetadataPath() {
3213
+ return join11(getBaselinesDir(), "baselines.json");
3214
+ }
3215
+ function loadMetadata() {
3216
+ const metadataPath = getMetadataPath();
3217
+ if (!existsSync11(metadataPath)) {
3218
+ return {};
3219
+ }
3220
+ try {
3221
+ return JSON.parse(readFileSync3(metadataPath, "utf-8"));
3222
+ } catch {
3223
+ return {};
3224
+ }
3225
+ }
3226
+ function saveMetadata(metadata) {
3227
+ const dir = getBaselinesDir();
3228
+ if (!existsSync11(dir)) {
3229
+ mkdirSync2(dir, { recursive: true });
3230
+ }
3231
+ writeFileSync4(getMetadataPath(), JSON.stringify(metadata, null, 2));
3232
+ }
3233
+ async function checkPlaywright() {
3234
+ try {
3235
+ await import("playwright");
3236
+ return true;
3237
+ } catch {
3238
+ return false;
3239
+ }
3240
+ }
3241
+ async function visualCaptureCommand(name, url, options) {
3242
+ console.log(pc2.cyan("\n\u{1F4F8} Capturing Visual Baseline\n"));
3243
+ const hasPlaywright = await checkPlaywright();
3244
+ if (!hasPlaywright) {
3245
+ console.log(pc2.yellow("\u26A0\uFE0F Playwright is not installed."));
3246
+ console.log(pc2.dim("Install it with: npm install playwright"));
3247
+ console.log(
3248
+ pc2.dim("Then install browsers: npx playwright install chromium")
3249
+ );
3250
+ process.exit(1);
3251
+ }
3252
+ const width = parseInt(options.width || "1280");
3253
+ const height = parseInt(options.height || "720");
3254
+ const delay = parseInt(options.delay || "0");
3255
+ console.log(` Name: ${pc2.bold(name)}`);
3256
+ console.log(` URL: ${url}`);
3257
+ console.log(` Viewport: ${width}x${height}`);
3258
+ console.log("");
3259
+ try {
3260
+ const { chromium } = await import("playwright");
3261
+ const browser = await chromium.launch({ headless: true });
3262
+ const context = await browser.newContext({
3263
+ viewport: { width, height }
3264
+ });
3265
+ const page = await context.newPage();
3266
+ console.log(pc2.dim(" Loading page..."));
3267
+ await page.goto(url, { waitUntil: "networkidle" });
3268
+ if (options.waitFor) {
3269
+ console.log(pc2.dim(` Waiting for selector: ${options.waitFor}`));
3270
+ await page.waitForSelector(options.waitFor, { timeout: 1e4 });
3271
+ }
3272
+ if (delay > 0) {
3273
+ console.log(pc2.dim(` Waiting ${delay}ms...`));
3274
+ await page.waitForTimeout(delay);
3275
+ }
3276
+ const baselinesDir = getBaselinesDir();
3277
+ const outputPath = options.output || join11(baselinesDir, "screenshots", `${name}.png`);
3278
+ const outputDir = dirname3(outputPath);
3279
+ if (!existsSync11(outputDir)) {
3280
+ mkdirSync2(outputDir, { recursive: true });
3281
+ }
3282
+ console.log(pc2.dim(" Capturing screenshot..."));
3283
+ await page.screenshot({
3284
+ path: outputPath,
3285
+ fullPage: options.fullPage
3286
+ });
3287
+ await browser.close();
3288
+ const metadata = loadMetadata();
3289
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3290
+ metadata[name] = {
3291
+ name,
3292
+ url,
3293
+ path: outputPath,
3294
+ width,
3295
+ height,
3296
+ createdAt: metadata[name]?.createdAt || now,
3297
+ updatedAt: now
3298
+ };
3299
+ saveMetadata(metadata);
3300
+ console.log(pc2.green(`
3301
+ \u2705 Baseline "${name}" saved to ${outputPath}`));
3302
+ } catch (error) {
3303
+ console.error(pc2.red("\n\u274C Failed to capture screenshot:"), error);
3304
+ process.exit(1);
3305
+ }
3306
+ }
3307
+ async function visualCompareCommand(url, options) {
3308
+ console.log(pc2.cyan("\n\u{1F50D} Comparing Against Baseline\n"));
3309
+ const metadata = loadMetadata();
3310
+ const baseline = metadata[options.baseline];
3311
+ if (!baseline) {
3312
+ console.log(pc2.red(`\u274C Baseline "${options.baseline}" not found`));
3313
+ console.log(pc2.dim("Available baselines:"));
3314
+ Object.keys(metadata).forEach((name) => {
3315
+ console.log(pc2.dim(` - ${name}`));
3316
+ });
3317
+ process.exit(1);
3318
+ }
3319
+ if (!existsSync11(baseline.path)) {
3320
+ console.log(pc2.red(`\u274C Baseline screenshot not found: ${baseline.path}`));
3321
+ process.exit(1);
3322
+ }
3323
+ console.log(` Baseline: ${pc2.bold(options.baseline)}`);
3324
+ console.log(` URL: ${url}`);
3325
+ console.log(` Viewport: ${baseline.width}x${baseline.height}`);
3326
+ console.log("");
3327
+ const hasPlaywright = await checkPlaywright();
3328
+ if (!hasPlaywright) {
3329
+ console.log(pc2.yellow("\u26A0\uFE0F Playwright is not installed."));
3330
+ process.exit(1);
3331
+ }
3332
+ try {
3333
+ const { chromium } = await import("playwright");
3334
+ const browser = await chromium.launch({ headless: true });
3335
+ const context = await browser.newContext({
3336
+ viewport: { width: baseline.width, height: baseline.height }
3337
+ });
3338
+ const page = await context.newPage();
3339
+ console.log(pc2.dim(" Loading page..."));
3340
+ await page.goto(url, { waitUntil: "networkidle" });
3341
+ const baselinesDir = getBaselinesDir();
3342
+ const comparePath = options.output || join11(
3343
+ baselinesDir,
3344
+ "comparisons",
3345
+ `${options.baseline}-${Date.now()}.png`
3346
+ );
3347
+ const compareDir = dirname3(comparePath);
3348
+ if (!existsSync11(compareDir)) {
3349
+ mkdirSync2(compareDir, { recursive: true });
3350
+ }
3351
+ console.log(pc2.dim(" Capturing screenshot..."));
3352
+ await page.screenshot({ path: comparePath });
3353
+ await browser.close();
3354
+ const baselineBuffer = readFileSync3(baseline.path);
3355
+ const compareBuffer = readFileSync3(comparePath);
3356
+ const areSameSize = baselineBuffer.length === compareBuffer.length;
3357
+ const areIdentical = areSameSize && baselineBuffer.equals(compareBuffer);
3358
+ console.log("");
3359
+ if (areIdentical) {
3360
+ console.log(pc2.green("\u2705 Screenshots are identical"));
3361
+ } else {
3362
+ console.log(pc2.yellow("\u26A0\uFE0F Screenshots differ"));
3363
+ console.log(pc2.dim(` Baseline size: ${baselineBuffer.length} bytes`));
3364
+ console.log(pc2.dim(` Current size: ${compareBuffer.length} bytes`));
3365
+ console.log("");
3366
+ console.log(
3367
+ pc2.dim(
3368
+ "For detailed LLM-based comparison, use the GitHub App's visual testing."
3369
+ )
3370
+ );
3371
+ console.log(pc2.dim(`Comparison saved to: ${comparePath}`));
3372
+ process.exit(1);
3373
+ }
3374
+ } catch (error) {
3375
+ console.error(pc2.red("\n\u274C Failed to compare:"), error);
3376
+ process.exit(1);
3377
+ }
3378
+ }
3379
+ async function visualListCommand(options) {
3380
+ const metadata = loadMetadata();
3381
+ const baselines = Object.values(metadata);
3382
+ if (options.json) {
3383
+ console.log(JSON.stringify(baselines, null, 2));
3384
+ return;
3385
+ }
3386
+ if (baselines.length === 0) {
3387
+ console.log(pc2.dim("No baselines found."));
3388
+ console.log(pc2.dim("Create one with: workflow visual capture <name> <url>"));
3389
+ return;
3390
+ }
3391
+ console.log(pc2.cyan("\n\u{1F4F8} Visual Baselines\n"));
3392
+ for (const baseline of baselines) {
3393
+ console.log(` ${pc2.bold(baseline.name)}`);
3394
+ console.log(` URL: ${baseline.url}`);
3395
+ console.log(` Viewport: ${baseline.width}x${baseline.height}`);
3396
+ console.log(` Path: ${baseline.path}`);
3397
+ console.log(` Updated: ${baseline.updatedAt}`);
3398
+ console.log("");
3399
+ }
3400
+ }
3401
+ async function visualUpdateCommand(name, options) {
3402
+ const metadata = loadMetadata();
3403
+ const baseline = metadata[name];
3404
+ if (!baseline) {
3405
+ console.log(pc2.red(`\u274C Baseline "${name}" not found`));
3406
+ process.exit(1);
3407
+ }
3408
+ console.log(pc2.cyan(`
3409
+ \u{1F504} Updating baseline "${name}"...
3410
+ `));
3411
+ await visualCaptureCommand(name, baseline.url, {
3412
+ width: options.width || String(baseline.width),
3413
+ height: options.height || String(baseline.height),
3414
+ fullPage: options.fullPage,
3415
+ output: baseline.path
3416
+ });
3417
+ }
3418
+ async function visualApproveCommand(name) {
3419
+ const metadata = loadMetadata();
3420
+ const baseline = metadata[name];
3421
+ if (!baseline) {
3422
+ console.log(pc2.red(`\u274C Baseline "${name}" not found`));
3423
+ process.exit(1);
3424
+ }
3425
+ const confirm8 = await p8.confirm({
3426
+ message: `Update baseline "${name}" with the latest comparison?`,
3427
+ initialValue: false
3428
+ });
3429
+ if (p8.isCancel(confirm8) || !confirm8) {
3430
+ console.log(pc2.dim("Cancelled."));
3431
+ return;
3432
+ }
3433
+ const baselinesDir = getBaselinesDir();
3434
+ const comparisonsDir = join11(baselinesDir, "comparisons");
3435
+ if (!existsSync11(comparisonsDir)) {
3436
+ console.log(pc2.yellow("No comparisons found to approve."));
3437
+ return;
3438
+ }
3439
+ console.log(
3440
+ pc2.yellow(
3441
+ "To approve, re-capture the baseline with: workflow visual update " + name
3442
+ )
3443
+ );
3444
+ }
3445
+
2711
3446
  // src/cli/index.ts
2712
3447
  var program = new Command2();
2713
- program.name("workflow").description("A self-evolving workflow management system for AI agent development").version("1.0.0");
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);
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);
3448
+ program.name("workflow").description(
3449
+ "A self-evolving workflow management system for AI agent development"
3450
+ ).version("1.0.0");
3451
+ program.command("init").description("Initialize workflow in current project").option("--migrate", "Auto-detect existing patterns and migrate").option("--workspace", "Initialize for multiple repositories").option(
3452
+ "--preset <preset>",
3453
+ "Preset to use (saas, library, api, ecommerce, cms, custom)"
3454
+ ).option("--name <name>", "Project name").option("-y, --yes", "Skip confirmation prompts").action(initCommand);
3455
+ program.command("validate <type>").description("Validate branch name, commit message, or PR title").argument("<type>", "What to validate: branch, commit, or pr").argument(
3456
+ "[value]",
3457
+ "Value to validate (defaults to current branch/HEAD commit)"
3458
+ ).option(
3459
+ "--suggest-on-error",
3460
+ "Offer improvement suggestions on validation errors"
3461
+ ).action(validateCommand);
2716
3462
  program.addCommand(createConfigCommand());
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);
3463
+ program.command("suggest").description("Submit an improvement suggestion").argument("<feedback>", "Your improvement suggestion").option("--author <author>", "Your name or username").option(
3464
+ "--category <category>",
3465
+ "Category: feature, bug, documentation, performance, other"
3466
+ ).action(suggestCommand);
2718
3467
  program.command("setup").description("Add workflow scripts to package.json").action(setupCommand);
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);
3468
+ program.command("doctor").description("Run health check and get optimization suggestions").option(
3469
+ "--check-guidelines-only",
3470
+ "Only check mandatory guidelines exist (exits 0 or 1)"
3471
+ ).action(doctorCommand);
2720
3472
  program.command("hooks").description("Manage git hooks (install, uninstall, status)").argument("<action>", "Action: install, uninstall, status").action(hooksCommand);
2721
3473
  program.command("github").description("Manage GitHub Actions CI (setup, check)").argument("<action>", "Action: setup, check").action(githubCommand);
2722
- program.command("scope:create").description("Create a custom scope package").option("--name <name>", 'Package name (e.g., "fintech", "gaming")').option("--scopes <scopes>", "Comma-separated scopes (format: name:description:emoji:category)").option("--preset-name <preset>", "Preset display name").option("--output-dir <dir>", "Output directory").option("--no-test", "Skip test file generation").action(scopeCreateCommand);
3474
+ program.command("scope:create").description("Create a custom scope package").option("--name <name>", 'Package name (e.g., "fintech", "gaming")').option(
3475
+ "--scopes <scopes>",
3476
+ "Comma-separated scopes (format: name:description:emoji:category)"
3477
+ ).option("--preset-name <preset>", "Preset display name").option("--output-dir <dir>", "Output directory").option("--no-test", "Skip test file generation").action(scopeCreateCommand);
2723
3478
  program.command("scope:migrate").description("Migrate inline scopes to a custom package").option("--name <name>", "Package name for the preset").option("--output-dir <dir>", "Output directory").option("--keep-config", "Keep inline scopes in config after migration").action(scopeMigrateCommand);
3479
+ program.command("fix").description("Auto-heal pipeline failures using LLM").option("--error <error>", "Error message to fix (required)").option("--context <context>", "Additional context JSON").option("--files <files>", "Comma-separated file paths to analyze").option("--auto", "Apply fix automatically without confirmation").option("--dry-run", "Show what would be changed without applying").action((options) => {
3480
+ fixCommand({
3481
+ error: options.error,
3482
+ context: options.context,
3483
+ files: options.files?.split(","),
3484
+ auto: options.auto,
3485
+ dryRun: options.dryRun
3486
+ });
3487
+ });
3488
+ var visual = program.command("visual").description("Visual testing commands");
3489
+ visual.command("capture").description("Capture a new baseline screenshot").argument("<name>", "Name for the baseline").argument("<url>", "URL to capture").option("-w, --width <width>", "Viewport width", "1280").option("-h, --height <height>", "Viewport height", "720").option("--full-page", "Capture full page").option("-o, --output <path>", "Output path").option("--wait-for <selector>", "Wait for selector before capture").option("--delay <ms>", "Additional delay in ms").action(visualCaptureCommand);
3490
+ visual.command("compare").description("Compare a URL against a baseline").argument("<url>", "URL to compare").option("-b, --baseline <name>", "Baseline name to compare against (required)").option("-o, --output <path>", "Output path for comparison screenshot").option("-t, --threshold <percent>", "Difference threshold percentage").action((url, options) => {
3491
+ if (!options.baseline) {
3492
+ console.error("Error: --baseline is required");
3493
+ process.exit(1);
3494
+ }
3495
+ visualCompareCommand(url, options);
3496
+ });
3497
+ visual.command("list").description("List all baselines").option("--json", "Output as JSON").action(visualListCommand);
3498
+ visual.command("update").description("Update an existing baseline").argument("<name>", "Baseline name to update").option("-w, --width <width>", "Override viewport width").option("-h, --height <height>", "Override viewport height").option("--full-page", "Capture full page").action(visualUpdateCommand);
3499
+ visual.command("approve").description("Approve a comparison as the new baseline").argument("<name>", "Baseline name to approve").action(visualApproveCommand);
2724
3500
  program.parse();
2725
3501
  //# sourceMappingURL=index.js.map