workflow-agent-cli 2.1.0 → 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.
@@ -51,12 +51,12 @@ Located in `vitest.config.ts`:
51
51
  export default defineConfig({
52
52
  test: {
53
53
  globals: true,
54
- environment: 'jsdom',
55
- setupFiles: ['./test/setup.ts'],
56
- include: ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
54
+ environment: "jsdom",
55
+ setupFiles: ["./test/setup.ts"],
56
+ include: ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
57
57
  coverage: {
58
- provider: 'v8',
59
- reporter: ['text', 'json', 'html'],
58
+ provider: "v8",
59
+ reporter: ["text", "json", "html"],
60
60
  },
61
61
  },
62
62
  });
@@ -149,16 +149,16 @@ describe("TaskCard", () => {
149
149
  #### Mocking Hooks
150
150
 
151
151
  ```typescript
152
- import { vi } from 'vitest';
152
+ import { vi } from "vitest";
153
153
 
154
154
  // Mock a custom hook
155
- vi.mock('@/hooks/useAuthorization', () => ({
155
+ vi.mock("@/hooks/useAuthorization", () => ({
156
156
  useAuthorization: () => ({
157
157
  can: {
158
158
  editTask: () => true,
159
159
  deleteTask: () => false,
160
160
  },
161
- currentUserRole: 'developer',
161
+ currentUserRole: "developer",
162
162
  }),
163
163
  }));
164
164
  ```
@@ -169,11 +169,11 @@ vi.mock('@/hooks/useAuthorization', () => ({
169
169
  // Already set up in test/setup.ts - uses MSW for API mocking
170
170
  // For unit tests, you can also mock directly:
171
171
 
172
- vi.mock('@/lib/supabase/client', () => ({
172
+ vi.mock("@/lib/supabase/client", () => ({
173
173
  getSupabaseClient: vi.fn(() => ({
174
174
  auth: {
175
175
  getUser: vi.fn().mockResolvedValue({
176
- data: { user: { id: 'test-user-id', email: 'test@example.com' } },
176
+ data: { user: { id: "test-user-id", email: "test@example.com" } },
177
177
  error: null,
178
178
  }),
179
179
  },
@@ -191,7 +191,7 @@ vi.mock('@/lib/supabase/client', () => ({
191
191
  #### Mocking Server Actions
192
192
 
193
193
  ```typescript
194
- vi.mock('@/app/actions/tasks', () => ({
194
+ vi.mock("@/app/actions/tasks", () => ({
195
195
  getTasks: vi.fn().mockResolvedValue({ data: mockTasks, error: null }),
196
196
  createTask: vi.fn().mockResolvedValue({ data: mockTask, error: null }),
197
197
  deleteTask: vi.fn().mockResolvedValue({ success: true, error: null }),
@@ -397,25 +397,25 @@ Located in `playwright.config.ts`:
397
397
 
398
398
  ```typescript
399
399
  export default defineConfig({
400
- testDir: './e2e',
400
+ testDir: "./e2e",
401
401
  fullyParallel: true,
402
402
  retries: process.env.CI ? 2 : 0,
403
403
  workers: process.env.CI ? 1 : undefined,
404
- reporter: 'html',
404
+ reporter: "html",
405
405
  use: {
406
- baseURL: 'http://localhost:5173',
407
- trace: 'on-first-retry',
406
+ baseURL: "http://localhost:5173",
407
+ trace: "on-first-retry",
408
408
  },
409
409
  projects: [
410
- { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
411
- { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
412
- { name: 'webkit', use: { ...devices['Desktop Safari'] } },
413
- { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
414
- { name: 'Mobile Safari', use: { ...devices['iPhone 12'] } },
410
+ { name: "chromium", use: { ...devices["Desktop Chrome"] } },
411
+ { name: "firefox", use: { ...devices["Desktop Firefox"] } },
412
+ { name: "webkit", use: { ...devices["Desktop Safari"] } },
413
+ { name: "Mobile Chrome", use: { ...devices["Pixel 5"] } },
414
+ { name: "Mobile Safari", use: { ...devices["iPhone 12"] } },
415
415
  ],
416
416
  webServer: {
417
- command: 'pnpm dev',
418
- url: 'http://localhost:5173',
417
+ command: "pnpm dev",
418
+ url: "http://localhost:5173",
419
419
  reuseExistingServer: !process.env.CI,
420
420
  },
421
421
  });
@@ -443,19 +443,19 @@ npx playwright show-report
443
443
  ### E2E Test Structure
444
444
 
445
445
  ```typescript
446
- import { test, expect } from '@playwright/test';
446
+ import { test, expect } from "@playwright/test";
447
447
 
448
- test.describe('Task Management', () => {
448
+ test.describe("Task Management", () => {
449
449
  test.beforeEach(async ({ page }) => {
450
450
  // Login or set up authenticated state
451
- await page.goto('/login');
452
- await page.fill('[data-testid="email-input"]', 'test@example.com');
453
- await page.fill('[data-testid="password-input"]', 'password');
451
+ await page.goto("/login");
452
+ await page.fill('[data-testid="email-input"]', "test@example.com");
453
+ await page.fill('[data-testid="password-input"]', "password");
454
454
  await page.click('[data-testid="login-button"]');
455
- await page.waitForURL('/dashboard');
455
+ await page.waitForURL("/dashboard");
456
456
  });
457
457
 
458
- test('should create a new task', async ({ page }) => {
458
+ test("should create a new task", async ({ page }) => {
459
459
  // Navigate to board
460
460
  await page.click('[data-testid="nav-boards"]');
461
461
 
@@ -463,21 +463,23 @@ test.describe('Task Management', () => {
463
463
  await page.click('[data-testid="create-task-btn"]');
464
464
 
465
465
  // Fill form
466
- await page.fill('[data-testid="task-title-input"]', 'New E2E Task');
467
- await page.selectOption('[data-testid="priority-select"]', 'high');
466
+ await page.fill('[data-testid="task-title-input"]', "New E2E Task");
467
+ await page.selectOption('[data-testid="priority-select"]', "high");
468
468
 
469
469
  // Submit
470
470
  await page.click('[data-testid="submit-task-btn"]');
471
471
 
472
472
  // Verify creation
473
473
  await expect(
474
- page.locator('[data-testid="task-card"]').filter({ hasText: 'New E2E Task' })
474
+ page
475
+ .locator('[data-testid="task-card"]')
476
+ .filter({ hasText: "New E2E Task" }),
475
477
  ).toBeVisible();
476
478
  });
477
479
 
478
- test('should move task between columns', async ({ page }) => {
480
+ test("should move task between columns", async ({ page }) => {
479
481
  // Navigate to kanban board
480
- await page.goto('/dashboard?view=kanban');
482
+ await page.goto("/dashboard?view=kanban");
481
483
 
482
484
  // Get task card
483
485
  const taskCard = page.locator('[data-testid="task-card-TASK-0001"]');
@@ -487,7 +489,9 @@ test.describe('Task Management', () => {
487
489
  await taskCard.dragTo(targetColumn);
488
490
 
489
491
  // Verify move
490
- await expect(targetColumn.locator('[data-testid="task-card-TASK-0001"]')).toBeVisible();
492
+ await expect(
493
+ targetColumn.locator('[data-testid="task-card-TASK-0001"]'),
494
+ ).toBeVisible();
491
495
  });
492
496
  });
493
497
  ```
@@ -536,23 +540,23 @@ The setup file initializes:
536
540
  4. **jsdom Environment** - DOM simulation
537
541
 
538
542
  ```typescript
539
- import { beforeAll, afterAll, afterEach, vi } from 'vitest';
540
- import { server } from '@/lib/test-utils/server';
541
- import '@testing-library/jest-dom';
543
+ import { beforeAll, afterAll, afterEach, vi } from "vitest";
544
+ import { server } from "@/lib/test-utils/server";
545
+ import "@testing-library/jest-dom";
542
546
 
543
547
  // Start MSW server
544
- beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
548
+ beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
545
549
  afterEach(() => server.resetHandlers());
546
550
  afterAll(() => server.close());
547
551
 
548
552
  // Mock Next.js
549
- vi.mock('next/navigation', () => ({
553
+ vi.mock("next/navigation", () => ({
550
554
  useRouter: () => ({ push: vi.fn(), replace: vi.fn() }),
551
- usePathname: () => '/dashboard',
555
+ usePathname: () => "/dashboard",
552
556
  useSearchParams: () => new URLSearchParams(),
553
557
  }));
554
558
 
555
- vi.mock('next/cache', () => ({
559
+ vi.mock("next/cache", () => ({
556
560
  revalidatePath: vi.fn(),
557
561
  revalidateTag: vi.fn(),
558
562
  }));
@@ -563,24 +567,30 @@ vi.mock('next/cache', () => ({
563
567
  Provides mock data factories and seeding utilities:
564
568
 
565
569
  ```typescript
566
- import type { Task, Board, Sprint, User } from '@/types';
570
+ import type { Task, Board, Sprint, User } from "@/types";
567
571
 
568
572
  // ============== Mock Data ==============
569
573
  export const mockUser: User = {
570
- id: 'user-001',
571
- email: 'test@example.com',
572
- name: 'Test User',
573
- role: 'developer',
574
+ id: "user-001",
575
+ email: "test@example.com",
576
+ name: "Test User",
577
+ role: "developer",
574
578
  };
575
579
 
576
580
  export const mockTasks: Task[] = [
577
- { id: 'task-001', ticketId: 'TEST-0001', title: 'First Task', priority: 'high', status: 'todo' },
578
581
  {
579
- id: 'task-002',
580
- ticketId: 'TEST-0002',
581
- title: 'Second Task',
582
- priority: 'medium',
583
- status: 'in_progress',
582
+ id: "task-001",
583
+ ticketId: "TEST-0001",
584
+ title: "First Task",
585
+ priority: "high",
586
+ status: "todo",
587
+ },
588
+ {
589
+ id: "task-002",
590
+ ticketId: "TEST-0002",
591
+ title: "Second Task",
592
+ priority: "medium",
593
+ status: "in_progress",
584
594
  },
585
595
  ];
586
596
 
@@ -590,13 +600,13 @@ export function createMockTask(overrides: Partial<Task> = {}): Task {
590
600
  id: `task-${Date.now()}`,
591
601
  ticketId: `TEST-${Math.floor(Math.random() * 9999)
592
602
  .toString()
593
- .padStart(4, '0')}`,
594
- title: 'Mock Task',
595
- description: '',
596
- priority: 'medium',
597
- status: 'todo',
598
- type: 'task',
599
- boardId: 'board-001',
603
+ .padStart(4, "0")}`,
604
+ title: "Mock Task",
605
+ description: "",
606
+ priority: "medium",
607
+ status: "todo",
608
+ type: "task",
609
+ boardId: "board-001",
600
610
  createdAt: new Date().toISOString(),
601
611
  updatedAt: new Date().toISOString(),
602
612
  ...overrides,
@@ -612,7 +622,7 @@ export function createMockSprint(overrides: Partial<Sprint> = {}): Sprint {
612
622
 
613
623
  // ============== Seeding Functions ==============
614
624
  export function seedTasks(tasks: Task[] = mockTasks): void {
615
- localStorage.setItem('pm_tasks', JSON.stringify(tasks));
625
+ localStorage.setItem("pm_tasks", JSON.stringify(tasks));
616
626
  }
617
627
 
618
628
  export function seedBoards(): void {
@@ -629,9 +639,9 @@ export function clearLocalStorage(): void {
629
639
  // ============== Known Gaps ==============
630
640
  // Document areas that don't have full test coverage yet
631
641
  export const KNOWN_GAPS = {
632
- dragAndDrop: 'Drag-and-drop testing requires special handling with react-dnd',
633
- realTime: 'Real-time subscription testing not fully implemented',
634
- fileUpload: 'File upload testing requires MSW file handling',
642
+ dragAndDrop: "Drag-and-drop testing requires special handling with react-dnd",
643
+ realTime: "Real-time subscription testing not fully implemented",
644
+ fileUpload: "File upload testing requires MSW file handling",
635
645
  };
636
646
  ```
637
647
 
@@ -654,21 +664,21 @@ lib/test-utils/
654
664
  Example handler (`lib/test-utils/handlers/tasks.ts`):
655
665
 
656
666
  ```typescript
657
- import { http, HttpResponse } from 'msw';
658
- import { mockTasks } from '@test/fixtures';
667
+ import { http, HttpResponse } from "msw";
668
+ import { mockTasks } from "@test/fixtures";
659
669
 
660
670
  export const taskHandlers = [
661
- http.get('*/rest/v1/tasks*', () => {
671
+ http.get("*/rest/v1/tasks*", () => {
662
672
  return HttpResponse.json(mockTasks);
663
673
  }),
664
674
 
665
- http.post('*/rest/v1/tasks', async ({ request }) => {
675
+ http.post("*/rest/v1/tasks", async ({ request }) => {
666
676
  const body = await request.json();
667
677
  const newTask = { id: `task-${Date.now()}`, ...body };
668
678
  return HttpResponse.json(newTask, { status: 201 });
669
679
  }),
670
680
 
671
- http.delete('*/rest/v1/tasks*', () => {
681
+ http.delete("*/rest/v1/tasks*", () => {
672
682
  return new HttpResponse(null, { status: 204 });
673
683
  }),
674
684
  ];
@@ -18,6 +18,7 @@
18
18
  Valid branch format: `<type>/<scope>/<description>`
19
19
 
20
20
  Examples:
21
+
21
22
  - `feature/{{scopes}}`
22
23
  - `fix/{{scopes}}`
23
24
 
@@ -25,4 +26,4 @@ Examples:
25
26
 
26
27
  ---
27
28
 
28
- *This document was auto-generated by Workflow Agent. Do not edit directly.*
29
+ _This document was auto-generated by Workflow Agent. Do not edit directly._
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Workflow Agent Team
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/index.ts","../src/config/schema.ts"],"sourcesContent":["import { cosmiconfig } from 'cosmiconfig';\nimport { WorkflowConfig, WorkflowConfigSchema, validateScopeDefinitions } 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(cwd: string = process.cwd()): 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.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 = result?.config?.scopes?.[scopeIndex]?.name || `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(/Scope name \"([^\"]+)\" is reserved/);\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 }).join('\\n • ');\n \n throw new Error(`Invalid workflow configuration:\\n • ${formattedErrors}\\n\\n💡 Fix these issues in workflow.config.json or run: workflow config validate`);\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 { WorkflowConfig, WorkflowConfigSchema, Scope, BranchType, ConventionalType, validateScopeName, DEFAULT_RESERVED_SCOPE_NAMES } from './schema.js';\n","import { z } from 'zod';\n\n// Default reserved scope names that cannot be used\nexport const DEFAULT_RESERVED_SCOPE_NAMES = ['init', 'create', 'build', 'test', 'config', 'docs', 'ci', 'deps'];\n\n/**\n * Validates a scope name against reserved words and naming rules\n */\nexport function validateScopeName(name: string, reservedNames: string[] = DEFAULT_RESERVED_SCOPE_NAMES): {\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.string()\n .min(1)\n .max(32, 'Scope name must be 32 characters or less')\n .regex(/^[a-z0-9-]+$/, 'Scope name must be lowercase alphanumeric with hyphens'),\n description: z.string().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.enum(['auth', 'features', 'infrastructure', 'documentation', 'testing', 'performance', 'other']).optional(),\n});\n\nexport const EnforcementLevelSchema = z.enum(['strict', 'advisory', 'learning']);\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.array(HookCheckSchema).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(['lint', 'typecheck', 'format', 'test', 'build']);\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.array(CICheckSchema).default(['lint', 'typecheck', 'format', 'build', 'test']),\n});\n\nexport const WorkflowConfigSchema = z.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.array(z.string()).optional().default(DEFAULT_RESERVED_SCOPE_NAMES),\n ci: CIConfigSchema.optional(),\n}).superRefine((config, ctx) => {\n // Validate scopes against reserved names\n const reservedNames = 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"]}
@@ -1 +0,0 @@
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(workspacePath: string = process.cwd()): 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 = [\n join(workspacePath, 'packages'),\n workspacePath,\n ];\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\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(config: WorkflowConfig, workspacePath?: string): 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 || ['feature', 'bugfix', 'hotfix', 'chore', 'refactor', 'docs', 'test'];\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 = 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 = 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":[]}