deepflow 0.1.1 → 0.1.3
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/.claude/commands/df/spec.md +65 -10
- package/.claude/skills/gap-discovery/SKILL.md +87 -6
- package/VERSION +1 -1
- package/bin/install.js +84 -41
- package/package.json +1 -1
|
@@ -22,9 +22,25 @@ Before generating, use the `gap-discovery` skill to analyze conversation.
|
|
|
22
22
|
- [ ] Key constraints identified
|
|
23
23
|
- [ ] Success criteria stated
|
|
24
24
|
|
|
25
|
-
**If gaps exist**,
|
|
25
|
+
**If gaps exist**, use the `AskUserQuestion` tool to ask structured questions:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"questions": [
|
|
30
|
+
{
|
|
31
|
+
"question": "Clear, specific question ending with ?",
|
|
32
|
+
"header": "Short label",
|
|
33
|
+
"multiSelect": false,
|
|
34
|
+
"options": [
|
|
35
|
+
{"label": "Option 1", "description": "What this means"},
|
|
36
|
+
{"label": "Option 2", "description": "What this means"}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
```
|
|
26
42
|
|
|
27
|
-
Max
|
|
43
|
+
Max 4 questions per tool call. Wait for answers before proceeding.
|
|
28
44
|
|
|
29
45
|
### 2. GENERATE SPEC
|
|
30
46
|
|
|
@@ -81,14 +97,53 @@ Next: Run /df:plan to generate tasks
|
|
|
81
97
|
```
|
|
82
98
|
USER: I want to add image upload
|
|
83
99
|
|
|
84
|
-
CLAUDE:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
CLAUDE: [Uses AskUserQuestion tool]
|
|
101
|
+
{
|
|
102
|
+
"questions": [
|
|
103
|
+
{
|
|
104
|
+
"question": "What file types should be supported?",
|
|
105
|
+
"header": "File types",
|
|
106
|
+
"multiSelect": true,
|
|
107
|
+
"options": [
|
|
108
|
+
{"label": "JPG/PNG only", "description": "Standard formats"},
|
|
109
|
+
{"label": "Include WebP", "description": "Modern compression"},
|
|
110
|
+
{"label": "Include GIF", "description": "Animated images"}
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"question": "What's the maximum upload size?",
|
|
115
|
+
"header": "Size limit",
|
|
116
|
+
"multiSelect": false,
|
|
117
|
+
"options": [
|
|
118
|
+
{"label": "5 MB", "description": "Fast uploads"},
|
|
119
|
+
{"label": "10 MB (Recommended)", "description": "Balanced"},
|
|
120
|
+
{"label": "25 MB", "description": "High-res photos"}
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"question": "Where should files be stored?",
|
|
125
|
+
"header": "Storage",
|
|
126
|
+
"multiSelect": false,
|
|
127
|
+
"options": [
|
|
128
|
+
{"label": "S3 (Recommended)", "description": "Scalable cloud storage"},
|
|
129
|
+
{"label": "Local filesystem", "description": "Simple, single server"},
|
|
130
|
+
{"label": "Cloudflare R2", "description": "S3-compatible, no egress fees"}
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"question": "Who can upload files?",
|
|
135
|
+
"header": "Auth",
|
|
136
|
+
"multiSelect": false,
|
|
137
|
+
"options": [
|
|
138
|
+
{"label": "Logged-in users", "description": "Require authentication"},
|
|
139
|
+
{"label": "Public", "description": "Anyone can upload"},
|
|
140
|
+
{"label": "Role-based", "description": "Specific roles only"}
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
USER: [Selects: JPG/PNG + WebP, 10MB, S3, Logged-in users]
|
|
92
147
|
|
|
93
148
|
CLAUDE: ✓ Created specs/image-upload.md
|
|
94
149
|
|
|
@@ -18,28 +18,109 @@ Proactively identify missing requirements before implementation.
|
|
|
18
18
|
| **Success criteria** | "How will you know this works?" |
|
|
19
19
|
| **Anti-goals** | "What should this explicitly NOT do?" |
|
|
20
20
|
|
|
21
|
+
## Implementation
|
|
22
|
+
|
|
23
|
+
**Use the `AskUserQuestion` tool** to ask structured questions with predefined options.
|
|
24
|
+
|
|
25
|
+
### AskUserQuestion Format
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"questions": [
|
|
30
|
+
{
|
|
31
|
+
"question": "What file types should be supported?",
|
|
32
|
+
"header": "File types",
|
|
33
|
+
"multiSelect": true,
|
|
34
|
+
"options": [
|
|
35
|
+
{"label": "JPG/PNG only", "description": "Standard image formats"},
|
|
36
|
+
{"label": "Include WebP", "description": "Modern format with better compression"},
|
|
37
|
+
{"label": "Include GIF", "description": "Animated images supported"},
|
|
38
|
+
{"label": "Include video", "description": "MP4, WebM formats"}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Guidelines for AskUserQuestion
|
|
46
|
+
|
|
47
|
+
- **header**: Max 12 characters (e.g., "File types", "Auth", "Storage")
|
|
48
|
+
- **options**: 2-4 choices per question, each with label + description
|
|
49
|
+
- **multiSelect**: Set `true` when choices aren't mutually exclusive
|
|
50
|
+
- **questions**: Max 4 questions per tool call (tool limit)
|
|
51
|
+
- Users can always select "Other" to provide custom input
|
|
52
|
+
|
|
53
|
+
### Example Questions by Category
|
|
54
|
+
|
|
55
|
+
**Scope:**
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"question": "Should this feature include admin management?",
|
|
59
|
+
"header": "Scope",
|
|
60
|
+
"multiSelect": false,
|
|
61
|
+
"options": [
|
|
62
|
+
{"label": "Yes, include admin", "description": "Add admin dashboard for management"},
|
|
63
|
+
{"label": "No, user-only", "description": "Only end-user functionality"},
|
|
64
|
+
{"label": "Phase 2", "description": "Add admin features later"}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Constraints:**
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"question": "What's the maximum file size for uploads?",
|
|
73
|
+
"header": "Size limit",
|
|
74
|
+
"multiSelect": false,
|
|
75
|
+
"options": [
|
|
76
|
+
{"label": "5 MB", "description": "Conservative, fast uploads"},
|
|
77
|
+
{"label": "10 MB (Recommended)", "description": "Balanced for most images"},
|
|
78
|
+
{"label": "25 MB", "description": "High-res photos supported"},
|
|
79
|
+
{"label": "50 MB", "description": "Large files, slower uploads"}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Dependencies:**
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"question": "What authentication is required?",
|
|
88
|
+
"header": "Auth",
|
|
89
|
+
"multiSelect": false,
|
|
90
|
+
"options": [
|
|
91
|
+
{"label": "Public access", "description": "No login required"},
|
|
92
|
+
{"label": "Logged-in users", "description": "Require authentication"},
|
|
93
|
+
{"label": "Role-based", "description": "Different permissions per role"}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
21
98
|
## Process
|
|
22
99
|
|
|
23
100
|
1. Listen to user's description
|
|
24
101
|
2. Identify categories lacking clarity
|
|
25
|
-
3.
|
|
102
|
+
3. Use `AskUserQuestion` with 1-4 targeted questions
|
|
26
103
|
4. Wait for answers
|
|
27
|
-
5. Follow up if answers reveal new gaps
|
|
104
|
+
5. Follow up if answers reveal new gaps (another AskUserQuestion call)
|
|
28
105
|
6. Signal when ready: "Requirements clear. Ready to proceed."
|
|
29
106
|
|
|
30
107
|
## Question Quality
|
|
31
108
|
|
|
32
109
|
```
|
|
33
110
|
BAD: "Any other requirements?"
|
|
34
|
-
GOOD: "Max file size for uploads?"
|
|
111
|
+
GOOD: "Max file size for uploads?" with concrete options
|
|
35
112
|
|
|
36
113
|
BAD: "What about errors?"
|
|
37
|
-
GOOD: "If upload fails, retry automatically or show error to user?"
|
|
114
|
+
GOOD: "If upload fails, retry automatically or show error to user?" with clear choices
|
|
38
115
|
```
|
|
39
116
|
|
|
40
117
|
## Rules
|
|
41
118
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
119
|
+
- Use `AskUserQuestion` tool for structured input
|
|
120
|
+
- Max 4 questions per tool call (tool limitation)
|
|
121
|
+
- Headers max 12 characters
|
|
122
|
+
- 2-4 options per question with descriptions
|
|
123
|
+
- Use multiSelect when choices can combine
|
|
124
|
+
- Be specific, offer choices with trade-offs explained
|
|
44
125
|
- Don't assume - ask
|
|
45
126
|
- Stop when gaps are covered
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.3
|
package/bin/install.js
CHANGED
|
@@ -19,23 +19,35 @@ const c = {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
// Paths
|
|
22
|
-
const
|
|
22
|
+
const GLOBAL_DIR = path.join(os.homedir(), '.claude');
|
|
23
|
+
const PROJECT_DIR = path.join(process.cwd(), '.claude');
|
|
23
24
|
const PACKAGE_DIR = path.resolve(__dirname, '..');
|
|
24
25
|
|
|
25
26
|
async function main() {
|
|
26
27
|
console.log('');
|
|
27
|
-
console.log(`${c.cyan}
|
|
28
|
+
console.log(`${c.cyan}deepflow installer${c.reset}`);
|
|
29
|
+
console.log('');
|
|
30
|
+
|
|
31
|
+
// Ask for installation level
|
|
32
|
+
const level = await askInstallLevel();
|
|
33
|
+
const CLAUDE_DIR = level === 'global' ? GLOBAL_DIR : PROJECT_DIR;
|
|
34
|
+
const levelLabel = level === 'global' ? 'globally' : 'in this project';
|
|
35
|
+
|
|
36
|
+
console.log('');
|
|
37
|
+
console.log(`Installing ${levelLabel}...`);
|
|
28
38
|
console.log('');
|
|
29
39
|
|
|
30
40
|
// Create directories
|
|
31
41
|
const dirs = [
|
|
32
42
|
'commands/df',
|
|
33
43
|
'skills',
|
|
34
|
-
'agents'
|
|
35
|
-
'hooks',
|
|
36
|
-
'deepflow'
|
|
44
|
+
'agents'
|
|
37
45
|
];
|
|
38
46
|
|
|
47
|
+
if (level === 'global') {
|
|
48
|
+
dirs.push('hooks', 'deepflow');
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
for (const dir of dirs) {
|
|
40
52
|
fs.mkdirSync(path.join(CLAUDE_DIR, dir), { recursive: true });
|
|
41
53
|
}
|
|
@@ -61,55 +73,71 @@ async function main() {
|
|
|
61
73
|
);
|
|
62
74
|
log('Agents installed');
|
|
63
75
|
|
|
64
|
-
// Copy hooks
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
// Copy hooks (global only - statusline requires global settings)
|
|
77
|
+
if (level === 'global') {
|
|
78
|
+
const hooksDir = path.join(PACKAGE_DIR, 'hooks');
|
|
79
|
+
if (fs.existsSync(hooksDir)) {
|
|
80
|
+
for (const file of fs.readdirSync(hooksDir)) {
|
|
81
|
+
if (file.endsWith('.js')) {
|
|
82
|
+
fs.copyFileSync(
|
|
83
|
+
path.join(hooksDir, file),
|
|
84
|
+
path.join(CLAUDE_DIR, 'hooks', file)
|
|
85
|
+
);
|
|
86
|
+
}
|
|
73
87
|
}
|
|
88
|
+
log('Hooks installed');
|
|
74
89
|
}
|
|
75
|
-
log('Hooks installed');
|
|
76
90
|
}
|
|
77
91
|
|
|
78
|
-
// Copy VERSION
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
fs.
|
|
82
|
-
|
|
92
|
+
// Copy VERSION (global only - for update checking)
|
|
93
|
+
if (level === 'global') {
|
|
94
|
+
const versionFile = path.join(PACKAGE_DIR, 'VERSION');
|
|
95
|
+
if (fs.existsSync(versionFile)) {
|
|
96
|
+
fs.copyFileSync(versionFile, path.join(CLAUDE_DIR, 'deepflow', 'VERSION'));
|
|
97
|
+
log('Version file installed');
|
|
98
|
+
}
|
|
83
99
|
}
|
|
84
100
|
|
|
85
|
-
// Configure statusline
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
// Configure statusline (global only)
|
|
102
|
+
if (level === 'global') {
|
|
103
|
+
await configureStatusline(CLAUDE_DIR);
|
|
104
|
+
|
|
105
|
+
// Trigger background update check
|
|
106
|
+
const updateChecker = path.join(CLAUDE_DIR, 'hooks', 'df-check-update.js');
|
|
107
|
+
if (fs.existsSync(updateChecker)) {
|
|
108
|
+
const { spawn } = require('child_process');
|
|
109
|
+
const child = spawn(process.execPath, [updateChecker], {
|
|
110
|
+
detached: true,
|
|
111
|
+
stdio: 'ignore'
|
|
112
|
+
});
|
|
113
|
+
child.unref();
|
|
114
|
+
}
|
|
97
115
|
}
|
|
98
116
|
|
|
99
117
|
console.log('');
|
|
100
118
|
console.log(`${c.green}Installation complete!${c.reset}`);
|
|
101
119
|
console.log('');
|
|
102
|
-
console.log(`Installed to ${CLAUDE_DIR}:`);
|
|
120
|
+
console.log(`Installed to ${c.cyan}${CLAUDE_DIR}${c.reset}:`);
|
|
103
121
|
console.log(' commands/df/ — /df:spec, /df:plan, /df:execute, /df:verify');
|
|
104
122
|
console.log(' skills/ — gap-discovery, atomic-commits, code-completeness');
|
|
105
123
|
console.log(' agents/ — reasoner');
|
|
106
|
-
|
|
124
|
+
if (level === 'global') {
|
|
125
|
+
console.log(' hooks/ — statusline, update checker');
|
|
126
|
+
}
|
|
107
127
|
console.log('');
|
|
128
|
+
if (level === 'project') {
|
|
129
|
+
console.log(`${c.dim}Note: Statusline is only available with global install.${c.reset}`);
|
|
130
|
+
console.log('');
|
|
131
|
+
}
|
|
108
132
|
console.log('Quick start:');
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
133
|
+
if (level === 'global') {
|
|
134
|
+
console.log(' 1. cd your-project');
|
|
135
|
+
console.log(' 2. claude');
|
|
136
|
+
} else {
|
|
137
|
+
console.log(' 1. claude');
|
|
138
|
+
}
|
|
139
|
+
console.log(' 2. Describe what you want to build');
|
|
140
|
+
console.log(' 3. /df:spec feature-name');
|
|
113
141
|
console.log('');
|
|
114
142
|
}
|
|
115
143
|
|
|
@@ -130,9 +158,9 @@ function copyDir(src, dest) {
|
|
|
130
158
|
}
|
|
131
159
|
}
|
|
132
160
|
|
|
133
|
-
async function configureStatusline() {
|
|
134
|
-
const settingsPath = path.join(
|
|
135
|
-
const hookCmd = `node "${path.join(
|
|
161
|
+
async function configureStatusline(claudeDir) {
|
|
162
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
163
|
+
const hookCmd = `node "${path.join(claudeDir, 'hooks', 'df-statusline.js')}"`;
|
|
136
164
|
|
|
137
165
|
let settings = {};
|
|
138
166
|
|
|
@@ -177,6 +205,21 @@ function ask(question) {
|
|
|
177
205
|
});
|
|
178
206
|
}
|
|
179
207
|
|
|
208
|
+
async function askInstallLevel() {
|
|
209
|
+
console.log('Where do you want to install deepflow?');
|
|
210
|
+
console.log('');
|
|
211
|
+
console.log(` ${c.cyan}1${c.reset}) Global ${c.dim}(~/.claude/ - available in all projects)${c.reset}`);
|
|
212
|
+
console.log(` ${c.cyan}2${c.reset}) Project ${c.dim}(./.claude/ - only this project)${c.reset}`);
|
|
213
|
+
console.log('');
|
|
214
|
+
|
|
215
|
+
const answer = await ask('Choose [1/2]: ');
|
|
216
|
+
|
|
217
|
+
if (answer === '2') {
|
|
218
|
+
return 'project';
|
|
219
|
+
}
|
|
220
|
+
return 'global';
|
|
221
|
+
}
|
|
222
|
+
|
|
180
223
|
function log(msg) {
|
|
181
224
|
console.log(` ${c.green}✓${c.reset} ${msg}`);
|
|
182
225
|
}
|