@itz4blitz/agentful 1.3.0 → 1.4.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 +20 -68
- package/bin/cli.js +30 -1
- package/bin/hooks/architect-drift-detector.js +242 -0
- package/bin/hooks/context-awareness.js +369 -0
- package/bin/hooks/post-action-suggestions.js +75 -0
- package/bin/hooks/session-start.js +93 -0
- package/lib/context-awareness.js +369 -0
- package/lib/index.js +17 -3
- package/lib/init.js +97 -3
- package/lib/parallel-execution.js +26 -2
- package/lib/presets.js +55 -1
- package/lib/state-validator.README.md +442 -0
- package/lib/state-validator.example.js +262 -0
- package/lib/state-validator.js +562 -0
- package/package.json +1 -1
- package/template/.claude/commands/agentful-analyze.md +47 -59
- package/template/.claude/commands/agentful-decide.md +73 -95
- package/template/.claude/commands/agentful-product.md +26 -37
- package/template/.claude/commands/agentful-start.md +36 -121
- package/template/.claude/commands/agentful-status.md +51 -68
- package/template/.claude/commands/agentful-validate.md +29 -69
- package/template/.claude/commands/agentful.md +1 -1
- package/template/.claude/settings.json +17 -0
- package/template/CLAUDE.md +222 -28
- package/template/bin/hooks/analyze-trigger.js +69 -0
- package/template/bin/hooks/architect-drift-detector.js +0 -0
- package/template/bin/hooks/block-file-creation.js +271 -0
- package/template/bin/hooks/health-check.js +153 -0
- package/version.json +1 -1
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context Awareness Module
|
|
5
|
+
*
|
|
6
|
+
* Analyzes project state and provides intelligent suggestions for next actions.
|
|
7
|
+
* Used by session-start and post-action hooks.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Read JSON file safely
|
|
19
|
+
*/
|
|
20
|
+
function readJSON(filePath) {
|
|
21
|
+
try {
|
|
22
|
+
if (!fs.existsSync(filePath)) return null;
|
|
23
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
24
|
+
return JSON.parse(content);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if file exists
|
|
32
|
+
*/
|
|
33
|
+
function fileExists(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
return fs.existsSync(filePath);
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Analyze project state and return context
|
|
43
|
+
*/
|
|
44
|
+
export function analyzeProjectState(projectRoot = process.cwd()) {
|
|
45
|
+
const state = {
|
|
46
|
+
hasProductSpec: false,
|
|
47
|
+
hasArchitecture: false,
|
|
48
|
+
hasState: false,
|
|
49
|
+
hasCompletion: false,
|
|
50
|
+
hasPendingDecisions: false,
|
|
51
|
+
architectureValid: true,
|
|
52
|
+
architectureIssues: [],
|
|
53
|
+
currentPhase: 'idle',
|
|
54
|
+
completionPercent: 0,
|
|
55
|
+
totalFeatures: 0,
|
|
56
|
+
completedFeatures: 0,
|
|
57
|
+
pendingDecisionCount: 0,
|
|
58
|
+
blockingIssues: [],
|
|
59
|
+
suggestedActions: []
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Check product spec
|
|
63
|
+
const productIndex = path.join(projectRoot, '.claude/product/index.md');
|
|
64
|
+
const productDomains = path.join(projectRoot, '.claude/product/domains');
|
|
65
|
+
state.hasProductSpec = fileExists(productIndex) || fileExists(productDomains);
|
|
66
|
+
|
|
67
|
+
// Check architecture
|
|
68
|
+
const architecturePath = path.join(projectRoot, '.agentful/architecture.json');
|
|
69
|
+
if (fileExists(architecturePath)) {
|
|
70
|
+
state.hasArchitecture = true;
|
|
71
|
+
const arch = readJSON(architecturePath);
|
|
72
|
+
|
|
73
|
+
if (arch) {
|
|
74
|
+
// Validate architecture structure
|
|
75
|
+
if (!arch.techStack || !arch.agents) {
|
|
76
|
+
state.architectureValid = false;
|
|
77
|
+
state.architectureIssues.push('Missing techStack or agents fields');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check if architecture is stale (older than package.json)
|
|
81
|
+
try {
|
|
82
|
+
const packagePath = path.join(projectRoot, 'package.json');
|
|
83
|
+
if (fileExists(packagePath)) {
|
|
84
|
+
const archStat = fs.statSync(architecturePath);
|
|
85
|
+
const pkgStat = fs.statSync(packagePath);
|
|
86
|
+
|
|
87
|
+
if (pkgStat.mtime > archStat.mtime) {
|
|
88
|
+
state.architectureValid = false;
|
|
89
|
+
state.architectureIssues.push('Architecture older than package.json - may need regeneration');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
// Ignore stat errors
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
state.architectureValid = false;
|
|
97
|
+
state.architectureIssues.push('Invalid JSON format');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check state
|
|
102
|
+
const statePath = path.join(projectRoot, '.agentful/state.json');
|
|
103
|
+
if (fileExists(statePath)) {
|
|
104
|
+
state.hasState = true;
|
|
105
|
+
const stateData = readJSON(statePath);
|
|
106
|
+
if (stateData) {
|
|
107
|
+
state.currentPhase = stateData.current_phase || 'idle';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Check completion
|
|
112
|
+
const completionPath = path.join(projectRoot, '.agentful/completion.json');
|
|
113
|
+
if (fileExists(completionPath)) {
|
|
114
|
+
state.hasCompletion = true;
|
|
115
|
+
const completion = readJSON(completionPath);
|
|
116
|
+
|
|
117
|
+
if (completion && completion.features) {
|
|
118
|
+
const features = Object.values(completion.features);
|
|
119
|
+
state.totalFeatures = features.length;
|
|
120
|
+
state.completedFeatures = features.filter(f => f.completion >= 100).length;
|
|
121
|
+
|
|
122
|
+
if (state.totalFeatures > 0) {
|
|
123
|
+
state.completionPercent = Math.round((state.completedFeatures / state.totalFeatures) * 100);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check decisions
|
|
129
|
+
const decisionsPath = path.join(projectRoot, '.agentful/decisions.json');
|
|
130
|
+
if (fileExists(decisionsPath)) {
|
|
131
|
+
const decisions = readJSON(decisionsPath);
|
|
132
|
+
|
|
133
|
+
if (decisions && decisions.pending) {
|
|
134
|
+
state.pendingDecisionCount = decisions.pending.length;
|
|
135
|
+
state.hasPendingDecisions = state.pendingDecisionCount > 0;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Determine blocking issues
|
|
140
|
+
if (!state.hasProductSpec) {
|
|
141
|
+
state.blockingIssues.push('No product specification found');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (state.hasArchitecture && !state.architectureValid) {
|
|
145
|
+
state.blockingIssues.push('Architecture needs attention');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (state.hasPendingDecisions) {
|
|
149
|
+
state.blockingIssues.push(`${state.pendingDecisionCount} pending decision(s)`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Generate suggested actions
|
|
153
|
+
state.suggestedActions = generateSuggestions(state);
|
|
154
|
+
|
|
155
|
+
return state;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Generate smart suggestions based on project state
|
|
160
|
+
*/
|
|
161
|
+
function generateSuggestions(state) {
|
|
162
|
+
const suggestions = [];
|
|
163
|
+
|
|
164
|
+
// First-time setup
|
|
165
|
+
if (!state.hasProductSpec) {
|
|
166
|
+
suggestions.push({
|
|
167
|
+
priority: 'critical',
|
|
168
|
+
action: 'Create product specification',
|
|
169
|
+
command: 'Edit .claude/product/index.md',
|
|
170
|
+
description: 'Define your product requirements'
|
|
171
|
+
});
|
|
172
|
+
return suggestions; // Block other suggestions until product spec exists
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!state.hasArchitecture) {
|
|
176
|
+
suggestions.push({
|
|
177
|
+
priority: 'critical',
|
|
178
|
+
action: 'Generate architecture',
|
|
179
|
+
command: '/agentful-generate',
|
|
180
|
+
description: 'Analyze tech stack and create specialized agents'
|
|
181
|
+
});
|
|
182
|
+
return suggestions;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Architecture issues
|
|
186
|
+
if (state.hasArchitecture && !state.architectureValid) {
|
|
187
|
+
suggestions.push({
|
|
188
|
+
priority: 'high',
|
|
189
|
+
action: 'Fix architecture',
|
|
190
|
+
command: '/agentful-generate',
|
|
191
|
+
description: state.architectureIssues.join('; ')
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Pending decisions block work
|
|
196
|
+
if (state.hasPendingDecisions) {
|
|
197
|
+
suggestions.push({
|
|
198
|
+
priority: 'high',
|
|
199
|
+
action: 'Answer pending decisions',
|
|
200
|
+
command: '/agentful-decide',
|
|
201
|
+
description: `${state.pendingDecisionCount} decision(s) blocking progress`
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Phase-specific suggestions
|
|
206
|
+
if (state.currentPhase === 'idle' || state.currentPhase === 'planning') {
|
|
207
|
+
suggestions.push({
|
|
208
|
+
priority: 'medium',
|
|
209
|
+
action: 'Start development',
|
|
210
|
+
command: '/agentful-start',
|
|
211
|
+
description: 'Begin or resume structured development'
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (state.currentPhase === 'implementation' || state.currentPhase === 'testing') {
|
|
216
|
+
suggestions.push({
|
|
217
|
+
priority: 'medium',
|
|
218
|
+
action: 'Check progress',
|
|
219
|
+
command: '/agentful-status',
|
|
220
|
+
description: `Current: ${state.completionPercent}% complete (${state.completedFeatures}/${state.totalFeatures} features)`
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Validation suggestion
|
|
225
|
+
if (state.hasCompletion && state.completionPercent > 0) {
|
|
226
|
+
suggestions.push({
|
|
227
|
+
priority: 'low',
|
|
228
|
+
action: 'Run quality checks',
|
|
229
|
+
command: '/agentful-validate',
|
|
230
|
+
description: 'Verify code quality and production readiness'
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Product analysis
|
|
235
|
+
suggestions.push({
|
|
236
|
+
priority: 'low',
|
|
237
|
+
action: 'Analyze product spec',
|
|
238
|
+
command: '/agentful-product',
|
|
239
|
+
description: 'Check for gaps and ambiguities'
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return suggestions;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Format suggestions for display
|
|
247
|
+
*/
|
|
248
|
+
export function formatSuggestions(suggestions, options = {}) {
|
|
249
|
+
const { maxSuggestions = 5, includeNumbers = true } = options;
|
|
250
|
+
|
|
251
|
+
if (suggestions.length === 0) {
|
|
252
|
+
return '💡 All set! Type a command or ask what you need.';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Sort by priority
|
|
256
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
257
|
+
const sorted = suggestions.sort((a, b) => {
|
|
258
|
+
return priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Take top N
|
|
262
|
+
const topSuggestions = sorted.slice(0, maxSuggestions);
|
|
263
|
+
|
|
264
|
+
// Format output
|
|
265
|
+
let output = '💡 Suggested next steps:\n';
|
|
266
|
+
|
|
267
|
+
topSuggestions.forEach((suggestion, index) => {
|
|
268
|
+
const number = includeNumbers ? `${index + 1}. ` : ' • ';
|
|
269
|
+
const icon = suggestion.priority === 'critical' ? '🔴' :
|
|
270
|
+
suggestion.priority === 'high' ? '⚠️ ' : '';
|
|
271
|
+
|
|
272
|
+
output += ` ${number}${icon}${suggestion.action} → ${suggestion.command}\n`;
|
|
273
|
+
if (suggestion.description) {
|
|
274
|
+
output += ` ${suggestion.description}\n`;
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
return output.trim();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Generate session start message
|
|
283
|
+
*/
|
|
284
|
+
export function generateSessionStartMessage(projectRoot = process.cwd()) {
|
|
285
|
+
const state = analyzeProjectState(projectRoot);
|
|
286
|
+
let message = '';
|
|
287
|
+
|
|
288
|
+
// Status line
|
|
289
|
+
if (state.hasCompletion && state.totalFeatures > 0) {
|
|
290
|
+
message += `📊 Project Status: ${state.completionPercent}% complete (${state.completedFeatures}/${state.totalFeatures} features)\n`;
|
|
291
|
+
} else if (state.hasArchitecture) {
|
|
292
|
+
message += '📊 Project Status: Architecture ready, no active development\n';
|
|
293
|
+
} else {
|
|
294
|
+
message += '📊 Project Status: Initial setup\n';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Blocking issues
|
|
298
|
+
if (state.blockingIssues.length > 0) {
|
|
299
|
+
state.blockingIssues.forEach(issue => {
|
|
300
|
+
message += `⚠️ ${issue}\n`;
|
|
301
|
+
});
|
|
302
|
+
message += '\n';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Current phase
|
|
306
|
+
if (state.currentPhase !== 'idle') {
|
|
307
|
+
message += `🔄 Current Phase: ${state.currentPhase}\n\n`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Suggestions
|
|
311
|
+
message += formatSuggestions(state.suggestedActions, { maxSuggestions: 3 });
|
|
312
|
+
|
|
313
|
+
return message;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Generate post-action suggestions
|
|
318
|
+
*/
|
|
319
|
+
export function generatePostActionSuggestions(action, projectRoot = process.cwd()) {
|
|
320
|
+
const state = analyzeProjectState(projectRoot);
|
|
321
|
+
|
|
322
|
+
// Action-specific follow-ups
|
|
323
|
+
const actionMap = {
|
|
324
|
+
'agentful-generate': () => {
|
|
325
|
+
if (state.completionPercent === 0) {
|
|
326
|
+
return [{
|
|
327
|
+
priority: 'high',
|
|
328
|
+
action: 'Start development',
|
|
329
|
+
command: '/agentful-start',
|
|
330
|
+
description: 'Begin building features'
|
|
331
|
+
}];
|
|
332
|
+
}
|
|
333
|
+
return [];
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
'agentful-start': () => [{
|
|
337
|
+
priority: 'medium',
|
|
338
|
+
action: 'Monitor progress',
|
|
339
|
+
command: '/agentful-status',
|
|
340
|
+
description: 'Check completion and active work'
|
|
341
|
+
}],
|
|
342
|
+
|
|
343
|
+
'agentful-decide': () => {
|
|
344
|
+
if (state.pendingDecisionCount === 0) {
|
|
345
|
+
return [{
|
|
346
|
+
priority: 'high',
|
|
347
|
+
action: 'Resume development',
|
|
348
|
+
command: '/agentful-start',
|
|
349
|
+
description: 'Continue with unblocked work'
|
|
350
|
+
}];
|
|
351
|
+
}
|
|
352
|
+
return [];
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
'agentful-validate': () => [{
|
|
356
|
+
priority: 'medium',
|
|
357
|
+
action: 'Fix validation issues',
|
|
358
|
+
command: 'Review output and address failures',
|
|
359
|
+
description: 'Fixer agent can auto-resolve some issues'
|
|
360
|
+
}]
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const specificSuggestions = actionMap[action]?.() || [];
|
|
364
|
+
const generalSuggestions = state.suggestedActions.filter(s =>
|
|
365
|
+
s.command !== `/${action}`
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
return [...specificSuggestions, ...generalSuggestions];
|
|
369
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-Action Suggestions Hook
|
|
5
|
+
*
|
|
6
|
+
* Runs after specific slash commands complete.
|
|
7
|
+
* Provides smart suggestions for what to do next.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
|
|
17
|
+
// Try to import context-awareness module
|
|
18
|
+
let contextModule = null;
|
|
19
|
+
try {
|
|
20
|
+
const modulePath = path.join(__dirname, './context-awareness.js');
|
|
21
|
+
if (fs.existsSync(modulePath)) {
|
|
22
|
+
contextModule = await import(modulePath);
|
|
23
|
+
}
|
|
24
|
+
} catch (error) {
|
|
25
|
+
// Silently fail
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Detect which action was just completed
|
|
29
|
+
const lastAction = process.env.LAST_COMMAND || '';
|
|
30
|
+
|
|
31
|
+
// Map of slash commands to action names
|
|
32
|
+
const actionMap = {
|
|
33
|
+
'agentful-generate': 'agentful-generate',
|
|
34
|
+
'agentful-start': 'agentful-start',
|
|
35
|
+
'agentful-decide': 'agentful-decide',
|
|
36
|
+
'agentful-validate': 'agentful-validate',
|
|
37
|
+
'agentful-status': 'agentful-status',
|
|
38
|
+
'agentful-product': 'agentful-product'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Find matching action
|
|
42
|
+
let detectedAction = null;
|
|
43
|
+
for (const [cmd, action] of Object.entries(actionMap)) {
|
|
44
|
+
if (lastAction.includes(cmd)) {
|
|
45
|
+
detectedAction = action;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Show suggestions if we have context module and detected action
|
|
51
|
+
if (contextModule && contextModule.generatePostActionSuggestions && detectedAction) {
|
|
52
|
+
try {
|
|
53
|
+
const suggestions = contextModule.generatePostActionSuggestions(
|
|
54
|
+
detectedAction,
|
|
55
|
+
process.cwd()
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (suggestions.length > 0) {
|
|
59
|
+
const formatted = contextModule.formatSuggestions(suggestions, {
|
|
60
|
+
maxSuggestions: 3,
|
|
61
|
+
includeNumbers: true
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log('');
|
|
65
|
+
console.log('─'.repeat(60));
|
|
66
|
+
console.log(formatted);
|
|
67
|
+
console.log('─'.repeat(60));
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
// Silently fail - don't disrupt user experience
|
|
71
|
+
if (process.env.VERBOSE) {
|
|
72
|
+
console.log(`Post-action suggestion error: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Session Start Hook
|
|
5
|
+
*
|
|
6
|
+
* Runs when Claude Code session starts.
|
|
7
|
+
* Provides intelligent context awareness and suggests next actions.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { execSync } from 'child_process';
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
17
|
+
|
|
18
|
+
// Try to import context-awareness module from agentful package
|
|
19
|
+
let contextModule = null;
|
|
20
|
+
try {
|
|
21
|
+
// Import from same directory (bin/hooks/)
|
|
22
|
+
const modulePath = path.join(__dirname, './context-awareness.js');
|
|
23
|
+
if (fs.existsSync(modulePath)) {
|
|
24
|
+
contextModule = await import(modulePath);
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Silently fail - we'll show basic status instead
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Detect if TeammateTool (parallel execution) is enabled
|
|
32
|
+
*/
|
|
33
|
+
function detectParallelExecution() {
|
|
34
|
+
try {
|
|
35
|
+
// Find Claude Code binary
|
|
36
|
+
const npmRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
|
|
37
|
+
const cliPath = path.join(npmRoot, '@anthropic-ai', 'claude-code', 'cli.js');
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(cliPath)) {
|
|
40
|
+
return { enabled: false, reason: 'Claude Code binary not found' };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Check for TeammateTool pattern
|
|
44
|
+
const content = fs.readFileSync(cliPath, 'utf8');
|
|
45
|
+
const hasTeammateTool = /TeammateTool|teammate_mailbox|launchSwarm/.test(content);
|
|
46
|
+
|
|
47
|
+
if (!hasTeammateTool) {
|
|
48
|
+
return { enabled: false, reason: 'Claude Code version too old' };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check if gate is disabled (means it's patched/enabled)
|
|
52
|
+
const SWARM_GATE_MARKER = /tengu_brass_pebble/;
|
|
53
|
+
const gateExists = SWARM_GATE_MARKER.test(content);
|
|
54
|
+
|
|
55
|
+
if (!gateExists) {
|
|
56
|
+
return { enabled: true, method: 'patched' };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { enabled: false, reason: 'TeammateTool not enabled' };
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return { enabled: false, reason: error.message };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Main execution
|
|
66
|
+
const detection = detectParallelExecution();
|
|
67
|
+
|
|
68
|
+
// Basic parallel execution status
|
|
69
|
+
const parallelStatus = detection.enabled
|
|
70
|
+
? '✅ Agentful ready (parallel execution: ON)'
|
|
71
|
+
: '⚠️ Agentful ready (parallel execution: OFF - agents will run sequentially)';
|
|
72
|
+
|
|
73
|
+
// Try to show intelligent context awareness
|
|
74
|
+
if (contextModule && contextModule.generateSessionStartMessage) {
|
|
75
|
+
try {
|
|
76
|
+
const message = contextModule.generateSessionStartMessage(process.cwd());
|
|
77
|
+
console.log(parallelStatus);
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(message);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// Fall back to basic status
|
|
82
|
+
console.log(parallelStatus);
|
|
83
|
+
if (process.env.VERBOSE) {
|
|
84
|
+
console.log(` Context awareness error: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
// No context module - show basic status
|
|
89
|
+
console.log(parallelStatus);
|
|
90
|
+
if (process.env.VERBOSE && !detection.enabled) {
|
|
91
|
+
console.log(` Reason: ${detection.reason}`);
|
|
92
|
+
}
|
|
93
|
+
}
|