claude-cli-advanced-starter-pack 1.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/LICENSE +21 -0
- package/OVERVIEW.md +597 -0
- package/README.md +439 -0
- package/bin/gtask.js +282 -0
- package/bin/postinstall.js +53 -0
- package/package.json +69 -0
- package/src/agents/phase-dev-templates.js +1011 -0
- package/src/agents/templates.js +668 -0
- package/src/analysis/checklist-parser.js +414 -0
- package/src/analysis/codebase.js +481 -0
- package/src/cli/menu.js +958 -0
- package/src/commands/claude-audit.js +1482 -0
- package/src/commands/claude-settings.js +2243 -0
- package/src/commands/create-agent.js +681 -0
- package/src/commands/create-command.js +337 -0
- package/src/commands/create-hook.js +262 -0
- package/src/commands/create-phase-dev/codebase-analyzer.js +813 -0
- package/src/commands/create-phase-dev/documentation-generator.js +352 -0
- package/src/commands/create-phase-dev/post-completion.js +404 -0
- package/src/commands/create-phase-dev/scale-calculator.js +344 -0
- package/src/commands/create-phase-dev/wizard.js +492 -0
- package/src/commands/create-phase-dev.js +481 -0
- package/src/commands/create-skill.js +313 -0
- package/src/commands/create.js +446 -0
- package/src/commands/decompose.js +392 -0
- package/src/commands/detect-tech-stack.js +768 -0
- package/src/commands/explore-mcp/claude-md-updater.js +252 -0
- package/src/commands/explore-mcp/mcp-installer.js +346 -0
- package/src/commands/explore-mcp/mcp-registry.js +438 -0
- package/src/commands/explore-mcp.js +638 -0
- package/src/commands/gtask-init.js +641 -0
- package/src/commands/help.js +128 -0
- package/src/commands/init.js +1890 -0
- package/src/commands/install.js +250 -0
- package/src/commands/list.js +116 -0
- package/src/commands/roadmap.js +750 -0
- package/src/commands/setup-wizard.js +482 -0
- package/src/commands/setup.js +351 -0
- package/src/commands/sync.js +534 -0
- package/src/commands/test-run.js +456 -0
- package/src/commands/test-setup.js +456 -0
- package/src/commands/validate.js +67 -0
- package/src/config/tech-stack.defaults.json +182 -0
- package/src/config/tech-stack.schema.json +502 -0
- package/src/github/client.js +359 -0
- package/src/index.js +84 -0
- package/src/templates/claude-command.js +244 -0
- package/src/templates/issue-body.js +284 -0
- package/src/testing/config.js +411 -0
- package/src/utils/template-engine.js +398 -0
- package/src/utils/validate-templates.js +223 -0
- package/src/utils.js +396 -0
- package/templates/commands/ccasp-setup.template.md +113 -0
- package/templates/commands/context-audit.template.md +97 -0
- package/templates/commands/create-task-list.template.md +382 -0
- package/templates/commands/deploy-full.template.md +261 -0
- package/templates/commands/github-task-start.template.md +99 -0
- package/templates/commands/github-update.template.md +69 -0
- package/templates/commands/happy-start.template.md +117 -0
- package/templates/commands/phase-track.template.md +142 -0
- package/templates/commands/tunnel-start.template.md +127 -0
- package/templates/commands/tunnel-stop.template.md +106 -0
- package/templates/hooks/context-guardian.template.js +173 -0
- package/templates/hooks/deployment-orchestrator.template.js +219 -0
- package/templates/hooks/github-progress-hook.template.js +197 -0
- package/templates/hooks/happy-checkpoint-manager.template.js +222 -0
- package/templates/hooks/phase-dev-enforcer.template.js +183 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Happy Checkpoint Manager Hook
|
|
3
|
+
*
|
|
4
|
+
* Manages automatic checkpoints for Happy Engineering mobile app integration.
|
|
5
|
+
* Creates periodic snapshots of session state for mobile viewing and control.
|
|
6
|
+
*
|
|
7
|
+
* Event: PostToolUse
|
|
8
|
+
* Priority: {{hooks.priorities.automation}}
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
// Configuration from tech-stack.json
|
|
15
|
+
const CONFIG = {
|
|
16
|
+
enabled: {{happyMode.enabled}},
|
|
17
|
+
checkpointInterval: {{happyMode.checkpointInterval}}, // minutes
|
|
18
|
+
verbosity: '{{happyMode.verbosity}}',
|
|
19
|
+
notifications: {
|
|
20
|
+
onTaskComplete: {{happyMode.notifications.onTaskComplete}},
|
|
21
|
+
onError: {{happyMode.notifications.onError}},
|
|
22
|
+
onCheckpoint: {{happyMode.notifications.onCheckpoint}},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const CHECKPOINT_DIR = '.claude/self-hosted-happy/checkpoints';
|
|
27
|
+
const STATE_FILE = '.claude/self-hosted-happy/EXECUTION_STATE.json';
|
|
28
|
+
|
|
29
|
+
let lastCheckpointTime = Date.now();
|
|
30
|
+
let taskHistory = [];
|
|
31
|
+
let currentSessionId = null;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Generate session ID
|
|
35
|
+
*/
|
|
36
|
+
function getSessionId() {
|
|
37
|
+
if (!currentSessionId) {
|
|
38
|
+
currentSessionId = `happy-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;
|
|
39
|
+
}
|
|
40
|
+
return currentSessionId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Load execution state
|
|
45
|
+
*/
|
|
46
|
+
function loadState() {
|
|
47
|
+
const statePath = path.join(process.cwd(), STATE_FILE);
|
|
48
|
+
|
|
49
|
+
if (fs.existsSync(statePath)) {
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.warn('[happy-checkpoint] Could not parse state file');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
sessionId: getSessionId(),
|
|
59
|
+
mode: 'happy',
|
|
60
|
+
status: 'active',
|
|
61
|
+
tasksCompleted: 0,
|
|
62
|
+
tasksRemaining: 0,
|
|
63
|
+
currentTask: null,
|
|
64
|
+
lastCheckpoint: null,
|
|
65
|
+
history: [],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Save execution state
|
|
71
|
+
*/
|
|
72
|
+
function saveState(state) {
|
|
73
|
+
const statePath = path.join(process.cwd(), STATE_FILE);
|
|
74
|
+
const stateDir = path.dirname(statePath);
|
|
75
|
+
|
|
76
|
+
if (!fs.existsSync(stateDir)) {
|
|
77
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
state.lastUpdated = new Date().toISOString();
|
|
81
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2), 'utf8');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Create a checkpoint
|
|
86
|
+
*/
|
|
87
|
+
function createCheckpoint(state, context) {
|
|
88
|
+
const checkpointDir = path.join(process.cwd(), CHECKPOINT_DIR);
|
|
89
|
+
|
|
90
|
+
if (!fs.existsSync(checkpointDir)) {
|
|
91
|
+
fs.mkdirSync(checkpointDir, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
95
|
+
const checkpointPath = path.join(checkpointDir, `checkpoint-${timestamp}.json`);
|
|
96
|
+
|
|
97
|
+
const checkpoint = {
|
|
98
|
+
timestamp: new Date().toISOString(),
|
|
99
|
+
sessionId: state.sessionId,
|
|
100
|
+
progress: {
|
|
101
|
+
tasksCompleted: state.tasksCompleted,
|
|
102
|
+
tasksRemaining: state.tasksRemaining,
|
|
103
|
+
currentTask: state.currentTask,
|
|
104
|
+
},
|
|
105
|
+
context: {
|
|
106
|
+
recentTools: taskHistory.slice(-5).map((t) => t.tool),
|
|
107
|
+
verbosity: CONFIG.verbosity,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
fs.writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2), 'utf8');
|
|
112
|
+
|
|
113
|
+
return checkpointPath;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Check if checkpoint is due
|
|
118
|
+
*/
|
|
119
|
+
function isCheckpointDue() {
|
|
120
|
+
const elapsed = (Date.now() - lastCheckpointTime) / 1000 / 60; // minutes
|
|
121
|
+
return elapsed >= CONFIG.checkpointInterval;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Format response for mobile based on verbosity
|
|
126
|
+
*/
|
|
127
|
+
function formatForMobile(message, verbosity) {
|
|
128
|
+
if (verbosity === 'minimal') {
|
|
129
|
+
// Strip to essentials
|
|
130
|
+
return message.split('\n')[0].substring(0, 100);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (verbosity === 'condensed') {
|
|
134
|
+
// Convert to bullet points, truncate
|
|
135
|
+
const lines = message.split('\n').filter((l) => l.trim());
|
|
136
|
+
return lines
|
|
137
|
+
.slice(0, 5)
|
|
138
|
+
.map((l) => `• ${l.trim().substring(0, 80)}`)
|
|
139
|
+
.join('\n');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Full verbosity
|
|
143
|
+
return message;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Main hook handler
|
|
148
|
+
*/
|
|
149
|
+
module.exports = async function happyCheckpointManager(context) {
|
|
150
|
+
// Skip if disabled
|
|
151
|
+
if (!CONFIG.enabled) {
|
|
152
|
+
return { continue: true };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const { tool, input, output, error } = context;
|
|
156
|
+
|
|
157
|
+
// Load current state
|
|
158
|
+
const state = loadState();
|
|
159
|
+
|
|
160
|
+
// Track tool usage
|
|
161
|
+
taskHistory.push({
|
|
162
|
+
tool,
|
|
163
|
+
timestamp: new Date().toISOString(),
|
|
164
|
+
success: !error,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Keep history manageable
|
|
168
|
+
if (taskHistory.length > 100) {
|
|
169
|
+
taskHistory = taskHistory.slice(-50);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Update state based on tool
|
|
173
|
+
if (tool === 'TaskUpdate' || tool === 'TodoWrite') {
|
|
174
|
+
// Track task progress
|
|
175
|
+
if (input && input.status === 'completed') {
|
|
176
|
+
state.tasksCompleted += 1;
|
|
177
|
+
|
|
178
|
+
if (CONFIG.notifications.onTaskComplete) {
|
|
179
|
+
// In a real implementation, this would send to mobile app
|
|
180
|
+
console.log(`[Happy] Task completed: ${state.tasksCompleted} total`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Handle errors
|
|
186
|
+
if (error && CONFIG.notifications.onError) {
|
|
187
|
+
state.lastError = {
|
|
188
|
+
tool,
|
|
189
|
+
message: error.message || String(error),
|
|
190
|
+
timestamp: new Date().toISOString(),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check if checkpoint is due
|
|
195
|
+
let checkpointPath = null;
|
|
196
|
+
if (isCheckpointDue()) {
|
|
197
|
+
checkpointPath = createCheckpoint(state, context);
|
|
198
|
+
lastCheckpointTime = Date.now();
|
|
199
|
+
state.lastCheckpoint = checkpointPath;
|
|
200
|
+
|
|
201
|
+
if (CONFIG.notifications.onCheckpoint) {
|
|
202
|
+
console.log(`[Happy] Checkpoint created: ${checkpointPath}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Save updated state
|
|
207
|
+
saveState(state);
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
continue: true,
|
|
211
|
+
// Add checkpoint info if one was created
|
|
212
|
+
metadata: checkpointPath
|
|
213
|
+
? {
|
|
214
|
+
happyCheckpoint: {
|
|
215
|
+
path: checkpointPath,
|
|
216
|
+
sessionId: state.sessionId,
|
|
217
|
+
tasksCompleted: state.tasksCompleted,
|
|
218
|
+
},
|
|
219
|
+
}
|
|
220
|
+
: undefined,
|
|
221
|
+
};
|
|
222
|
+
};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase Dev Enforcer Hook
|
|
3
|
+
*
|
|
4
|
+
* Enforces phased development patterns during implementation.
|
|
5
|
+
* Ensures tasks are completed in phase order and success criteria are met.
|
|
6
|
+
*
|
|
7
|
+
* Event: PreToolUse
|
|
8
|
+
* Priority: {{hooks.priorities.tools}}
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
// Configuration from tech-stack.json
|
|
15
|
+
const CONFIG = {
|
|
16
|
+
enabled: {{phasedDevelopment.enabled}},
|
|
17
|
+
defaultScale: '{{phasedDevelopment.defaultScale}}',
|
|
18
|
+
successTarget: {{phasedDevelopment.successTarget}},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Find active phase dev project
|
|
23
|
+
*/
|
|
24
|
+
function findActiveProject() {
|
|
25
|
+
const docsDir = path.join(process.cwd(), '.claude/docs');
|
|
26
|
+
|
|
27
|
+
if (!fs.existsSync(docsDir)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Look for PROGRESS.json files
|
|
32
|
+
const subdirs = fs.readdirSync(docsDir);
|
|
33
|
+
|
|
34
|
+
for (const subdir of subdirs) {
|
|
35
|
+
const progressPath = path.join(docsDir, subdir, 'PROGRESS.json');
|
|
36
|
+
if (fs.existsSync(progressPath)) {
|
|
37
|
+
try {
|
|
38
|
+
const progress = JSON.parse(fs.readFileSync(progressPath, 'utf8'));
|
|
39
|
+
// Return first active (non-completed) project
|
|
40
|
+
if (progress.status !== 'completed') {
|
|
41
|
+
return { path: progressPath, data: progress, slug: subdir };
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// Skip invalid files
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get current phase
|
|
54
|
+
*/
|
|
55
|
+
function getCurrentPhase(project) {
|
|
56
|
+
if (!project || !project.data || !project.data.phases) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Find first non-completed phase
|
|
61
|
+
return project.data.phases.find((p) => p.status !== 'completed');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if task belongs to current phase
|
|
66
|
+
*/
|
|
67
|
+
function isTaskInCurrentPhase(taskId, currentPhase) {
|
|
68
|
+
if (!currentPhase || !currentPhase.tasks) {
|
|
69
|
+
return true; // Allow if no phase tracking
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return currentPhase.tasks.some(
|
|
73
|
+
(t) => t.id === taskId || t.description.includes(taskId)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Calculate phase completion percentage
|
|
79
|
+
*/
|
|
80
|
+
function getPhaseCompletion(phase) {
|
|
81
|
+
if (!phase || !phase.tasks || phase.tasks.length === 0) {
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const completed = phase.tasks.filter((t) => t.completed).length;
|
|
86
|
+
return completed / phase.tasks.length;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Main hook handler
|
|
91
|
+
*/
|
|
92
|
+
module.exports = async function phaseDevEnforcer(context) {
|
|
93
|
+
// Skip if disabled
|
|
94
|
+
if (!CONFIG.enabled) {
|
|
95
|
+
return { continue: true };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const { tool, input } = context;
|
|
99
|
+
|
|
100
|
+
// Only enforce on task-related operations
|
|
101
|
+
if (!['TaskUpdate', 'Write', 'Edit'].includes(tool)) {
|
|
102
|
+
return { continue: true };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Find active phased development project
|
|
106
|
+
const project = findActiveProject();
|
|
107
|
+
|
|
108
|
+
if (!project) {
|
|
109
|
+
// No active phase dev project, allow all
|
|
110
|
+
return { continue: true };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const currentPhase = getCurrentPhase(project);
|
|
114
|
+
|
|
115
|
+
if (!currentPhase) {
|
|
116
|
+
// All phases completed
|
|
117
|
+
return { continue: true };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// For TaskUpdate, check if completing tasks out of order
|
|
121
|
+
if (tool === 'TaskUpdate' && input && input.status === 'completed') {
|
|
122
|
+
const taskId = input.taskId || input.subject;
|
|
123
|
+
|
|
124
|
+
// Check if this task is in the current phase
|
|
125
|
+
if (!isTaskInCurrentPhase(taskId, currentPhase)) {
|
|
126
|
+
return {
|
|
127
|
+
continue: true, // Allow but warn
|
|
128
|
+
message: `⚠️ Warning: Completing task "${taskId}" which may not be in the current phase (${currentPhase.name}).
|
|
129
|
+
|
|
130
|
+
Current phase: ${currentPhase.name}
|
|
131
|
+
Phase tasks: ${currentPhase.tasks.map((t) => t.id).join(', ')}
|
|
132
|
+
|
|
133
|
+
Consider completing phase tasks in order for best results.`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// For Write/Edit, check if modifying files not in current phase scope
|
|
139
|
+
if ((tool === 'Write' || tool === 'Edit') && currentPhase.scope) {
|
|
140
|
+
const filePath = input.file_path || input.path;
|
|
141
|
+
|
|
142
|
+
if (filePath) {
|
|
143
|
+
const isInScope = currentPhase.scope.some((pattern) => {
|
|
144
|
+
if (pattern.includes('*')) {
|
|
145
|
+
// Simple glob matching
|
|
146
|
+
const regex = new RegExp(pattern.replace(/\*/g, '.*'));
|
|
147
|
+
return regex.test(filePath);
|
|
148
|
+
}
|
|
149
|
+
return filePath.includes(pattern);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!isInScope) {
|
|
153
|
+
return {
|
|
154
|
+
continue: true, // Allow but warn
|
|
155
|
+
message: `ℹ️ Note: Modifying "${filePath}" which is outside current phase scope.
|
|
156
|
+
|
|
157
|
+
Current phase: ${currentPhase.name}
|
|
158
|
+
Phase scope: ${currentPhase.scope.join(', ')}
|
|
159
|
+
|
|
160
|
+
This may be intentional for cross-cutting concerns.`,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Check if phase is ready for completion
|
|
167
|
+
const phaseCompletion = getPhaseCompletion(currentPhase);
|
|
168
|
+
if (phaseCompletion >= CONFIG.successTarget) {
|
|
169
|
+
return {
|
|
170
|
+
continue: true,
|
|
171
|
+
message: `✅ Phase "${currentPhase.name}" is ${Math.round(phaseCompletion * 100)}% complete!
|
|
172
|
+
|
|
173
|
+
Consider:
|
|
174
|
+
1. Running phase validation tests
|
|
175
|
+
2. Creating a checkpoint
|
|
176
|
+
3. Moving to the next phase
|
|
177
|
+
|
|
178
|
+
Use /phase-track to see full progress.`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { continue: true };
|
|
183
|
+
};
|