@itz4blitz/agentful 1.2.0 → 1.3.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 (59) hide show
  1. package/README.md +28 -1
  2. package/bin/cli.js +11 -1055
  3. package/bin/hooks/block-file-creation.js +271 -0
  4. package/bin/hooks/product-spec-watcher.js +151 -0
  5. package/lib/index.js +0 -11
  6. package/lib/init.js +2 -21
  7. package/lib/parallel-execution.js +235 -0
  8. package/lib/presets.js +26 -4
  9. package/package.json +4 -7
  10. package/template/.claude/agents/architect.md +2 -2
  11. package/template/.claude/agents/backend.md +17 -30
  12. package/template/.claude/agents/frontend.md +17 -39
  13. package/template/.claude/agents/orchestrator.md +63 -4
  14. package/template/.claude/agents/product-analyzer.md +1 -1
  15. package/template/.claude/agents/tester.md +16 -29
  16. package/template/.claude/commands/agentful-generate.md +221 -14
  17. package/template/.claude/commands/agentful-init.md +621 -0
  18. package/template/.claude/commands/agentful-product.md +1 -1
  19. package/template/.claude/commands/agentful-start.md +99 -1
  20. package/template/.claude/product/EXAMPLES.md +2 -2
  21. package/template/.claude/product/index.md +1 -1
  22. package/template/.claude/settings.json +22 -0
  23. package/template/.claude/skills/research/SKILL.md +432 -0
  24. package/template/CLAUDE.md +5 -6
  25. package/template/bin/hooks/architect-drift-detector.js +242 -0
  26. package/template/bin/hooks/product-spec-watcher.js +151 -0
  27. package/version.json +1 -1
  28. package/bin/hooks/post-agent.js +0 -101
  29. package/bin/hooks/post-feature.js +0 -227
  30. package/bin/hooks/pre-agent.js +0 -118
  31. package/bin/hooks/pre-feature.js +0 -138
  32. package/lib/VALIDATION_README.md +0 -455
  33. package/lib/ci/claude-action-integration.js +0 -641
  34. package/lib/ci/index.js +0 -10
  35. package/lib/core/analyzer.js +0 -497
  36. package/lib/core/cli.js +0 -141
  37. package/lib/core/detectors/conventions.js +0 -342
  38. package/lib/core/detectors/framework.js +0 -276
  39. package/lib/core/detectors/index.js +0 -15
  40. package/lib/core/detectors/language.js +0 -199
  41. package/lib/core/detectors/patterns.js +0 -356
  42. package/lib/core/generator.js +0 -626
  43. package/lib/core/index.js +0 -9
  44. package/lib/core/output-parser.js +0 -458
  45. package/lib/core/storage.js +0 -515
  46. package/lib/core/templates.js +0 -556
  47. package/lib/pipeline/cli.js +0 -423
  48. package/lib/pipeline/engine.js +0 -928
  49. package/lib/pipeline/executor.js +0 -440
  50. package/lib/pipeline/index.js +0 -33
  51. package/lib/pipeline/integrations.js +0 -559
  52. package/lib/pipeline/schemas.js +0 -288
  53. package/lib/remote/client.js +0 -361
  54. package/lib/server/auth.js +0 -270
  55. package/lib/server/client-example.js +0 -190
  56. package/lib/server/executor.js +0 -477
  57. package/lib/server/index.js +0 -494
  58. package/lib/update-helpers.js +0 -505
  59. package/lib/validation.js +0 -460
