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.
@@ -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**, ask targeted questions (see skill for categories).
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 5 questions per round. Wait for answers before proceeding.
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: A few questions before I create the spec:
85
-
86
- 1. **File types**: Just images (jpg/png), or also gifs/videos?
87
- 2. **Size limit**: Max file size?
88
- 3. **Storage**: Local, S3, or other?
89
- 4. **Auth**: Anyone can upload, or logged-in users only?
90
-
91
- USER: jpg/png/webp only, max 10MB, S3, logged-in only
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. Ask 3-5 targeted questions (not overwhelming)
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
- - Max 5 questions per round
43
- - Be specific, offer choices when possible
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
1
+ 0.1.3
package/bin/install.js CHANGED
@@ -19,23 +19,35 @@ const c = {
19
19
  };
20
20
 
21
21
  // Paths
22
- const CLAUDE_DIR = path.join(os.homedir(), '.claude');
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}Installing deepflow...${c.reset}`);
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
- const hooksDir = path.join(PACKAGE_DIR, 'hooks');
66
- if (fs.existsSync(hooksDir)) {
67
- for (const file of fs.readdirSync(hooksDir)) {
68
- if (file.endsWith('.js')) {
69
- fs.copyFileSync(
70
- path.join(hooksDir, file),
71
- path.join(CLAUDE_DIR, 'hooks', file)
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
- const versionFile = path.join(PACKAGE_DIR, 'VERSION');
80
- if (fs.existsSync(versionFile)) {
81
- fs.copyFileSync(versionFile, path.join(CLAUDE_DIR, 'deepflow', 'VERSION'));
82
- log('Version file installed');
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
- await configureStatusline();
87
-
88
- // Trigger background update check
89
- const updateChecker = path.join(CLAUDE_DIR, 'hooks', 'df-check-update.js');
90
- if (fs.existsSync(updateChecker)) {
91
- const { spawn } = require('child_process');
92
- const child = spawn(process.execPath, [updateChecker], {
93
- detached: true,
94
- stdio: 'ignore'
95
- });
96
- child.unref();
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
- console.log(' hooks/ — statusline, update checker');
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
- console.log(' 1. cd your-project');
110
- console.log(' 2. claude');
111
- console.log(' 3. Describe what you want to build');
112
- console.log(' 4. /df:spec feature-name');
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(CLAUDE_DIR, 'settings.json');
135
- const hookCmd = `node "${path.join(CLAUDE_DIR, 'hooks', 'df-statusline.js')}"`;
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepflow",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Stay in flow state - lightweight spec-driven task orchestration for Claude Code",
5
5
  "keywords": [
6
6
  "claude",