claude-cli-advanced-starter-pack 1.8.2 → 1.8.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/README.md +6 -2
- package/bin/gtask.js +35 -0
- package/package.json +1 -1
- 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/uninstall.js +414 -0
- package/src/data/releases.json +15 -0
- package/src/utils/global-registry.js +230 -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-issues-list.template.md +288 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Project Registry
|
|
3
|
+
* Tracks all projects configured with CCASP across the system
|
|
4
|
+
* Location: ~/.claude/ccasp-registry.json
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import {
|
|
10
|
+
globalClaudePath,
|
|
11
|
+
getHomeDir,
|
|
12
|
+
toForwardSlashes,
|
|
13
|
+
pathsEqual,
|
|
14
|
+
getPathSegment
|
|
15
|
+
} from './paths.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get the path to the global registry file
|
|
19
|
+
* @returns {string} Path to ~/.claude/ccasp-registry.json
|
|
20
|
+
*/
|
|
21
|
+
export function getRegistryPath() {
|
|
22
|
+
return globalClaudePath('ccasp-registry.json');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the global .claude directory path
|
|
27
|
+
* @returns {string} Path to ~/.claude/
|
|
28
|
+
*/
|
|
29
|
+
export function getGlobalClaudeDir() {
|
|
30
|
+
return join(getHomeDir(), '.claude');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Ensure the global .claude directory exists
|
|
35
|
+
*/
|
|
36
|
+
function ensureGlobalDir() {
|
|
37
|
+
const globalDir = getGlobalClaudeDir();
|
|
38
|
+
if (!existsSync(globalDir)) {
|
|
39
|
+
mkdirSync(globalDir, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Load the global registry
|
|
45
|
+
* @returns {Object} Registry object with projects array and metadata
|
|
46
|
+
*/
|
|
47
|
+
export function loadRegistry() {
|
|
48
|
+
const registryPath = getRegistryPath();
|
|
49
|
+
|
|
50
|
+
if (!existsSync(registryPath)) {
|
|
51
|
+
return {
|
|
52
|
+
version: '1.0.0',
|
|
53
|
+
projects: [],
|
|
54
|
+
lastModified: null
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const content = readFileSync(registryPath, 'utf-8');
|
|
60
|
+
return JSON.parse(content);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(`Warning: Could not parse registry file: ${err.message}`);
|
|
63
|
+
return {
|
|
64
|
+
version: '1.0.0',
|
|
65
|
+
projects: [],
|
|
66
|
+
lastModified: null
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Save the global registry
|
|
73
|
+
* @param {Object} registry - Registry object to save
|
|
74
|
+
*/
|
|
75
|
+
export function saveRegistry(registry) {
|
|
76
|
+
ensureGlobalDir();
|
|
77
|
+
const registryPath = getRegistryPath();
|
|
78
|
+
|
|
79
|
+
registry.lastModified = new Date().toISOString();
|
|
80
|
+
|
|
81
|
+
writeFileSync(registryPath, JSON.stringify(registry, null, 2), 'utf-8');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Register a project in the global registry
|
|
86
|
+
* @param {string} projectPath - Absolute path to the project
|
|
87
|
+
* @param {Object} metadata - Optional metadata (name, version, features)
|
|
88
|
+
* @returns {boolean} True if newly registered, false if already existed
|
|
89
|
+
*/
|
|
90
|
+
export function registerProject(projectPath, metadata = {}) {
|
|
91
|
+
const registry = loadRegistry();
|
|
92
|
+
|
|
93
|
+
// Check if already registered (using cross-platform path comparison)
|
|
94
|
+
const existingIndex = registry.projects.findIndex(
|
|
95
|
+
p => pathsEqual(p.path, projectPath)
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const projectEntry = {
|
|
99
|
+
path: projectPath,
|
|
100
|
+
name: metadata.name || getPathSegment(projectPath),
|
|
101
|
+
registeredAt: new Date().toISOString(),
|
|
102
|
+
lastInitAt: new Date().toISOString(),
|
|
103
|
+
ccaspVersion: metadata.version || 'unknown',
|
|
104
|
+
features: metadata.features || []
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
if (existingIndex >= 0) {
|
|
108
|
+
// Update existing entry
|
|
109
|
+
registry.projects[existingIndex] = {
|
|
110
|
+
...registry.projects[existingIndex],
|
|
111
|
+
...projectEntry,
|
|
112
|
+
registeredAt: registry.projects[existingIndex].registeredAt // Keep original registration date
|
|
113
|
+
};
|
|
114
|
+
saveRegistry(registry);
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Add new entry
|
|
119
|
+
registry.projects.push(projectEntry);
|
|
120
|
+
saveRegistry(registry);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Unregister a project from the global registry
|
|
126
|
+
* @param {string} projectPath - Absolute path to the project
|
|
127
|
+
* @returns {boolean} True if removed, false if not found
|
|
128
|
+
*/
|
|
129
|
+
export function unregisterProject(projectPath) {
|
|
130
|
+
const registry = loadRegistry();
|
|
131
|
+
|
|
132
|
+
const initialLength = registry.projects.length;
|
|
133
|
+
registry.projects = registry.projects.filter(
|
|
134
|
+
p => !pathsEqual(p.path, projectPath)
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if (registry.projects.length < initialLength) {
|
|
138
|
+
saveRegistry(registry);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get all registered projects
|
|
147
|
+
* @param {Object} options - Filter options
|
|
148
|
+
* @param {boolean} options.existsOnly - Only return projects that still exist on disk
|
|
149
|
+
* @returns {Array} Array of project entries
|
|
150
|
+
*/
|
|
151
|
+
export function getRegisteredProjects(options = {}) {
|
|
152
|
+
const registry = loadRegistry();
|
|
153
|
+
let projects = registry.projects;
|
|
154
|
+
|
|
155
|
+
if (options.existsOnly) {
|
|
156
|
+
projects = projects.filter(p => existsSync(p.path));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return projects;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if a project is registered
|
|
164
|
+
* @param {string} projectPath - Absolute path to the project
|
|
165
|
+
* @returns {boolean} True if registered
|
|
166
|
+
*/
|
|
167
|
+
export function isProjectRegistered(projectPath) {
|
|
168
|
+
const registry = loadRegistry();
|
|
169
|
+
|
|
170
|
+
return registry.projects.some(
|
|
171
|
+
p => pathsEqual(p.path, projectPath)
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get registry statistics
|
|
177
|
+
* @returns {Object} Stats about registered projects
|
|
178
|
+
*/
|
|
179
|
+
export function getRegistryStats() {
|
|
180
|
+
const registry = loadRegistry();
|
|
181
|
+
const projects = registry.projects;
|
|
182
|
+
|
|
183
|
+
let existingCount = 0;
|
|
184
|
+
let missingCount = 0;
|
|
185
|
+
|
|
186
|
+
for (const project of projects) {
|
|
187
|
+
if (existsSync(project.path)) {
|
|
188
|
+
existingCount++;
|
|
189
|
+
} else {
|
|
190
|
+
missingCount++;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
total: projects.length,
|
|
196
|
+
existing: existingCount,
|
|
197
|
+
missing: missingCount,
|
|
198
|
+
lastModified: registry.lastModified
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Clean up registry by removing projects that no longer exist
|
|
204
|
+
* @returns {number} Number of projects removed
|
|
205
|
+
*/
|
|
206
|
+
export function cleanupRegistry() {
|
|
207
|
+
const registry = loadRegistry();
|
|
208
|
+
const initialLength = registry.projects.length;
|
|
209
|
+
|
|
210
|
+
registry.projects = registry.projects.filter(p => existsSync(p.path));
|
|
211
|
+
|
|
212
|
+
const removed = initialLength - registry.projects.length;
|
|
213
|
+
if (removed > 0) {
|
|
214
|
+
saveRegistry(registry);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return removed;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Clear the entire registry
|
|
222
|
+
*/
|
|
223
|
+
export function clearRegistry() {
|
|
224
|
+
const registry = {
|
|
225
|
+
version: '1.0.0',
|
|
226
|
+
projects: [],
|
|
227
|
+
lastModified: new Date().toISOString()
|
|
228
|
+
};
|
|
229
|
+
saveRegistry(registry);
|
|
230
|
+
}
|
|
@@ -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
|