@agentic15.com/agentic15-claude-zen 4.0.2 ā 4.0.4
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/package.json +1 -1
- package/src/cli/CommitCommand.js +316 -331
- package/src/cli/UpgradeCommand.js +191 -189
- package/src/core/TemplateManager.js +0 -8
- package/templates/.claude/hooks/session-start-context.js +131 -128
- package/templates/.claude/settings.json +1 -81
- package/templates/package.json +1 -16
- package/templates/.babelrc +0 -6
- package/templates/.claude/hooks/post-merge.js +0 -163
- package/templates/.claude/hooks/validate-git-workflow.js +0 -74
- package/templates/__mocks__/fileMock.js +0 -9
- package/templates/jest.config.js +0 -48
- package/templates/jest.setup.js +0 -13
|
@@ -1,128 +1,131 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Session Start Context Display Hook
|
|
5
|
-
*
|
|
6
|
-
* CRITICAL: Shows Claude the current context at session start
|
|
7
|
-
* - Active plan name and location
|
|
8
|
-
* - Active task ID and description
|
|
9
|
-
* - Project structure
|
|
10
|
-
* - Workflow reminder
|
|
11
|
-
*
|
|
12
|
-
* This hook FORCES Claude to acknowledge the agentic15-claude-zen workflow
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const path = require('path');
|
|
17
|
-
|
|
18
|
-
function log(message, color = 'reset') {
|
|
19
|
-
const colors = {
|
|
20
|
-
reset: '\x1b[0m',
|
|
21
|
-
green: '\x1b[32m',
|
|
22
|
-
yellow: '\x1b[33m',
|
|
23
|
-
blue: '\x1b[34m',
|
|
24
|
-
cyan: '\x1b[36m',
|
|
25
|
-
red: '\x1b[31m',
|
|
26
|
-
bold: '\x1b[1m'
|
|
27
|
-
};
|
|
28
|
-
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Check if active plan exists
|
|
32
|
-
const activePlanFile = '.claude/ACTIVE-PLAN';
|
|
33
|
-
let activePlan = null;
|
|
34
|
-
let planDir = null;
|
|
35
|
-
let tracker = null;
|
|
36
|
-
let activeTask = null;
|
|
37
|
-
|
|
38
|
-
if (fs.existsSync(activePlanFile)) {
|
|
39
|
-
activePlan = fs.readFileSync(activePlanFile, 'utf8').trim();
|
|
40
|
-
planDir = path.join('.claude/plans', activePlan);
|
|
41
|
-
|
|
42
|
-
const trackerPath = path.join(planDir, 'TASK-TRACKER.json');
|
|
43
|
-
if (fs.existsSync(trackerPath)) {
|
|
44
|
-
tracker = JSON.parse(fs.readFileSync(trackerPath, 'utf8'));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
console.log('\n' + 'ā'.repeat(70));
|
|
49
|
-
log('šÆ
|
|
50
|
-
console.log('ā'.repeat(70) + '\n');
|
|
51
|
-
|
|
52
|
-
// Display active context
|
|
53
|
-
if (activePlan && tracker) {
|
|
54
|
-
log('ā
ACTIVE PROJECT CONTEXT:', 'green');
|
|
55
|
-
log(` Project: ${tracker.projectName}`, 'cyan');
|
|
56
|
-
log(` Plan: ${activePlan}`, 'cyan');
|
|
57
|
-
log(` Location: .claude/plans/${activePlan}/`, 'cyan');
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
log(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
log(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
log('
|
|
84
|
-
log('
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
log('
|
|
91
|
-
log('
|
|
92
|
-
log('
|
|
93
|
-
log('
|
|
94
|
-
log('
|
|
95
|
-
log('
|
|
96
|
-
log('
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console.log('ā'.repeat(70));
|
|
101
|
-
log('
|
|
102
|
-
log('
|
|
103
|
-
log('
|
|
104
|
-
log(' ./
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
log('
|
|
108
|
-
|
|
109
|
-
log('
|
|
110
|
-
log(' npx agentic15
|
|
111
|
-
log(' npx agentic15
|
|
112
|
-
log(' npx agentic15
|
|
113
|
-
log(' npx agentic15
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
log('
|
|
117
|
-
|
|
118
|
-
log('
|
|
119
|
-
log('
|
|
120
|
-
log('
|
|
121
|
-
log(' ā¢
|
|
122
|
-
log(' ā¢
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
log('
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Session Start Context Display Hook
|
|
5
|
+
*
|
|
6
|
+
* CRITICAL: Shows Claude the current context at session start
|
|
7
|
+
* - Active plan name and location
|
|
8
|
+
* - Active task ID and description
|
|
9
|
+
* - Project structure
|
|
10
|
+
* - Workflow reminder
|
|
11
|
+
*
|
|
12
|
+
* This hook FORCES Claude to acknowledge the agentic15-claude-zen workflow
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
function log(message, color = 'reset') {
|
|
19
|
+
const colors = {
|
|
20
|
+
reset: '\x1b[0m',
|
|
21
|
+
green: '\x1b[32m',
|
|
22
|
+
yellow: '\x1b[33m',
|
|
23
|
+
blue: '\x1b[34m',
|
|
24
|
+
cyan: '\x1b[36m',
|
|
25
|
+
red: '\x1b[31m',
|
|
26
|
+
bold: '\x1b[1m'
|
|
27
|
+
};
|
|
28
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check if active plan exists
|
|
32
|
+
const activePlanFile = '.claude/ACTIVE-PLAN';
|
|
33
|
+
let activePlan = null;
|
|
34
|
+
let planDir = null;
|
|
35
|
+
let tracker = null;
|
|
36
|
+
let activeTask = null;
|
|
37
|
+
|
|
38
|
+
if (fs.existsSync(activePlanFile)) {
|
|
39
|
+
activePlan = fs.readFileSync(activePlanFile, 'utf8').trim();
|
|
40
|
+
planDir = path.join('.claude/plans', activePlan);
|
|
41
|
+
|
|
42
|
+
const trackerPath = path.join(planDir, 'TASK-TRACKER.json');
|
|
43
|
+
if (fs.existsSync(trackerPath)) {
|
|
44
|
+
tracker = JSON.parse(fs.readFileSync(trackerPath, 'utf8'));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log('\n' + 'ā'.repeat(70));
|
|
49
|
+
log('šÆ AGENTIC15-CLAUDE-ZEN WORKFLOW - SESSION START', 'bold');
|
|
50
|
+
console.log('ā'.repeat(70) + '\n');
|
|
51
|
+
|
|
52
|
+
// Display active context
|
|
53
|
+
if (activePlan && tracker) {
|
|
54
|
+
log('ā
ACTIVE PROJECT CONTEXT:', 'green');
|
|
55
|
+
log(` Project: ${tracker.projectName}`, 'cyan');
|
|
56
|
+
log(` Plan: ${activePlan}`, 'cyan');
|
|
57
|
+
log(` Location: .claude/plans/${activePlan}/`, 'cyan');
|
|
58
|
+
|
|
59
|
+
// Find task with in_progress status
|
|
60
|
+
const inProgressTask = tracker.taskFiles.find(t => t.status === 'in_progress');
|
|
61
|
+
|
|
62
|
+
if (inProgressTask) {
|
|
63
|
+
const taskFile = path.join(planDir, 'tasks', `${inProgressTask.id}.json`);
|
|
64
|
+
if (fs.existsSync(taskFile)) {
|
|
65
|
+
const task = JSON.parse(fs.readFileSync(taskFile, 'utf8'));
|
|
66
|
+
log(`\n š TASK IN PROGRESS: ${inProgressTask.id}`, 'yellow');
|
|
67
|
+
log(` Title: ${task.title}`, 'yellow');
|
|
68
|
+
log(` Description: ${task.description}`, 'yellow');
|
|
69
|
+
log(`\n ā ļø COMPLETE THIS TASK FIRST: npx agentic15 commit`, 'red');
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
log('\n ā No task in progress - start next:', 'yellow');
|
|
73
|
+
log(' npx agentic15 task next', 'yellow');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Show progress
|
|
77
|
+
const stats = tracker.statistics;
|
|
78
|
+
log(`\n Progress: ${stats.completed}/${stats.totalTasks} tasks complete`, 'cyan');
|
|
79
|
+
log(` In Progress: ${stats.inProgress}`, 'cyan');
|
|
80
|
+
log(` Pending: ${stats.pending}`, 'cyan');
|
|
81
|
+
|
|
82
|
+
} else {
|
|
83
|
+
log('ā NO ACTIVE PROJECT PLAN', 'red');
|
|
84
|
+
log('\n You MUST work within the agentic15-claude-zen framework.', 'yellow');
|
|
85
|
+
log(' Initialize the plan and start execution:', 'yellow');
|
|
86
|
+
log(' npx agentic15 plan', 'yellow');
|
|
87
|
+
log(' npx agentic15 task next\n', 'yellow');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log('ā'.repeat(70));
|
|
91
|
+
log('š MANDATORY WORKFLOW RULES - NO EXCEPTIONS:', 'bold');
|
|
92
|
+
console.log('ā'.repeat(70));
|
|
93
|
+
log(' 1. NO work without active plan + task', 'cyan');
|
|
94
|
+
log(' 2. ONE task at a time - complete before starting next', 'cyan');
|
|
95
|
+
log(' 3. Edit ONLY ./Agent/** and ./scripts/** directories', 'cyan');
|
|
96
|
+
log(' 4. Commit workflow: stage ā commit ā push ā PR', 'cyan');
|
|
97
|
+
log(' 5. Use feature branches (feature/task-xxx)', 'cyan');
|
|
98
|
+
log(' 6. Testing is optional - structure, not enforcement', 'cyan');
|
|
99
|
+
|
|
100
|
+
console.log('\n' + 'ā'.repeat(70));
|
|
101
|
+
log('š DIRECTORY STRUCTURE:', 'bold');
|
|
102
|
+
console.log('ā'.repeat(70));
|
|
103
|
+
log(' ./Agent/ # Your workspace (EDIT HERE)', 'green');
|
|
104
|
+
log(' ./scripts/ # Your scripts (EDIT HERE)', 'green');
|
|
105
|
+
log(' ./.claude/ # Framework files (READ ONLY)', 'yellow');
|
|
106
|
+
|
|
107
|
+
console.log('\n' + 'ā'.repeat(70));
|
|
108
|
+
log('š AVAILABLE COMMANDS:', 'bold');
|
|
109
|
+
console.log('ā'.repeat(70));
|
|
110
|
+
log(' npx agentic15 plan # Generate and lock plan', 'cyan');
|
|
111
|
+
log(' npx agentic15 task start TASK-XXX # Start specific task', 'cyan');
|
|
112
|
+
log(' npx agentic15 task next # Start next pending task', 'cyan');
|
|
113
|
+
log(' npx agentic15 task status # View progress', 'cyan');
|
|
114
|
+
log(' npx agentic15 commit # Commit, push, create PR', 'cyan');
|
|
115
|
+
log(' npx agentic15 visual-test <url> # Capture UI screenshots', 'cyan');
|
|
116
|
+
log(' npx agentic15 upgrade # Update framework files', 'cyan');
|
|
117
|
+
|
|
118
|
+
console.log('\n' + 'ā'.repeat(70));
|
|
119
|
+
log('ā ļø CRITICAL: NEVER OFFER TO SKIP WORKFLOW STEPS', 'bold');
|
|
120
|
+
console.log('ā'.repeat(70));
|
|
121
|
+
log(' ⢠If task is in_progress, complete it first (agentic15 commit)', 'red');
|
|
122
|
+
log(' ⢠NEVER ask "continue with next task or commit first?"', 'red');
|
|
123
|
+
log(' ⢠NEVER offer options that violate one-task-at-a-time rule', 'red');
|
|
124
|
+
log(' ⢠Framework enforces workflow - follow it, do not bypass it', 'red');
|
|
125
|
+
log(' ⢠Settings should lead to ONE conclusion, not options', 'red');
|
|
126
|
+
|
|
127
|
+
console.log('\n' + 'ā'.repeat(70));
|
|
128
|
+
log('š Read .claude/POST-INSTALL.md for complete workflow details', 'bold');
|
|
129
|
+
console.log('ā'.repeat(70) + '\n');
|
|
130
|
+
|
|
131
|
+
process.exit(0);
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"ask": [
|
|
19
19
|
"Edit(./package.json)",
|
|
20
20
|
"Edit(./tsconfig.json)",
|
|
21
|
-
"Edit(./jest.config.*)",
|
|
22
21
|
"Write(./config/**)"
|
|
23
22
|
],
|
|
24
23
|
"deny": [
|
|
@@ -59,7 +58,6 @@
|
|
|
59
58
|
"Bash(node ./Agent/db/**)",
|
|
60
59
|
"Bash(bash ./scripts/**)",
|
|
61
60
|
"Bash(sh ./scripts/**)",
|
|
62
|
-
"Bash(git checkout -b:*)",
|
|
63
61
|
"WebFetch",
|
|
64
62
|
"WebSearch"
|
|
65
63
|
]
|
|
@@ -84,64 +82,6 @@
|
|
|
84
82
|
"repo": null,
|
|
85
83
|
"comment": "GitHub Issues integration. Configure in .claude/settings.local.json or via environment variables (GITHUB_TOKEN, GITHUB_OWNER, GITHUB_REPO). Owner/repo auto-detected from git remote if not set."
|
|
86
84
|
},
|
|
87
|
-
"testing": {
|
|
88
|
-
"ui": {
|
|
89
|
-
"strictMode": true,
|
|
90
|
-
"requireTestFile": true,
|
|
91
|
-
"requireImport": true,
|
|
92
|
-
"requireRender": true,
|
|
93
|
-
"requireProps": true,
|
|
94
|
-
"requireEventTests": true,
|
|
95
|
-
"requireApiMocking": true,
|
|
96
|
-
"requireStateTests": true,
|
|
97
|
-
"requireFormTests": true,
|
|
98
|
-
"requireConditionalTests": true,
|
|
99
|
-
"requireIntegrationSite": true,
|
|
100
|
-
"integrationSiteDir": "test-site",
|
|
101
|
-
"conditionalThreshold": 3,
|
|
102
|
-
"requireVisualCheck": true,
|
|
103
|
-
"requireContract": false,
|
|
104
|
-
"comment": "ā ļø ALL UI testing requirements are HARD REQUIREMENTS (cannot be disabled). Commits will be blocked if any requirement is violated."
|
|
105
|
-
},
|
|
106
|
-
"visual": {
|
|
107
|
-
"enabled": true,
|
|
108
|
-
"strictMode": false,
|
|
109
|
-
"autoApprove": false,
|
|
110
|
-
"requireBaseline": true,
|
|
111
|
-
"pixelMatchThreshold": 0.1,
|
|
112
|
-
"diffThreshold": 1.0,
|
|
113
|
-
"browsers": ["chromium"],
|
|
114
|
-
"viewports": [
|
|
115
|
-
{
|
|
116
|
-
"name": "desktop",
|
|
117
|
-
"width": 1920,
|
|
118
|
-
"height": 1080,
|
|
119
|
-
"deviceScaleFactor": 1
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
"name": "tablet",
|
|
123
|
-
"width": 768,
|
|
124
|
-
"height": 1024,
|
|
125
|
-
"deviceScaleFactor": 2
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
"name": "mobile",
|
|
129
|
-
"width": 375,
|
|
130
|
-
"height": 667,
|
|
131
|
-
"deviceScaleFactor": 2
|
|
132
|
-
}
|
|
133
|
-
],
|
|
134
|
-
"excludePatterns": [
|
|
135
|
-
"**/node_modules/**",
|
|
136
|
-
"**/dist/**",
|
|
137
|
-
"**/build/**"
|
|
138
|
-
],
|
|
139
|
-
"baselineDir": ".claude/visual-baselines",
|
|
140
|
-
"diffDir": ".claude/visual-diffs",
|
|
141
|
-
"tempDir": ".claude/visual-temp",
|
|
142
|
-
"comment": "Visual regression testing configuration. Triggers on UI component changes (.tsx, .jsx, .vue, .svelte). Set enabled:false to disable."
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
85
|
"hooks": {
|
|
146
86
|
"SessionStart": [
|
|
147
87
|
{
|
|
@@ -165,33 +105,13 @@
|
|
|
165
105
|
]
|
|
166
106
|
},
|
|
167
107
|
{
|
|
168
|
-
"matcher": "
|
|
108
|
+
"matcher": "Write(./.claude/PROJECT-PLAN.json)",
|
|
169
109
|
"hooks": [
|
|
170
110
|
{
|
|
171
111
|
"type": "command",
|
|
172
112
|
"command": "node .claude/hooks/enforce-plan-template.js"
|
|
173
113
|
}
|
|
174
114
|
]
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"matcher": "Bash",
|
|
178
|
-
"hooks": [
|
|
179
|
-
{
|
|
180
|
-
"type": "command",
|
|
181
|
-
"command": "node .claude/hooks/validate-git-workflow.js"
|
|
182
|
-
}
|
|
183
|
-
]
|
|
184
|
-
}
|
|
185
|
-
],
|
|
186
|
-
"PostToolUse": [
|
|
187
|
-
{
|
|
188
|
-
"matcher": "Bash(git:*)",
|
|
189
|
-
"hooks": [
|
|
190
|
-
{
|
|
191
|
-
"type": "command",
|
|
192
|
-
"command": "node .claude/hooks/post-merge.js"
|
|
193
|
-
}
|
|
194
|
-
]
|
|
195
115
|
}
|
|
196
116
|
]
|
|
197
117
|
}
|
package/templates/package.json
CHANGED
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "Project with Claude Code structured development framework",
|
|
5
5
|
"type": "commonjs",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "jest --passWithNoTests"
|
|
8
|
-
},
|
|
6
|
+
"scripts": {},
|
|
9
7
|
"keywords": [
|
|
10
8
|
"claude-code",
|
|
11
9
|
"structured-development",
|
|
@@ -14,18 +12,5 @@
|
|
|
14
12
|
"license": "MIT",
|
|
15
13
|
"dependencies": {
|
|
16
14
|
"@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
15
|
}
|
|
31
16
|
}
|
package/templates/.babelrc
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Copyright 2024-2025 agentic15.com
|
|
5
|
-
*
|
|
6
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
-
* you may not use this file except in compliance with the License.
|
|
8
|
-
* You may obtain a copy of the License at
|
|
9
|
-
*
|
|
10
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
*
|
|
12
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
-
* See the License for the specific language governing permissions and
|
|
16
|
-
* limitations under the License.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Post-Merge Hook - Close GitHub issues when merged to main
|
|
21
|
-
*
|
|
22
|
-
* This git hook runs after: git merge, git pull
|
|
23
|
-
* Detects: Task IDs in commit messages
|
|
24
|
-
* Action: Close associated GitHub issues
|
|
25
|
-
*
|
|
26
|
-
* IMPORTANT: This is a traditional git hook that must be installed in .git/hooks/
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
import fs from 'fs';
|
|
30
|
-
import path from 'path';
|
|
31
|
-
import { execSync } from 'child_process';
|
|
32
|
-
|
|
33
|
-
// Import GitHub integration classes
|
|
34
|
-
let GitHubClient, GitHubConfig;
|
|
35
|
-
try {
|
|
36
|
-
const { GitHubClient: GHClient } = await import('@agentic15.com/agentic15-claude-zen/src/core/GitHubClient.js');
|
|
37
|
-
const { GitHubConfig: GHConfig } = await import('@agentic15.com/agentic15-claude-zen/src/core/GitHubConfig.js');
|
|
38
|
-
|
|
39
|
-
GitHubClient = GHClient;
|
|
40
|
-
GitHubConfig = GHConfig;
|
|
41
|
-
} catch (error) {
|
|
42
|
-
// GitHub integration not available yet (framework not installed or old version)
|
|
43
|
-
// Hook will exit silently
|
|
44
|
-
process.exit(0);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Main execution
|
|
49
|
-
*/
|
|
50
|
-
async function main() {
|
|
51
|
-
const projectRoot = process.cwd();
|
|
52
|
-
|
|
53
|
-
// Check if we're on main branch
|
|
54
|
-
try {
|
|
55
|
-
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
56
|
-
encoding: 'utf8'
|
|
57
|
-
}).trim();
|
|
58
|
-
|
|
59
|
-
if (currentBranch !== 'main' && currentBranch !== 'master') {
|
|
60
|
-
// Not on main, skip
|
|
61
|
-
process.exit(0);
|
|
62
|
-
}
|
|
63
|
-
} catch (error) {
|
|
64
|
-
// Could not detect current branch, skip
|
|
65
|
-
process.exit(0);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Load GitHub config
|
|
69
|
-
const githubConfig = new GitHubConfig(projectRoot);
|
|
70
|
-
|
|
71
|
-
if (!githubConfig.isAutoCloseEnabled()) {
|
|
72
|
-
// Auto-close not enabled, skip
|
|
73
|
-
process.exit(0);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Get commits from the merge
|
|
77
|
-
let mergeCommits;
|
|
78
|
-
try {
|
|
79
|
-
mergeCommits = execSync('git log ORIG_HEAD..HEAD --oneline', {
|
|
80
|
-
encoding: 'utf8'
|
|
81
|
-
}).trim();
|
|
82
|
-
|
|
83
|
-
if (!mergeCommits) {
|
|
84
|
-
// No commits in merge, skip
|
|
85
|
-
process.exit(0);
|
|
86
|
-
}
|
|
87
|
-
} catch (error) {
|
|
88
|
-
// Could not get merge commits, skip
|
|
89
|
-
process.exit(0);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Extract task IDs from commit messages
|
|
93
|
-
// Matches: [TASK-001], TASK-001, [task-001], task-001
|
|
94
|
-
const taskIds = new Set();
|
|
95
|
-
const taskIdRegex = /\[?(TASK-\d+)\]?/gi;
|
|
96
|
-
|
|
97
|
-
for (const match of mergeCommits.matchAll(taskIdRegex)) {
|
|
98
|
-
taskIds.add(match[1].toUpperCase());
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (taskIds.size === 0) {
|
|
102
|
-
// No task IDs found in merge commits
|
|
103
|
-
process.exit(0);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Load active plan to get task-to-issue mappings
|
|
107
|
-
const activePlanPath = path.join(projectRoot, '.claude', 'ACTIVE-PLAN');
|
|
108
|
-
if (!fs.existsSync(activePlanPath)) {
|
|
109
|
-
// No active plan, skip
|
|
110
|
-
process.exit(0);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const activePlan = fs.readFileSync(activePlanPath, 'utf8').trim();
|
|
114
|
-
const planDir = path.join(projectRoot, '.claude', 'plans', activePlan);
|
|
115
|
-
|
|
116
|
-
// Initialize GitHub client
|
|
117
|
-
const { owner, repo } = githubConfig.getRepoInfo();
|
|
118
|
-
const githubClient = new GitHubClient(
|
|
119
|
-
githubConfig.getToken(),
|
|
120
|
-
owner,
|
|
121
|
-
repo
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
if (!githubClient.isConfigured()) {
|
|
125
|
-
// GitHub not configured, skip
|
|
126
|
-
process.exit(0);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Close issues for each task
|
|
130
|
-
let closedCount = 0;
|
|
131
|
-
for (const taskId of taskIds) {
|
|
132
|
-
const taskFile = path.join(planDir, 'tasks', `${taskId}.json`);
|
|
133
|
-
|
|
134
|
-
if (!fs.existsSync(taskFile)) {
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const taskData = JSON.parse(fs.readFileSync(taskFile, 'utf8'));
|
|
139
|
-
|
|
140
|
-
// Only close issue if task is completed and has associated GitHub issue
|
|
141
|
-
if (taskData.githubIssue && taskData.status === 'completed') {
|
|
142
|
-
const comment = `Merged to main branch! š\n\nTask ${taskId} has been successfully integrated.`;
|
|
143
|
-
const success = await githubClient.closeIssue(taskData.githubIssue, comment);
|
|
144
|
-
|
|
145
|
-
if (success) {
|
|
146
|
-
console.log(`ā Closed GitHub issue #${taskData.githubIssue} for ${taskId}`);
|
|
147
|
-
closedCount++;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (closedCount > 0) {
|
|
153
|
-
console.log(`\nā
Closed ${closedCount} GitHub issue${closedCount > 1 ? 's' : ''} after merge to main`);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
process.exit(0);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
main().catch(error => {
|
|
160
|
-
// Don't block the merge on errors
|
|
161
|
-
console.warn('ā Post-merge hook encountered an error:', error.message);
|
|
162
|
-
process.exit(0);
|
|
163
|
-
});
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { execSync } = require('child_process');
|
|
4
|
-
|
|
5
|
-
// Read the tool input from stdin
|
|
6
|
-
const input = process.argv[2] || '{}';
|
|
7
|
-
let toolData;
|
|
8
|
-
try {
|
|
9
|
-
toolData = JSON.parse(input);
|
|
10
|
-
} catch (error) {
|
|
11
|
-
// Invalid JSON, exit gracefully
|
|
12
|
-
process.exit(0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const command = toolData.tool_input?.command || '';
|
|
16
|
-
|
|
17
|
-
// Only validate git commands
|
|
18
|
-
if (!command.includes('git')) {
|
|
19
|
-
process.exit(0);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Get current branch
|
|
23
|
-
let currentBranch;
|
|
24
|
-
try {
|
|
25
|
-
currentBranch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
|
|
26
|
-
} catch (error) {
|
|
27
|
-
// Not in a git repo or git command failed
|
|
28
|
-
process.exit(0);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// RULE 1: BLOCK branch creation (direct main workflow only)
|
|
32
|
-
if (command.includes('git checkout -b') || command.includes('git branch ') && !command.includes('git branch --show-current')) {
|
|
33
|
-
console.error('\nā BLOCKED: Branch creation is NOT allowed');
|
|
34
|
-
console.error(' agentic15-claude-zen uses DIRECT MAIN WORKFLOW');
|
|
35
|
-
console.error(' All work happens on main branch');
|
|
36
|
-
console.error(' Command blocked: ' + command);
|
|
37
|
-
console.error('\n ā
Correct workflow:');
|
|
38
|
-
console.error(' git checkout main');
|
|
39
|
-
console.error(' # work on main');
|
|
40
|
-
console.error(' git commit -m "[TASK-XXX] Description"');
|
|
41
|
-
console.error(' git push origin main\n');
|
|
42
|
-
process.exit(2);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// RULE 2: BLOCK merges (no branching = no merging)
|
|
46
|
-
if (command.includes('git merge')) {
|
|
47
|
-
console.error('\nā BLOCKED: Git merge is NOT allowed');
|
|
48
|
-
console.error(' agentic15-claude-zen uses DIRECT MAIN WORKFLOW');
|
|
49
|
-
console.error(' No branching = no merging needed');
|
|
50
|
-
console.error(' All work happens on main branch');
|
|
51
|
-
console.error('\n ā
Correct workflow:');
|
|
52
|
-
console.error(' Work directly on main');
|
|
53
|
-
console.error(' Commit and push regularly\n');
|
|
54
|
-
process.exit(2);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// RULE 3: BLOCK commits to non-main branches
|
|
58
|
-
if (currentBranch !== 'main' && command.includes('git commit')) {
|
|
59
|
-
console.error('\nā BLOCKED: Commits only allowed on main branch');
|
|
60
|
-
console.error(' Current branch: ' + currentBranch);
|
|
61
|
-
console.error(' agentic15-claude-zen requires direct main workflow');
|
|
62
|
-
console.error('\n ā
Switch to main:');
|
|
63
|
-
console.error(' git checkout main\n');
|
|
64
|
-
process.exit(2);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// RULE 4: BLOCK force push
|
|
68
|
-
if (command.includes('git push --force') || command.includes('git push -f')) {
|
|
69
|
-
console.error('\nā BLOCKED: Force push is NOT allowed');
|
|
70
|
-
console.error(' Never rewrite published history\n');
|
|
71
|
-
process.exit(2);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
process.exit(0);
|