@cliangdev/flux-plugin 0.0.0-dev.cf5e864 → 0.0.0-dev.df3e9bb

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.
Files changed (100) hide show
  1. package/README.md +12 -12
  2. package/agents/coder.md +192 -0
  3. package/agents/critic.md +174 -0
  4. package/agents/researcher.md +146 -0
  5. package/agents/verifier.md +149 -0
  6. package/bin/install.cjs +191 -65
  7. package/commands/breakdown.md +1 -0
  8. package/commands/flux.md +128 -84
  9. package/commands/implement.md +1 -0
  10. package/commands/linear.md +171 -0
  11. package/commands/prd.md +1 -0
  12. package/manifest.json +15 -0
  13. package/package.json +14 -13
  14. package/skills/agent-creator/SKILL.md +2 -0
  15. package/skills/epic-template/SKILL.md +2 -0
  16. package/skills/flux-orchestrator/SKILL.md +60 -76
  17. package/skills/prd-template/SKILL.md +2 -0
  18. package/src/__tests__/version.test.ts +37 -0
  19. package/src/adapters/local/.gitkeep +0 -0
  20. package/src/server/__tests__/config.test.ts +163 -0
  21. package/src/server/adapters/__tests__/a-client-linear.test.ts +197 -0
  22. package/src/server/adapters/__tests__/adapter-factory.test.ts +230 -0
  23. package/src/server/adapters/__tests__/dependency-ops.test.ts +395 -0
  24. package/src/server/adapters/__tests__/document-ops.test.ts +306 -0
  25. package/src/server/adapters/__tests__/linear-adapter.test.ts +91 -0
  26. package/src/server/adapters/__tests__/linear-config.test.ts +425 -0
  27. package/src/server/adapters/__tests__/linear-criteria-parser.test.ts +287 -0
  28. package/src/server/adapters/__tests__/linear-description-test.ts +238 -0
  29. package/src/server/adapters/__tests__/linear-epic-crud.test.ts +496 -0
  30. package/src/server/adapters/__tests__/linear-mappers-description.test.ts +276 -0
  31. package/src/server/adapters/__tests__/linear-mappers-epic.test.ts +294 -0
  32. package/src/server/adapters/__tests__/linear-mappers-prd.test.ts +300 -0
  33. package/src/server/adapters/__tests__/linear-mappers-task.test.ts +197 -0
  34. package/src/server/adapters/__tests__/linear-prd-crud.test.ts +620 -0
  35. package/src/server/adapters/__tests__/linear-stats.test.ts +450 -0
  36. package/src/server/adapters/__tests__/linear-task-crud.test.ts +534 -0
  37. package/src/server/adapters/__tests__/linear-types.test.ts +243 -0
  38. package/src/server/adapters/__tests__/status-ops.test.ts +441 -0
  39. package/src/server/adapters/factory.ts +90 -0
  40. package/src/server/adapters/index.ts +9 -0
  41. package/src/server/adapters/linear/adapter.ts +1136 -0
  42. package/src/server/adapters/linear/client.ts +169 -0
  43. package/src/server/adapters/linear/config.ts +152 -0
  44. package/src/server/adapters/linear/helpers/criteria-parser.ts +197 -0
  45. package/src/server/adapters/linear/helpers/index.ts +7 -0
  46. package/src/server/adapters/linear/index.ts +16 -0
  47. package/src/server/adapters/linear/mappers/description.ts +136 -0
  48. package/src/server/adapters/linear/mappers/epic.ts +81 -0
  49. package/src/server/adapters/linear/mappers/index.ts +27 -0
  50. package/src/server/adapters/linear/mappers/prd.ts +178 -0
  51. package/src/server/adapters/linear/mappers/task.ts +82 -0
  52. package/src/server/adapters/linear/types.ts +264 -0
  53. package/src/server/adapters/local-adapter.ts +968 -0
  54. package/src/server/adapters/types.ts +293 -0
  55. package/src/server/config.ts +73 -0
  56. package/src/server/db/__tests__/queries.test.ts +472 -0
  57. package/src/server/db/ids.ts +17 -0
  58. package/src/server/db/index.ts +69 -0
  59. package/src/server/db/queries.ts +142 -0
  60. package/src/server/db/refs.ts +60 -0
  61. package/src/server/db/schema.ts +88 -0
  62. package/src/server/db/sqlite.ts +10 -0
  63. package/src/server/index.ts +83 -0
  64. package/src/server/tools/__tests__/crud.test.ts +301 -0
  65. package/src/server/tools/__tests__/get-version.test.ts +27 -0
  66. package/src/server/tools/__tests__/mcp-interface.test.ts +388 -0
  67. package/src/server/tools/__tests__/query.test.ts +353 -0
  68. package/src/server/tools/__tests__/z-configure-linear.test.ts +511 -0
  69. package/src/server/tools/__tests__/z-get-linear-url.test.ts +108 -0
  70. package/src/server/tools/configure-linear.ts +373 -0
  71. package/src/server/tools/create-epic.ts +35 -0
  72. package/src/server/tools/create-prd.ts +31 -0
  73. package/src/server/tools/create-task.ts +38 -0
  74. package/src/server/tools/criteria.ts +50 -0
  75. package/src/server/tools/delete-entity.ts +76 -0
  76. package/src/server/tools/dependencies.ts +55 -0
  77. package/src/server/tools/get-entity.ts +238 -0
  78. package/src/server/tools/get-linear-url.ts +28 -0
  79. package/src/server/tools/get-project-context.ts +33 -0
  80. package/src/server/tools/get-stats.ts +52 -0
  81. package/src/server/tools/get-version.ts +20 -0
  82. package/src/server/tools/index.ts +114 -0
  83. package/src/server/tools/init-project.ts +108 -0
  84. package/src/server/tools/query-entities.ts +167 -0
  85. package/src/server/tools/render-status.ts +201 -0
  86. package/src/server/tools/update-entity.ts +140 -0
  87. package/src/server/tools/update-status.ts +166 -0
  88. package/src/server/utils/__tests__/mcp-response.test.ts +331 -0
  89. package/src/server/utils/logger.ts +9 -0
  90. package/src/server/utils/mcp-response.ts +254 -0
  91. package/src/server/utils/status-transitions.ts +160 -0
  92. package/src/status-line/__tests__/status-line.test.ts +215 -0
  93. package/src/status-line/index.ts +147 -0
  94. package/src/utils/__tests__/chalk-import.test.ts +32 -0
  95. package/src/utils/__tests__/display.test.ts +97 -0
  96. package/src/utils/__tests__/status-renderer.test.ts +310 -0
  97. package/src/utils/display.ts +62 -0
  98. package/src/utils/status-renderer.ts +188 -0
  99. package/src/version.ts +5 -0
  100. package/dist/server/index.js +0 -86958
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: flux-verifier
3
+ description: Verifies acceptance criteria coverage after implementation. Supports scope from multiple PRDs to a single epic. Runs tests, checks AC coverage, and generates concise verification reports.
4
+ tools: Read, Bash, Grep, Glob, mcp__flux__get_entity, mcp__flux__query_entities, mcp__flux__mark_criteria_met
5
+ model: haiku
6
+ ---
7
+
8
+ # Flux Verification Subagent
9
+
10
+ You are a quality verification agent. You verify that acceptance criteria are properly covered after implementation.
11
+
12
+ ## Scope
13
+
14
+ Verification can run at different levels:
15
+
16
+ | Scope | When | What's Verified |
17
+ |-------|------|-----------------|
18
+ | Multiple PRDs | `tag:phase-3` implementation complete | All epics across PRDs |
19
+ | Single PRD | PRD implementation complete | All epics in PRD |
20
+ | Single Epic | Epic tasks complete | All tasks in epic |
21
+
22
+ ## Verification Process
23
+
24
+ ### Step 1: Gather Data
25
+
26
+ Based on scope, fetch all relevant criteria:
27
+
28
+ ```typescript
29
+ // For PRD(s)
30
+ for (const prd of prds) {
31
+ const epics = query_entities({ type: 'epic', prd_ref: prd.ref })
32
+ // get tasks and criteria for each
33
+ }
34
+
35
+ // For single epic
36
+ get_entity({ ref: epicRef, include: ['tasks', 'criteria'] })
37
+ ```
38
+
39
+ ### Step 2: Run Tests
40
+
41
+ ```bash
42
+ # Run full test suite
43
+ bun test
44
+ # or
45
+ npm test
46
+ ```
47
+
48
+ Capture: pass/fail count, any failures.
49
+
50
+ ### Step 3: Categorize & Count Criteria
51
+
52
+ ```
53
+ [auto] criteria → must have passing test
54
+ [manual] criteria → needs user verification
55
+ ```
56
+
57
+ ### Step 4: Generate Report
58
+
59
+ **Keep it concise.** One-line summary per epic, details only for issues.
60
+
61
+ ```markdown
62
+ ## Verification Report
63
+
64
+ **Scope:** {PRD ref(s) or Epic ref}
65
+ **Tests:** ✅ 42 passed | ❌ 0 failed
66
+
67
+ | Epic | Auto | Manual | Status |
68
+ |------|------|--------|--------|
69
+ | FP-E14 | 8/8 ✅ | 2 pending | READY |
70
+ | FP-E15 | 5/6 ⚠️ | 1 pending | NEEDS_FIX |
71
+
72
+ ### Issues
73
+ - FP-E15: Missing test for "validates email format"
74
+
75
+ ### Manual Verification Checklist
76
+ - [ ] FP-E14: Error messages are user-friendly → Check message clarity
77
+ - [ ] FP-E14: UI renders on mobile → Test on phone
78
+ - [ ] FP-E15: Loading feels smooth → Test on slow network
79
+
80
+ ### Suggested Manual Test Cases
81
+
82
+ For criteria without explicit verification steps:
83
+
84
+ 1. **"User can cancel operation"**
85
+ - Start a long operation
86
+ - Press Cancel or Ctrl+C
87
+ - Verify operation stops and state is clean
88
+
89
+ 2. **"Form validates correctly"**
90
+ - Submit empty form → expect validation errors
91
+ - Submit with invalid email → expect email error
92
+ - Submit valid data → expect success
93
+
94
+ ### Recommendation
95
+ {READY | NEEDS_FIX | BLOCKED}: {one-line reason}
96
+ ```
97
+
98
+ ## Suggesting Manual Test Cases
99
+
100
+ When `[manual]` criteria lack explicit verification steps (no `→ Verify:`), suggest test cases:
101
+
102
+ | Criterion Pattern | Suggested Test |
103
+ |-------------------|----------------|
104
+ | "renders correctly" | Visual check on target device/browser |
105
+ | "feels smooth/fast" | Test on slow network/device |
106
+ | "user-friendly" | Have someone unfamiliar try it |
107
+ | "accessible" | Test with screen reader, keyboard nav |
108
+ | "works offline" | Disable network, test functionality |
109
+ | "handles errors" | Trigger error conditions, check recovery |
110
+
111
+ ## Marking Criteria Met
112
+
113
+ ```typescript
114
+ // Only auto-mark [auto] criteria when tests pass
115
+ mark_criteria_met({ criteria_id: criterionId })
116
+ ```
117
+
118
+ Leave `[manual]` criteria for user to confirm after verification.
119
+
120
+ ## Output to Orchestrator
121
+
122
+ **Concise format:**
123
+
124
+ ```
125
+ ## Verification: {PASSED | NEEDS_FIX | BLOCKED}
126
+
127
+ Tests: 42/42 ✅
128
+ Auto AC: 15/16 (1 missing test)
129
+ Manual AC: 4 pending
130
+
131
+ Issues:
132
+ - {issue 1}
133
+
134
+ Manual Checklist:
135
+ - [ ] {item 1}
136
+ - [ ] {item 2}
137
+
138
+ Suggested Tests:
139
+ - {suggestion if no explicit steps}
140
+ ```
141
+
142
+ ## Boundaries
143
+
144
+ - **DO** run tests and report results
145
+ - **DO** keep reports concise
146
+ - **DO** suggest manual test cases when steps are missing
147
+ - **DON'T** mark manual criteria as met
148
+ - **DON'T** write new tests or modify code
149
+ - **DON'T** generate verbose reports - be brief
package/bin/install.cjs CHANGED
@@ -4,31 +4,47 @@ const fs = require("fs");
4
4
  const path = require("path");
