workflow-agent-cli 2.0.1 → 2.2.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/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
  **Workflow Agent** is a portable, framework-agnostic CLI tool that brings structure and consistency to your development workflow. It enforces branch naming conventions, validates commit messages, and includes a self-improvement system that learns from community feedback.
11
11
 
12
12
  **šŸŽÆ Perfect for:**
13
+
13
14
  - AI agent development with strict workflow requirements
14
15
  - Teams maintaining multiple repositories
15
16
  - Open source projects enforcing contribution guidelines
@@ -94,6 +95,7 @@ This adds these scripts to your `package.json`:
94
95
  ### 1. Initialize Your Project
95
96
 
96
97
  #### Interactive Mode
98
+
97
99
  ```bash
98
100
  # If installed globally:
99
101
  workflow-agent init
@@ -107,11 +109,13 @@ pnpm run workflow:init
107
109
  ```
108
110
 
109
111
  Prompts you to:
112
+
110
113
  1. Enter project name
111
114
  2. Choose a preset (SaaS, Library, API, E-commerce, CMS, Custom)
112
115
  3. Generate guidelines (optional)
113
116
 
114
117
  #### Non-Interactive Mode
118
+
115
119
  ```bash
116
120
  # Perfect for CI/CD or automation
117
121
 
@@ -134,6 +138,7 @@ workflow-agent validate commit "feat(auth): add OAuth support"
134
138
  ```
135
139
 
136
140
  **Expected formats:**
141
+
137
142
  - **Branch:** `<type>/<scope>/<description>`
138
143
  - Types: `feature`, `bugfix`, `hotfix`, `chore`, `refactor`, `docs`, `test`
139
144
  - Example: `feature/auth/implement-2fa`
@@ -172,30 +177,33 @@ workflow-agent scope:migrate
172
177
 
173
178
  ## šŸ› ļø Commands
174
179
 
175
- | Command | Description |
176
- |---------|-------------|
177
- | `workflow-agent init` | Initialize project with interactive prompts |
178
- | `workflow-agent validate branch [name]` | Validate branch name format |
179
- | `workflow-agent validate commit [message]` | Validate commit message format |
180
- | `workflow-agent config get [key]` | View configuration values |
181
- | `workflow-agent config set <key> <value>` | Update configuration |
182
- | `workflow-agent suggest <idea>` | Submit improvement suggestion |
183
- | `workflow-agent doctor` | Run health checks and get optimization tips |
184
- | `workflow-agent scope:create` | Create a custom scope package |
185
- | `workflow-agent scope:migrate` | Migrate inline scopes to package |
180
+ | Command | Description |
181
+ | ------------------------------------------ | ------------------------------------------- |
182
+ | `workflow-agent init` | Initialize project with interactive prompts |
183
+ | `workflow-agent validate branch [name]` | Validate branch name format |
184
+ | `workflow-agent validate commit [message]` | Validate commit message format |
185
+ | `workflow-agent config get [key]` | View configuration values |
186
+ | `workflow-agent config set <key> <value>` | Update configuration |
187
+ | `workflow-agent suggest <idea>` | Submit improvement suggestion |
188
+ | `workflow-agent doctor` | Run health checks and get optimization tips |
189
+ | `workflow-agent scope:create` | Create a custom scope package |
190
+ | `workflow-agent scope:migrate` | Migrate inline scopes to package |
186
191
 
187
192
  ### Command Options
188
193
 
189
194
  #### `init`
195
+
190
196
  - `--preset <name>` - Skip preset selection (saas, library, api, ecommerce, cms, custom)
191
197
  - `--name <name>` - Set project name without prompt
192
198
  - `--yes` - Accept all defaults (non-interactive)
193
199
 
194
200
  #### `validate`
201
+
195
202
  - `--fix` - Apply automatic fixes (coming soon)
196
203
  - `--json` - Output in JSON format
197
204
 
198
205
  #### `suggest`
206
+
199
207
  - `--category <type>` - Suggestion category (feature, bug, improvement, documentation)
200
208
  - `--author <name>` - Your name or username
201
209
 
@@ -204,18 +212,23 @@ workflow-agent scope:migrate
204
212
  ## šŸ“¦ Preset Scope Libraries
205
213
 
206
214
  ### SaaS (17 scopes)
215
+
207
216
  `auth`, `billing`, `analytics`, `notifications`, `teams`, `admin`, `api`, `integration`, `subscription`, `dashboard`, `onboarding`, `settings`, `payments`, `reports`, `support`, `webhooks`, `search`
208
217
 
209
218
  ### Library (10 scopes)
219
+
210
220
  `core`, `utils`, `types`, `config`, `cli`, `api`, `docs`, `examples`, `test`, `build`
211
221
 
212
222
  ### API (13 scopes)
223
+
213
224
  `routes`, `middleware`, `controllers`, `models`, `services`, `auth`, `validation`, `errors`, `logging`, `cache`, `queue`, `websocket`, `graphql`
214
225
 
215
226
  ### E-commerce (12 scopes)
