@agentic15.com/agentic15-claude-zen 3.2.1 → 4.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.
- package/README.md +90 -16
- package/bin/agentic15.js +64 -56
- package/package.json +4 -2
- package/src/cli/TaskCommand.js +35 -0
- package/src/cli/VisualTestCommand.js +191 -0
- package/src/core/TemplateManager.js +137 -160
- package/templates/.claude/hooks/complete-task.js +4 -4
- package/templates/.claude/hooks/require-active-task.js +89 -89
- package/templates/.claude/hooks/session-start-context.js +9 -11
- package/templates/.claude/hooks/start-task.js +6 -8
- package/templates/.claude/settings.json +5 -91
- package/templates/package.json +31 -31
package/README.md
CHANGED
|
@@ -23,28 +23,102 @@ npx "@agentic15.com/agentic15-claude-zen" my-project
|
|
|
23
23
|
cd my-project
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
**Step 3:
|
|
26
|
+
**Step 3: Initialize Git and Link to GitHub**
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Initialize git (if not already done)
|
|
30
|
+
git init
|
|
31
|
+
git add .
|
|
32
|
+
git commit -m "Initial commit"
|
|
33
|
+
|
|
34
|
+
# Create GitHub repository and link it
|
|
35
|
+
gh repo create OWNER/REPO --public # or --private
|
|
36
|
+
git remote add origin https://github.com/OWNER/REPO.git
|
|
37
|
+
git push -u origin main
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Replace `OWNER/REPO` with your GitHub username and repository name (e.g., `myusername/my-project`).
|
|
41
|
+
|
|
42
|
+
> **REQUIRED**: This step is mandatory. The framework needs a GitHub remote to create issues and pull requests.
|
|
43
|
+
|
|
44
|
+
**Step 4: Configure Repository Settings (Recommended)**
|
|
45
|
+
|
|
46
|
+
**For Bash/Mac/Linux:**
|
|
47
|
+
```bash
|
|
48
|
+
# Prevent direct pushes to main - require PRs for all changes
|
|
49
|
+
cat > /tmp/protection.json << 'EOF'
|
|
50
|
+
{
|
|
51
|
+
"required_pull_request_reviews": {
|
|
52
|
+
"required_approving_review_count": 0
|
|
53
|
+
},
|
|
54
|
+
"enforce_admins": true,
|
|
55
|
+
"allow_force_pushes": false,
|
|
56
|
+
"allow_deletions": false,
|
|
57
|
+
"required_status_checks": null,
|
|
58
|
+
"restrictions": null
|
|
59
|
+
}
|
|
60
|
+
EOF
|
|
61
|
+
|
|
62
|
+
gh api repos/OWNER/REPO/branches/main/protection -X PUT \
|
|
63
|
+
-H "Accept: application/vnd.github+json" \
|
|
64
|
+
--input /tmp/protection.json
|
|
65
|
+
|
|
66
|
+
# Auto-delete branches after PR merge
|
|
67
|
+
gh api repos/OWNER/REPO -X PATCH \
|
|
68
|
+
-H "Accept: application/vnd.github+json" \
|
|
69
|
+
-f delete_branch_on_merge=true
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**For PowerShell (Windows):**
|
|
73
|
+
```powershell
|
|
74
|
+
# Prevent direct pushes to main - require PRs for all changes
|
|
75
|
+
$body = @"
|
|
76
|
+
{
|
|
77
|
+
"required_pull_request_reviews": {
|
|
78
|
+
"required_approving_review_count": 0
|
|
79
|
+
},
|
|
80
|
+
"enforce_admins": true,
|
|
81
|
+
"allow_force_pushes": false,
|
|
82
|
+
"allow_deletions": false,
|
|
83
|
+
"required_status_checks": null,
|
|
84
|
+
"restrictions": null
|
|
85
|
+
}
|
|
86
|
+
"@
|
|
87
|
+
|
|
88
|
+
echo $body | gh api repos/OWNER/REPO/branches/main/protection -X PUT -H "Accept: application/vnd.github+json" --input -
|
|
89
|
+
|
|
90
|
+
# Auto-delete branches after PR merge
|
|
91
|
+
gh api repos/OWNER/REPO -X PATCH -H "Accept: application/vnd.github+json" -f delete_branch_on_merge=true
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Replace `OWNER/REPO` with your GitHub username and repository name.
|
|
95
|
+
|
|
96
|
+
**Step 5: Launch Claude Code**
|
|
27
97
|
|
|
28
98
|
Start Claude Code CLI from inside the `my-project` directory. Claude Code MUST be running from inside your project directory to access the framework files.
|
|
29
99
|
|
|
30
|
-
**
|
|
100
|
+
> **IMPORTANT**: Always launch Claude Code from inside your project directory, not from the parent directory.
|
|
101
|
+
|
|
102
|
+
**Step 6: Use Framework Commands**
|
|
31
103
|
```bash
|
|
32
|
-
npx agentic15 auth
|
|
33
|
-
npx agentic15 plan
|
|
104
|
+
npx agentic15 auth # One-time GitHub setup
|
|
105
|
+
npx agentic15 plan # Enter interactive mode
|
|
34
106
|
# Type/paste your requirements, press Ctrl+D when done
|
|
35
|
-
|
|
36
|
-
#
|
|
37
|
-
npx agentic15
|
|
107
|
+
# Open another terminal. Make sure that you in your project directory. Launch Claude
|
|
108
|
+
# Ask Claude: "Read the requirements file and generate a task breakdown plan"
|
|
109
|
+
npx agentic15 task next # Start first task
|
|
110
|
+
# Ask Claude: "Implement this task"
|
|
111
|
+
npx agentic15 commit # Test, commit, push, PR
|
|
38
112
|
```
|
|
39
113
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
114
|
+
**Step 7: Clean Up Local Branches**
|
|
115
|
+
```bash
|
|
116
|
+
# If auto-delete is enabled, only clean up local branches
|
|
117
|
+
git branch -d feature/task-001
|
|
118
|
+
|
|
119
|
+
# For repositories without auto-delete, also delete remote
|
|
120
|
+
git push origin --delete feature/task-001
|
|
121
|
+
```
|
|
48
122
|
|
|
49
123
|
**See [WORKFLOWS.md](WORKFLOWS.md) for complete workflows.**
|
|
50
124
|
|
|
@@ -56,8 +130,8 @@ npx agentic15 commit # Test, commit, push, PR
|
|
|
56
130
|
- `npx agentic15 plan` - Generate and lock plans
|
|
57
131
|
- `npx agentic15 task next` - Start next task
|
|
58
132
|
- `npx agentic15 commit` - Test + commit + push + PR
|
|
133
|
+
- `npx agentic15 visual-test <url>` - Capture screenshots & console errors
|
|
59
134
|
- `npx agentic15 status` - Check progress
|
|
60
|
-
- `npx agentic15 upgrade` - Upgrade framework files
|
|
61
135
|
- `npm test` - Run tests
|
|
62
136
|
|
|
63
137
|
**Automates:**
|
package/bin/agentic15.js
CHANGED
|
@@ -1,57 +1,65 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { Command } from 'commander';
|
|
4
|
-
import { AuthCommand } from '../src/cli/AuthCommand.js';
|
|
5
|
-
import { TaskCommand } from '../src/cli/TaskCommand.js';
|
|
6
|
-
import { CommitCommand } from '../src/cli/CommitCommand.js';
|
|
7
|
-
import { StatusCommand } from '../src/cli/StatusCommand.js';
|
|
8
|
-
import { PlanCommand } from '../src/cli/PlanCommand.js';
|
|
9
|
-
import { UpgradeCommand } from '../src/cli/UpgradeCommand.js';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
.
|
|
22
|
-
.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.
|
|
28
|
-
.
|
|
29
|
-
.argument('
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
-
.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
.
|
|
42
|
-
.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.
|
|
48
|
-
.
|
|
49
|
-
.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
.
|
|
56
|
-
|
|
57
|
-
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { AuthCommand } from '../src/cli/AuthCommand.js';
|
|
5
|
+
import { TaskCommand } from '../src/cli/TaskCommand.js';
|
|
6
|
+
import { CommitCommand } from '../src/cli/CommitCommand.js';
|
|
7
|
+
import { StatusCommand } from '../src/cli/StatusCommand.js';
|
|
8
|
+
import { PlanCommand } from '../src/cli/PlanCommand.js';
|
|
9
|
+
import { UpgradeCommand } from '../src/cli/UpgradeCommand.js';
|
|
10
|
+
import { VisualTestCommand } from '../src/cli/VisualTestCommand.js';
|
|
11
|
+
|
|
12
|
+
const program = new Command();
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.name('agentic15')
|
|
16
|
+
.description('Agentic15 Claude Zen - Automated AI development workflow')
|
|
17
|
+
.version('2.0.0');
|
|
18
|
+
|
|
19
|
+
// GitHub authentication setup
|
|
20
|
+
program
|
|
21
|
+
.command('auth')
|
|
22
|
+
.description('GitHub authentication setup')
|
|
23
|
+
.action(() => AuthCommand.setup());
|
|
24
|
+
|
|
25
|
+
// Task management
|
|
26
|
+
program
|
|
27
|
+
.command('task')
|
|
28
|
+
.description('Task management')
|
|
29
|
+
.argument('<action>', 'Action: start, next, status')
|
|
30
|
+
.argument('[taskId]', 'Task ID (e.g., TASK-001) - required for "start"')
|
|
31
|
+
.action((action, taskId) => TaskCommand.handle(action, taskId));
|
|
32
|
+
|
|
33
|
+
// Auto-commit workflow
|
|
34
|
+
program
|
|
35
|
+
.command('commit')
|
|
36
|
+
.description('Run tests, commit, push, create PR')
|
|
37
|
+
.action(() => CommitCommand.execute());
|
|
38
|
+
|
|
39
|
+
// Show status
|
|
40
|
+
program
|
|
41
|
+
.command('status')
|
|
42
|
+
.description('Show current task status and progress')
|
|
43
|
+
.action(() => StatusCommand.show());
|
|
44
|
+
|
|
45
|
+
// Plan management (single command for generate + lock)
|
|
46
|
+
program
|
|
47
|
+
.command('plan')
|
|
48
|
+
.description('Generate and lock plan')
|
|
49
|
+
.argument('[description]', 'Project description (required for first run)')
|
|
50
|
+
.action((description) => PlanCommand.handle(description));
|
|
51
|
+
|
|
52
|
+
// Upgrade framework
|
|
53
|
+
program
|
|
54
|
+
.command('upgrade')
|
|
55
|
+
.description('Upgrade framework files to latest version')
|
|
56
|
+
.action(() => UpgradeCommand.execute());
|
|
57
|
+
|
|
58
|
+
// Visual testing - capture screenshots and console errors
|
|
59
|
+
program
|
|
60
|
+
.command('visual-test')
|
|
61
|
+
.description('Capture screenshots and console errors for UI debugging')
|
|
62
|
+
.argument('<url>', 'URL to test (e.g., http://localhost:3000)')
|
|
63
|
+
.action((url) => VisualTestCommand.execute(url));
|
|
64
|
+
|
|
65
|
+
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentic15.com/agentic15-claude-zen",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Structured AI-assisted development framework for Claude Code with enforced quality standards",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"test": "node test/integration.test.js",
|
|
13
13
|
"test:e2e": "node test/e2e-verification.test.js",
|
|
14
|
-
"test:site": "node test/verify-test-site.js"
|
|
14
|
+
"test:site": "node test/verify-test-site.js",
|
|
15
|
+
"sync-readme": "node -e \"require('fs').copyFileSync('../../README.md', 'README.md')\"",
|
|
16
|
+
"prepublishOnly": "npm run sync-readme"
|
|
15
17
|
},
|
|
16
18
|
"keywords": [
|
|
17
19
|
"agentic15",
|
package/src/cli/TaskCommand.js
CHANGED
|
@@ -28,6 +28,9 @@ export class TaskCommand {
|
|
|
28
28
|
process.exit(1);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// Verify git remote is configured
|
|
32
|
+
this.validateGitRemote();
|
|
33
|
+
|
|
31
34
|
// Load task tracker
|
|
32
35
|
const tracker = this.loadTracker();
|
|
33
36
|
const task = tracker.taskFiles.find(t => t.id === taskId);
|
|
@@ -248,4 +251,36 @@ export class TaskCommand {
|
|
|
248
251
|
const planId = readFileSync(activePlanPath, 'utf-8').trim();
|
|
249
252
|
return join(process.cwd(), '.claude', 'plans', planId, 'tasks', `${taskId}.json`);
|
|
250
253
|
}
|
|
254
|
+
|
|
255
|
+
static validateGitRemote() {
|
|
256
|
+
try {
|
|
257
|
+
// Check if git remote origin exists
|
|
258
|
+
const remote = execSync('git remote get-url origin', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
259
|
+
|
|
260
|
+
if (!remote || remote.length === 0) {
|
|
261
|
+
throw new Error('No remote URL');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Validate it's a GitHub URL
|
|
265
|
+
if (!remote.includes('github.com')) {
|
|
266
|
+
console.log('\n⚠️ Warning: Remote is not a GitHub repository');
|
|
267
|
+
console.log(` Remote URL: ${remote}`);
|
|
268
|
+
console.log(' GitHub integration features may not work.\n');
|
|
269
|
+
}
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.log('\n❌ Git remote "origin" is not configured');
|
|
272
|
+
console.log('\n Before starting tasks, you must link your project to a GitHub repository:');
|
|
273
|
+
console.log('\n 1. Create a GitHub repository:');
|
|
274
|
+
console.log(' gh repo create OWNER/REPO --public (or --private)');
|
|
275
|
+
console.log('\n 2. Link it to your local project:');
|
|
276
|
+
console.log(' git remote add origin https://github.com/OWNER/REPO.git');
|
|
277
|
+
console.log('\n 3. Push your initial code:');
|
|
278
|
+
console.log(' git add .');
|
|
279
|
+
console.log(' git commit -m "Initial commit"');
|
|
280
|
+
console.log(' git push -u origin main');
|
|
281
|
+
console.log('\n 4. Then start your task:');
|
|
282
|
+
console.log(' npx agentic15 task next\n');
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
251
286
|
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { existsSync, writeFileSync, mkdirSync, unlinkSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* VisualTestCommand - Capture screenshots and console errors for UI debugging
|
|
7
|
+
*
|
|
8
|
+
* Uses Claude Code's built-in screenshot capabilities (no API key needed)
|
|
9
|
+
* Helps report UI issues to Claude without manual back-and-forth
|
|
10
|
+
*/
|
|
11
|
+
export class VisualTestCommand {
|
|
12
|
+
static async execute(url) {
|
|
13
|
+
console.log('\n🎯 Visual Test - Capture screenshots and console errors\n');
|
|
14
|
+
|
|
15
|
+
if (!url) {
|
|
16
|
+
console.log('❌ URL required');
|
|
17
|
+
console.log(' Usage: npx agentic15 visual-test <url>\n');
|
|
18
|
+
console.log(' Example: npx agentic15 visual-test http://localhost:3000\n');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Check if Playwright is installed
|
|
23
|
+
const hasPlaywright = this.checkPlaywright();
|
|
24
|
+
|
|
25
|
+
if (!hasPlaywright) {
|
|
26
|
+
console.log('⚠️ Playwright not installed');
|
|
27
|
+
console.log(' Install with: npx playwright install chromium\n');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log(`📸 Capturing screenshots and logs from: ${url}\n`);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// Run Playwright visual test
|
|
35
|
+
this.runVisualTest(url);
|
|
36
|
+
|
|
37
|
+
console.log('\n✅ Visual test complete');
|
|
38
|
+
console.log(' Screenshots saved to: .claude/visual-test/\n');
|
|
39
|
+
console.log('💡 Next steps:');
|
|
40
|
+
console.log(' 1. Review screenshots in .claude/visual-test/');
|
|
41
|
+
console.log(' 2. Check console-errors.log for JavaScript errors');
|
|
42
|
+
console.log(' 3. Ask Claude to analyze the visual test results\n');
|
|
43
|
+
|
|
44
|
+
process.exit(0);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.log(`\n❌ Visual test failed: ${error.message}\n`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static checkPlaywright() {
|
|
52
|
+
const projectRoot = process.cwd();
|
|
53
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
54
|
+
|
|
55
|
+
if (!existsSync(packageJsonPath)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
// Check if playwright is in devDependencies
|
|
61
|
+
execSync('npx playwright --version', { stdio: 'pipe' });
|
|
62
|
+
return true;
|
|
63
|
+
} catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static runVisualTest(url) {
|
|
69
|
+
const testScript = `
|
|
70
|
+
const { chromium } = require('playwright');
|
|
71
|
+
const { writeFileSync, mkdirSync } = require('fs');
|
|
72
|
+
const { join } = require('path');
|
|
73
|
+
|
|
74
|
+
(async () => {
|
|
75
|
+
const outputDir = join(process.cwd(), '.claude', 'visual-test');
|
|
76
|
+
mkdirSync(outputDir, { recursive: true });
|
|
77
|
+
|
|
78
|
+
const consoleErrors = [];
|
|
79
|
+
const consoleWarnings = [];
|
|
80
|
+
|
|
81
|
+
const browser = await chromium.launch({ headless: true });
|
|
82
|
+
const context = await browser.newContext({
|
|
83
|
+
viewport: { width: 1920, height: 1080 }
|
|
84
|
+
});
|
|
85
|
+
const page = await context.newPage();
|
|
86
|
+
|
|
87
|
+
// Capture console errors
|
|
88
|
+
page.on('console', msg => {
|
|
89
|
+
if (msg.type() === 'error') {
|
|
90
|
+
consoleErrors.push({
|
|
91
|
+
timestamp: new Date().toISOString(),
|
|
92
|
+
message: msg.text()
|
|
93
|
+
});
|
|
94
|
+
} else if (msg.type() === 'warning') {
|
|
95
|
+
consoleWarnings.push({
|
|
96
|
+
timestamp: new Date().toISOString(),
|
|
97
|
+
message: msg.text()
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Capture page errors
|
|
103
|
+
page.on('pageerror', error => {
|
|
104
|
+
consoleErrors.push({
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
message: error.message,
|
|
107
|
+
stack: error.stack
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
// Navigate to URL
|
|
113
|
+
await page.goto('${url}', { waitUntil: 'networkidle', timeout: 30000 });
|
|
114
|
+
|
|
115
|
+
// Wait for page to stabilize
|
|
116
|
+
await page.waitForTimeout(2000);
|
|
117
|
+
|
|
118
|
+
// Capture full page screenshot
|
|
119
|
+
await page.screenshot({
|
|
120
|
+
path: join(outputDir, 'fullpage.png'),
|
|
121
|
+
fullPage: true
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Capture viewport screenshot
|
|
125
|
+
await page.screenshot({
|
|
126
|
+
path: join(outputDir, 'viewport.png'),
|
|
127
|
+
fullPage: false
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Save console errors
|
|
131
|
+
if (consoleErrors.length > 0) {
|
|
132
|
+
const errorLog = consoleErrors.map(e =>
|
|
133
|
+
\`[\${e.timestamp}] \${e.message}\${e.stack ? '\\n' + e.stack : ''}\`
|
|
134
|
+
).join('\\n\\n');
|
|
135
|
+
|
|
136
|
+
writeFileSync(join(outputDir, 'console-errors.log'), errorLog);
|
|
137
|
+
console.log(\`❌ Found \${consoleErrors.length} console errors\`);
|
|
138
|
+
} else {
|
|
139
|
+
console.log('✅ No console errors detected');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Save console warnings
|
|
143
|
+
if (consoleWarnings.length > 0) {
|
|
144
|
+
const warningLog = consoleWarnings.map(w =>
|
|
145
|
+
\`[\${w.timestamp}] \${w.message}\`
|
|
146
|
+
).join('\\n\\n');
|
|
147
|
+
|
|
148
|
+
writeFileSync(join(outputDir, 'console-warnings.log'), warningLog);
|
|
149
|
+
console.log(\`⚠️ Found \${consoleWarnings.length} console warnings\`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Capture page HTML for debugging
|
|
153
|
+
const html = await page.content();
|
|
154
|
+
writeFileSync(join(outputDir, 'page.html'), html);
|
|
155
|
+
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error('Error during visual test:', error.message);
|
|
158
|
+
|
|
159
|
+
// Try to capture screenshot even on error
|
|
160
|
+
try {
|
|
161
|
+
await page.screenshot({
|
|
162
|
+
path: join(outputDir, 'error-screenshot.png')
|
|
163
|
+
});
|
|
164
|
+
} catch {}
|
|
165
|
+
|
|
166
|
+
throw error;
|
|
167
|
+
} finally {
|
|
168
|
+
await browser.close();
|
|
169
|
+
}
|
|
170
|
+
})();
|
|
171
|
+
`;
|
|
172
|
+
|
|
173
|
+
// Write test script to temp file and execute
|
|
174
|
+
const tempScriptPath = join(process.cwd(), '.claude', 'temp-visual-test.js');
|
|
175
|
+
|
|
176
|
+
mkdirSync(join(process.cwd(), '.claude'), { recursive: true });
|
|
177
|
+
writeFileSync(tempScriptPath, testScript);
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
execSync(`node "${tempScriptPath}"`, {
|
|
181
|
+
stdio: 'inherit',
|
|
182
|
+
cwd: process.cwd()
|
|
183
|
+
});
|
|
184
|
+
} finally {
|
|
185
|
+
// Clean up temp script
|
|
186
|
+
try {
|
|
187
|
+
unlinkSync(tempScriptPath);
|
|
188
|
+
} catch {}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -1,160 +1,137 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright 2024-2025 agentic15.com
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { mkdirSync, cpSync, readFileSync, writeFileSync, existsSync } from 'fs';
|
|
18
|
-
import { join, dirname } from 'path';
|
|
19
|
-
import { fileURLToPath } from 'url';
|
|
20
|
-
|
|
21
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
-
const __dirname = dirname(__filename);
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* TemplateManager - Manages template copying and customization
|
|
26
|
-
*
|
|
27
|
-
* Single Responsibility: Copy and customize project templates
|
|
28
|
-
*/
|
|
29
|
-
export class TemplateManager {
|
|
30
|
-
constructor() {
|
|
31
|
-
// From src/core/, go up two levels to package root, then into templates
|
|
32
|
-
this.templatesDir = join(__dirname, '..', '..', 'templates');
|
|
33
|
-
this.distDir = join(__dirname, '.');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Copy all templates to target directory
|
|
38
|
-
*
|
|
39
|
-
* @param {string} projectName - Name of the project
|
|
40
|
-
* @param {string} targetDir - Target directory path
|
|
41
|
-
*/
|
|
42
|
-
async copyTemplates(projectName, targetDir) {
|
|
43
|
-
console.log('📦 Creating project directory...');
|
|
44
|
-
mkdirSync(targetDir, { recursive: true });
|
|
45
|
-
|
|
46
|
-
console.log('📋 Copying framework templates...');
|
|
47
|
-
|
|
48
|
-
// Copy .claude directory structure
|
|
49
|
-
this.copyDirectory('.claude', targetDir);
|
|
50
|
-
|
|
51
|
-
// Copy and customize package.json
|
|
52
|
-
this.copyAndCustomize('package.json', targetDir, projectName);
|
|
53
|
-
|
|
54
|
-
// Copy and customize README.md
|
|
55
|
-
this.copyAndCustomize('README.md', targetDir, projectName);
|
|
56
|
-
|
|
57
|
-
// Copy .gitignore (npm may rename it)
|
|
58
|
-
this.copyGitignore(targetDir);
|
|
59
|
-
|
|
60
|
-
// Copy test-site
|
|
61
|
-
this.copyDirectory('test-site', targetDir);
|
|
62
|
-
|
|
63
|
-
// Copy Agent directory
|
|
64
|
-
this.copyDirectory('Agent', targetDir);
|
|
65
|
-
|
|
66
|
-
// Copy scripts directory
|
|
67
|
-
this.copyDirectory('scripts', targetDir);
|
|
68
|
-
|
|
69
|
-
// Copy Jest configuration files
|
|
70
|
-
this.copySingleFile('jest.config.js', targetDir);
|
|
71
|
-
this.copySingleFile('jest.setup.js', targetDir);
|
|
72
|
-
this.copySingleFile('.babelrc', targetDir);
|
|
73
|
-
|
|
74
|
-
// Copy __mocks__ directory
|
|
75
|
-
this.copyDirectory('__mocks__', targetDir);
|
|
76
|
-
|
|
77
|
-
console.log('✅ Framework structure created');
|
|
78
|
-
console.log('✅ Templates copied');
|
|
79
|
-
console.log('✅ Configuration files generated');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* @param {string}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.log(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
* @param {string} targetDir - Target directory path
|
|
139
|
-
* @param {string} projectName - Project name for replacement
|
|
140
|
-
*/
|
|
141
|
-
copyAndCustomize(fileName, targetDir, projectName) {
|
|
142
|
-
console.log(` ├─ ${fileName}`);
|
|
143
|
-
const template = readFileSync(join(this.templatesDir, fileName), 'utf8');
|
|
144
|
-
const customized = template.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
145
|
-
writeFileSync(join(targetDir, fileName), customized);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Copy .gitignore file (handles npm renaming issue)
|
|
150
|
-
*
|
|
151
|
-
* @param {string} targetDir - Target directory path
|
|
152
|
-
*/
|
|
153
|
-
copyGitignore(targetDir) {
|
|
154
|
-
console.log(' ├─ .gitignore');
|
|
155
|
-
const gitignoreSource = existsSync(join(this.templatesDir, '.gitignore'))
|
|
156
|
-
? join(this.templatesDir, '.gitignore')
|
|
157
|
-
: join(this.templatesDir, '.npmignore');
|
|
158
|
-
cpSync(gitignoreSource, join(targetDir, '.gitignore'));
|
|
159
|
-
}
|
|
160
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2024-2025 agentic15.com
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { mkdirSync, cpSync, readFileSync, writeFileSync, existsSync } from 'fs';
|
|
18
|
+
import { join, dirname } from 'path';
|
|
19
|
+
import { fileURLToPath } from 'url';
|
|
20
|
+
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = dirname(__filename);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* TemplateManager - Manages template copying and customization
|
|
26
|
+
*
|
|
27
|
+
* Single Responsibility: Copy and customize project templates
|
|
28
|
+
*/
|
|
29
|
+
export class TemplateManager {
|
|
30
|
+
constructor() {
|
|
31
|
+
// From src/core/, go up two levels to package root, then into templates
|
|
32
|
+
this.templatesDir = join(__dirname, '..', '..', 'templates');
|
|
33
|
+
this.distDir = join(__dirname, '.');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Copy all templates to target directory
|
|
38
|
+
*
|
|
39
|
+
* @param {string} projectName - Name of the project
|
|
40
|
+
* @param {string} targetDir - Target directory path
|
|
41
|
+
*/
|
|
42
|
+
async copyTemplates(projectName, targetDir) {
|
|
43
|
+
console.log('📦 Creating project directory...');
|
|
44
|
+
mkdirSync(targetDir, { recursive: true });
|
|
45
|
+
|
|
46
|
+
console.log('📋 Copying framework templates...');
|
|
47
|
+
|
|
48
|
+
// Copy .claude directory structure
|
|
49
|
+
this.copyDirectory('.claude', targetDir);
|
|
50
|
+
|
|
51
|
+
// Copy and customize package.json
|
|
52
|
+
this.copyAndCustomize('package.json', targetDir, projectName);
|
|
53
|
+
|
|
54
|
+
// Copy and customize README.md
|
|
55
|
+
this.copyAndCustomize('README.md', targetDir, projectName);
|
|
56
|
+
|
|
57
|
+
// Copy .gitignore (npm may rename it)
|
|
58
|
+
this.copyGitignore(targetDir);
|
|
59
|
+
|
|
60
|
+
// Copy test-site
|
|
61
|
+
this.copyDirectory('test-site', targetDir);
|
|
62
|
+
|
|
63
|
+
// Copy Agent directory
|
|
64
|
+
this.copyDirectory('Agent', targetDir);
|
|
65
|
+
|
|
66
|
+
// Copy scripts directory
|
|
67
|
+
this.copyDirectory('scripts', targetDir);
|
|
68
|
+
|
|
69
|
+
// Copy Jest configuration files
|
|
70
|
+
this.copySingleFile('jest.config.js', targetDir);
|
|
71
|
+
this.copySingleFile('jest.setup.js', targetDir);
|
|
72
|
+
this.copySingleFile('.babelrc', targetDir);
|
|
73
|
+
|
|
74
|
+
// Copy __mocks__ directory
|
|
75
|
+
this.copyDirectory('__mocks__', targetDir);
|
|
76
|
+
|
|
77
|
+
console.log('✅ Framework structure created');
|
|
78
|
+
console.log('✅ Templates copied');
|
|
79
|
+
console.log('✅ Configuration files generated');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Copy a directory from templates to target
|
|
84
|
+
*
|
|
85
|
+
* @param {string} dirName - Directory name
|
|
86
|
+
* @param {string} targetDir - Target directory path
|
|
87
|
+
*/
|
|
88
|
+
copyDirectory(dirName, targetDir) {
|
|
89
|
+
console.log(` ├─ ${dirName}/`);
|
|
90
|
+
cpSync(
|
|
91
|
+
join(this.templatesDir, dirName),
|
|
92
|
+
join(targetDir, dirName),
|
|
93
|
+
{ recursive: true }
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Copy a single file from templates to target
|
|
99
|
+
*
|
|
100
|
+
* @param {string} fileName - File name
|
|
101
|
+
* @param {string} targetDir - Target directory path
|
|
102
|
+
*/
|
|
103
|
+
copySingleFile(fileName, targetDir) {
|
|
104
|
+
console.log(` ├─ ${fileName}`);
|
|
105
|
+
cpSync(
|
|
106
|
+
join(this.templatesDir, fileName),
|
|
107
|
+
join(targetDir, fileName)
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Copy and customize a file with project name replacement
|
|
113
|
+
*
|
|
114
|
+
* @param {string} fileName - File name
|
|
115
|
+
* @param {string} targetDir - Target directory path
|
|
116
|
+
* @param {string} projectName - Project name for replacement
|
|
117
|
+
*/
|
|
118
|
+
copyAndCustomize(fileName, targetDir, projectName) {
|
|
119
|
+
console.log(` ├─ ${fileName}`);
|
|
120
|
+
const template = readFileSync(join(this.templatesDir, fileName), 'utf8');
|
|
121
|
+
const customized = template.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
122
|
+
writeFileSync(join(targetDir, fileName), customized);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Copy .gitignore file (handles npm renaming issue)
|
|
127
|
+
*
|
|
128
|
+
* @param {string} targetDir - Target directory path
|
|
129
|
+
*/
|
|
130
|
+
copyGitignore(targetDir) {
|
|
131
|
+
console.log(' ├─ .gitignore');
|
|
132
|
+
const gitignoreSource = existsSync(join(this.templatesDir, '.gitignore'))
|
|
133
|
+
? join(this.templatesDir, '.gitignore')
|
|
134
|
+
: join(this.templatesDir, '.npmignore');
|
|
135
|
+
cpSync(gitignoreSource, join(targetDir, '.gitignore'));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -46,7 +46,7 @@ async function main() {
|
|
|
46
46
|
|
|
47
47
|
if (!taskId) {
|
|
48
48
|
console.error('\n❌ ERROR: Task ID required');
|
|
49
|
-
console.error('Usage:
|
|
49
|
+
console.error('Usage: Internal - called by npx agentic15 commit\n');
|
|
50
50
|
process.exit(1);
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -54,7 +54,7 @@ async function main() {
|
|
|
54
54
|
const activePlanFile = '.claude/ACTIVE-PLAN';
|
|
55
55
|
if (!fs.existsSync(activePlanFile)) {
|
|
56
56
|
console.error('\n❌ ERROR: No active plan found');
|
|
57
|
-
console.error('Set active plan first:
|
|
57
|
+
console.error('Set active plan first: npx agentic15 plan\n');
|
|
58
58
|
process.exit(1);
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -67,7 +67,7 @@ async function main() {
|
|
|
67
67
|
if (!fs.existsSync(trackerFile)) {
|
|
68
68
|
console.error('\n❌ ERROR: Task tracker not found');
|
|
69
69
|
console.error(`Plan: ${activePlan}`);
|
|
70
|
-
console.error('Initialize first:
|
|
70
|
+
console.error('Initialize first: npx agentic15 plan\n');
|
|
71
71
|
process.exit(1);
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -208,7 +208,7 @@ async function main() {
|
|
|
208
208
|
console.log('');
|
|
209
209
|
console.log('📝 Next task:');
|
|
210
210
|
console.log(` ${nextPendingTask.id}: ${nextPendingTask.title}`);
|
|
211
|
-
console.log(` Run:
|
|
211
|
+
console.log(` Run: npx agentic15 task next`);
|
|
212
212
|
} else {
|
|
213
213
|
console.log('');
|
|
214
214
|
console.log('🎉 All tasks completed!');
|
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Require Active Task Hook
|
|
5
|
-
*
|
|
6
|
-
* BLOCKS all Edit/Write operations when no active task exists
|
|
7
|
-
*
|
|
8
|
-
* This is the enforcement mechanism that prevents workflow violations
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
|
|
14
|
-
// Read tool use from stdin
|
|
15
|
-
let input = '';
|
|
16
|
-
process.stdin.on('data', chunk => {
|
|
17
|
-
input += chunk;
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
process.stdin.on('end', () => {
|
|
21
|
-
try {
|
|
22
|
-
const toolUse = JSON.parse(input);
|
|
23
|
-
|
|
24
|
-
// Only check Edit and Write operations
|
|
25
|
-
if (toolUse.name !== 'Edit' && toolUse.name !== 'Write') {
|
|
26
|
-
// Allow all other tools
|
|
27
|
-
process.exit(0);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Check if active task exists
|
|
32
|
-
const activePlanFile = '.claude/ACTIVE-PLAN';
|
|
33
|
-
|
|
34
|
-
if (!fs.existsSync(activePlanFile)) {
|
|
35
|
-
console.error('\n' + '═'.repeat(70));
|
|
36
|
-
console.error('❌ BLOCKED: No active plan exists');
|
|
37
|
-
console.error('═'.repeat(70));
|
|
38
|
-
console.error('\nYou MUST have an active plan before making code changes.');
|
|
39
|
-
console.error('\nTo create a plan:');
|
|
40
|
-
console.error(' npx agentic15 plan "Your project requirements"');
|
|
41
|
-
console.error('\n' + '═'.repeat(70) + '\n');
|
|
42
|
-
process.exit(1);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const activePlan = fs.readFileSync(activePlanFile, 'utf8').trim();
|
|
47
|
-
const planDir = path.join('.claude/plans', activePlan);
|
|
48
|
-
const trackerPath = path.join(planDir, 'TASK-TRACKER.json');
|
|
49
|
-
|
|
50
|
-
if (!fs.existsSync(trackerPath)) {
|
|
51
|
-
console.error('\n' + '═'.repeat(70));
|
|
52
|
-
console.error('❌ BLOCKED: Task tracker not found');
|
|
53
|
-
console.error('═'.repeat(70));
|
|
54
|
-
console.error('\nPlan exists but task tracker is missing.');
|
|
55
|
-
console.error('This indicates a corrupted plan state.');
|
|
56
|
-
console.error('\n' + '═'.repeat(70) + '\n');
|
|
57
|
-
process.exit(1);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const tracker = JSON.parse(fs.readFileSync(trackerPath, 'utf8'));
|
|
62
|
-
|
|
63
|
-
if (!tracker.activeTask) {
|
|
64
|
-
console.error('\n' + '═'.repeat(70));
|
|
65
|
-
console.error('❌ BLOCKED: No active task');
|
|
66
|
-
console.error('═'.repeat(70));
|
|
67
|
-
console.error('\nYou MUST have an active task before making code changes.');
|
|
68
|
-
console.error('\nTo start a task:');
|
|
69
|
-
console.error(' npx agentic15 task next');
|
|
70
|
-
console.error('\nThis will:');
|
|
71
|
-
console.error(' 1. Show you the next pending task');
|
|
72
|
-
console.error(' 2. Create a feature branch');
|
|
73
|
-
console.error(' 3. Create a GitHub issue');
|
|
74
|
-
console.error(' 4. Mark the task as active');
|
|
75
|
-
console.error('\nThen you can make your changes.');
|
|
76
|
-
console.error('\n' + '═'.repeat(70) + '\n');
|
|
77
|
-
process.exit(1);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Active task exists - allow the operation
|
|
82
|
-
process.exit(0);
|
|
83
|
-
|
|
84
|
-
} catch (error) {
|
|
85
|
-
// If we can't parse or check, fail safe and allow
|
|
86
|
-
// (don't want to block legitimate work due to hook errors)
|
|
87
|
-
process.exit(0);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Require Active Task Hook
|
|
5
|
+
*
|
|
6
|
+
* BLOCKS all Edit/Write operations when no active task exists
|
|
7
|
+
*
|
|
8
|
+
* This is the enforcement mechanism that prevents workflow violations
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
// Read tool use from stdin
|
|
15
|
+
let input = '';
|
|
16
|
+
process.stdin.on('data', chunk => {
|
|
17
|
+
input += chunk;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
process.stdin.on('end', () => {
|
|
21
|
+
try {
|
|
22
|
+
const toolUse = JSON.parse(input);
|
|
23
|
+
|
|
24
|
+
// Only check Edit and Write operations
|
|
25
|
+
if (toolUse.name !== 'Edit' && toolUse.name !== 'Write') {
|
|
26
|
+
// Allow all other tools
|
|
27
|
+
process.exit(0);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check if active task exists
|
|
32
|
+
const activePlanFile = '.claude/ACTIVE-PLAN';
|
|
33
|
+
|
|
34
|
+
if (!fs.existsSync(activePlanFile)) {
|
|
35
|
+
console.error('\n' + '═'.repeat(70));
|
|
36
|
+
console.error('❌ BLOCKED: No active plan exists');
|
|
37
|
+
console.error('═'.repeat(70));
|
|
38
|
+
console.error('\nYou MUST have an active plan before making code changes.');
|
|
39
|
+
console.error('\nTo create a plan:');
|
|
40
|
+
console.error(' npx agentic15 plan "Your project requirements"');
|
|
41
|
+
console.error('\n' + '═'.repeat(70) + '\n');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const activePlan = fs.readFileSync(activePlanFile, 'utf8').trim();
|
|
47
|
+
const planDir = path.join('.claude/plans', activePlan);
|
|
48
|
+
const trackerPath = path.join(planDir, 'TASK-TRACKER.json');
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(trackerPath)) {
|
|
51
|
+
console.error('\n' + '═'.repeat(70));
|
|
52
|
+
console.error('❌ BLOCKED: Task tracker not found');
|
|
53
|
+
console.error('═'.repeat(70));
|
|
54
|
+
console.error('\nPlan exists but task tracker is missing.');
|
|
55
|
+
console.error('This indicates a corrupted plan state.');
|
|
56
|
+
console.error('\n' + '═'.repeat(70) + '\n');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const tracker = JSON.parse(fs.readFileSync(trackerPath, 'utf8'));
|
|
62
|
+
|
|
63
|
+
if (!tracker.activeTask) {
|
|
64
|
+
console.error('\n' + '═'.repeat(70));
|
|
65
|
+
console.error('❌ BLOCKED: No active task');
|
|
66
|
+
console.error('═'.repeat(70));
|
|
67
|
+
console.error('\nYou MUST have an active task before making code changes.');
|
|
68
|
+
console.error('\nTo start a task:');
|
|
69
|
+
console.error(' npx agentic15 task next');
|
|
70
|
+
console.error('\nThis will:');
|
|
71
|
+
console.error(' 1. Show you the next pending task');
|
|
72
|
+
console.error(' 2. Create a feature branch');
|
|
73
|
+
console.error(' 3. Create a GitHub issue');
|
|
74
|
+
console.error(' 4. Mark the task as active');
|
|
75
|
+
console.error('\nThen you can make your changes.');
|
|
76
|
+
console.error('\n' + '═'.repeat(70) + '\n');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Active task exists - allow the operation
|
|
82
|
+
process.exit(0);
|
|
83
|
+
|
|
84
|
+
} catch (error) {
|
|
85
|
+
// If we can't parse or check, fail safe and allow
|
|
86
|
+
// (don't want to block legitimate work due to hook errors)
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
@@ -67,7 +67,7 @@ if (activePlan && tracker) {
|
|
|
67
67
|
}
|
|
68
68
|
} else {
|
|
69
69
|
log('\n ⚠️ No active task - start one:', 'yellow');
|
|
70
|
-
log('
|
|
70
|
+
log(' npx agentic15 task next', 'yellow');
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Show progress
|
|
@@ -79,11 +79,9 @@ if (activePlan && tracker) {
|
|
|
79
79
|
} else {
|
|
80
80
|
log('❌ NO ACTIVE PROJECT PLAN', 'red');
|
|
81
81
|
log('\n You MUST work within the agentic15-claude-zen framework.', 'yellow');
|
|
82
|
-
log('
|
|
83
|
-
log('
|
|
84
|
-
log('
|
|
85
|
-
log(' 3. npm run plan:init', 'yellow');
|
|
86
|
-
log(' 4. npm run task:next\n', 'yellow');
|
|
82
|
+
log(' Initialize the plan and start execution:', 'yellow');
|
|
83
|
+
log(' npx agentic15 plan', 'yellow');
|
|
84
|
+
log(' npx agentic15 task next\n', 'yellow');
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
console.log('─'.repeat(70));
|
|
@@ -108,11 +106,11 @@ log(' ./node_modules/.agentic15-claude-zen/ # Bundled scripts & hooks', 'yell
|
|
|
108
106
|
console.log('\n' + '─'.repeat(70));
|
|
109
107
|
log('📋 AVAILABLE COMMANDS:', 'bold');
|
|
110
108
|
console.log('─'.repeat(70));
|
|
111
|
-
log('
|
|
112
|
-
log('
|
|
113
|
-
log('
|
|
114
|
-
log('
|
|
115
|
-
log('
|
|
109
|
+
log(' npx agentic15 plan # Generate and lock plan', 'cyan');
|
|
110
|
+
log(' npx agentic15 task next # Start next task', 'cyan');
|
|
111
|
+
log(' npx agentic15 status # View progress', 'cyan');
|
|
112
|
+
log(' npx agentic15 commit # Test, commit, push, PR', 'cyan');
|
|
113
|
+
log(' npx agentic15 visual-test <url> # Capture UI screenshots', 'cyan');
|
|
116
114
|
|
|
117
115
|
console.log('\n' + '─'.repeat(70));
|
|
118
116
|
log('⚠️ ENFORCEMENT ACTIVE:', 'bold');
|
|
@@ -53,7 +53,7 @@ async function main() {
|
|
|
53
53
|
|
|
54
54
|
if (!taskId) {
|
|
55
55
|
console.error('\n❌ ERROR: Task ID required');
|
|
56
|
-
console.error('Usage:
|
|
56
|
+
console.error('Usage: npx agentic15 task start TASK-001\n');
|
|
57
57
|
process.exit(1);
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -61,7 +61,7 @@ async function main() {
|
|
|
61
61
|
const activePlanFile = '.claude/ACTIVE-PLAN';
|
|
62
62
|
if (!fs.existsSync(activePlanFile)) {
|
|
63
63
|
console.error('\n❌ ERROR: No active plan found');
|
|
64
|
-
console.error('Set active plan first:
|
|
64
|
+
console.error('Set active plan first: npx agentic15 plan\n');
|
|
65
65
|
process.exit(1);
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -74,7 +74,7 @@ async function main() {
|
|
|
74
74
|
if (!fs.existsSync(trackerFile)) {
|
|
75
75
|
console.error('\n❌ ERROR: Task tracker not found');
|
|
76
76
|
console.error(`Plan: ${activePlan}`);
|
|
77
|
-
console.error('Initialize first:
|
|
77
|
+
console.error('Initialize first: npx agentic15 plan\n');
|
|
78
78
|
process.exit(1);
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -218,11 +218,9 @@ async function main() {
|
|
|
218
218
|
|
|
219
219
|
console.log(`\n📂 Task file: ${taskFile}`);
|
|
220
220
|
console.log('\n📝 WORKFLOW:');
|
|
221
|
-
console.log(' 1.
|
|
222
|
-
console.log(' 2.
|
|
223
|
-
console.log(`
|
|
224
|
-
console.log(' 3. When finished:');
|
|
225
|
-
console.log(` npm run task:done ${taskId}`);
|
|
221
|
+
console.log(' 1. Implement the task requirements');
|
|
222
|
+
console.log(' 2. When finished, commit and create PR:');
|
|
223
|
+
console.log(` npx agentic15 commit`);
|
|
226
224
|
|
|
227
225
|
process.exit(0);
|
|
228
226
|
}
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"Edit(./.claude/settings.json)",
|
|
35
35
|
"Edit(./.claude/hooks/**)",
|
|
36
36
|
"Write(./.claude/hooks/**)",
|
|
37
|
-
"Edit(./.claude/CLAUDE.md)",
|
|
38
37
|
"Edit(./.claude/TASK-TRACKER.json)",
|
|
39
38
|
"Read(./.claude/POST-INSTALL.md)",
|
|
40
39
|
"Read(./docs/**)",
|
|
@@ -150,11 +149,7 @@
|
|
|
150
149
|
"hooks": [
|
|
151
150
|
{
|
|
152
151
|
"type": "command",
|
|
153
|
-
"command": "node
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
"type": "command",
|
|
157
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/detect-pending-reviews.js"
|
|
152
|
+
"command": "node .claude/hooks/session-start-context.js"
|
|
158
153
|
}
|
|
159
154
|
]
|
|
160
155
|
}
|
|
@@ -174,19 +169,7 @@
|
|
|
174
169
|
"hooks": [
|
|
175
170
|
{
|
|
176
171
|
"type": "command",
|
|
177
|
-
"command": "node
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
"type": "command",
|
|
181
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/prevent-read-bypass.js"
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
"type": "command",
|
|
185
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/enforce-structured-development.js"
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
"type": "command",
|
|
189
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/enforce-plan-template.js"
|
|
172
|
+
"command": "node .claude/hooks/enforce-plan-template.js"
|
|
190
173
|
}
|
|
191
174
|
]
|
|
192
175
|
},
|
|
@@ -195,87 +178,18 @@
|
|
|
195
178
|
"hooks": [
|
|
196
179
|
{
|
|
197
180
|
"type": "command",
|
|
198
|
-
"command": "node
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
"type": "command",
|
|
202
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-task-completion.js"
|
|
181
|
+
"command": "node .claude/hooks/validate-git-workflow.js"
|
|
203
182
|
}
|
|
204
183
|
]
|
|
205
184
|
}
|
|
206
185
|
],
|
|
207
186
|
"PostToolUse": [
|
|
208
187
|
{
|
|
209
|
-
"matcher": "
|
|
188
|
+
"matcher": "Bash(git:*)",
|
|
210
189
|
"hooks": [
|
|
211
190
|
{
|
|
212
191
|
"type": "command",
|
|
213
|
-
"command": "node
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
"type": "command",
|
|
217
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/auto-format.js"
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
"type": "command",
|
|
221
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-ui-syntax.js"
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
"type": "command",
|
|
225
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-ui-runtime.js"
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"type": "command",
|
|
229
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-ui-visual-native.js"
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
"type": "command",
|
|
233
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-component-contract.js"
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
"type": "command",
|
|
237
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-test-quality.js"
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
"type": "command",
|
|
241
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-ui-integration.js"
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
"type": "command",
|
|
245
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-integration-site.js"
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
"type": "command",
|
|
249
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-database-changes.js"
|
|
250
|
-
},
|
|
251
|
-
{
|
|
252
|
-
"type": "command",
|
|
253
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-migration-impact.js"
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
"type": "command",
|
|
257
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-visual-regression.js"
|
|
258
|
-
}
|
|
259
|
-
]
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
"matcher": "Bash",
|
|
263
|
-
"hooks": [
|
|
264
|
-
{
|
|
265
|
-
"type": "command",
|
|
266
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-test-results.js"
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
"type": "command",
|
|
270
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/validate-e2e-coverage.js"
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
"type": "command",
|
|
274
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/enforce-test-pyramid.js"
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
"type": "command",
|
|
278
|
-
"command": "node node_modules/.agentic15-claude-zen/hooks/enforce-migration-workflow.js"
|
|
192
|
+
"command": "node .claude/hooks/post-merge.js"
|
|
279
193
|
}
|
|
280
194
|
]
|
|
281
195
|
}
|
package/templates/package.json
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{PROJECT_NAME}}",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "Project with Claude Code structured development framework",
|
|
5
|
-
"type": "commonjs",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "jest --passWithNoTests"
|
|
8
|
-
},
|
|
9
|
-
"keywords": [
|
|
10
|
-
"claude-code",
|
|
11
|
-
"structured-development",
|
|
12
|
-
"task-tracking"
|
|
13
|
-
],
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"@agentic15.com/agentic15-claude-zen": "^2.0.0"
|
|
17
|
-
},
|
|
18
|
-
"devDependencies": {
|
|
19
|
-
"jest": "^30.2.0",
|
|
20
|
-
"@testing-library/react": "^16.1.0",
|
|
21
|
-
"@testing-library/jest-dom": "^6.6.3",
|
|
22
|
-
"@testing-library/user-event": "^14.5.2",
|
|
23
|
-
"@babel/preset-env": "^7.26.0",
|
|
24
|
-
"@babel/preset-react": "^7.26.3",
|
|
25
|
-
"babel-jest": "^30.0.0",
|
|
26
|
-
"jest-environment-jsdom": "^30.0.0",
|
|
27
|
-
"prop-types": "^15.8.1",
|
|
28
|
-
"identity-obj-proxy": "^3.0.0",
|
|
29
|
-
"@playwright/test": "^1.41.0"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Project with Claude Code structured development framework",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "jest --passWithNoTests"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"claude-code",
|
|
11
|
+
"structured-development",
|
|
12
|
+
"task-tracking"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@agentic15.com/agentic15-claude-zen": "^2.0.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"jest": "^30.2.0",
|
|
20
|
+
"@testing-library/react": "^16.1.0",
|
|
21
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
22
|
+
"@testing-library/user-event": "^14.5.2",
|
|
23
|
+
"@babel/preset-env": "^7.26.0",
|
|
24
|
+
"@babel/preset-react": "^7.26.3",
|
|
25
|
+
"babel-jest": "^30.0.0",
|
|
26
|
+
"jest-environment-jsdom": "^30.0.0",
|
|
27
|
+
"prop-types": "^15.8.1",
|
|
28
|
+
"identity-obj-proxy": "^3.0.0",
|
|
29
|
+
"@playwright/test": "^1.41.0"
|
|
30
|
+
}
|
|
31
|
+
}
|