5
5
  const os = require("os");
6
6
  const readline = require("readline");
7
+ const { execSync, spawn } = require("child_process");
7
8
 
8
- // Parse args first to check for serve command
9
9
  const args = process.argv.slice(2);
10
10
 
11
- // Check for "serve" subcommand - starts MCP server
12
11
  if (args[0] === "serve") {
13
- // Dynamic import to load ESM server
14
- import("../dist/server/index.js").catch((err) => {
12
+ const serverSrc = path.join(__dirname, "..", "src", "server", "index.ts");
13
+ const bunPath = getBunPath();
14
+ if (!bunPath) {
15
+ console.error("Failed to start Flux MCP server: Bun is required but not found");
16
+ process.exit(1);
17
+ }
18
+ const child = spawn(bunPath, ["run", serverSrc], { stdio: "inherit" });
19
+ child.on("error", (err) => {
15
20
  console.error("Failed to start Flux MCP server:", err.message);
16
21
  process.exit(1);
17
22
  });
23
+ child.on("close", (code) => process.exit(code || 0));
18
24
  } else {
19
- // Run installer
20
25
  runInstaller();
21
26
  }
22
27
 
28
+ function getBunPath() {
29
+ const bunDir = path.join(os.homedir(), ".bun", "bin");
30
+ const bunBinary = process.platform === "win32" ? "bun.exe" : "bun";
31
+ const localBunPath = path.join(bunDir, bunBinary);
32
+ if (fs.existsSync(localBunPath)) return localBunPath;
33
+ try {
34
+ execSync("bun --version", { stdio: "ignore" });
35
+ return "bun";
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
23
41
  function runInstaller() {
24
- // Colors
25
42
  const cyan = "\x1b[36m";
26
43
  const green = "\x1b[32m";
27
44
  const yellow = "\x1b[33m";
45
+ const red = "\x1b[31m";
28
46
  const dim = "\x1b[2m";
29
47
  const reset = "\x1b[0m";
30
-
31
- // Get version from package.json
32
48
  const pkg = require("../package.json");
33
49
 
34
50
  const banner = `
@@ -49,9 +65,8 @@ ${cyan} ███████╗██╗ ██╗ ██╗██╗
49
65
 
50
66
  console.log(banner);
51
67
 
52
- // Show help
53
68
  if (hasHelp) {
54
- console.log(` ${yellow}Usage:${reset} npx @cliangdev/flux-plugin [options]
69
+ console.log(` ${yellow}Usage:${reset} bunx @cliangdev/flux-plugin [options]
55
70
 
56
71
  ${yellow}Options:${reset}
57
72
  ${cyan}-g, --global${reset} Install globally (to ~/.claude)
@@ -60,20 +75,123 @@ ${cyan} ███████╗██╗ ██╗ ██╗██╗
60
75
 
61
76
  ${yellow}Examples:${reset}
62
77
  ${dim}# Interactive installation${reset}
63
- npx @cliangdev/flux-plugin
78
+ bunx @cliangdev/flux-plugin
64
79
 
65
80
  ${dim}# Install globally (all projects)${reset}
66
- npx @cliangdev/flux-plugin --global
81
+ bunx @cliangdev/flux-plugin --global
67
82
 
68
83
  ${dim}# Install locally (current project only)${reset}
69
- npx @cliangdev/flux-plugin --local
84
+ bunx @cliangdev/flux-plugin --local
85
+
86
+ ${yellow}Note:${reset} This plugin requires Bun. Install from https://bun.sh
70
87
  `);
71
88
  process.exit(0);
72
89
  }
73
90
 
74
- /**
75
- * Recursively copy directory
76
- */
91
+ function isBunInstalled() {
92
+ const bunDir = path.join(os.homedir(), ".bun", "bin");
93
+ const envPath = process.env.PATH || "";
94
+ const pathWithBun = envPath.includes(bunDir)
95
+ ? envPath
96
+ : `${bunDir}${path.delimiter}${envPath}`;
97
+
98
+ try {
99
+ execSync("bun --version", {
100
+ stdio: "ignore",
101
+ env: { ...process.env, PATH: pathWithBun },
102
+ });
103
+ return true;
104
+ } catch {
105
+ return false;
106
+ }
107
+ }
108
+
109
+ function installBun() {
110
+ return new Promise((resolve, reject) => {
111
+ const platform = os.platform();
112
+ const installCmd = platform === "win32" ? "powershell" : "/bin/sh";
113
+ const installArgs = platform === "win32"
114
+ ? ["-c", "irm bun.sh/install.ps1 | iex"]
115
+ : ["-c", "curl -fsSL https://bun.sh/install | bash"];
116
+
117
+ console.log(`\n ${cyan}Installing Bun...${reset}\n`);
118
+
119
+ const child = spawn(installCmd, installArgs, {
120
+ stdio: "inherit",
121
+ shell: false,
122
+ });
123
+
124
+ child.on("close", (code) => {
125
+ if (code === 0) {
126
+ console.log(`\n ${green}✓${reset} Bun installed successfully\n`);
127
+ resolve(true);
128
+ } else {
129
+ reject(new Error(`Installation exited with code ${code}`));
130
+ }
131
+ });
132
+
133
+ child.on("error", (err) => {
134
+ reject(err);
135
+ });
136
+ });
137
+ }
138
+
139
+ function showBunInstallInstructions() {
140
+ console.log(`
141
+ ${yellow}Bun is required but not installed.${reset}
142
+
143
+ Install Bun manually:
144
+
145
+ ${cyan}macOS/Linux:${reset}
146
+ curl -fsSL https://bun.sh/install | bash
147
+
148
+ ${cyan}Windows:${reset}
149
+ powershell -c "irm bun.sh/install.ps1 | iex"
150
+
151
+ Then restart your terminal and run this installer again.
152
+
153
+ ${dim}Learn more: https://bun.sh${reset}
154
+ `);
155
+ }
156
+
157
+ async function checkBunAndContinue(callback) {
158
+ if (isBunInstalled()) {
159
+ callback();
160
+ return;
161
+ }
162
+
163
+ const rl = readline.createInterface({
164
+ input: process.stdin,
165
+ output: process.stdout,
166
+ });
167
+
168
+ console.log(` ${yellow}Bun is required but not installed.${reset}\n`);
169
+
170
+ rl.question(` Install Bun now? ${dim}[Y/n]${reset}: `, async (answer) => {
171
+ rl.close();
172
+ const shouldInstall = answer.trim().toLowerCase() !== "n";
173
+
174
+ if (shouldInstall) {
175
+ try {
176
+ await installBun();
177
+ if (isBunInstalled()) {
178
+ callback();
179
+ } else {
180
+ console.log(` ${yellow}Please restart your terminal to use Bun, then run the installer again.${reset}\n`);
181
+ process.exit(0);
182
+ }
183
+ } catch (err) {
184
+ console.log(`\n ${red}Failed to install Bun:${reset} ${err.message}\n`);
185
+ showBunInstallInstructions();
186
+ process.exit(1);
187
+ }
188
+ } else {
189
+ showBunInstallInstructions();
190
+ process.exit(1);
191
+ }
192
+ });
193
+ }
194
+
77
195
  function copyDir(src, dest) {
78
196
  fs.mkdirSync(dest, { recursive: true });
79
197
  const entries = fs.readdirSync(src, { withFileTypes: true });
@@ -90,9 +208,6 @@ ${cyan} ███████╗██╗ ██╗ ██╗██╗
90
208
  }
91
209
  }
92
210
 
93
- /**
94
- * Read JSON file, return empty object if doesn't exist
95
- */
96
211
  function readJson(filePath) {
97
212
  if (fs.existsSync(filePath)) {
98
213
  try {
@@ -104,58 +219,53 @@ ${cyan} ███████╗██╗ ██╗ ██╗██╗
104
219
  return {};
105
220
  }
106
221
 
107
- /**
108
- * Write JSON file with formatting
109
- */
110
222
  function writeJson(filePath, data) {
111
223
  fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
112
224
  }
113
225
 
114
- /**
115
- * Install to specified directory
116
- */
117
226
  function install(isGlobal) {
118
227
  const src = path.join(__dirname, "..");
119
228
  const claudeDir = isGlobal
120
229
  ? path.join(os.homedir(), ".claude")
121
230
  : path.join(process.cwd(), ".claude");
122
-
123
231
  const locationLabel = isGlobal ? "~/.claude" : "./.claude";
124
232
 
125
233
  console.log(` Installing to ${cyan}${locationLabel}${reset}\n`);
126
234
 
127
- // Create directories
128
235
  fs.mkdirSync(claudeDir, { recursive: true });
129
236
 
130
- // Copy commands
131
237
  const commandsSrc = path.join(src, "commands");
132
238
  if (fs.existsSync(commandsSrc)) {
133
239
  const commandsDest = path.join(claudeDir, "commands");
134
- fs.mkdirSync(commandsDest, { recursive: true });
240
+ const fluxSubDir = path.join(commandsDest, "flux");
241
+ fs.mkdirSync(fluxSubDir, { recursive: true });
135
242
 
136
- // Copy each command as a directory (flux.md -> commands/flux/COMMAND.md)
137
243
  const commandFiles = fs.readdirSync(commandsSrc);
138
244
  for (const file of commandFiles) {
139
245
  if (file.endsWith(".md")) {
140
246
  const name = file.replace(".md", "");
141
- const destDir = path.join(commandsDest, name);
142
- fs.mkdirSync(destDir, { recursive: true });
143
- fs.copyFileSync(
144
- path.join(commandsSrc, file),
145
- path.join(destDir, "COMMAND.md")
146
- );
147
- console.log(` ${green}✓${reset} Installed command: /${name}`);
247
+ if (name === "flux") {
248
+ fs.copyFileSync(
249
+ path.join(commandsSrc, file),
250
+ path.join(commandsDest, file)
251
+ );
252
+ console.log(` ${green}✓${reset} Installed command: /flux`);
253
+ } else {
254
+ fs.copyFileSync(
255
+ path.join(commandsSrc, file),
256
+ path.join(fluxSubDir, file)
257
+ );
258
+ console.log(` ${green}✓${reset} Installed command: /flux:${name}`);
259
+ }
148
260
  }
149
261
  }
150
262
  }
151
263
 
152
- // Copy skills
153
264
  const skillsSrc = path.join(src, "skills");
154
265
  if (fs.existsSync(skillsSrc)) {
155
266
  const skillsDest = path.join(claudeDir, "skills");
156
267
  fs.mkdirSync(skillsDest, { recursive: true });
157
268
 
158
- // Copy each skill directory
159
269
  const skillDirs = fs.readdirSync(skillsSrc, { withFileTypes: true });
160
270
  for (const dir of skillDirs) {
161
271
  if (dir.isDirectory()) {
@@ -168,29 +278,45 @@ ${cyan} ███████╗██╗ ██╗ ██╗██╗
168
278
  }
169
279
  }
170
280
 
171
- // Configure MCP server
172
- const claudeJsonPath = isGlobal
281
+ const agentsSrc = path.join(src, "agents");
282
+ if (fs.existsSync(agentsSrc)) {
283
+ const agentsDest = path.join(claudeDir, "agents");
284
+ fs.mkdirSync(agentsDest, { recursive: true });
285
+
286
+ const agentFiles = fs.readdirSync(agentsSrc);
287
+ for (const file of agentFiles) {
288
+ if (file.endsWith(".md")) {
289
+ fs.copyFileSync(
290
+ path.join(agentsSrc, file),
291
+ path.join(agentsDest, file)
292
+ );
293
+ const name = file.replace(".md", "");
294
+ console.log(` ${green}✓${reset} Installed agent: ${name}`);
295
+ }
296
+ }
297
+ }
298
+
299
+ const mcpConfigPath = isGlobal
173
300
  ? path.join(os.homedir(), ".claude.json")
174
- : path.join(process.cwd(), ".claude.json");
301
+ : path.join(process.cwd(), ".mcp.json");
175
302
 
176
- const claudeJson = readJson(claudeJsonPath);
303
+ const mcpConfig = readJson(mcpConfigPath);
177
304
 
178
- if (!claudeJson.mcpServers) {
179
- claudeJson.mcpServers = {};
305
+ if (!mcpConfig.mcpServers) {
306
+ mcpConfig.mcpServers = {};
180
307
  }
181
308
 
182
- // Add or update flux MCP server
183
- claudeJson.mcpServers.flux = {
184
- command: "npx",
185
- args: ["-y", "@cliangdev/flux-plugin", "serve"],
309
+ const versionTag = pkg.version.includes("-dev.") ? "latest" : pkg.version;
310
+ mcpConfig.mcpServers.flux = {
311
+ command: "bunx",
312
+ args: [`@cliangdev/flux-plugin@${versionTag}`, "serve"],
186
313
  };
187
314
 
188
- writeJson(claudeJsonPath, claudeJson);
315
+ writeJson(mcpConfigPath, mcpConfig);
189
316
  console.log(
190
- ` ${green}✓${reset} Configured MCP server in ${isGlobal ? "~/.claude.json" : "./.claude.json"}`
317
+ ` ${green}✓${reset} Configured MCP server in ${isGlobal ? "~/.claude.json" : "./.mcp.json"}`
191
318
  );
192
319
 
193
- // Write version file for update checking
194
320
  const versionFile = path.join(claudeDir, "flux-version");
195
321
  fs.writeFileSync(versionFile, pkg.version);
196
322
 
@@ -207,9 +333,6 @@ ${cyan} ███████╗██╗ ██╗ ██╗██╗
207
333
  `);
208
334
  }
209
335
 
210
- /**
211
- * Prompt for install location
212
- */
213
336
  function promptLocation() {
214
337
  const rl = readline.createInterface({
215
338
  input: process.stdin,
@@ -229,15 +352,18 @@ ${cyan} ███████╗██╗ ██╗ ██╗██╗
229
352
  });
230
353
  }
231
354
 
232
- // Main
233
- if (hasGlobal && hasLocal) {
234
- console.error(` ${yellow}Cannot specify both --global and --local${reset}`);
235
- process.exit(1);
236
- } else if (hasGlobal) {
237
- install(true);
238
- } else if (hasLocal) {
239
- install(false);
240
- } else {
241
- promptLocation();
355
+ function startInstallation() {
356
+ if (hasGlobal && hasLocal) {
357
+ console.error(` ${yellow}Cannot specify both --global and --local${reset}`);
358
+ process.exit(1);
359
+ } else if (hasGlobal) {
360
+ install(true);
361
+ } else if (hasLocal) {
362
+ install(false);
363
+ } else {
364
+ promptLocation();
365
+ }
242
366
  }
367
+
368
+ checkBunAndContinue(startInstallation);
243
369
  }
@@ -1,4 +1,5 @@
1
1
  ---
2
+ name: flux:breakdown
2
3
  description: Break approved PRD into dependency-ordered epics and tasks
3
4
  allowed-tools: mcp__flux__*, Read, AskUserQuestion
4
5
  ---