227
+
216
228
  `products`, `cart`, `checkout`, `orders`, `payments`, `shipping`, `inventory`, `customers`, `reviews`, `discounts`, `recommendations`, `analytics`
217
229
 
218
230
  ### CMS (13 scopes)
231
+
219
232
  `content`, `media`, `pages`, `posts`, `categories`, `tags`, `users`, `comments`, `seo`, `templates`, `widgets`, `api`, `admin`
220
233
 
221
234
  ---
@@ -234,12 +247,12 @@ workflow-agent scope:create
234
247
  // packages/scopes-medical/src/index.ts
235
248
  export default {
236
249
  scopes: [
237
- { name: 'patient', description: 'Patient records and profiles' },
238
- { name: 'appointment', description: 'Scheduling and appointments' },
239
- { name: 'billing', description: 'Medical billing and insurance' },
240
- { name: 'prescription', description: 'Prescriptions and medications' },
241
- { name: 'lab', description: 'Laboratory tests and results' }
242
- ]
250
+ { name: "patient", description: "Patient records and profiles" },
251
+ { name: "appointment", description: "Scheduling and appointments" },
252
+ { name: "billing", description: "Medical billing and insurance" },
253
+ { name: "prescription", description: "Prescriptions and medications" },
254
+ { name: "lab", description: "Laboratory tests and results" },
255
+ ],
243
256
  };
244
257
  ```
245
258
 
@@ -298,6 +311,7 @@ This typically means your npm token doesn't have the correct permissions. To fix
298
311
  - Copy the token immediately
299
312
 
300
313
  2. **Test the token locally:**
314
+
301
315
  ```bash
302
316
  echo '//registry.npmjs.org/:_authToken=YOUR_TOKEN' > ~/.npmrc
303
317
  npm whoami # Should show your npm username
@@ -379,6 +393,7 @@ pnpm build
379
393
  If templates aren't bundled with the npm package:
380
394
 
381
395
  1. **Ensure templates are in the package:**
396
+
382
397
  ```json
383
398
  // packages/core/package.json
384
399
  {
@@ -387,6 +402,7 @@ If templates aren't bundled with the npm package:
387
402
  ```
388
403
 
389
404
  2. **Copy templates to package directory:**
405
+
390
406
  ```bash
391
407
  cp -r templates packages/core/
392
408
  ```
