@jigyasudham/veto 0.8.3 → 1.0.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.
Files changed (111) hide show
  1. package/README.md +209 -52
  2. package/dist/agents/executor.js +36 -3
  3. package/dist/cli.js +246 -7
  4. package/dist/context/reader.js +113 -0
  5. package/dist/council/index.js +3 -1
  6. package/dist/plugins/loader.js +49 -0
  7. package/dist/router/index.js +2 -2
  8. package/dist/router/learning-updater.js +45 -1
  9. package/dist/server.js +478 -14
  10. package/dist/watcher/index.js +77 -0
  11. package/dist/workflow/pipeline.js +64 -0
  12. package/package.json +12 -3
  13. package/.claude/settings.local.json +0 -9
  14. package/src/adapters/claude.ts +0 -70
  15. package/src/adapters/codex.ts +0 -71
  16. package/src/adapters/gemini.ts +0 -71
  17. package/src/adapters/index.ts +0 -217
  18. package/src/agents/development/api.ts +0 -120
  19. package/src/agents/development/backend.ts +0 -85
  20. package/src/agents/development/coder.ts +0 -213
  21. package/src/agents/development/database.ts +0 -83
  22. package/src/agents/development/debugger.ts +0 -238
  23. package/src/agents/development/devops.ts +0 -86
  24. package/src/agents/development/frontend.ts +0 -85
  25. package/src/agents/development/migration.ts +0 -144
  26. package/src/agents/development/performance.ts +0 -144
  27. package/src/agents/development/refactor.ts +0 -86
  28. package/src/agents/development/reviewer.ts +0 -268
  29. package/src/agents/development/tester.ts +0 -151
  30. package/src/agents/executor.ts +0 -158
  31. package/src/agents/memory/context-manager.ts +0 -171
  32. package/src/agents/memory/decision-logger.ts +0 -160
  33. package/src/agents/memory/knowledge-base.ts +0 -124
  34. package/src/agents/memory/pattern-learner.ts +0 -143
  35. package/src/agents/memory/project-mapper.ts +0 -118
  36. package/src/agents/quality/accessibility.ts +0 -99
  37. package/src/agents/quality/code-quality.ts +0 -115
  38. package/src/agents/quality/compatibility.ts +0 -58
  39. package/src/agents/quality/documentation.ts +0 -105
  40. package/src/agents/quality/error-handling.ts +0 -96
  41. package/src/agents/research/competitor-analyzer.ts +0 -45
  42. package/src/agents/research/cost-analyzer.ts +0 -54
  43. package/src/agents/research/estimator.ts +0 -60
  44. package/src/agents/research/ethics-bias.ts +0 -113
  45. package/src/agents/research/researcher.ts +0 -114
  46. package/src/agents/research/risk-assessor.ts +0 -63
  47. package/src/agents/research/tech-advisor.ts +0 -55
  48. package/src/agents/security/auth.ts +0 -287
  49. package/src/agents/security/dependency-audit.ts +0 -337
  50. package/src/agents/security/penetration.ts +0 -262
  51. package/src/agents/security/privacy.ts +0 -285
  52. package/src/agents/security/scanner.ts +0 -322
  53. package/src/agents/security/secrets.ts +0 -249
  54. package/src/agents/types.ts +0 -66
  55. package/src/agents/workflow/automation.ts +0 -59
  56. package/src/agents/workflow/file-manager.ts +0 -52
  57. package/src/agents/workflow/git-agent.ts +0 -55
  58. package/src/agents/workflow/reporter.ts +0 -51
  59. package/src/agents/workflow/search-agent.ts +0 -40
  60. package/src/agents/workflow/task-coordinator.ts +0 -41
  61. package/src/agents/workflow/task-planner.ts +0 -47
  62. package/src/cli.ts +0 -204
  63. package/src/council/decision-engine.ts +0 -171
  64. package/src/council/devil-advocate.ts +0 -116
  65. package/src/council/index.ts +0 -44
  66. package/src/council/lead-developer.ts +0 -118
  67. package/src/council/legal-compliance.ts +0 -152
  68. package/src/council/product-manager.ts +0 -102
  69. package/src/council/security.ts +0 -172
  70. package/src/council/system-architect.ts +0 -132
  71. package/src/council/types.ts +0 -33
  72. package/src/council/ux-designer.ts +0 -121
  73. package/src/memory/local.ts +0 -305
  74. package/src/memory/schema.ts +0 -174
  75. package/src/memory/sync.ts +0 -274
  76. package/src/router/complexity-scorer.ts +0 -96
  77. package/src/router/context-compressor.ts +0 -74
  78. package/src/router/index.ts +0 -60
  79. package/src/router/learning-updater.ts +0 -271
  80. package/src/router/model-selector.ts +0 -83
  81. package/src/router/rate-monitor.ts +0 -103
  82. package/src/server.ts +0 -1038
  83. package/src/skills/development/skill-api-design.ts +0 -329
  84. package/src/skills/development/skill-auth.ts +0 -271
  85. package/src/skills/development/skill-ci-cd.ts +0 -0
  86. package/src/skills/development/skill-crud.ts +0 -209
  87. package/src/skills/development/skill-db-schema.ts +0 -0
  88. package/src/skills/development/skill-docker.ts +0 -0
  89. package/src/skills/development/skill-env-setup.ts +0 -0
  90. package/src/skills/development/skill-scaffold.ts +0 -323
  91. package/src/skills/intelligence/skill-complexity-score.ts +0 -69
  92. package/src/skills/intelligence/skill-cost-track.ts +0 -39
  93. package/src/skills/intelligence/skill-learning-loop.ts +0 -69
  94. package/src/skills/intelligence/skill-pattern-detect.ts +0 -38
  95. package/src/skills/intelligence/skill-rate-watch.ts +0 -61
  96. package/src/skills/memory/skill-context-compress.ts +0 -98
  97. package/src/skills/memory/skill-cross-sync.ts +0 -104
  98. package/src/skills/memory/skill-decision-log.ts +0 -119
  99. package/src/skills/memory/skill-session-restore.ts +0 -59
  100. package/src/skills/memory/skill-session-save.ts +0 -94
  101. package/src/skills/quality/skill-accessibility.ts +0 -0
  102. package/src/skills/quality/skill-code-review.ts +0 -84
  103. package/src/skills/quality/skill-docs-gen.ts +0 -0
  104. package/src/skills/quality/skill-perf-audit.ts +0 -0
  105. package/src/skills/quality/skill-security-scan.ts +0 -91
  106. package/src/skills/quality/skill-test-suite.ts +0 -290
  107. package/src/skills/workflow/skill-deploy.ts +0 -0
  108. package/src/skills/workflow/skill-git-workflow.ts +0 -0
  109. package/src/skills/workflow/skill-rollback.ts +0 -0
  110. package/src/skills/workflow/skill-task-breakdown.ts +0 -0
  111. package/tsconfig.json +0 -20
