@itz4blitz/agentful 1.7.0 → 1.8.1
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 +10 -0
- package/bin/cli.js +7 -0
- package/bin/hooks/block-file-creation.js +7 -1
- package/bin/hooks/ensure-worktree.js +234 -0
- package/bin/hooks/worktree-service.js +514 -0
- package/package.json +2 -1
- package/template/.claude/agents/backend.md +20 -1
- package/template/.claude/agents/fixer.md +1 -1
- package/template/.claude/agents/frontend.md +20 -1
- package/template/.claude/agents/orchestrator.md +227 -2
- package/template/.claude/agents/reviewer.md +37 -7
- package/template/.claude/agents/tester.md +1 -1
- package/template/.claude/commands/agentful-worktree.md +106 -0
- package/template/.claude/settings.json +13 -1
- package/template/CLAUDE.md +46 -0
- package/version.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,16 @@ claude
|
|
|
49
49
|
/agentful-start
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Pattern Learning
|
|
53
|
+
|
|
54
|
+
Enable agents to learn from every session and reuse successful patterns:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
claude mcp add agentful -- npx -y @itz4blitz/agentful-mcp-server
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The reviewer stores error patterns, the fixer looks up known fixes, and the orchestrator stores successful implementation patterns - compounding knowledge across sessions.
|
|
61
|
+
|
|
52
62
|
## Installation Options
|
|
53
63
|
|
|
54
64
|
```bash
|
package/bin/cli.js
CHANGED
|
@@ -411,6 +411,13 @@ async function init(args) {
|
|
|
411
411
|
}
|
|
412
412
|
log(colors.dim, 'Optional: Edit CLAUDE.md and .claude/product/index.md first to customize.');
|
|
413
413
|
console.log('');
|
|
414
|
+
log(colors.bright, 'Recommended: Enable Pattern Learning');
|
|
415
|
+
console.log('');
|
|
416
|
+
log(colors.dim, ' Agents get smarter when they can store and reuse patterns.');
|
|
417
|
+
log(colors.dim, ' Run this once to enable:');
|
|
418
|
+
console.log('');
|
|
419
|
+
log(colors.cyan, ' claude mcp add agentful -- npx -y @itz4blitz/agentful-mcp-server');
|
|
420
|
+
console.log('');
|
|
414
421
|
}
|
|
415
422
|
|
|
416
423
|
function showStatus() {
|
|
@@ -176,7 +176,10 @@ if (isInAllowedDir) {
|
|
|
176
176
|
'.agentful/conversation-state.json',
|
|
177
177
|
'.agentful/conversation-history.json',
|
|
178
178
|
'.agentful/agent-metrics.json',
|
|
179
|
-
'.agentful/metadata.json'
|
|
179
|
+
'.agentful/metadata.json',
|
|
180
|
+
'.agentful/learnings.json',
|
|
181
|
+
'.agentful/last-validation.json',
|
|
182
|
+
'.agentful/product-analysis.json'
|
|
180
183
|
];
|
|
181
184
|
|
|
182
185
|
if (agentfulFiles.includes(normalizedPath)) {
|
|
@@ -198,6 +201,9 @@ Allowed .agentful/ files:
|
|
|
198
201
|
- conversation-history.json (message history)
|
|
199
202
|
- agent-metrics.json (agent lifecycle hooks)
|
|
200
203
|
- metadata.json (version tracking)
|
|
204
|
+
- learnings.json (compound engineering retrospectives)
|
|
205
|
+
- last-validation.json (latest validation report)
|
|
206
|
+
- product-analysis.json (product spec analysis)
|
|
201
207
|
|
|
202
208
|
Do NOT create random state snapshots or debug files in .agentful/.
|
|
203
209
|
`);
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ensure Worktree Hook
|
|
5
|
+
*
|
|
6
|
+
* PreToolUse hook that enforces git worktree usage for file modifications.
|
|
7
|
+
*
|
|
8
|
+
* Modes:
|
|
9
|
+
* off - Allow all edits (backward compatible)
|
|
10
|
+
* block - Require existing worktree, reject if not in one
|
|
11
|
+
* auto - Create worktree automatically if not in one
|
|
12
|
+
*
|
|
13
|
+
* Environment Variables:
|
|
14
|
+
* AGENTFUL_WORKTREE_MODE - off|block|auto (default: auto)
|
|
15
|
+
* AGENTFUL_WORKTREE_DIR - Where to create worktrees (default: ../)
|
|
16
|
+
* AGENTFUL_WORKTREE_AUTO_CLEANUP - Auto-remove after completion (default: true)
|
|
17
|
+
* AGENTFUL_WORKTREE_RETENTION_DAYS - Days before cleanup (default: 7)
|
|
18
|
+
* AGENTFUL_WORKTREE_MAX_ACTIVE - Max active worktrees (default: 5)
|
|
19
|
+
*
|
|
20
|
+
* To disable this hook:
|
|
21
|
+
* Temporary: export AGENTFUL_WORKTREE_MODE=off
|
|
22
|
+
* Permanent: Remove from .claude/settings.json PreToolUse hooks
|
|
23
|
+
* Customize: Edit bin/hooks/ensure-worktree.js
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import fs from 'fs';
|
|
27
|
+
import path from 'path';
|
|
28
|
+
import { execSync } from 'child_process';
|
|
29
|
+
import { fileURLToPath } from 'url';
|
|
30
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
31
|
+
|
|
32
|
+
// Get configuration
|
|
33
|
+
const MODE = process.env.AGENTFUL_WORKTREE_MODE || 'auto';
|
|
34
|
+
const WORKTREE_DIR = process.env.AGENTFUL_WORKTREE_DIR || '../';
|
|
35
|
+
const AUTO_CLEANUP = process.env.AGENTFUL_WORKTREE_AUTO_CLEANUP !== 'false';
|
|
36
|
+
const RETENTION_DAYS = parseInt(process.env.AGENTFUL_WORKTREE_RETENTION_DAYS || '7', 10);
|
|
37
|
+
const MAX_ACTIVE = parseInt(process.env.AGENTFUL_WORKTREE_MAX_ACTIVE || '5', 10);
|
|
38
|
+
const AGENT_TYPE = process.env.AGENTFUL_AGENT_TYPE || 'general';
|
|
39
|
+
const TASK_TYPE = process.env.AGENTFUL_TASK_TYPE || 'general';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Detect if currently in a git worktree
|
|
43
|
+
*/
|
|
44
|
+
function isInWorktree() {
|
|
45
|
+
try {
|
|
46
|
+
const cwd = process.cwd();
|
|
47
|
+
const gitFile = path.join(cwd, '.git');
|
|
48
|
+
|
|
49
|
+
// If .git is a file (not a directory), we're in a worktree
|
|
50
|
+
if (existsSync(gitFile) && statSync(gitFile).isFile()) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Determine worktree purpose from agent/task context
|
|
60
|
+
*/
|
|
61
|
+
function determinePurpose() {
|
|
62
|
+
// Agent-based purposes
|
|
63
|
+
const agentPurposes = {
|
|
64
|
+
'fixer': 'fix',
|
|
65
|
+
'reviewer': 'review',
|
|
66
|
+
'tester': 'test',
|
|
67
|
+
'backend': 'backend',
|
|
68
|
+
'frontend': 'frontend',
|
|
69
|
+
'architect': 'architect',
|
|
70
|
+
'orchestrator': 'orchestrator',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Task-based purposes
|
|
74
|
+
const taskPurposes = {
|
|
75
|
+
'feature': 'feature',
|
|
76
|
+
'hotfix': 'hotfix',
|
|
77
|
+
'bugfix': 'bugfix',
|
|
78
|
+
'experiment': 'experiment',
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Determine purpose based on agent type, then task type
|
|
82
|
+
if (agentPurposes[AGENT_TYPE]) {
|
|
83
|
+
return agentPurposes[AGENT_TYPE];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (taskPurposes[TASK_TYPE]) {
|
|
87
|
+
return taskPurposes[TASK_TYPE];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Default to general
|
|
91
|
+
return 'general';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Show block message with helpful error
|
|
96
|
+
*/
|
|
97
|
+
function showBlockMessage() {
|
|
98
|
+
const branch = getCurrentBranch();
|
|
99
|
+
|
|
100
|
+
console.error(`
|
|
101
|
+
:::error
|
|
102
|
+
═════════════════════════════════════════════════
|
|
103
|
+
🚫 Blocked: Direct Repository Edits
|
|
104
|
+
═════════════════════════════════════════════════
|
|
105
|
+
|
|
106
|
+
You are attempting to edit files in the root repository, but AGENTFUL_WORKTREE_MODE
|
|
107
|
+
is set to "block" which requires working in a git worktree.
|
|
108
|
+
|
|
109
|
+
Current branch: ${branch}
|
|
110
|
+
Current directory: ${process.cwd()}
|
|
111
|
+
|
|
112
|
+
To proceed, choose one option:
|
|
113
|
+
|
|
114
|
+
1. 🌳 Create a worktree (recommended):
|
|
115
|
+
git worktree add ../my-worktree -b ${branch}
|
|
116
|
+
cd ../my-worktree
|
|
117
|
+
|
|
118
|
+
2. ⚙️ Change mode to auto (creates worktrees automatically):
|
|
119
|
+
export AGENTFUL_WORKTREE_MODE=auto
|
|
120
|
+
|
|
121
|
+
3. 🚫 Disable worktree protection (not recommended):
|
|
122
|
+
export AGENTFUL_WORKTREE_MODE=off
|
|
123
|
+
|
|
124
|
+
For more information, see: /agentful-worktree or docs/pages/concepts/git-worktrees.mdx
|
|
125
|
+
:::`);
|
|
126
|
+
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Create worktree automatically
|
|
132
|
+
*/
|
|
133
|
+
function createWorktree() {
|
|
134
|
+
const repoRoot = findRepoRoot();
|
|
135
|
+
if (!repoRoot) {
|
|
136
|
+
console.error(':::error Not in a git repository:::');
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const purpose = determinePurpose();
|
|
141
|
+
const branch = getCurrentBranch();
|
|
142
|
+
const timestamp = Date.now();
|
|
143
|
+
|
|
144
|
+
// Generate worktree name
|
|
145
|
+
const worktreeName = `agentful-${purpose}-${sanitizeBranchName(branch)}-${timestamp}`;
|
|
146
|
+
|
|
147
|
+
// Create worktree
|
|
148
|
+
const worktreePath = path.join(repoRoot, WORKTREE_DIR, worktreeName);
|
|
149
|
+
|
|
150
|
+
console.log(`🌳 Creating worktree: ${worktreeName}`);
|
|
151
|
+
console.log(` Branch: ${branch}`);
|
|
152
|
+
console.log(` Path: ${worktreePath}`);
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
execSync(
|
|
156
|
+
`git worktree add "${worktreePath}" -b "${branch}"`,
|
|
157
|
+
{ cwd: repoRoot, stdio: 'inherit' }
|
|
158
|
+
);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error(`:::error Failed to create worktree: ${error.message}:::`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Track in state.json (would happen in orchestrator, but this is standalone)
|
|
165
|
+
try {
|
|
166
|
+
const stateFile = path.join(repoRoot, '.agentful', 'state.json');
|
|
167
|
+
if (existsSync(stateFile)) {
|
|
168
|
+
const state = JSON.parse(readFileSync(stateFile, 'utf8'));
|
|
169
|
+
state.current_worktree = {
|
|
170
|
+
name: worktreeName,
|
|
171
|
+
path: worktreePath,
|
|
172
|
+
branch: branch,
|
|
173
|
+
purpose: purpose,
|
|
174
|
+
created_at: new Date().toISOString(),
|
|
175
|
+
};
|
|
176
|
+
writeFileSync(stateFile, JSON.stringify(state, null, 2));
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
// State file might not exist yet, that's okay
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Export for caller to capture
|
|
183
|
+
console.log(`export AGENTFUL_WORKTREE_DIR="${worktreePath}"`);
|
|
184
|
+
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Main execution
|
|
190
|
+
*/
|
|
191
|
+
(() => {
|
|
192
|
+
// Get tool and file from environment
|
|
193
|
+
const tool = process.env.TOOL || '';
|
|
194
|
+
const file = process.env.FILE || '';
|
|
195
|
+
|
|
196
|
+
// Only check Write and Edit tools
|
|
197
|
+
if (tool !== 'Write' && tool !== 'Edit') {
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Auto-disable in CI environments
|
|
202
|
+
if (isCIEnvironment()) {
|
|
203
|
+
process.exit(0);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Check if already in worktree (explicitly set or detected)
|
|
207
|
+
if (WORKTREE_DIR) {
|
|
208
|
+
// In worktree - allow operation
|
|
209
|
+
process.exit(0);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Not in worktree - handle based on mode
|
|
213
|
+
switch (MODE) {
|
|
214
|
+
case 'off':
|
|
215
|
+
// Allow all edits silently
|
|
216
|
+
process.exit(0);
|
|
217
|
+
break;
|
|
218
|
+
|
|
219
|
+
case 'block':
|
|
220
|
+
// Require existing worktree
|
|
221
|
+
showBlockMessage();
|
|
222
|
+
break;
|
|
223
|
+
|
|
224
|
+
case 'auto':
|
|
225
|
+
// Create worktree automatically
|
|
226
|
+
createWorktree();
|
|
227
|
+
break;
|
|
228
|
+
|
|
229
|
+
default:
|
|
230
|
+
console.error(`:::warning Invalid AGENTFUL_WORKTREE_MODE: ${MODE}:::`);
|
|
231
|
+
console.error(`:::warning Valid options: off, block, auto:::`);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
})();
|