@@ -0,0 +1,293 @@
1
+ // src/config/index.ts
2
+ import { cosmiconfig } from "cosmiconfig";
3
+
4
+ // src/config/schema.ts
5
+ import { z } from "zod";
6
+ var DEFAULT_RESERVED_SCOPE_NAMES = [
7
+ "init",
8
+ "create",
9
+ "build",
10
+ "test",
11
+ "config",
12
+ "docs",
13
+ "ci",
14
+ "deps"
15
+ ];
16
+ function validateScopeName(name, reservedNames = DEFAULT_RESERVED_SCOPE_NAMES) {
17
+ if (reservedNames.includes(name)) {
18
+ const suggestions = {
19
+ docs: "documentation",
20
+ test: "testing",
21
+ config: "configuration",
22
+ build: "builds",
23
+ ci: "cicd",
24
+ deps: "dependencies"
25
+ };
26
+ return {
27
+ valid: false,
28
+ error: `Scope name "${name}" is reserved`,
29
+ suggestion: suggestions[name] || `${name}-scope`
30
+ };
31
+ }
32
+ if (!/^[a-z0-9-]+$/.test(name)) {
33
+ return {
34
+ valid: false,
35
+ error: "Scope name must be lowercase alphanumeric with hyphens"
36
+ };
37
+ }
38
+ if (name.length === 0 || name.length > 32) {
39
+ return {
40
+ valid: false,
41
+ error: "Scope name must be 1-32 characters"
42
+ };
43
+ }
44
+ return { valid: true };
45
+ }
46
+ var BranchTypeSchema = z.enum([
47
+ "feature",
48
+ "bugfix",
49
+ "hotfix",
50
+ "chore",
51
+ "refactor",
52
+ "docs",
53
+ "test",
54
+ "release"
55
+ ]);
56
+ var ConventionalTypeSchema = z.enum([
57
+ "feat",
58
+ "fix",
59
+ "refactor",
60
+ "chore",
61
+ "docs",
62
+ "test",
63
+ "perf",
64
+ "style",
65
+ "ci",
66
+ "build",
67
+ "revert"
68
+ ]);
69
+ var ScopeSchema = z.object({
70
+ name: z.string().min(1).max(32, "Scope name must be 32 characters or less").regex(
71
+ /^[a-z0-9-]+$/,
72
+ "Scope name must be lowercase alphanumeric with hyphens"
73
+ ),
74
+ description: z.string().min(10, "Scope description must be at least 10 characters"),
75
+ allowedTypes: z.array(ConventionalTypeSchema).optional(),
76
+ mandatoryGuidelines: z.array(z.string()).optional(),
77
+ emoji: z.string().optional(),
78
+ category: z.enum([
79
+ "auth",
80
+ "features",
81
+ "infrastructure",
82
+ "documentation",
83
+ "testing",
84
+ "performance",
85
+ "other"
86
+ ]).optional()
87
+ });
88
+ var EnforcementLevelSchema = z.enum([
89
+ "strict",
90
+ "advisory",
91
+ "learning"
92
+ ]);
93
+ var AnalyticsConfigSchema = z.object({
94
+ enabled: z.boolean().default(false),
95
+ shareAnonymous: z.boolean().default(false)
96
+ });
97
+ var HookCheckSchema = z.enum([
98
+ "validate-branch",
99
+ "validate-commit",
100
+ "check-guidelines",
101
+ "validate-scopes"
102
+ ]);
103
+ var HooksConfigSchema = z.object({
104
+ /** Whether hooks are enabled */
105
+ enabled: z.boolean().default(true),
106
+ /** Checks to run on pre-commit */
107
+ preCommit: z.array(HookCheckSchema).default(["validate-branch", "check-guidelines"]),
108
+ /** Checks to run on commit-msg */
109
+ commitMsg: z.array(HookCheckSchema).default(["validate-commit"])
110
+ });
111
+ var GuidelinesConfigSchema = z.object({
112
+ /** Additional templates to make mandatory (beyond the core set) */
113
+ additionalMandatory: z.array(z.string()).optional(),
114
+ /** Templates to make optional (override core mandatory templates) */
115
+ optionalOverrides: z.array(z.string()).optional()
116
+ });
117
+ var CIProviderSchema = z.enum(["github", "gitlab", "bitbucket"]);
118
+ var CICheckSchema = z.enum([
119
+ "lint",
120
+ "typecheck",
121
+ "format",
122
+ "test",
123
+ "build"
124
+ ]);
125
+ var CIConfigSchema = z.object({
126
+ /** Whether CI setup is enabled */
127
+ enabled: z.boolean().default(true),
128
+ /** CI provider (currently only github supported) */
129
+ provider: CIProviderSchema.default("github"),
130
+ /** Checks to run in CI pipeline */
131
+ checks: z.array(CICheckSchema).default(["lint", "typecheck", "format", "build", "test"])
132
+ });
133
+ var WorkflowConfigSchema = z.object({
134
+ projectName: z.string().min(1),
135
+ scopes: z.array(ScopeSchema).min(1),
136
+ branchTypes: z.array(BranchTypeSchema).optional(),
137
+ conventionalTypes: z.array(ConventionalTypeSchema).optional(),
138
+ enforcement: EnforcementLevelSchema.default("strict"),
139
+ language: z.string().default("en"),
140
+ analytics: AnalyticsConfigSchema.optional(),
141
+ adapter: z.string().optional(),
142
+ syncRemote: z.string().optional(),
143
+ hooks: HooksConfigSchema.optional(),
144
+ guidelines: GuidelinesConfigSchema.optional(),
145
+ reservedScopeNames: z.array(z.string()).optional().default(DEFAULT_RESERVED_SCOPE_NAMES),
146
+ ci: CIConfigSchema.optional()
147
+ }).superRefine((config, ctx) => {
148
+ const reservedNames = config.reservedScopeNames || DEFAULT_RESERVED_SCOPE_NAMES;
149
+ config.scopes.forEach((scope, index) => {
150
+ const validation = validateScopeName(scope.name, reservedNames);
151
+ if (!validation.valid) {
152
+ let message = validation.error || "Invalid scope name";
153
+ if (validation.suggestion) {
154
+ message += `. Try renaming to "${validation.suggestion}"`;
155
+ }
156
+ ctx.addIssue({
157
+ code: z.ZodIssueCode.custom,
158
+ path: ["scopes", index, "name"],
159
+ message
160
+ });
161
+ }
162
+ });
163
+ });
164
+ function validateScopeDefinitions(scopes) {
165
+ const errors = [];
166
+ const seenNames = /* @__PURE__ */ new Set();
167
+ for (const scope of scopes) {
168
+ if (seenNames.has(scope.name)) {
169
+ errors.push(`Duplicate scope name: "${scope.name}"`);
170
+ }
171
+ seenNames.add(scope.name);
172
+ const result = ScopeSchema.safeParse(scope);
173
+ if (!result.success) {
174
+ result.error.errors.forEach((err) => {
175
+ errors.push(`Scope "${scope.name}": ${err.message}`);
176
+ });
177
+ }
178
+ }
179
+ return {
180
+ valid: errors.length === 0,
181
+ errors
182
+ };
183
+ }
184
+
185
+ // src/config/index.ts
186
+ import { join } from "path";
187
+ import { existsSync } from "fs";
188
+ import { z as z2 } from "zod";
189
+ var explorer = cosmiconfig("workflow", {
190
+ searchPlaces: [
191
+ "workflow.config.ts",
192
+ "workflow.config.js",
193
+ "workflow.config.json",
194
+ ".workflowrc",
195
+ ".workflowrc.json",
196
+ "package.json"
197
+ ]
198
+ });
199
+ async function loadConfig(cwd = process.cwd()) {
200
+ try {
201
+ const result = await explorer.search(cwd);
202
+ if (!result || !result.config) {
203
+ return null;
204
+ }
205
+ const validated = WorkflowConfigSchema.parse(result.config);
206
+ return validated;
207
+ } catch (error) {
208
+ if (error instanceof z2.ZodError) {
209
+ const result = await explorer.search(cwd);
210
+ const formattedErrors = error.errors.map((err) => {
211
+ const path = err.path.join(".");
212
+ if (err.path[0] === "scopes" && typeof err.path[1] === "number") {
213
+ const scopeIndex = err.path[1];
214
+ const scopeName = result?.config?.scopes?.[scopeIndex]?.name || `scope at index ${scopeIndex}`;
215
+ const field = err.path[2] || "definition";
216
+ let message = err.message;
217
+ if (message.includes("reserved word")) {
218
+ const reservedMatch = message.match(
219
+ /Scope name "([^"]+)" is reserved/
220
+ );
221
+ if (reservedMatch) {
222
+ const suggestions = {
223
+ docs: "documentation",
224
+ test: "testing",
225
+ config: "configuration",
226
+ build: "builds",
227
+ ci: "cicd",
228
+ deps: "dependencies"
229
+ };
230
+ const badName = reservedMatch[1];
231
+ const suggestion = suggestions[badName] || `${badName}-scope`;
232
+ message = `${message}. Try renaming to "${suggestion}"`;
233
+ }
234
+ }
235
+ return field === "definition" ? `Scope "${scopeName}": ${message}` : `Scope "${scopeName}" ${field}: ${message}`;
236
+ }
237
+ return `${path}: ${err.message}`;
238
+ }).join("\n \u2022 ");
239
+ throw new Error(
240
+ `Invalid workflow configuration:
241
+ \u2022 ${formattedErrors}
242
+
243
+ \u{1F4A1} Fix these issues in workflow.config.json or run: workflow config validate`
244
+ );
245
+ }
246
+ if (error instanceof Error) {
247
+ throw new Error(`Failed to load workflow config: ${error.message}`);
248
+ }
249
+ throw error;
250
+ }
251
+ }
252
+ async function validateConfig(cwd = process.cwd()) {
253
+ const errors = [];
254
+ const warnings = [];
255
+ try {
256
+ const config = await loadConfig(cwd);
257
+ if (!config) {
258
+ errors.push("No configuration file found");
259
+ return { valid: false, errors, warnings };
260
+ }
261
+ const scopeValidation = validateScopeDefinitions(config.scopes);
262
+ errors.push(...scopeValidation.errors);
263
+ return {
264
+ valid: errors.length === 0,
265
+ errors,
266
+ warnings
267
+ };
268
+ } catch (error) {
269
+ errors.push(error instanceof Error ? error.message : String(error));
270
+ return { valid: false, errors, warnings };
271
+ }
272
+ }
273
+ function hasConfig(cwd = process.cwd()) {
274
+ const configPaths = [
275
+ "workflow.config.ts",
276
+ "workflow.config.js",
277
+ "workflow.config.json",
278
+ ".workflowrc",
279
+ ".workflowrc.json"
280
+ ];
281
+ return configPaths.some((path) => existsSync(join(cwd, path)));
282
+ }
283
+
284
+ export {
285
+ DEFAULT_RESERVED_SCOPE_NAMES,
286
+ validateScopeName,
287
+ WorkflowConfigSchema,
288
+ validateScopeDefinitions,
289
+ loadConfig,
290
+ validateConfig,
291
+ hasConfig
292
+ };
293
+ //# sourceMappingURL=chunk-IPMSSOXR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/index.ts","../src/config/schema.ts"],"sourcesContent":["import { cosmiconfig } from \"cosmiconfig\";\nimport {\n WorkflowConfig,\n WorkflowConfigSchema,\n validateScopeDefinitions,\n} from \"./schema.js\";\nimport { join } from \"path\";\nimport { existsSync } from \"fs\";\nimport { z } from \"zod\";\n\nconst explorer = cosmiconfig(\"workflow\", {\n searchPlaces: [\n \"workflow.config.ts\",\n \"workflow.config.js\",\n \"workflow.config.json\",\n \".workflowrc\",\n \".workflowrc.json\",\n \"package.json\",\n ],\n});\n\nexport async function loadConfig(\n cwd: string = process.cwd(),\n): Promise<WorkflowConfig | null> {\n try {\n const result = await explorer.search(cwd);\n\n if (!result || !result.config) {\n return null;\n }\n\n // Validate config against schema\n const validated = WorkflowConfigSchema.parse(result.config);\n return validated;\n } catch (error) {\n if (error instanceof z.ZodError) {\n // Format Zod errors to be more user-friendly\n const result = await explorer.search(cwd);\n const formattedErrors = error.errors\n .map((err) => {\n const path = err.path.join(\".\");\n\n // If error is in scopes array, show the scope name\n if (err.path[0] === \"scopes\" && typeof err.path[1] === \"number\") {\n const scopeIndex = err.path[1];\n const scopeName =\n result?.config?.scopes?.[scopeIndex]?.name ||\n `scope at index ${scopeIndex}`;\n const field = err.path[2] || \"definition\";\n\n // Add helpful suggestions for common errors\n let message = err.message;\n if (message.includes(\"reserved word\")) {\n const reservedMatch = message.match(\n /Scope name \"([^\"]+)\" is reserved/,\n );\n if (reservedMatch) {\n const suggestions: Record<string, string> = {\n docs: \"documentation\",\n test: \"testing\",\n config: \"configuration\",\n build: \"builds\",\n ci: \"cicd\",\n deps: \"dependencies\",\n };\n const badName = reservedMatch[1];\n const suggestion = suggestions[badName] || `${badName}-scope`;\n message = `${message}. Try renaming to \"${suggestion}\"`;\n }\n }\n\n return field === \"definition\"\n ? `Scope \"${scopeName}\": ${message}`\n : `Scope \"${scopeName}\" ${field}: ${message}`;\n }\n\n return `${path}: ${err.message}`;\n })\n .join(\"\\n • \");\n\n throw new Error(\n `Invalid workflow configuration:\\n • ${formattedErrors}\\n\\nšŸ’” Fix these issues in workflow.config.json or run: workflow config validate`,\n );\n }\n\n if (error instanceof Error) {\n throw new Error(`Failed to load workflow config: ${error.message}`);\n }\n throw error;\n }\n}\n\nexport async function validateConfig(cwd: string = process.cwd()): Promise<{\n valid: boolean;\n errors: string[];\n warnings: string[];\n}> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n try {\n const config = await loadConfig(cwd);\n if (!config) {\n errors.push(\"No configuration file found\");\n return { valid: false, errors, warnings };\n }\n\n // Additional validation beyond schema\n const scopeValidation = validateScopeDefinitions(config.scopes);\n errors.push(...scopeValidation.errors);\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n return { valid: false, errors, warnings };\n }\n}\n\nexport function hasConfig(cwd: string = process.cwd()): boolean {\n const configPaths = [\n \"workflow.config.ts\",\n \"workflow.config.js\",\n \"workflow.config.json\",\n \".workflowrc\",\n \".workflowrc.json\",\n ];\n\n return configPaths.some((path) => existsSync(join(cwd, path)));\n}\n\nexport {\n WorkflowConfig,\n WorkflowConfigSchema,\n Scope,\n BranchType,\n ConventionalType,\n validateScopeName,\n DEFAULT_RESERVED_SCOPE_NAMES,\n} from \"./schema.js\";\n","import { z } from \"zod\";\n\n// Default reserved scope names that cannot be used\nexport const DEFAULT_RESERVED_SCOPE_NAMES = [\n \"init\",\n \"create\",\n \"build\",\n \"test\",\n \"config\",\n \"docs\",\n \"ci\",\n \"deps\",\n];\n\n/**\n * Validates a scope name against reserved words and naming rules\n */\nexport function validateScopeName(\n name: string,\n reservedNames: string[] = DEFAULT_RESERVED_SCOPE_NAMES,\n): {\n valid: boolean;\n error?: string;\n suggestion?: string;\n} {\n if (reservedNames.includes(name)) {\n // Provide suggestions for common reserved words\n const suggestions: Record<string, string> = {\n docs: \"documentation\",\n test: \"testing\",\n config: \"configuration\",\n build: \"builds\",\n ci: \"cicd\",\n deps: \"dependencies\",\n };\n\n return {\n valid: false,\n error: `Scope name \"${name}\" is reserved`,\n suggestion: suggestions[name] || `${name}-scope`,\n };\n }\n\n if (!/^[a-z0-9-]+$/.test(name)) {\n return {\n valid: false,\n error: \"Scope name must be lowercase alphanumeric with hyphens\",\n };\n }\n\n if (name.length === 0 || name.length > 32) {\n return {\n valid: false,\n error: \"Scope name must be 1-32 characters\",\n };\n }\n\n return { valid: true };\n}\n\nexport const BranchTypeSchema = z.enum([\n \"feature\",\n \"bugfix\",\n \"hotfix\",\n \"chore\",\n \"refactor\",\n \"docs\",\n \"test\",\n \"release\",\n]);\n\nexport const ConventionalTypeSchema = z.enum([\n \"feat\",\n \"fix\",\n \"refactor\",\n \"chore\",\n \"docs\",\n \"test\",\n \"perf\",\n \"style\",\n \"ci\",\n \"build\",\n \"revert\",\n]);\n\nexport const ScopeSchema = z.object({\n name: z\n .string()\n .min(1)\n .max(32, \"Scope name must be 32 characters or less\")\n .regex(\n /^[a-z0-9-]+$/,\n \"Scope name must be lowercase alphanumeric with hyphens\",\n ),\n description: z\n .string()\n .min(10, \"Scope description must be at least 10 characters\"),\n allowedTypes: z.array(ConventionalTypeSchema).optional(),\n mandatoryGuidelines: z.array(z.string()).optional(),\n emoji: z.string().optional(),\n category: z\n .enum([\n \"auth\",\n \"features\",\n \"infrastructure\",\n \"documentation\",\n \"testing\",\n \"performance\",\n \"other\",\n ])\n .optional(),\n});\n\nexport const EnforcementLevelSchema = z.enum([\n \"strict\",\n \"advisory\",\n \"learning\",\n]);\n\nexport const AnalyticsConfigSchema = z.object({\n enabled: z.boolean().default(false),\n shareAnonymous: z.boolean().default(false),\n});\n\n// Pre-commit hook check types\nexport const HookCheckSchema = z.enum([\n \"validate-branch\",\n \"validate-commit\",\n \"check-guidelines\",\n \"validate-scopes\",\n]);\n\n// Git hooks configuration\nexport const HooksConfigSchema = z.object({\n /** Whether hooks are enabled */\n enabled: z.boolean().default(true),\n /** Checks to run on pre-commit */\n preCommit: z\n .array(HookCheckSchema)\n .default([\"validate-branch\", \"check-guidelines\"]),\n /** Checks to run on commit-msg */\n commitMsg: z.array(HookCheckSchema).default([\"validate-commit\"]),\n});\n\n// Guidelines configuration with mandatory templates and user overrides\nexport const GuidelinesConfigSchema = z.object({\n /** Additional templates to make mandatory (beyond the core set) */\n additionalMandatory: z.array(z.string()).optional(),\n /** Templates to make optional (override core mandatory templates) */\n optionalOverrides: z.array(z.string()).optional(),\n});\n\n// CI provider types\nexport const CIProviderSchema = z.enum([\"github\", \"gitlab\", \"bitbucket\"]);\n\n// CI check types\nexport const CICheckSchema = z.enum([\n \"lint\",\n \"typecheck\",\n \"format\",\n \"test\",\n \"build\",\n]);\n\n// CI/CD configuration\nexport const CIConfigSchema = z.object({\n /** Whether CI setup is enabled */\n enabled: z.boolean().default(true),\n /** CI provider (currently only github supported) */\n provider: CIProviderSchema.default(\"github\"),\n /** Checks to run in CI pipeline */\n checks: z\n .array(CICheckSchema)\n .default([\"lint\", \"typecheck\", \"format\", \"build\", \"test\"]),\n});\n\nexport const WorkflowConfigSchema = z\n .object({\n projectName: z.string().min(1),\n scopes: z.array(ScopeSchema).min(1),\n branchTypes: z.array(BranchTypeSchema).optional(),\n conventionalTypes: z.array(ConventionalTypeSchema).optional(),\n enforcement: EnforcementLevelSchema.default(\"strict\"),\n language: z.string().default(\"en\"),\n analytics: AnalyticsConfigSchema.optional(),\n adapter: z.string().optional(),\n syncRemote: z.string().optional(),\n hooks: HooksConfigSchema.optional(),\n guidelines: GuidelinesConfigSchema.optional(),\n reservedScopeNames: z\n .array(z.string())\n .optional()\n .default(DEFAULT_RESERVED_SCOPE_NAMES),\n ci: CIConfigSchema.optional(),\n })\n .superRefine((config, ctx) => {\n // Validate scopes against reserved names\n const reservedNames =\n config.reservedScopeNames || DEFAULT_RESERVED_SCOPE_NAMES;\n\n config.scopes.forEach((scope, index) => {\n const validation = validateScopeName(scope.name, reservedNames);\n if (!validation.valid) {\n let message = validation.error || \"Invalid scope name\";\n if (validation.suggestion) {\n message += `. Try renaming to \"${validation.suggestion}\"`;\n }\n\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"scopes\", index, \"name\"],\n message,\n });\n }\n });\n });\n\nexport type Scope = z.infer<typeof ScopeSchema>;\nexport type BranchType = z.infer<typeof BranchTypeSchema>;\nexport type ConventionalType = z.infer<typeof ConventionalTypeSchema>;\nexport type EnforcementLevel = z.infer<typeof EnforcementLevelSchema>;\nexport type AnalyticsConfig = z.infer<typeof AnalyticsConfigSchema>;\nexport type HookCheck = z.infer<typeof HookCheckSchema>;\nexport type HooksConfig = z.infer<typeof HooksConfigSchema>;\nexport type GuidelinesConfig = z.infer<typeof GuidelinesConfigSchema>;\nexport type CIProvider = z.infer<typeof CIProviderSchema>;\nexport type CICheck = z.infer<typeof CICheckSchema>;\nexport type CIConfig = z.infer<typeof CIConfigSchema>;\nexport type WorkflowConfig = z.infer<typeof WorkflowConfigSchema>;\n\nexport const defaultBranchTypes: BranchType[] = [\n \"feature\",\n \"bugfix\",\n \"hotfix\",\n \"chore\",\n \"refactor\",\n \"docs\",\n \"test\",\n];\n\nexport const defaultConventionalTypes: ConventionalType[] = [\n \"feat\",\n \"fix\",\n \"refactor\",\n \"chore\",\n \"docs\",\n \"test\",\n \"perf\",\n \"style\",\n];\n\n/**\n * Validates scope definitions for duplicates, description quality, and category values\n * @param scopes Array of scope definitions to validate\n * @returns Object with validation result and error messages\n */\nexport function validateScopeDefinitions(scopes: Scope[]): {\n valid: boolean;\n errors: string[];\n} {\n const errors: string[] = [];\n const seenNames = new Set<string>();\n\n for (const scope of scopes) {\n // Check for duplicate names\n if (seenNames.has(scope.name)) {\n errors.push(`Duplicate scope name: \"${scope.name}\"`);\n }\n seenNames.add(scope.name);\n\n // Validate using schema (this will catch min length, reserved names, etc.)\n const result = ScopeSchema.safeParse(scope);\n if (!result.success) {\n result.error.errors.forEach((err) => {\n errors.push(`Scope \"${scope.name}\": ${err.message}`);\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n"],"mappings":"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","names":["z"]}
@@ -12,10 +12,7 @@ async function discoverCustomScopes(workspacePath = process.cwd()) {
12
12
  }