@@ -1,227 +0,0 @@
1
- #!/usr/bin/env node
2
- // post-feature.js
3
- // Feature completion validation and tracking
4
-
5
- import fs from 'fs';
6
- import { execSync } from 'child_process';
7
-
8
- // Helper function to run command and capture output
9
- function runCommand(command, description) {
10
- try {
11
- const output = execSync(command, {
12
- encoding: 'utf8',
13
- stdio: 'pipe',
14
- timeout: 60000 // 60 second timeout
15
- });
16
- return { success: true, output };
17
- } catch (err) {
18
- return { success: false, output: err.stdout || err.stderr || '' };
19
- }
20
- }
21
-
22
- /**
23
- * Validate feature completion with automated checks
24
- * @param {string} feature - Feature name
25
- * @param {string} domain - Domain name (optional)
26
- * @returns {object} - { errors, validationResults, exitCode }
27
- */
28
- export function validateFeatureCompletion(feature, domain = '') {
29
- // Exit successfully if no feature specified
30
- if (!feature) {
31
- return { errors: 0, validationResults: [], exitCode: 0 };
32
- }
33
-
34
- const TIMESTAMP = new Date().toISOString();
35
- let errors = 0;
36
- const validationResults = [];
37
-
38
- console.log(`=== Post-Feature Validation: ${feature} ===`);
39
- console.log('');
40
-
41
- // Detect stack
42
- const hasPackageJson = fs.existsSync('package.json');
43
- const hasPyProject = fs.existsSync('pyproject.toml') || fs.existsSync('requirements.txt');
44
- const hasGoMod = fs.existsSync('go.mod');
45
- const hasPomXml = fs.existsSync('pom.xml');
46
- const hasCargoToml = fs.existsSync('Cargo.toml');
47
-
48
- // Check 1: Run tests
49
- console.log('[1/4] Running tests...');
50
- let testCmd = null;
51
- if (hasPackageJson) testCmd = 'npm test 2>&1';
52
- else if (hasPyProject) testCmd = 'pytest 2>&1';
53
- else if (hasGoMod) testCmd = 'go test ./... 2>&1';
54
- else if (hasPomXml) testCmd = 'mvn test 2>&1';
55
- else if (hasCargoToml) testCmd = 'cargo test 2>&1';
56
-
57
- if (testCmd) {
58
- const testResult = runCommand(testCmd, 'tests');
59
- if (testResult.success) {
60
- console.log(' Tests: PASS');
61
- validationResults.push('tests:pass');
62
- } else {
63
- console.log(' Tests: FAIL');
64
- validationResults.push('tests:fail');
65
- errors++;
66
- }
67
- } else {
68
- console.log(' Tests: SKIP (no test framework detected)');
69
- validationResults.push('tests:skip');
70
- }
71
- console.log('');
72
-
73
- // Check 2: Type checking
74
- console.log('[2/4] Running type check...');
75
- let typeCmd = null;
76
- if (fs.existsSync('tsconfig.json')) typeCmd = 'npx tsc --noEmit 2>&1';
77
- else if (hasPyProject) typeCmd = 'mypy . --ignore-missing-imports 2>&1';
78
- else if (hasGoMod) typeCmd = 'go vet ./... 2>&1';
79
- else if (hasCargoToml) typeCmd = 'cargo check 2>&1';
80
-
81
- if (typeCmd) {
82
- const tscResult = runCommand(typeCmd, 'type-check');
83
- if (tscResult.success) {
84
- console.log(' Type Check: PASS');
85
- validationResults.push('types:pass');
86
- } else {
87
- console.log(' Type Check: FAIL');
88
- validationResults.push('types:fail');
89
- errors++;
90
- }
91
- } else {
92
- console.log(' Type Check: SKIP (no type checker detected)');
93
- validationResults.push('types:skip');
94
- }
95
- console.log('');
96
-
97
- // Check 3: Linting
98
- console.log('[3/4] Running linter...');
99
- let lintCmd = null;
100
- if (hasPackageJson) lintCmd = 'npm run lint 2>&1';
101
- else if (hasPyProject) lintCmd = 'ruff check . 2>&1 || pylint **/*.py 2>&1';
102
- else if (hasGoMod) lintCmd = 'golangci-lint run 2>&1';
103
- else if (hasCargoToml) lintCmd = 'cargo clippy -- -D warnings 2>&1';
104
-
105
- if (lintCmd) {
106
- const lintResult = runCommand(lintCmd, 'lint');
107
- if (lintResult.success) {
108
- console.log(' Lint: PASS');
109
- validationResults.push('lint:pass');
110
- } else {
111
- console.log(' Lint: FAIL');
112
- validationResults.push('lint:fail');
113
- errors++;
114
- }
115
- } else {
116
- console.log(' Lint: SKIP (no linter detected)');
117
- validationResults.push('lint:skip');
118
- }
119
- console.log('');
120
-
121
- // Check 4: Coverage check
122
- console.log('[4/4] Checking test coverage...');
123
- console.log(' Coverage: SKIP (run /agentful-validate for full coverage report)');
124
- validationResults.push('coverage:skip');
125
- console.log('');
126
-
127
- // Update completion.json with validation results
128
- const completionJsonPath = '.agentful/completion.json';
129
- if (fs.existsSync(completionJsonPath)) {
130
- try {
131
- const completionContent = fs.readFileSync(completionJsonPath, 'utf8');
132
- const completion = JSON.parse(completionContent);
133
-
134
- const validationStatus = errors > 0 ? 'failed' : 'passed';
135
- const validationObject = {
136
- status: validationStatus,
137
- timestamp: TIMESTAMP,
138
- errors: errors,
139
- results: validationResults
140
- };
141
-
142
- if (domain) {
143
- // Hierarchical structure
144
- if (!completion.domains) completion.domains = {};
145
- if (!completion.domains[domain]) completion.domains[domain] = {};
146
- if (!completion.domains[domain].features) completion.domains[domain].features = {};
147
- if (!completion.domains[domain].features[feature]) completion.domains[domain].features[feature] = {};
148
- completion.domains[domain].features[feature].validation = validationObject;
149
- } else {
150
- // Flat structure
151
- if (!completion.features) completion.features = {};
152
- if (!completion.features[feature]) completion.features[feature] = {};
153
- completion.features[feature].validation = validationObject;
154
- }
155
-
156
- fs.writeFileSync(completionJsonPath, JSON.stringify(completion, null, 2));
157
- } catch (err) {
158
- console.error('WARNING: Failed to update completion.json');
159
- }
160
- }
161
-
162
- // Log to metrics
163
- const metricsPath = '.agentful/agent-metrics.json';
164
- if (fs.existsSync(metricsPath)) {
165
- try {
166
- const metricsContent = fs.readFileSync(metricsPath, 'utf8');
167
- const metrics = JSON.parse(metricsContent);
168
-
169
- if (!metrics.feature_hooks) metrics.feature_hooks = [];
170
- metrics.feature_hooks.push({
171
- hook: 'PostFeature',
172
- feature: feature,
173
- domain: domain,
174
- timestamp: TIMESTAMP,
175
- result: errors > 0 ? 'failed' : 'passed'
176
- });
177
-
178
- fs.writeFileSync(metricsPath, JSON.stringify(metrics, null, 2));
179
- } catch (err) {
180
- console.error('WARNING: Failed to update agent-metrics.json');
181
- }
182
- }
183
-
184
- // Create git commit if all validations pass
185
- if (errors === 0) {
186
- console.log('=== All Validations Passed ===');
187
- console.log('');
188
-
189
- // Check if there are changes to commit
190
- try {
191
- execSync('git diff --quiet 2>/dev/null', { stdio: 'pipe' });
192
- execSync('git diff --cached --quiet 2>/dev/null', { stdio: 'pipe' });
193
- console.log('No changes to commit');
194
- } catch (err) {
195
- // There are changes
196
- const commitMsg = domain
197
- ? `feat(${domain}): complete ${feature} feature`
198
- : `feat: complete ${feature} feature`;
199
-
200
- console.log('Creating git commit...');
201
- try {
202
- execSync('git add -A', { stdio: 'pipe' });
203
- execSync(`git commit -m "${commitMsg}"`, { stdio: 'pipe' });
204
- console.log(` Commit created: ${commitMsg}`);
205
- } catch (err) {
206
- console.log('WARNING: Git commit failed (this is non-blocking)');
207
- }
208
- }
209
-
210
- return { errors: 0, validationResults, exitCode: 0 };
211
- } else {
212
- console.log(`=== Validation Failed (${errors} error(s)) ===`);
213
- console.log('');
214
- console.log('Fix validation errors before completing feature.');
215
- console.log('Run /agentful-validate for detailed output');
216
- return { errors, validationResults, exitCode: 1 };
217
- }
218
- }
219
-
220
- // CLI entrypoint
221
- if (import.meta.url === `file://${process.argv[1]}`) {
222
- const FEATURE = process.env.AGENTFUL_FEATURE || '';
223
- const DOMAIN = process.env.AGENTFUL_DOMAIN || '';
224
-
225
- const result = validateFeatureCompletion(FEATURE, DOMAIN);
226
- process.exit(result.exitCode);
227
- }
@@ -1,118 +0,0 @@
1
- #!/usr/bin/env node
2
- // pre-agent.js
3
- // Validates agent preconditions before invocation
4
-
5
- import fs from 'fs';
6
-
7
- /**
8
- * Validate agent preconditions
9
- * @param {string} agentName - Agent name
10
- * @param {string} feature - Feature name (optional)
11
- * @param {string} domain - Domain name (optional)
12
- * @returns {object} - { errors, exitCode }
13
- */
14
- export function validateAgentPreconditions(agentName, feature = '', domain = '') {
15
- // Exit successfully if no agent specified
16
- if (!agentName) {
17
- return { errors: 0, exitCode: 0 };
18
- }
19
-
20
- let errors = 0;
21
-
22
- // Check 1: Agent file exists
23
- const agentFile = `.claude/agents/${agentName}.md`;
24
- if (!fs.existsSync(agentFile)) {
25
- console.error(`ERROR: Agent file not found: ${agentFile}`);
26
- errors++;
27
- }
28
-
29
- // Check 2: Required state files exist
30
- const stateFiles = ['state.json', 'completion.json', 'decisions.json'];
31
- for (const file of stateFiles) {
32
- const filePath = `.agentful/${file}`;
33
- if (!fs.existsSync(filePath)) {
34
- console.error(`ERROR: Missing state file: ${filePath}`);
35
- errors++;
36
- }
37
- }
38
-
39
- // Check 3: Validate state.json structure
40
- const stateJsonPath = '.agentful/state.json';
41
- if (fs.existsSync(stateJsonPath)) {
42
- try {
43
- const stateContent = fs.readFileSync(stateJsonPath, 'utf8');
44
- const state = JSON.parse(stateContent);
45
- if (!state.current_phase) {
46
- console.error('ERROR: .agentful/state.json is malformed (missing current_phase)');
47
- errors++;
48
- }
49
- } catch (err) {
50
- console.error('ERROR: .agentful/state.json is invalid JSON');
51
- errors++;
52
- }
53
- }
54
-
55
- // Check 4: If feature specified, verify it exists in product spec
56
- if (feature) {
57
- let featureFound = false;
58
-
59
- // Check hierarchical structure
60
- if (domain) {
61
- const featureFile = `.claude/product/domains/${domain}/features/${feature}.md`;
62
- if (fs.existsSync(featureFile)) {
63
- featureFound = true;
64
- }
65
- }
66
-
67
- // Check flat structure
68
- if (!featureFound) {
69
- const featureFile = `.claude/product/features/${feature}.md`;
70
- if (fs.existsSync(featureFile)) {
71
- featureFound = true;
72
- }
73
- }
74
-
75
- if (!featureFound) {
76
- console.log(`WARNING: Feature '${feature}' not found in product specification`);
77
- // Warning only, don't block
78
- }
79
- }
80
-
81
- // Check 5: Verify orchestrator isn't blocked
82
- if (fs.existsSync(stateJsonPath)) {
83
- try {
84
- const stateContent = fs.readFileSync(stateJsonPath, 'utf8');
85
- const state = JSON.parse(stateContent);
86
- const blockedOn = state.blocked_on || [];
87
- if (Array.isArray(blockedOn) && blockedOn.length > 0) {
88
- console.log(`WARNING: Orchestrator is blocked on decisions: ${JSON.stringify(blockedOn)}`);
89
- // Warning only, don't block
90
- }
91
- } catch (err) {
92
- // Already handled in Check 3
93
- }
94
- }
95
-
96
- // Exit with error if critical checks failed
97
- if (errors > 0) {
98
- console.log('');
99
- console.log(`Pre-agent validation failed with ${errors} error(s)`);
100
- console.log(`Agent: ${agentName}`);
101
- if (feature) console.log(`Feature: ${feature}`);
102
- if (domain) console.log(`Domain: ${domain}`);
103
- return { errors, exitCode: 1 };
104
- }
105
-
106
- // All checks passed
107
- return { errors: 0, exitCode: 0 };
108
- }
109
-
110
- // CLI entrypoint
111
- if (import.meta.url === `file://${process.argv[1]}`) {
112
- const AGENT_NAME = process.env.AGENTFUL_AGENT || '';
113
- const FEATURE = process.env.AGENTFUL_FEATURE || '';
114
- const DOMAIN = process.env.AGENTFUL_DOMAIN || '';
115
-
116
- const result = validateAgentPreconditions(AGENT_NAME, FEATURE, DOMAIN);
117
- process.exit(result.exitCode);
118
- }
@@ -1,138 +0,0 @@
1
- #!/usr/bin/env node
2
- // pre-feature.js
3
- // Validates feature readiness before implementation
4
-
5
- import fs from 'fs';
6
-
7
- /**
8
- * Validate feature readiness before implementation
9
- * @param {string} feature - Feature name
10
- * @param {string} domain - Domain name (optional)
11
- * @returns {object} - { errors, warnings, exitCode }
12
- */
13
- export function validateFeatureReadiness(feature, domain = '') {
14
- // Exit successfully if no feature specified
15
- if (!feature) {
16
- return { errors: 0, warnings: 0, exitCode: 0 };
17
- }
18
-
19
- let errors = 0;
20
- let warnings = 0;
21
-
22
- // Check 1: Feature file exists
23
- let featureFile = '';
24
- if (domain) {
25
- // Hierarchical structure
26
- featureFile = `.claude/product/domains/${domain}/features/${feature}.md`;
27
- } else {
28
- // Flat structure
29
- featureFile = `.claude/product/features/${feature}.md`;
30
- }
31
-
32
- if (!fs.existsSync(featureFile)) {
33
- console.error(`ERROR: Feature file not found: ${featureFile}`);
34
- errors++;
35
- }
36
-
37
- // Check 2: Verify completion.json exists
38
- const completionJsonPath = '.agentful/completion.json';
39
- if (!fs.existsSync(completionJsonPath)) {
40
- console.error('ERROR: .agentful/completion.json not found');
41
- errors++;
42
- }
43
-
44
- // Check 3: Check feature dependencies
45
- if (fs.existsSync(completionJsonPath)) {
46
- try {
47
- const completionContent = fs.readFileSync(completionJsonPath, 'utf8');
48
- const completion = JSON.parse(completionContent);
49
-
50
- // Check if feature has dependencies that are incomplete
51
- if (domain) {
52
- // Hierarchical: check domain-level dependencies
53
- const domainStatus = completion.domains?.[domain]?.status || 'unknown';
54
- if (domainStatus === 'blocked') {
55
- console.error(`ERROR: Domain '${domain}' is blocked`);
56
- errors++;
57
- }
58
- }
59
-
60
- // Check for blocking decisions
61
- const decisionsJsonPath = '.agentful/decisions.json';
62
- if (fs.existsSync(decisionsJsonPath)) {
63
- try {
64
- const decisionsContent = fs.readFileSync(decisionsJsonPath, 'utf8');
65
- const decisions = JSON.parse(decisionsContent);
66
-
67
- const featurePath = domain ? `${domain}/${feature}` : feature;
68
- const blockingDecisions = (decisions.pending || [])
69
- .filter(d => (d.blocking || []).some(b => b.includes(featurePath)))
70
- .map(d => d.id);
71
-
72
- if (blockingDecisions.length > 0) {
73
- console.error(`ERROR: Feature '${feature}' is blocked by decisions: ${blockingDecisions.join(', ')}`);
74
- console.error('Run /agentful-decide to resolve blocking decisions');
75
- errors++;
76
- }
77
- } catch (err) {
78
- // Ignore JSON parse errors for decisions.json
79
- }
80
- }
81
- } catch (err) {
82
- // Ignore JSON parse errors for completion.json
83
- }
84
- }
85
-
86
- // Check 4: Tech stack compatibility (if architecture.json exists)
87
- const architectureJsonPath = '.agentful/architecture.json';
88
- if (fs.existsSync(architectureJsonPath)) {
89
- try {
90
- const archContent = fs.readFileSync(architectureJsonPath, 'utf8');
91
- const arch = JSON.parse(archContent);
92
- const techStack = arch.techStack;
93
-
94
- if (!techStack || techStack === null) {
95
- console.log('WARNING: Tech stack not analyzed. Run /agentful-generate');
96
- warnings++;
97
- }
98
- } catch (err) {
99
- // Ignore JSON parse errors
100
- }
101
- }
102
-
103
- // Check 5: Verify required agents exist
104
- const requiredAgents = ['backend', 'frontend', 'tester', 'reviewer'];
105
- for (const agent of requiredAgents) {
106
- const agentPath = `.claude/agents/${agent}.md`;
107
- if (!fs.existsSync(agentPath)) {
108
- console.log(`WARNING: Core agent missing: ${agentPath}`);
109
- warnings++;
110
- }
111
- }
112
-
113
- // Exit with error if critical checks failed
114
- if (errors > 0) {
115
- console.log('');
116
- console.log(`Pre-feature validation failed with ${errors} error(s)`);
117
- console.log(`Feature: ${feature}`);
118
- if (domain) console.log(`Domain: ${domain}`);
119
- return { errors, warnings, exitCode: 1 };
120
- }
121
-
122
- if (warnings > 0) {
123
- console.log('');
124
- console.log(`Pre-feature validation passed with ${warnings} warning(s)`);
125
- }
126
-
127
- // All checks passed
128
- return { errors: 0, warnings, exitCode: 0 };
129
- }
130
-
131
- // CLI entrypoint
132
- if (import.meta.url === `file://${process.argv[1]}`) {
133
- const FEATURE = process.env.AGENTFUL_FEATURE || '';
134
- const DOMAIN = process.env.AGENTFUL_DOMAIN || '';
135
-
136
- const result = validateFeatureReadiness(FEATURE, DOMAIN);
137
- process.exit(result.exitCode);
138
- }