claude-cli-advanced-starter-pack 1.8.3 → 1.8.5
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 +6 -2
- package/bin/gtask.js +24 -0
- package/package.json +1 -1
- package/src/cli/menu.js +171 -1
- package/src/cli/mobile-menu.js +230 -0
- package/src/commands/global-reinstall.js +243 -0
- package/src/commands/global-uninstall.js +229 -0
- package/src/commands/init.js +224 -0
- package/src/commands/panel.js +84 -0
- package/src/commands/uninstall.js +8 -1
- package/src/data/releases.json +30 -0
- package/src/utils/global-registry.js +230 -0
- package/src/utils/happy-detect.js +66 -0
- package/src/utils/paths.js +146 -0
- package/templates/commands/create-task-list-for-issue.template.md +216 -0
- package/templates/commands/create-task-list.template.md +280 -82
- package/templates/commands/menu-for-happy-ui.template.md +109 -0
- package/templates/commands/menu-issues-list.template.md +288 -0
- package/templates/hooks/github-progress-hook.template.cjs +248 -0
- package/templates/hooks/github-progress-hook.template.js +0 -197
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Happy CLI Detection Utility
|
|
3
|
+
*
|
|
4
|
+
* Detects if CCASP is running inside Happy Coder mobile CLI wrapper.
|
|
5
|
+
* Happy CLI sets HAPPY_* environment variables when active.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/slopus/happy-cli
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if running inside Happy CLI environment
|
|
12
|
+
* @returns {boolean} True if Happy CLI detected
|
|
13
|
+
*/
|
|
14
|
+
export function isHappyMode() {
|
|
15
|
+
return !!(
|
|
16
|
+
process.env.HAPPY_HOME_DIR ||
|
|
17
|
+
process.env.HAPPY_SERVER_URL ||
|
|
18
|
+
process.env.HAPPY_WEBAPP_URL ||
|
|
19
|
+
process.env.HAPPY_EXPERIMENTAL
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get Happy CLI configuration from environment
|
|
25
|
+
* @returns {object} Happy configuration details
|
|
26
|
+
*/
|
|
27
|
+
export function getHappyConfig() {
|
|
28
|
+
return {
|
|
29
|
+
detected: isHappyMode(),
|
|
30
|
+
homeDir: process.env.HAPPY_HOME_DIR || null,
|
|
31
|
+
serverUrl: process.env.HAPPY_SERVER_URL || 'https://api.cluster-fluster.com',
|
|
32
|
+
webappUrl: process.env.HAPPY_WEBAPP_URL || 'https://app.happy.engineering',
|
|
33
|
+
experimental: process.env.HAPPY_EXPERIMENTAL === 'true',
|
|
34
|
+
disableCaffeinate: process.env.HAPPY_DISABLE_CAFFEINATE === 'true',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get recommended terminal width for mobile display
|
|
40
|
+
* @returns {number} Optimal width for mobile screens
|
|
41
|
+
*/
|
|
42
|
+
export function getMobileWidth() {
|
|
43
|
+
// Happy mobile UI typically works best at 40 chars
|
|
44
|
+
// to avoid horizontal scrolling on phone screens
|
|
45
|
+
return 40;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if we should use mobile-optimized UI
|
|
50
|
+
* Respects both Happy CLI detection and tech-stack.json happyMode.enabled
|
|
51
|
+
* @param {object} techStack - Optional tech-stack.json config
|
|
52
|
+
* @returns {boolean} True if mobile UI should be used
|
|
53
|
+
*/
|
|
54
|
+
export function shouldUseMobileUI(techStack = null) {
|
|
55
|
+
// Auto-detect Happy CLI environment
|
|
56
|
+
if (isHappyMode()) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check tech-stack.json happyMode.enabled setting
|
|
61
|
+
if (techStack?.happyMode?.enabled) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Platform Path Utilities
|
|
3
|
+
*
|
|
4
|
+
* Centralized path handling for Windows/macOS/Linux compatibility.
|
|
5
|
+
* All path operations should use these utilities to ensure consistency.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { join, normalize, sep } from 'path';
|
|
9
|
+
import { homedir } from 'os';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Normalize a path to use forward slashes (for comparison and storage)
|
|
13
|
+
* @param {string} filePath - Path to normalize
|
|
14
|
+
* @returns {string} Path with forward slashes
|
|
15
|
+
*/
|
|
16
|
+
export function toForwardSlashes(filePath) {
|
|
17
|
+
if (!filePath) return filePath;
|
|
18
|
+
return filePath.replace(/\\/g, '/');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Normalize a path to use the platform's native separator
|
|
23
|
+
* @param {string} filePath - Path to normalize
|
|
24
|
+
* @returns {string} Path with native separators
|
|
25
|
+
*/
|
|
26
|
+
export function toNativePath(filePath) {
|
|
27
|
+
if (!filePath) return filePath;
|
|
28
|
+
return filePath.replace(/[/\\]/g, sep);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Compare two paths for equality (cross-platform safe)
|
|
33
|
+
* @param {string} path1 - First path
|
|
34
|
+
* @param {string} path2 - Second path
|
|
35
|
+
* @returns {boolean} True if paths are equivalent
|
|
36
|
+
*/
|
|
37
|
+
export function pathsEqual(path1, path2) {
|
|
38
|
+
if (!path1 || !path2) return path1 === path2;
|
|
39
|
+
const norm1 = toForwardSlashes(path1).replace(/\/$/, '').toLowerCase();
|
|
40
|
+
const norm2 = toForwardSlashes(path2).replace(/\/$/, '').toLowerCase();
|
|
41
|
+
return norm1 === norm2;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the last segment of a path (cross-platform safe)
|
|
46
|
+
* @param {string} filePath - Path to extract from
|
|
47
|
+
* @returns {string} Last segment of the path
|
|
48
|
+
*/
|
|
49
|
+
export function getPathSegment(filePath) {
|
|
50
|
+
if (!filePath) return '';
|
|
51
|
+
return filePath.split(/[/\\]/).pop() || '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Build a .claude-relative path string for use in config/templates
|
|
56
|
+
* Always uses forward slashes for consistency in JSON/templates
|
|
57
|
+
* @param {...string} segments - Path segments after .claude/
|
|
58
|
+
* @returns {string} Path string like ".claude/hooks/file.js"
|
|
59
|
+
*/
|
|
60
|
+
export function claudeRelativePath(...segments) {
|
|
61
|
+
return '.claude/' + segments.join('/');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Build an absolute path to a .claude directory item
|
|
66
|
+
* @param {string} baseDir - Project root directory
|
|
67
|
+
* @param {...string} segments - Path segments after .claude/
|
|
68
|
+
* @returns {string} Absolute path using native separators
|
|
69
|
+
*/
|
|
70
|
+
export function claudeAbsolutePath(baseDir, ...segments) {
|
|
71
|
+
return join(baseDir, '.claude', ...segments);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get the user's home directory (cross-platform)
|
|
76
|
+
* @returns {string} Home directory path
|
|
77
|
+
*/
|
|
78
|
+
export function getHomeDir() {
|
|
79
|
+
return process.env.HOME || process.env.USERPROFILE || homedir();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Build a path relative to user's home directory
|
|
84
|
+
* @param {...string} segments - Path segments after home
|
|
85
|
+
* @returns {string} Absolute path using native separators
|
|
86
|
+
*/
|
|
87
|
+
export function homeRelativePath(...segments) {
|
|
88
|
+
return join(getHomeDir(), ...segments);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Build a path to global .claude directory
|
|
93
|
+
* @param {...string} segments - Path segments after ~/.claude/
|
|
94
|
+
* @returns {string} Absolute path using native separators
|
|
95
|
+
*/
|
|
96
|
+
export function globalClaudePath(...segments) {
|
|
97
|
+
return join(getHomeDir(), '.claude', ...segments);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if running on Windows
|
|
102
|
+
* @returns {boolean} True if Windows
|
|
103
|
+
*/
|
|
104
|
+
export function isWindows() {
|
|
105
|
+
return process.platform === 'win32';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get the appropriate command existence checker
|
|
110
|
+
* @returns {string} 'where' on Windows, 'which' on Unix
|
|
111
|
+
*/
|
|
112
|
+
export function getWhichCommand() {
|
|
113
|
+
return isWindows() ? 'where' : 'which';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Normalize line endings to Unix style (LF)
|
|
118
|
+
* @param {string} content - Content to normalize
|
|
119
|
+
* @returns {string} Content with Unix line endings
|
|
120
|
+
*/
|
|
121
|
+
export function normalizeLineEndings(content) {
|
|
122
|
+
if (!content) return content;
|
|
123
|
+
return content.replace(/\r\n/g, '\n');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Build a Node.js command that works cross-platform
|
|
128
|
+
* Uses forward slashes which Node.js handles on all platforms
|
|
129
|
+
* @param {string} scriptPath - Path to the script (relative to project root)
|
|
130
|
+
* @returns {string} Command string like "node .claude/hooks/script.js"
|
|
131
|
+
*/
|
|
132
|
+
export function nodeCommand(scriptPath) {
|
|
133
|
+
// Node.js handles forward slashes on all platforms
|
|
134
|
+
const normalizedPath = toForwardSlashes(scriptPath);
|
|
135
|
+
return `node ${normalizedPath}`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Ensure a path uses consistent separators for storage/comparison
|
|
140
|
+
* Stores with forward slashes, converts to native when needed for fs operations
|
|
141
|
+
* @param {string} filePath - Path to store
|
|
142
|
+
* @returns {string} Normalized path for storage
|
|
143
|
+
*/
|
|
144
|
+
export function storagePath(filePath) {
|
|
145
|
+
return toForwardSlashes(filePath);
|
|
146
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Start working on a GitHub issue by number with full workflow
|
|
3
|
+
type: utility
|
|
4
|
+
complexity: simple
|
|
5
|
+
model: haiku
|
|
6
|
+
argument-hint: <issue-number>
|
|
7
|
+
allowed-tools:
|
|
8
|
+
- Bash
|
|
9
|
+
- AskUserQuestion
|
|
10
|
+
- Task
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# /create-task-list-for-issue - Quick Issue Start
|
|
14
|
+
|
|
15
|
+
**Start working on a GitHub issue by number. Confirms details, then runs full `/create-task-list` workflow.**
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## USAGE
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
/create-task-list-for-issue 123
|
|
23
|
+
/create-task-list-for-issue #45
|
|
24
|
+
/create-task-list-for-issue 7
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## EXECUTION
|
|
30
|
+
|
|
31
|
+
### Step 1: Parse Issue Number
|
|
32
|
+
|
|
33
|
+
Extract issue number from `$ARGUMENTS`:
|
|
34
|
+
- Strip `#` prefix if present
|
|
35
|
+
- Validate it's a positive integer
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
If no issue number provided:
|
|
39
|
+
→ Use AskUserQuestion: "Which issue number would you like to work on?"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### Step 2: Fetch Issue Details
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
gh issue view [NUMBER] --json number,title,body,createdAt,labels,url
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### Step 3: Detect Issue Format
|
|
53
|
+
|
|
54
|
+
Check if the issue body contains BOTH of these indicators of `/github-task` format:
|
|
55
|
+
- `## Acceptance Criteria` OR `## Task Checklist` section
|
|
56
|
+
- `## Suggested Implementation` OR `## Implementation Approach` section
|
|
57
|
+
|
|
58
|
+
**Set `IS_TASK_READY`** = true if both indicators found, false otherwise.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Step 4: Display Issue Confirmation
|
|
63
|
+
|
|
64
|
+
**If IS_TASK_READY = true:**
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
68
|
+
║ Issue #[NUMBER] ✓ Task-Ready ║
|
|
69
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
70
|
+
║ ║
|
|
71
|
+
║ [Issue Title - max 50 chars] ║
|
|
72
|
+
║ ║
|
|
73
|
+
║ Created: [MM/DD/YYYY] ║
|
|
74
|
+
║ Labels: [label1, label2, ...] ║
|
|
75
|
+
║ URL: [github url] ║
|
|
76
|
+
║ ║
|
|
77
|
+
║ Format: Has task checklist - will use existing tasks ║
|
|
78
|
+
║ ║
|
|
79
|
+
║ Tasks found: ║
|
|
80
|
+
║ • [Task 1 from checklist] ║
|
|
81
|
+
║ • [Task 2 from checklist] ║
|
|
82
|
+
║ • ... ([N] total) ║
|
|
83
|
+
║ ║
|
|
84
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**If IS_TASK_READY = false:**
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
91
|
+
║ Issue #[NUMBER] ⚠ Needs Analysis ║
|
|
92
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
93
|
+
║ ║
|
|
94
|
+
║ [Issue Title - max 50 chars] ║
|
|
95
|
+
║ ║
|
|
96
|
+
║ Created: [MM/DD/YYYY] ║
|
|
97
|
+
║ Labels: [label1, label2, ...] ║
|
|
98
|
+
║ URL: [github url] ║
|
|
99
|
+
║ ║
|
|
100
|
+
║ Format: No task checklist - will generate via exploration ║
|
|
101
|
+
║ ║
|
|
102
|
+
║ Description preview: ║
|
|
103
|
+
║ [First 100 chars of issue body...] ║
|
|
104
|
+
║ ║
|
|
105
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### Step 5: Confirm and Proceed
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
header: "Start"
|
|
114
|
+
question: "Start working on this issue?"
|
|
115
|
+
options:
|
|
116
|
+
- label: "Y - Yes, proceed"
|
|
117
|
+
description: "Run full /create-task-list workflow"
|
|
118
|
+
- label: "V - View full details"
|
|
119
|
+
description: "Show complete issue body first"
|
|
120
|
+
- label: "N - Cancel"
|
|
121
|
+
description: "Return without starting"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**If user selects V (View):**
|
|
125
|
+
- Run `gh issue view [NUMBER]` and display full body
|
|
126
|
+
- Then re-ask the confirmation question (Y/N only)
|
|
127
|
+
|
|
128
|
+
**If user selects N (Cancel):**
|
|
129
|
+
- Exit command
|
|
130
|
+
|
|
131
|
+
**If user selects Y (Yes):**
|
|
132
|
+
- Proceed to Step 6
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### Step 6: Run Full /create-task-list Workflow
|
|
137
|
+
|
|
138
|
+
**If IS_TASK_READY = true:**
|
|
139
|
+
|
|
140
|
+
Display:
|
|
141
|
+
```
|
|
142
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
143
|
+
║ 📋 Starting Issue #[NUMBER] (Task-Ready) ║
|
|
144
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
145
|
+
║ Using existing task checklist from issue ║
|
|
146
|
+
║ Running full /create-task-list workflow for: ║
|
|
147
|
+
║ • Codebase exploration & context ║
|
|
148
|
+
║ • Testing configuration (Ralph loop, E2E) ║
|
|
149
|
+
║ • Workflow setup (branch, board sync) ║
|
|
150
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Run: `/create-task-list for issue #[NUMBER] --use-existing-tasks`
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
**If IS_TASK_READY = false:**
|
|
158
|
+
|
|
159
|
+
Display:
|
|
160
|
+
```
|
|
161
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
162
|
+
║ 📋 Starting Issue #[NUMBER] (Needs Analysis) ║
|
|
163
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
164
|
+
║ Running full /create-task-list workflow for: ║
|
|
165
|
+
║ • Task generation via codebase exploration ║
|
|
166
|
+
║ • Testing configuration (Ralph loop, E2E) ║
|
|
167
|
+
║ • Workflow setup (branch, board sync) ║
|
|
168
|
+
║ • Option to update issue with generated tasks ║
|
|
169
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Run: `/create-task-list for issue #[NUMBER]`
|
|
173
|
+
|
|
174
|
+
After `/create-task-list` completes and generates tasks, ask:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
header: "Update"
|
|
178
|
+
question: "Update GitHub issue with generated task list?"
|
|
179
|
+
options:
|
|
180
|
+
- label: "Y - Yes, update issue"
|
|
181
|
+
description: "Add task checklist to issue body"
|
|
182
|
+
- label: "N - No, just implement"
|
|
183
|
+
description: "Keep issue as-is, start work"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
If user selects Y:
|
|
187
|
+
```bash
|
|
188
|
+
# Append task checklist to issue body
|
|
189
|
+
gh issue edit [NUMBER] --body "$(gh issue view [NUMBER] --json body -q .body)
|
|
190
|
+
|
|
191
|
+
## Task Checklist (Auto-generated)
|
|
192
|
+
|
|
193
|
+
- [ ] Task 1
|
|
194
|
+
- [ ] Task 2
|
|
195
|
+
..."
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## ERROR HANDLING
|
|
201
|
+
|
|
202
|
+
| Error | Action |
|
|
203
|
+
|-------|--------|
|
|
204
|
+
| Issue not found | Display "Issue #[N] not found" and exit |
|
|
205
|
+
| gh not authenticated | Show `gh auth login` instructions |
|
|
206
|
+
| Invalid issue number | Ask user to provide valid number |
|
|
207
|
+
| Network error | Show retry option |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## RELATED COMMANDS
|
|
212
|
+
|
|
213
|
+
- `/menu-issues-list` - Browse all open issues with menu
|
|
214
|
+
- `/create-task-list` - Create task list from any prompt
|
|
215
|
+
- `/github-task-start` - Start working on issue (simpler flow)
|
|
216
|
+
- `/github-update` - Sync with project board
|