@@ -1,143 +0,0 @@
1
- import { AgentPlan, WorkerAgentType } from '../types.js';
2
-
3
- type PatternCategory = 'coding-style' | 'naming' | 'error-handling' | 'testing' | 'general';
4
-
5
- function detectCategory(task: string): PatternCategory {
6
- const t = task.toLowerCase();
7
- if (t.includes('style') || t.includes('format') || t.includes('indent') || t.includes('structure') || t.includes('code pattern')) return 'coding-style';
8
- if (t.includes('naming') || t.includes('convention') || t.includes('variable') || t.includes('function name') || t.includes('identifier')) return 'naming';
9
- if (t.includes('error') || t.includes('exception') || t.includes('catch') || t.includes('throw') || t.includes('handling')) return 'error-handling';
10
- if (t.includes('test') || t.includes('spec') || t.includes('unit') || t.includes('mock') || t.includes('assertion')) return 'testing';
11
- return 'general';
12
- }
13
-
14
- const categoryApproach: Record<PatternCategory, string> = {
15
- 'coding-style': 'Observe recurring structural patterns in the codebase: file layout, function organisation, import grouping, async patterns, class vs functional preference. Record each distinct pattern via veto_memory_store (type="pattern"). Increment confidence on re-observation. Use high-confidence patterns to guide future code generation.',
16
- 'naming': 'Extract naming conventions from the existing codebase: camelCase vs snake_case, file naming (kebab-case), export style (named vs default), constant casing (UPPER_SNAKE). Record as patterns with confidence scored by frequency. Apply consistently — an AI that ignores existing conventions creates noisy diffs.',
17
- 'error-handling': 'Identify the error-handling contract: typed errors vs raw strings, Result types vs exceptions, HTTP error mapping conventions, logging format. Record the dominant pattern so all generated code uses the same error style. Flag when new code diverges from the established pattern.',
18
- 'testing': 'Learn the testing conventions: framework (Jest / Vitest / Mocha), file placement (co-located vs __tests__/), describe/it nesting depth, mock style (jest.mock vs manual mocks), assertion verbosity. Record each observed pattern. Generated tests should be indistinguishable from human-written tests in this codebase.',
19
- 'general': 'Scan recent files modified in the session. Extract 3–5 recurring patterns that are non-obvious (not just "uses TypeScript"). Store each via veto_memory_store (type="pattern"). On subsequent observations of the same pattern, call upsertPattern to increment confidence.',
20
- };
21
-
22
- const categorySteps: Record<PatternCategory, string[]> = {
23
- 'coding-style': [
24
- 'Read 5–10 representative source files across the codebase',
25
- 'Identify the dominant import grouping order (stdlib → third-party → local)',
26
- 'Identify async pattern: async/await vs Promise chains vs callbacks',
27
- 'Identify class vs functional component preference',
28
- 'Identify single-return vs early-return guard clause preference',
29
- 'Identify comment style: JSDoc, inline comments, or none',
30
- 'Record each as a pattern: { key: "code.async-pattern", val: "async/await with try/catch" }',
31
- 'Call veto_memory_store for each new pattern with type="pattern"',
32
- 'On subsequent observation, call upsertPattern to increase confidence',
33
- 'Output a pattern summary for use in future code generation prompts',
34
- ],
35
- 'naming': [
36
- 'Scan file names in src/ to confirm naming convention (kebab-case, camelCase, etc.)',
37
- 'Read 5 files and extract variable names to confirm camelCase vs snake_case',
38
- 'Check constants for UPPER_SNAKE_CASE vs camelCase',
39
- 'Check type / interface names for PascalCase confirmation',
40
- 'Check function names for verb-first convention (getData vs getDataFetch)',
41
- 'Check boolean variable names for is/has/can prefix convention',
42
- 'Record each naming rule as a pattern with confidence',
43
- 'Flag any files that violate the dominant convention — they may be intentional exceptions',
44
- ],
45
- 'error-handling': [
46
- 'Search for throw new and catch patterns across the codebase',
47
- 'Identify if typed error classes are used (class NotFoundError extends Error)',
48
- 'Identify if Result<T, E> pattern is used vs throwing',
49
- 'Identify the HTTP status code mapping pattern for API errors',
50
- 'Identify the logging format for errors (structured JSON vs console.error)',
51
- 'Identify if error messages are user-facing strings or internal codes',
52
- 'Record the dominant error pattern as high-confidence',
53
- 'Record any secondary patterns as lower-confidence alternatives',
54
- ],
55
- 'testing': [
56
- 'Identify the test framework from package.json devDependencies',
57
- 'Find test files and confirm naming convention (*.test.ts vs *.spec.ts)',
58
- 'Confirm test file placement: co-located vs separate __tests__/ directory',
59
- 'Read 3 test files to identify describe/it nesting depth',
60
- 'Identify mock strategy: jest.mock() at top vs factory functions vs manual mocks',
61
- 'Identify setup/teardown patterns (beforeEach, afterEach usage)',
62
- 'Identify assertion library and verbosity (expect(x).toBe(y) vs x === y)',
63
- 'Record each pattern with confidence scored by frequency across test files',
64
- ],
65
- 'general': [
66
- 'Read the 5 most recently modified source files',
67
- 'Extract patterns that appear in 3 or more of the files',
68
- 'Identify patterns that are non-obvious (not just "uses TypeScript")',
69
- 'For each pattern: write a key (category.pattern-name) and a concise value',
70
- 'Call veto_memory_store with type="pattern" for new patterns',
71
- 'For patterns already stored, call upsertPattern to increment confidence',
72
- 'Output a pattern summary listing key, value, and confidence for each learned pattern',
73
- ],
74
- };
75
-
76
- const categoryChecklist: Record<PatternCategory, string[]> = {
77
- 'coding-style': [
78
- '[ ] At least 5 source files scanned',
79
- '[ ] Async pattern identified and recorded',
80
- '[ ] Import order identified and recorded',
81
- '[ ] Functional vs class preference identified',
82
- '[ ] Comment style identified',
83
- '[ ] All patterns stored via veto_memory_store',
84
- '[ ] Confidence incremented for re-observed patterns',
85
- ],
86
- 'naming': [
87
- '[ ] File naming convention confirmed',
88
- '[ ] Variable naming convention confirmed',
89
- '[ ] Constant naming convention confirmed',
90
- '[ ] Boolean naming prefix confirmed',
91
- '[ ] All naming rules stored as patterns',
92
- '[ ] Convention violations flagged',
93
- ],
94
- 'error-handling': [
95
- '[ ] Typed vs untyped error strategy identified',
96
- '[ ] Result type vs exception choice recorded',
97
- '[ ] HTTP error mapping pattern recorded',
98
- '[ ] Logging format pattern recorded',
99
- '[ ] Dominant pattern stored as high-confidence',
100
- ],
101
- 'testing': [
102
- '[ ] Test framework identified',
103
- '[ ] Test file naming convention recorded',
104
- '[ ] Test file placement recorded',
105
- '[ ] Mock strategy identified and recorded',
106
- '[ ] Assertion style recorded',
107
- '[ ] All patterns stored with confidence',
108
- ],
109
- 'general': [
110
- '[ ] At least 5 files scanned',
111
- '[ ] Only non-obvious patterns recorded',
112
- '[ ] pattern_key follows category.pattern-name format',
113
- '[ ] Existing patterns updated via upsertPattern',
114
- '[ ] Pattern summary outputted',
115
- ],
116
- };
117
-
118
- export function plan(task: string, context?: string): AgentPlan {
119
- const category = detectCategory(task + ' ' + (context ?? ''));
120
- return {
121
- agent: 'pattern-learner' as WorkerAgentType,
122
- task,
123
- tier: 1,
124
- approach: categoryApproach[category],
125
- steps: categorySteps[category],
126
- checklist: categoryChecklist[category],
127
- pitfalls: [
128
- 'Recording obvious patterns ("uses TypeScript", "has functions") — only record non-obvious recurring choices',
129
- 'Treating low-frequency patterns as conventions — require at least 3 observations before treating as established',
130
- 'Conflating two different patterns: e.g. "async/await in services, promises in utilities" — store separately',
131
- 'Not incrementing confidence on re-observation — all patterns stay at 1.0 and are equally trusted',
132
- 'Applying learned patterns to files that deliberately deviate (e.g. legacy files, test fixtures)',
133
- 'Over-specifying patterns: "uses 2-space indent in coder.ts" vs "uses 2-space indent across all TypeScript files"',
134
- ],
135
- patterns: [
136
- 'Frequency-confidence: confidence increases with each additional observation of the pattern',
137
- 'Category namespacing: key format "category.specific-pattern" enables prefix search',
138
- 'Deviation detection: compare new code to stored patterns and flag significant divergence',
139
- 'Pattern evolution: when a pattern changes (e.g. moving from callbacks to async/await), update the stored value rather than adding a duplicate',
140
- ],
141
- duration_estimate: '10-20 minutes',
142
- };
143
- }
@@ -1,118 +0,0 @@
1
- import { AgentPlan, WorkerAgentType } from '../types.js';
2
-
3
- type MapCategory = 'initial-map' | 'update' | 'query' | 'general';
4
-
5
- function detectCategory(task: string): MapCategory {
6
- const t = task.toLowerCase();
7
- if (t.includes('initial') || t.includes('first time') || t.includes('new project') || t.includes('onboard') || t.includes('create map')) return 'initial-map';
8
- if (t.includes('update') || t.includes('refresh') || t.includes('new file') || t.includes('delete') || t.includes('rename') || t.includes('move')) return 'update';
9
- if (t.includes('find') || t.includes('where') || t.includes('locate') || t.includes('search') || t.includes('query')) return 'query';
10
- return 'general';
11
- }
12
-
13
- const categoryApproach: Record<MapCategory, string> = {
14
- 'initial-map': 'Build the first project map by scanning the directory tree (excluding node_modules, .git, dist). Identify the tech stack from package.json / pyproject.toml / Cargo.toml. Identify key modules: entry points, router, config, schema, main service files. Store via veto_project_map_update.',
15
- 'update': 'Incrementally update the project map after file changes. Add new files to the structure, remove deleted files, update module roles if they changed. Call veto_project_map_update after every session that modifies files. Do not re-scan the full tree — apply a diff.',
16
- 'query': 'Query the project map via veto_project_map_get to answer "where is X" questions without reading the filesystem. Use the key_modules list for entry points, then follow imports. Fall back to a targeted filesystem search only if the map is stale.',
17
- 'general': 'Check if a project map exists (veto_project_map_get). Create one if absent. Update if the last updated_at timestamp is more than one session old. Use the map to navigate the codebase before touching the filesystem.',
18
- };
19
-
20
- const categorySteps: Record<MapCategory, string[]> = {
21
- 'initial-map': [
22
- 'Read package.json (or equivalent) to identify language, framework, and key dependencies',
23
- 'Scan the top-level src/ directory structure — list all directories and their purpose',
24
- 'Identify entry points: main.ts / index.ts / app.ts / server.ts / cli.ts',
25
- 'Identify router or routing config (routes.ts, app.ts, next.config.js, etc.)',
26
- 'Identify database layer: schema files, migration files, ORM config',
27
- 'Identify config files: .env, config/, settings files',
28
- 'Identify test directories and test runner config',
29
- 'Build the structure JSON: { "src/": { "agents/": [...], "router/": [...] } }',
30
- 'Identify key_modules: list of the 10–20 most important files with their role',
31
- 'Call veto_project_map_update with project_dir, structure, key_modules, tech_stack',
32
- 'Verify the map with veto_project_map_get and confirm all key files are present',
33
- ],
34
- 'update': [
35
- 'Identify which files were added, removed, or renamed in this session',
36
- 'Load the current map via veto_project_map_get',
37
- 'Apply adds: add new file paths to the appropriate structure branch',
38
- 'Apply removes: remove deleted file paths from the structure',
39
- 'Update key_modules if a new important file was added or an important file was removed',
40
- 'Update tech_stack if a new dependency was added (e.g. a new framework)',
41
- 'Call veto_project_map_update with the modified structure',
42
- 'Confirm the updated map reflects the current filesystem state',
43
- ],
44
- 'query': [
45
- 'Call veto_project_map_get to load the current map',
46
- 'Check updated_at — if older than the current session, consider triggering a refresh',
47
- 'Search key_modules for the file or module being queried',
48
- 'If not in key_modules, traverse the structure JSON for the relevant directory',
49
- 'Return the file path and module role without hitting the filesystem',
50
- 'If the map query is inconclusive, fall back to a targeted Glob search',
51
- 'If a Glob search finds a file missing from the map, trigger a map update',
52
- ],
53
- 'general': [
54
- 'Call veto_project_map_get to check if a map exists',
55
- 'If no map: run the initial-map flow',
56
- 'If map exists: check updated_at — update if stale',
57
- 'Use the map to answer navigation questions before scanning the filesystem',
58
- 'After each session that modifies files, call veto_project_map_update',
59
- ],
60
- };
61
-
62
- const categoryChecklist: Record<MapCategory, string[]> = {
63
- 'initial-map': [
64
- '[ ] Tech stack identified: language, framework, key libraries',
65
- '[ ] All src/ directories listed with role description',
66
- '[ ] Entry points identified and listed in key_modules',
67
- '[ ] Database / schema layer identified',
68
- '[ ] Test directory and runner identified',
69
- '[ ] Structure JSON stored via veto_project_map_update',
70
- '[ ] Map verified via veto_project_map_get',
71
- ],
72
- 'update': [
73
- '[ ] All added files included in structure',
74
- '[ ] All deleted files removed from structure',
75
- '[ ] key_modules updated if important file changed',
76
- '[ ] veto_project_map_update called with new structure',
77
- '[ ] Map verified post-update',
78
- ],
79
- 'query': [
80
- '[ ] veto_project_map_get called before any filesystem scan',
81
- '[ ] key_modules checked first for fast lookup',
82
- '[ ] Structure JSON traversed if not in key_modules',
83
- '[ ] Filesystem fallback used only if map is inconclusive',
84
- '[ ] Map updated if filesystem revealed a gap',
85
- ],
86
- 'general': [
87
- '[ ] Map existence checked at session start',
88
- '[ ] Map updated at session end if files were modified',
89
- '[ ] Map used as primary navigation source, not the filesystem',
90
- ],
91
- };
92
-
93
- export function plan(task: string, context?: string): AgentPlan {
94
- const category = detectCategory(task + ' ' + (context ?? ''));
95
- return {
96
- agent: 'project-mapper' as WorkerAgentType,
97
- task,
98
- tier: 1,
99
- approach: categoryApproach[category],
100
- steps: categorySteps[category],
101
- checklist: categoryChecklist[category],
102
- pitfalls: [
103
- 'Scanning the full project tree including node_modules — causes massive, useless maps',
104
- 'Only building the map once and never updating — the map becomes stale after file changes',
105
- 'Storing file contents in the map instead of just paths and roles — balloons storage',
106
- 'Not listing key_modules — forces a full structure search for common lookups',
107
- 'Building the map from memory instead of actually scanning — silently incorrect paths',
108
- 'Forgetting to update the map after a refactor that moves or renames many files',
109
- ],
110
- patterns: [
111
- 'Incremental update: diff-based map updates after file changes, not full re-scans',
112
- 'Key modules first: maintain a flat list of the most important files for O(1) lookup',
113
- 'Role annotation: each entry in key_modules includes the file\'s role (entry-point, router, schema, etc.)',
114
- 'Lazy refresh: check updated_at and only refresh when the map is stale',
115
- ],
116
- duration_estimate: '5-10 minutes',
117
- };
118
- }
@@ -1,99 +0,0 @@
1
- import { AgentPlan, AgentAnalysis, AgentFinding, WorkerAgentType } from '../types.js';
2
-
3
- export function plan(task: string, context?: string): AgentPlan {
4
- return {
5
- agent: 'accessibility' as WorkerAgentType,
6
- task,
7
- tier: 2,
8
- approach: 'Audit against WCAG 2.1 AA — the legal minimum for most jurisdictions. Work through four principles: Perceivable (can users perceive all content?), Operable (can users navigate with keyboard and assistive tech?), Understandable (is the UI predictable and error-recovery clear?), Robust (does it work with screen readers and future tech?). Flag failures by WCAG criterion number.',
9
- steps: [
10
- 'Check colour contrast: text must meet 4.5:1 (normal) or 3:1 (large text) against background — WCAG 1.4.3',
11
- 'Check all images have alt text — decorative images use alt="" — WCAG 1.1.1',
12
- 'Check all form inputs have associated <label> elements — WCAG 1.3.1',
13
- 'Check the entire UI is keyboard-navigable: Tab order is logical, no keyboard traps — WCAG 2.1.1',
14
- 'Check focus indicator is visible on all interactive elements — WCAG 2.4.7',
15
- 'Check no content flashes more than 3 times per second — WCAG 2.3.1',
16
- 'Check page has a descriptive <title> — WCAG 2.4.2',
17
- 'Check heading hierarchy: h1→h2→h3, no levels skipped — WCAG 1.3.1',
18
- 'Check error messages identify the field and explain how to fix — WCAG 3.3.1',
19
- 'Check interactive elements have accessible names (aria-label where needed) — WCAG 4.1.2',
20
- 'Test with a screen reader (NVDA/VoiceOver) on the critical path',
21
- ],
22
- checklist: [
23
- '[ ] Colour contrast ≥ 4.5:1 for normal text, 3:1 for large text',
24
- '[ ] All images have meaningful alt text',
25
- '[ ] All form inputs have visible labels',
26
- '[ ] Full keyboard navigation — no mouse required',
27
- '[ ] Visible focus indicator on all interactive elements',
28
- '[ ] No flashing content > 3 Hz',
29
- '[ ] Logical heading hierarchy',
30
- '[ ] Error messages identify field + explain fix',
31
- '[ ] Screen reader tested on critical path',
32
- ],
33
- pitfalls: [
34
- 'Using colour alone to convey information — 8% of men have colour vision deficiency',
35
- 'Placeholder text as a label substitute — placeholder disappears when typing',
36
- 'Custom interactive components without ARIA roles — screen readers see a div, not a button',
37
- 'Positive contrast ratio on a design tool that does not account for anti-aliasing',
38
- 'Fixing accessibility at end of development — 10× more expensive than building it in',
39
- ],
40
- patterns: [
41
- 'POUR framework: Perceivable → Operable → Understandable → Robust',
42
- 'Keyboard-first development: if it works with keyboard only, it usually works with everything',
43
- 'Semantic HTML over ARIA: a <button> is better than a <div role="button">',
44
- 'Error recovery: every error must name the field and tell the user exactly how to fix it',
45
- ],
46
- duration_estimate: '2-6 hours',
47
- };
48
- }
49
-
50
- export function analyze(code: string, context?: string): AgentAnalysis {
51
- const findings: AgentFinding[] = [];
52
-
53
- if (/<img(?![^>]*\balt=)/i.test(code)) {
54
- findings.push({ severity: 'high', category: 'WCAG-1.1.1', description: 'Image(s) missing alt attribute', fix: 'Add alt="description" to all <img> tags. Use alt="" for decorative images.' });
55
- }
56
-
57
- if (/<input(?![^>]*\btype="hidden")[^>]*>(?![\s\S]*?<label)/i.test(code) && !/<label/i.test(code)) {
58
- findings.push({ severity: 'high', category: 'WCAG-1.3.1', description: 'Form input(s) may lack associated label', fix: 'Add <label for="inputId"> or wrap input in <label>.' });
59
- }
60
-
61
- if (/onClick|onclick/.test(code) && !/<button|role="button"/i.test(code)) {
62
- findings.push({ severity: 'medium', category: 'WCAG-2.1.1', description: 'Click handler on non-interactive element — may not be keyboard accessible', fix: 'Use <button> for click interactions, or add role="button" tabIndex={0} and onKeyDown handler.' });
63
- }
64
-
65
- if (/:focus\s*\{[^}]*outline\s*:\s*none/i.test(code) || /:focus\s*\{[^}]*outline\s*:\s*0/i.test(code)) {
66
- findings.push({ severity: 'high', category: 'WCAG-2.4.7', description: 'Focus outline suppressed — keyboard users lose navigation indicator', fix: 'Remove outline:none from :focus. Use outline:none on :focus-visible only with a custom focus style.' });
67
- }
68
-
69
- if (/<h[1-6]/i.test(code)) {
70
- const headings = (code.match(/<h([1-6])/gi) ?? []).map(h => parseInt(h[2]));
71
- for (let i = 1; i < headings.length; i++) {
72
- if (headings[i] - headings[i - 1] > 1) {
73
- findings.push({ severity: 'medium', category: 'WCAG-1.3.1', description: `Heading level skipped: h${headings[i - 1]} → h${headings[i]}`, fix: 'Heading levels must be sequential. Do not skip levels.' });
74
- break;
75
- }
76
- }
77
- }
78
-
79
- if (/aria-label|aria-labelledby|role=/i.test(code)) {
80
- if (/role="presentation"|role="none"/i.test(code) && /<img/i.test(code)) {
81
- findings.push({ severity: 'low', category: 'WCAG-1.1.1', description: 'Image with role="presentation" — verify this is truly decorative', fix: 'If decorative, use alt="". If informative, remove role="presentation" and add meaningful alt.' });
82
- }
83
- }
84
-
85
- const critCount = findings.filter(f => f.severity === 'critical').length;
86
- const highCount = findings.filter(f => f.severity === 'high').length;
87
- const score = Math.max(0, 100 - critCount * 30 - highCount * 20 - findings.filter(f => f.severity === 'medium').length * 10);
88
-
89
- return {
90
- agent: 'accessibility' as WorkerAgentType,
91
- subject: context ?? 'UI code',
92
- findings,
93
- score,
94
- verdict: score >= 85 ? 'approved' : score >= 65 ? 'approved_with_warnings' : score >= 40 ? 'needs_revision' : 'rejected',
95
- summary: findings.length === 0 ? 'No accessibility issues detected in static analysis. Manual screen reader test still recommended.' : `${findings.length} accessibility issue(s). Top: ${findings[0].description}`,
96
- critical_count: critCount,
97
- high_count: highCount,
98
- };
99
- }
@@ -1,115 +0,0 @@
1
- import { AgentPlan, AgentAnalysis, AgentFinding, WorkerAgentType } from '../types.js';
2
-
3
- export function plan(task: string, context?: string): AgentPlan {
4
- const t = (task + ' ' + (context ?? '')).toLowerCase();
5
- const isRefactor = t.includes('refactor') || t.includes('clean') || t.includes('improve');
6
- const isReview = t.includes('review') || t.includes('audit') || t.includes('check');
7
-
8
- return {
9
- agent: 'code-quality' as WorkerAgentType,
10
- task,
11
- tier: 2,
12
- approach: isRefactor
13
- ? 'Refactor for quality by applying the three passes: first remove dead code and unused imports, then extract duplicated logic into shared utilities, then rename for clarity. Never change behaviour. Run tests after each pass.'
14
- : isReview
15
- ? 'Audit code quality across five dimensions: complexity (cyclomatic), duplication, naming clarity, function length, and comment quality. Score each 1–5 and produce a prioritised fix list ordered by impact.'
16
- : 'Assess code quality holistically. Identify the highest-impact improvement: the one change that most improves readability, maintainability, or testability. Deliver that change, verify nothing regressed.',
17
- steps: [
18
- 'Measure cyclomatic complexity — flag any function above 10',
19
- 'Identify duplicate blocks (3+ lines appearing 2+ times) — extract to a shared utility',
20
- 'Check function length — flag functions over 40 lines for extraction',
21
- 'Check naming: are variable, function, and class names self-documenting?',
22
- 'Check nesting depth — flag logic nested 4+ levels deep',
23
- 'Identify magic numbers and strings — replace with named constants',
24
- 'Check for dead code: unused variables, unreachable branches, exported symbols with no consumers',
25
- 'Check comment quality: comments should explain WHY, not WHAT',
26
- 'Verify no TODO comments without a linked issue number',
27
- 'Run the linter — fix all warnings, not just errors',
28
- ],
29
- checklist: [
30
- '[ ] No function above cyclomatic complexity 10',
31
- '[ ] No duplicate blocks of 3+ lines',
32
- '[ ] No function longer than 40 lines',
33
- '[ ] All names are self-documenting',
34
- '[ ] Nesting depth ≤ 3 levels',
35
- '[ ] No magic numbers or strings',
36
- '[ ] No dead code',
37
- '[ ] Linter passes with zero warnings',
38
- '[ ] No TODO without issue number',
39
- ],
40
- pitfalls: [
41
- 'Renaming for style without improving clarity — churn with no gain',
42
- 'Extracting functions so small they obscure the calling site',
43
- 'Removing comments that explain non-obvious WHY reasons',
44
- 'Refactoring without a test suite — introduces regressions silently',
45
- ],
46
- patterns: [
47
- 'Three-pass refactor: dead code → duplication → naming',
48
- 'Complexity budget: cyclomatic ≤ 10, nesting ≤ 3, length ≤ 40 lines',
49
- 'Magic constant extraction: all literals that carry domain meaning become named constants',
50
- ],
51
- duration_estimate: '1-3 hours',
52
- };
53
- }
54
-
55
- export function analyze(code: string, context?: string): AgentAnalysis {
56
- const findings: AgentFinding[] = [];
57
- const lines = code.split('\n');
58
-
59
- // Complexity: count decision points
60
- const decisionKeywords = /\b(if|else|for|while|case|catch|\?\?|&&|\|\|)\b/g;
61
- const decisions = (code.match(decisionKeywords) ?? []).length;
62
- if (decisions > 15) {
63
- findings.push({ severity: 'high', category: 'complexity', description: `High cyclomatic complexity: ~${decisions} decision points detected`, fix: 'Extract branches into well-named helper functions. Target < 10 per function.' });
64
- } else if (decisions > 8) {
65
- findings.push({ severity: 'medium', category: 'complexity', description: `Moderate complexity: ~${decisions} decision points`, fix: 'Consider extracting the most complex branches into helpers.' });
66
- }
67
-
68
- // Long functions
69
- const funcMatches = code.match(/(?:function\s+\w+|=>\s*\{|\w+\s*\([^)]*\)\s*\{)/g) ?? [];
70
- if (lines.length > 50 && funcMatches.length <= 2) {
71
- findings.push({ severity: 'medium', category: 'length', description: `File/function is ${lines.length} lines with few sub-functions`, fix: 'Extract logical sections into smaller, named functions.' });
72
- }
73
-
74
- // Magic numbers
75
- const magicNumbers = code.match(/[^.]\b([2-9]\d{1,3}|1[0-9]{2,3})\b(?!\s*[,\]])/g) ?? [];
76
- if (magicNumbers.length > 3) {
77
- findings.push({ severity: 'low', category: 'magic-values', description: `${magicNumbers.length} potential magic numbers detected`, fix: 'Extract numeric literals into named constants with descriptive names.' });
78
- }
79
-
80
- // Deep nesting
81
- let maxDepth = 0, currentDepth = 0;
82
- for (const ch of code) {
83
- if (ch === '{') { currentDepth++; maxDepth = Math.max(maxDepth, currentDepth); }
84
- else if (ch === '}') currentDepth--;
85
- }
86
- if (maxDepth > 5) {
87
- findings.push({ severity: 'medium', category: 'nesting', description: `Deep nesting detected: ${maxDepth} levels`, fix: 'Use early returns and guard clauses to reduce nesting depth to ≤ 3.' });
88
- }
89
-
90
- // Empty catch
91
- if (/catch\s*\([^)]*\)\s*\{\s*\}/.test(code)) {
92
- findings.push({ severity: 'high', category: 'error-handling', description: 'Empty catch block — exception silently swallowed', fix: 'Log the error or rethrow. Never silently swallow exceptions.' });
93
- }
94
-
95
- // TODO without issue
96
- const todos = (code.match(/\/\/\s*TODO(?!.*#\d)/gi) ?? []).length;
97
- if (todos > 0) {
98
- findings.push({ severity: 'low', category: 'maintainability', description: `${todos} TODO comment(s) without linked issue number`, fix: 'Add issue number (e.g. // TODO #123) or resolve the TODO.' });
99
- }
100
-
101
- const critCount = findings.filter(f => f.severity === 'critical').length;
102
- const highCount = findings.filter(f => f.severity === 'high').length;
103
- const score = Math.max(0, 100 - critCount * 25 - highCount * 15 - findings.filter(f => f.severity === 'medium').length * 8 - findings.filter(f => f.severity === 'low').length * 3);
104
-
105
- return {
106
- agent: 'code-quality' as WorkerAgentType,
107
- subject: context ?? 'code',
108
- findings,
109
- score,
110
- verdict: score >= 85 ? 'approved' : score >= 65 ? 'approved_with_warnings' : score >= 40 ? 'needs_revision' : 'rejected',
111
- summary: findings.length === 0 ? 'Code quality looks good.' : `${findings.length} quality issue(s) found. Top concern: ${findings[0].description}`,
112
- critical_count: critCount,
113
- high_count: highCount,
114
- };
115
- }
@@ -1,58 +0,0 @@
1
- import { AgentPlan, WorkerAgentType } from '../types.js';
2
-
3
- export function plan(task: string, context?: string): AgentPlan {
4
- const t = (task + ' ' + (context ?? '')).toLowerCase();
5
- const isBrowser = t.includes('browser') || t.includes('safari') || t.includes('firefox') || t.includes('frontend') || t.includes('css');
6
- const isNode = t.includes('node') || t.includes('runtime') || t.includes('version') || t.includes('backend');
7
- const isMobile = t.includes('mobile') || t.includes('ios') || t.includes('android') || t.includes('responsive');
8
-
9
- const approach = isBrowser
10
- ? 'Check browser compatibility for every CSS property, JS API, and Web API used. Target: Chrome 100+, Firefox 100+, Safari 15+, Edge 100+. Use caniuse.com for CSS and MDN compatibility tables for JS. Flag anything below 90% global usage without a polyfill.'
11
- : isNode
12
- ? 'Verify compatibility with the stated Node.js version range. Check: built-in modules (crypto, fs, sqlite), ES module vs CommonJS assumptions, and any native addons. Test on the minimum supported version, not just the latest.'
13
- : isMobile
14
- ? 'Test responsive behaviour at 320px (small phone), 375px (standard phone), 768px (tablet), 1024px (small desktop), 1440px (standard desktop). Verify touch targets are ≥ 44×44px. Verify no horizontal scroll at any breakpoint.'
15
- : 'Audit compatibility across the three dimensions relevant to this project: runtime version, browser support, and mobile breakpoints. Identify any usage of APIs not available in the minimum supported environment.';
16
-
17
- return {
18
- agent: 'compatibility' as WorkerAgentType,
19
- task,
20
- tier: 2,
21
- approach,
22
- steps: [
23
- 'Identify the minimum supported environment: Node version, browser versions, mobile screen sizes',
24
- 'List all external APIs, Web APIs, and language features used',
25
- 'Cross-reference each against the minimum environment\'s support tables (caniuse, MDN, Node.js docs)',
26
- 'Flag anything requiring a polyfill or transpile target adjustment',
27
- 'Check package.json engines field — does it accurately reflect the minimum Node version?',
28
- 'Check tsconfig.json target and lib — do they match the actual deployment environment?',
29
- 'Check CSS: use @supports for progressive enhancement, not as a workaround',
30
- 'Test responsive layout at 320px minimum width — the most common failure point',
31
- 'Verify touch targets ≥ 44×44px on all interactive elements',
32
- 'Check for deprecated APIs with removal dates within the support window',
33
- ],
34
- checklist: [
35
- '[ ] Minimum Node.js version documented in package.json engines field',
36
- '[ ] tsconfig target and lib match deployment environment',
37
- '[ ] No JS/CSS APIs used below 90% browser support without polyfill',
38
- '[ ] Responsive layout tested at 320px minimum width',
39
- '[ ] Touch targets ≥ 44×44px on mobile',
40
- '[ ] No deprecated APIs scheduled for removal within support window',
41
- '[ ] No native addons that break cross-platform (Windows/Mac/Linux)',
42
- ],
43
- pitfalls: [
44
- 'Testing only on the latest browser — Safari consistently lags on Web APIs',
45
- 'Assuming Node 22 features are available when minimum is Node 18',
46
- 'Using CSS grid subgrid without checking Safari 15 support',
47
- 'Touch targets that pass on desktop but fail on 320px mobile',
48
- 'Native addons that compile on Mac but not on Windows (different MSVC requirements)',
49
- ],
50
- patterns: [
51
- 'Progressive enhancement: build for the minimum, enhance for modern — not the reverse',
52
- 'Engines field as contract: package.json engines is a promise to users about compatibility',
53
- 'caniuse-first: check support tables before using any new browser API',
54
- '320px rule: if it works at 320px, it works on every phone',
55
- ],
56
- duration_estimate: '1-3 hours',
57
- };
58
- }
@@ -1,105 +0,0 @@
1
- import { AgentPlan, AgentAnalysis, AgentFinding, WorkerAgentType } from '../types.js';
2
-
3
- export function plan(task: string, context?: string): AgentPlan {
4
- const t = (task + ' ' + (context ?? '')).toLowerCase();
5
- const isApi = t.includes('api') || t.includes('endpoint') || t.includes('openapi');
6
- const isReadme = t.includes('readme') || t.includes('getting started') || t.includes('onboard');
7
-
8
- return {
9
- agent: 'documentation' as WorkerAgentType,
10
- task,
11
- tier: 1,
12
- approach: isApi
13
- ? 'Document the API using OpenAPI 3.0. Every endpoint needs: method, path, summary, request body schema, response schemas (200, 400, 401, 404, 500), and at least one request example. Generated docs should be accurate enough that a client can integrate without reading the source code.'
14
- : isReadme
15
- ? 'Write a README that answers the four questions every new user asks: what is this, how do I install it, how do I use it, and how do I contribute. Lead with a one-sentence description, then a quick-start that works in under 5 minutes.'
16
- : 'Document the public API surface. Every exported function, class, and type gets a JSDoc block with: one-line description, @param for each parameter, @returns, @throws for known errors, and one @example. Internal functions do not need JSDoc.',
17
- steps: [
18
- 'List all exported symbols that lack documentation',
19
- 'For each exported function: write a one-line description that explains what it does (not how)',
20
- 'Document every parameter: name, type, description, whether optional, default value',
21
- 'Document the return value: type and what it represents',
22
- 'Document known thrown errors with @throws',
23
- 'Write at least one @example per exported function',
24
- 'For APIs: document request/response shape with types or OpenAPI schema',
25
- 'For README: include quick-start that works in under 5 minutes',
26
- 'Remove outdated documentation that no longer matches the code',
27
- 'Verify all code examples actually run correctly',
28
- ],
29
- checklist: [
30
- '[ ] Every exported symbol has a JSDoc block',
31
- '[ ] Every @param has a description (not just a type)',
32
- '[ ] @returns documents what is returned, not just the type',
33
- '[ ] @throws present for all known error paths',
34
- '[ ] At least one @example per exported function',
35
- '[ ] No documentation that contradicts the current code',
36
- '[ ] README quick-start tested end-to-end',
37
- ],
38
- pitfalls: [
39
- 'Documenting HOW instead of WHY — "increments counter by 1" is not documentation',
40
- 'Copying type signatures into prose — JSDoc @param already has the type',
41
- 'Writing examples that do not actually run',
42
- 'Documenting internal functions that are not part of the public API',
43
- 'Leaving stale documentation that contradicts the current implementation',
44
- ],
45
- patterns: [
46
- 'API-first documentation: write the docs before the implementation to clarify the contract',
47
- 'Example-driven: code examples are the most useful documentation format',
48
- 'Quick-start rule: a new developer should have something running in under 5 minutes',
49
- ],
50
- duration_estimate: '1-4 hours',
51
- };
52
- }
53
-
54
- export function analyze(code: string, context?: string): AgentAnalysis {
55
- const findings: AgentFinding[] = [];
56
- const lines = code.split('\n');
57
-
58
- // Count exported symbols
59
- const exports = (code.match(/^export\s+(function|class|const|type|interface|async)/gm) ?? []).length;
60
- // Count JSDoc blocks before exports
61
- const jsdocs = (code.match(/\/\*\*[\s\S]*?\*\/\s*\nexport/g) ?? []).length;
62
- const undocumented = exports - jsdocs;
63
-
64
- if (undocumented > 0) {
65
- findings.push({
66
- severity: undocumented > 3 ? 'high' : 'medium',
67
- category: 'missing-docs',
68
- description: `${undocumented} of ${exports} exported symbol(s) lack JSDoc documentation`,
69
- fix: 'Add /** description */ block before each exported function, class, or type.',
70
- });
71
- }
72
-
73
- // Check for param docs
74
- const params = (code.match(/@param/g) ?? []).length;
75
- const funcParams = (code.match(/\([^)]{5,}\)/g) ?? []).length;
76
- if (exports > 0 && params === 0 && funcParams > 2) {
77
- findings.push({ severity: 'medium', category: 'missing-params', description: 'No @param documentation found', fix: 'Add @param {type} name — description for each parameter.' });
78
- }
79
-
80
- // Check for examples
81
- if (exports > 0 && !code.includes('@example')) {
82
- findings.push({ severity: 'low', category: 'missing-examples', description: 'No @example blocks found', fix: 'Add at least one @example showing typical usage for each exported function.' });
83
- }
84
-
85
- // Check for stale "TODO: document"
86
- const todoDoc = (code.match(/\/\/\s*TODO.*doc/gi) ?? []).length;
87
- if (todoDoc > 0) {
88
- findings.push({ severity: 'low', category: 'stale-todo', description: `${todoDoc} TODO documentation reminder(s) found`, fix: 'Write the documentation and remove the TODO.' });
89
- }
90
-
91
- const score = Math.max(0, 100 - findings.filter(f => f.severity === 'high').length * 20
92
- - findings.filter(f => f.severity === 'medium').length * 10
93
- - findings.filter(f => f.severity === 'low').length * 5);
94
-
95
- return {
96
- agent: 'documentation' as WorkerAgentType,
97
- subject: context ?? 'code',
98
- findings,
99
- score,
100
- verdict: score >= 85 ? 'approved' : score >= 65 ? 'approved_with_warnings' : score >= 40 ? 'needs_revision' : 'rejected',
101
- summary: findings.length === 0 ? 'Documentation looks complete.' : `${findings.length} documentation gap(s). Top: ${findings[0].description}`,
102
- critical_count: 0,
103
- high_count: findings.filter(f => f.severity === 'high').length,
104
- };
105
- }