13
13
  const discoveredScopes = [];
14
14
  try {
15
- const workspaceLocations = [
16
- join(workspacePath, "packages"),
17
- workspacePath
18
- ];
15
+ const workspaceLocations = [join(workspacePath, "packages"), workspacePath];
19
16
  for (const location of workspaceLocations) {
20
17
  try {
21
18
  const entries = await readdir(location, { withFileTypes: true });
@@ -61,7 +58,15 @@ async function getAllScopes(config, workspacePath) {
61
58
  return Array.from(scopeMap.values());
62
59
  }
63
60
  async function validateBranchName(branchName, config, workspacePath) {
64
- const branchTypes = config.branchTypes || ["feature", "bugfix", "hotfix", "chore", "refactor", "docs", "test"];
61
+ const branchTypes = config.branchTypes || [
62
+ "feature",
63
+ "bugfix",
64
+ "hotfix",
65
+ "chore",
66
+ "refactor",
67
+ "docs",
68
+ "test"
69
+ ];
65
70
  const allScopes = await getAllScopes(config, workspacePath);
66
71
  const scopes = allScopes.map((s) => s.name);
67
72
  const branchPattern = /^([a-z]+)\/([a-z0-9-]+)\/([a-z0-9-]+)$/;
@@ -167,4 +172,4 @@ export {
167
172
  validateCommitMessage,
168
173
  validatePRTitle
169
174
  };
170
- //# sourceMappingURL=chunk-X2NQJ2ZY.js.map
175
+ //# sourceMappingURL=chunk-NMHWD2GA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/validators/index.ts"],"sourcesContent":["import didYouMean from \"didyoumean2\";\nimport type { WorkflowConfig, BranchType, Scope } from \"../config/index.js\";\nimport { readdir } from \"fs/promises\";\nimport { join } from \"path\";\n\nexport interface ValidationResult {\n valid: boolean;\n error?: string;\n suggestion?: string;\n}\n\n// Cache for discovered custom scopes\nlet customScopesCache: Scope[] | null = null;\nlet cacheTimestamp: number = 0;\nconst CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Discovers custom scope packages in the workspace and node_modules\n * @param workspacePath Path to workspace root\n * @returns Array of discovered scopes\n */\nexport async function discoverCustomScopes(\n workspacePath: string = process.cwd(),\n): Promise<Scope[]> {\n // Check cache validity\n const now = Date.now();\n if (customScopesCache && now - cacheTimestamp < CACHE_TTL) {\n return customScopesCache;\n }\n\n const discoveredScopes: Scope[] = [];\n\n try {\n // Search for custom scope packages in workspace\n const workspaceLocations = [join(workspacePath, \"packages\"), workspacePath];\n\n for (const location of workspaceLocations) {\n try {\n const entries = await readdir(location, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory() && entry.name.startsWith(\"scopes-\")) {\n const indexPath = join(location, entry.name, \"src\", \"index.ts\");\n try {\n const module = await import(indexPath);\n const scopes = module.scopes || module.default?.scopes;\n\n if (Array.isArray(scopes)) {\n discoveredScopes.push(...scopes);\n }\n } catch {\n // Silently skip packages that can't be loaded\n }\n }\n }\n } catch {\n // Directory doesn't exist or can't be read\n }\n }\n\n // Update cache\n customScopesCache = discoveredScopes;\n cacheTimestamp = now;\n } catch (error) {\n // Return empty array on error\n console.warn(\"Warning: Error discovering custom scopes:\", error);\n }\n\n return discoveredScopes;\n}\n\n/**\n * Invalidates the custom scopes cache (useful after config changes)\n */\nexport function invalidateCustomScopesCache(): void {\n customScopesCache = null;\n cacheTimestamp = 0;\n}\n\n/**\n * Gets all available scopes including custom discovered ones\n * @param config Workflow configuration\n * @param workspacePath Optional workspace path\n * @returns Combined array of scopes\n */\nexport async function getAllScopes(\n config: WorkflowConfig,\n workspacePath?: string,\n): Promise<Scope[]> {\n const configScopes = config.scopes;\n const customScopes = await discoverCustomScopes(workspacePath);\n\n // Merge and deduplicate by name\n const scopeMap = new Map<string, Scope>();\n\n // Config scopes take precedence\n for (const scope of configScopes) {\n scopeMap.set(scope.name, scope);\n }\n\n // Add custom scopes that don't conflict\n for (const scope of customScopes) {\n if (!scopeMap.has(scope.name)) {\n scopeMap.set(scope.name, scope);\n }\n }\n\n return Array.from(scopeMap.values());\n}\n\nexport async function validateBranchName(\n branchName: string,\n config: WorkflowConfig,\n workspacePath?: string,\n): Promise<ValidationResult> {\n const branchTypes = config.branchTypes || [\n \"feature\",\n \"bugfix\",\n \"hotfix\",\n \"chore\",\n \"refactor\",\n \"docs\",\n \"test\",\n ];\n const allScopes = await getAllScopes(config, workspacePath);\n const scopes = allScopes.map((s) => s.name);\n\n // Expected format: <type>/<scope>/<description>\n const branchPattern = /^([a-z]+)\\/([a-z0-9-]+)\\/([a-z0-9-]+)$/;\n const match = branchName.match(branchPattern);\n\n if (!match) {\n return {\n valid: false,\n error: `Branch name must follow format: <type>/<scope>/<description> (e.g., feature/auth/add-login)`,\n suggestion: `Current: ${branchName}. All parts must be lowercase alphanumeric with hyphens.`,\n };\n }\n\n const [, type, scope, description] = match;\n\n // Validate type\n if (!branchTypes.includes(type as BranchType)) {\n const suggestion = didYouMean(type, branchTypes);\n return {\n valid: false,\n error: `Invalid branch type '${type}'. Must be one of: ${branchTypes.join(\", \")}`,\n suggestion: suggestion ? `Did you mean '${suggestion}'?` : undefined,\n };\n }\n\n // Validate scope\n if (!scopes.includes(scope)) {\n const suggestion = didYouMean(scope, scopes);\n const scopeList =\n scopes.slice(0, 5).join(\", \") + (scopes.length > 5 ? \"...\" : \"\");\n return {\n valid: false,\n error: `Invalid scope '${scope}'. Must be one of: ${scopeList}`,\n suggestion: suggestion ? `Did you mean '${suggestion}'?` : undefined,\n };\n }\n\n // Validate description (not empty, meaningful)\n if (description.length < 3) {\n return {\n valid: false,\n error: `Branch description '${description}' is too short (minimum 3 characters)`,\n };\n }\n\n return { valid: true };\n}\n\nexport async function validateCommitMessage(\n message: string,\n config: WorkflowConfig,\n workspacePath?: string,\n): Promise<ValidationResult> {\n const conventionalTypes = config.conventionalTypes || [\n \"feat\",\n \"fix\",\n \"refactor\",\n \"chore\",\n \"docs\",\n \"test\",\n \"perf\",\n \"style\",\n ];\n const allScopes = await getAllScopes(config, workspacePath);\n const scopes = allScopes.map((s) => s.name);\n\n // Expected format: <type>(<scope>): <description>\n const commitPattern = /^([a-z]+)(?:\\(([a-z0-9-]+)\\))?: (.+)$/;\n const match = message.match(commitPattern);\n\n if (!match) {\n return {\n valid: false,\n error: `Commit message must follow conventional commits format: <type>(<scope>): <description>`,\n suggestion: `Example: feat(auth): add login validation`,\n };\n }\n\n const [, type, scope, description] = match;\n\n // Validate type\n if (!conventionalTypes.includes(type as any)) {\n const suggestion = didYouMean(type, conventionalTypes);\n return {\n valid: false,\n error: `Invalid commit type '${type}'. Must be one of: ${conventionalTypes.join(\", \")}`,\n suggestion: suggestion ? `Did you mean '${suggestion}'?` : undefined,\n };\n }\n\n // Validate scope (optional but recommended)\n if (scope && !scopes.includes(scope)) {\n const suggestion = didYouMean(scope, scopes);\n const scopeList =\n scopes.slice(0, 5).join(\", \") + (scopes.length > 5 ? \"...\" : \"\");\n return {\n valid: false,\n error: `Invalid scope '${scope}'. Must be one of: ${scopeList}`,\n suggestion: suggestion ? `Did you mean '${suggestion}'?` : undefined,\n };\n }\n\n // Validate description\n if (description.length < 10) {\n return {\n valid: false,\n error: `Commit description is too short (minimum 10 characters)`,\n suggestion: `Be more descriptive about what changed`,\n };\n }\n\n if (description[0] !== description[0].toLowerCase()) {\n return {\n valid: false,\n error: `Commit description must start with lowercase letter`,\n suggestion: `Change '${description}' to '${description[0].toLowerCase()}${description.slice(1)}'`,\n };\n }\n\n return { valid: true };\n}\n\nexport async function validatePRTitle(\n title: string,\n config: WorkflowConfig,\n workspacePath?: string,\n): Promise<ValidationResult> {\n // PR titles follow same format as commit messages\n return validateCommitMessage(title, config, workspacePath);\n}\n"],"mappings":"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","names":[]}