@curdx/flow 2.3.11 → 3.1.0

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 (210) hide show
  1. package/CHANGELOG.md +21 -34
  2. package/LICENSE +1 -1
  3. package/README.md +28 -79
  4. package/dist/index.mjs +995 -0
  5. package/package.json +33 -42
  6. package/.claude-plugin/marketplace.json +0 -48
  7. package/.claude-plugin/plugin.json +0 -70
  8. package/agent-preamble/preamble.md +0 -314
  9. package/agents/flow-adversary.md +0 -202
  10. package/agents/flow-architect.md +0 -197
  11. package/agents/flow-brownfield-analyst.md +0 -142
  12. package/agents/flow-debugger.md +0 -321
  13. package/agents/flow-edge-hunter.md +0 -288
  14. package/agents/flow-executor.md +0 -269
  15. package/agents/flow-orchestrator.md +0 -145
  16. package/agents/flow-planner.md +0 -246
  17. package/agents/flow-product-designer.md +0 -159
  18. package/agents/flow-qa-engineer.md +0 -282
  19. package/agents/flow-researcher.md +0 -165
  20. package/agents/flow-reviewer.md +0 -303
  21. package/agents/flow-security-auditor.md +0 -401
  22. package/agents/flow-triage-analyst.md +0 -272
  23. package/agents/flow-ui-researcher.md +0 -229
  24. package/agents/flow-ux-designer.md +0 -221
  25. package/agents/flow-verifier.md +0 -349
  26. package/bin/curdx-flow +0 -5
  27. package/bin/curdx-flow.js +0 -54
  28. package/cli/README.md +0 -104
  29. package/cli/doctor-workflow.js +0 -483
  30. package/cli/doctor.js +0 -73
  31. package/cli/help.js +0 -59
  32. package/cli/install-bundled-mcps.js +0 -37
  33. package/cli/install-companions.js +0 -19
  34. package/cli/install-context7-config.js +0 -80
  35. package/cli/install-curdx-plugin.js +0 -96
  36. package/cli/install-language.js +0 -35
  37. package/cli/install-next-steps.js +0 -29
  38. package/cli/install-options.js +0 -9
  39. package/cli/install-paths.js +0 -52
  40. package/cli/install-recommended-plugins.js +0 -104
  41. package/cli/install-required-plugins.js +0 -57
  42. package/cli/install-self-update.js +0 -62
  43. package/cli/install-workflow.js +0 -209
  44. package/cli/install.js +0 -101
  45. package/cli/lib/claude-commands.js +0 -41
  46. package/cli/lib/claude-ops.js +0 -47
  47. package/cli/lib/claude.js +0 -183
  48. package/cli/lib/config.js +0 -24
  49. package/cli/lib/doctor-claude-settings.js +0 -1186
  50. package/cli/lib/doctor-report.js +0 -978
  51. package/cli/lib/doctor-runtime-environment.js +0 -196
  52. package/cli/lib/frontmatter.js +0 -44
  53. package/cli/lib/json-schema.js +0 -57
  54. package/cli/lib/logging.js +0 -25
  55. package/cli/lib/process.js +0 -60
  56. package/cli/lib/prompts.js +0 -135
  57. package/cli/lib/runtime.js +0 -107
  58. package/cli/lib/semver.js +0 -109
  59. package/cli/lib/version.js +0 -12
  60. package/cli/protocols-body.md +0 -22
  61. package/cli/protocols.js +0 -162
  62. package/cli/registry.js +0 -123
  63. package/cli/router.js +0 -49
  64. package/cli/uninstall-actions.js +0 -360
  65. package/cli/uninstall-workflow.js +0 -146
  66. package/cli/uninstall.js +0 -42
  67. package/cli/upgrade-workflow.js +0 -80
  68. package/cli/upgrade.js +0 -91
  69. package/cli/utils.js +0 -40
  70. package/gates/adversarial-review-gate.md +0 -219
  71. package/gates/coverage-audit-gate.md +0 -182
  72. package/gates/devex-gate.md +0 -254
  73. package/gates/edge-case-gate.md +0 -194
  74. package/gates/karpathy-gate.md +0 -130
  75. package/gates/security-gate.md +0 -218
  76. package/gates/tdd-gate.md +0 -182
  77. package/gates/test-quality-gate.md +0 -59
  78. package/gates/verification-gate.md +0 -179
  79. package/hooks/hooks.json +0 -58
  80. package/hooks/scripts/common.sh +0 -46
  81. package/hooks/scripts/inject-karpathy.sh +0 -53
  82. package/hooks/scripts/quick-mode-guard.sh +0 -68
  83. package/hooks/scripts/session-start.sh +0 -90
  84. package/hooks/scripts/stop-watcher.sh +0 -230
  85. package/hooks/scripts/subagent-artifact-guard.sh +0 -159
  86. package/hooks/scripts/subagent-statusline.sh +0 -105
  87. package/knowledge/artifact-output-discipline.md +0 -24
  88. package/knowledge/artifact-summary-contracts.md +0 -50
  89. package/knowledge/atomic-commits.md +0 -262
  90. package/knowledge/claude-code-runtime-contracts.md +0 -219
  91. package/knowledge/epic-decomposition.md +0 -307
  92. package/knowledge/execution-strategies.md +0 -303
  93. package/knowledge/karpathy-guidelines.md +0 -219
  94. package/knowledge/planning-reviews.md +0 -211
  95. package/knowledge/poc-first-workflow.md +0 -223
  96. package/knowledge/review-feedback-intake.md +0 -57
  97. package/knowledge/spec-driven-development.md +0 -180
  98. package/knowledge/systematic-debugging.md +0 -378
  99. package/knowledge/two-stage-review.md +0 -249
  100. package/knowledge/wave-execution.md +0 -403
  101. package/monitors/monitors.json +0 -8
  102. package/monitors/scripts/flow-state-monitor.sh +0 -99
  103. package/output-styles/curdx-evidence-first.md +0 -34
  104. package/schemas/agent-frontmatter.schema.json +0 -63
  105. package/schemas/config.schema.json +0 -134
  106. package/schemas/gate-frontmatter.schema.json +0 -30
  107. package/schemas/hooks.schema.json +0 -115
  108. package/schemas/output-style-frontmatter.schema.json +0 -22
  109. package/schemas/plugin-manifest.schema.json +0 -436
  110. package/schemas/plugin-settings.schema.json +0 -29
  111. package/schemas/skill-frontmatter.schema.json +0 -177
  112. package/schemas/spec-frontmatter.schema.json +0 -42
  113. package/schemas/spec-state.schema.json +0 -147
  114. package/settings.json +0 -7
  115. package/skills/brownfield-index/SKILL.md +0 -53
  116. package/skills/brownfield-index/references/applicability.md +0 -12
  117. package/skills/brownfield-index/references/handoff.md +0 -8
  118. package/skills/brownfield-index/references/index-contract.md +0 -10
  119. package/skills/browser-qa/SKILL.md +0 -39
  120. package/skills/browser-qa/references/handoff.md +0 -6
  121. package/skills/browser-qa/references/prerequisites.md +0 -10
  122. package/skills/browser-qa/references/qa-contract.md +0 -20
  123. package/skills/cancel/SKILL.md +0 -41
  124. package/skills/cancel/references/destructive-mode.md +0 -17
  125. package/skills/cancel/references/reporting.md +0 -18
  126. package/skills/cancel/references/state-recovery.md +0 -30
  127. package/skills/cancel/references/target-resolution.md +0 -7
  128. package/skills/debug/SKILL.md +0 -45
  129. package/skills/debug/references/context-gathering.md +0 -11
  130. package/skills/debug/references/failure-guard.md +0 -25
  131. package/skills/debug/references/intake.md +0 -12
  132. package/skills/debug/references/phase-workflow.md +0 -34
  133. package/skills/debug/references/reporting.md +0 -20
  134. package/skills/epic/SKILL.md +0 -39
  135. package/skills/epic/references/epic-artifacts.md +0 -20
  136. package/skills/epic/references/epic-intake.md +0 -9
  137. package/skills/epic/references/slice-handoff.md +0 -16
  138. package/skills/fast/SKILL.md +0 -62
  139. package/skills/fast/references/applicability.md +0 -25
  140. package/skills/fast/references/clarification.md +0 -20
  141. package/skills/fast/references/execution-contract.md +0 -56
  142. package/skills/help/SKILL.md +0 -55
  143. package/skills/help/references/dispatch.md +0 -20
  144. package/skills/help/references/overview.md +0 -39
  145. package/skills/help/references/troubleshoot.md +0 -47
  146. package/skills/help/references/workflow.md +0 -37
  147. package/skills/implement/SKILL.md +0 -96
  148. package/skills/implement/references/error-recovery.md +0 -36
  149. package/skills/implement/references/linear-execution.md +0 -32
  150. package/skills/implement/references/preflight.md +0 -43
  151. package/skills/implement/references/progress-contract.md +0 -32
  152. package/skills/implement/references/state-init.md +0 -33
  153. package/skills/implement/references/stop-hook-execution.md +0 -36
  154. package/skills/implement/references/strategy-router.md +0 -38
  155. package/skills/implement/references/subagent-execution.md +0 -43
  156. package/skills/implement/references/wave-execution.md +0 -162
  157. package/skills/init/SKILL.md +0 -49
  158. package/skills/init/references/gitignore-and-health.md +0 -26
  159. package/skills/init/references/next-steps.md +0 -22
  160. package/skills/init/references/preflight.md +0 -15
  161. package/skills/init/references/scaffold-contract.md +0 -27
  162. package/skills/review/SKILL.md +0 -82
  163. package/skills/review/references/optional-passes.md +0 -48
  164. package/skills/review/references/preflight.md +0 -38
  165. package/skills/review/references/report-contract.md +0 -49
  166. package/skills/review/references/reporting.md +0 -20
  167. package/skills/review/references/stage-execution.md +0 -32
  168. package/skills/security-audit/SKILL.md +0 -47
  169. package/skills/security-audit/references/audit-contract.md +0 -21
  170. package/skills/security-audit/references/gate-handoff.md +0 -8
  171. package/skills/security-audit/references/scope-and-depth.md +0 -9
  172. package/skills/spec/SKILL.md +0 -100
  173. package/skills/spec/references/artifact-landing.md +0 -31
  174. package/skills/spec/references/phase-execution.md +0 -50
  175. package/skills/spec/references/planning-review.md +0 -31
  176. package/skills/spec/references/preflight-and-routing.md +0 -46
  177. package/skills/spec/references/reporting.md +0 -21
  178. package/skills/start/SKILL.md +0 -84
  179. package/skills/start/references/branch-routing.md +0 -51
  180. package/skills/start/references/mode-semantics.md +0 -12
  181. package/skills/start/references/preflight.md +0 -13
  182. package/skills/start/references/reporting.md +0 -20
  183. package/skills/start/references/state-seeding.md +0 -44
  184. package/skills/start/references/workflow-handoff.md +0 -26
  185. package/skills/status/SKILL.md +0 -41
  186. package/skills/status/references/gather-contract.md +0 -27
  187. package/skills/status/references/health-rules.md +0 -27
  188. package/skills/status/references/output-contract.md +0 -24
  189. package/skills/status/references/preflight.md +0 -10
  190. package/skills/status/references/recovery-hints.md +0 -18
  191. package/skills/ui-sketch/SKILL.md +0 -39
  192. package/skills/ui-sketch/references/brief-intake.md +0 -10
  193. package/skills/ui-sketch/references/iteration-handoff.md +0 -5
  194. package/skills/ui-sketch/references/variant-contract.md +0 -15
  195. package/skills/verify/SKILL.md +0 -56
  196. package/skills/verify/references/evidence-workflow.md +0 -39
  197. package/skills/verify/references/output-contract.md +0 -23
  198. package/skills/verify/references/preflight.md +0 -11
  199. package/skills/verify/references/report-handoff.md +0 -35
  200. package/skills/verify/references/strict-mode.md +0 -12
  201. package/templates/CONTEXT.md.tmpl +0 -53
  202. package/templates/PROJECT.md.tmpl +0 -59
  203. package/templates/ROADMAP.md.tmpl +0 -50
  204. package/templates/STATE.md.tmpl +0 -49
  205. package/templates/config.json.tmpl +0 -51
  206. package/templates/design.md.tmpl +0 -83
  207. package/templates/progress.md.tmpl +0 -77
  208. package/templates/requirements.md.tmpl +0 -76
  209. package/templates/research.md.tmpl +0 -83
  210. package/templates/tasks.md.tmpl +0 -107
@@ -1,483 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- import { removeMcp } from "./lib/claude-ops.js";
6
- import { readProjectClaudeSettings } from "./lib/doctor-claude-settings.js";
7
- import { CONFIG_FILE, readConfig, writeConfig } from "./lib/config.js";
8
- import { inspectRuntimeEnvironment } from "./lib/doctor-runtime-environment.js";
9
- import {
10
- claudeVersion,
11
- color,
12
- ensureClaudeMemRuntimes,
13
- inspectClaudeMemRuntimes,
14
- listMcps,
15
- listPluginMarketplaces,
16
- listPlugins,
17
- log,
18
- readUserMcpConfig,
19
- runSync,
20
- } from "./utils.js";
21
-
22
- export { readProjectClaudeSettings };
23
- export { inspectRuntimeEnvironment };
24
-
25
- const PACKAGE_ROOT = fileURLToPath(new URL("../", import.meta.url));
26
- export const DOCTOR_JSON_CONTRACT_VERSION = 2;
27
- export const DOCTOR_SETTINGS_INSPECTION = Object.freeze({
28
- pluginOptionScopesInspected: ["managed-file", "user", "project", "local"],
29
- pluginOptionScopesNotInspected: ["managed-server", "managed-mdm", "cli"],
30
- });
31
-
32
- export function createDoctorContext(args = []) {
33
- return {
34
- fix: args.includes("--fix"),
35
- json: args.includes("--json"),
36
- verbose: args.includes("--verbose") || args.includes("-v"),
37
- };
38
- }
39
-
40
- function isUrlLike(value) {
41
- return /^[a-z][a-z0-9+.-]*:\/\//i.test(value);
42
- }
43
-
44
- function isWindowsAbsolutePath(value) {
45
- return /^[A-Za-z]:[\\/]/.test(value);
46
- }
47
-
48
- function looksLikeRelativePathToken(value) {
49
- if (typeof value !== "string") return false;
50
- const token = value.trim();
51
- if (!token) return false;
52
-
53
- if (token.startsWith("./") || token.startsWith("../")) return true;
54
- if (!/[\\/]/.test(token)) return false;
55
-
56
- if (
57
- token.startsWith("/") ||
58
- token.startsWith("~/") ||
59
- token.startsWith("${") ||
60
- token.startsWith("@") ||
61
- token.startsWith("--") ||
62
- isUrlLike(token) ||
63
- isWindowsAbsolutePath(token)
64
- ) {
65
- return false;
66
- }
67
-
68
- return (
69
- /\.(?:[cm]?js|mjs|ts|tsx|jsx|py|rb|sh|bash|zsh|fish|ps1|cmd|bat|exe)$/i.test(token) ||
70
- /(^|[\\/])(?:scripts?|bin|dist|src|tools|vendor|node_modules|venv|\.venv)([\\/]|$)/i.test(token)
71
- );
72
- }
73
- export async function readProjectMcpConfig(cwd = process.cwd()) {
74
- const rootPath = path.join(cwd, ".mcp.json");
75
- const misplacedPath = path.join(cwd, ".claude", ".mcp.json");
76
-
77
- const state = {
78
- exists: false,
79
- misplacedExists: false,
80
- invalid: false,
81
- parseError: null,
82
- shapeError: null,
83
- serverCount: 0,
84
- relativePathWarnings: [],
85
- };
86
-
87
- try {
88
- const misplacedStat = await fs.stat(misplacedPath);
89
- state.misplacedExists = misplacedStat.isFile();
90
- } catch {
91
- state.misplacedExists = false;
92
- }
93
-
94
- try {
95
- const stat = await fs.stat(rootPath);
96
- if (!stat.isFile()) return state;
97
- state.exists = true;
98
- } catch {
99
- return state;
100
- }
101
-
102
- let parsed;
103
- try {
104
- parsed = JSON.parse(await fs.readFile(rootPath, "utf-8"));
105
- } catch (error) {
106
- state.invalid = true;
107
- state.parseError = error.message;
108
- return state;
109
- }
110
-
111
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
112
- state.shapeError = "root value must be a JSON object";
113
- return state;
114
- }
115
-
116
- if (!parsed.mcpServers || typeof parsed.mcpServers !== "object" || Array.isArray(parsed.mcpServers)) {
117
- state.shapeError = 'missing top-level "mcpServers" object';
118
- return state;
119
- }
120
-
121
- state.serverCount = Object.keys(parsed.mcpServers).length;
122
-
123
- for (const [serverName, config] of Object.entries(parsed.mcpServers)) {
124
- if (!config || typeof config !== "object" || Array.isArray(config)) continue;
125
-
126
- if (looksLikeRelativePathToken(config.command)) {
127
- state.relativePathWarnings.push({
128
- serverName,
129
- field: "command",
130
- value: config.command,
131
- });
132
- }
133
-
134
- const args = Array.isArray(config.args) ? config.args : [];
135
- args.forEach((arg, index) => {
136
- if (!looksLikeRelativePathToken(arg)) return;
137
- state.relativePathWarnings.push({
138
- serverName,
139
- field: `args[${index}]`,
140
- value: arg,
141
- });
142
- });
143
- }
144
-
145
- return state;
146
- }
147
-
148
- export async function readProjectTeamConfig(cwd = process.cwd()) {
149
- const teamConfigPath = path.join(cwd, ".claude", "teams", "teams.json");
150
- const state = {
151
- exists: false,
152
- };
153
-
154
- try {
155
- const stat = await fs.stat(teamConfigPath);
156
- state.exists = stat.isFile();
157
- } catch {
158
- state.exists = false;
159
- }
160
-
161
- return state;
162
- }
163
-
164
- export async function readBundledPluginRuntimeDefaults(packageRoot = PACKAGE_ROOT) {
165
- const pluginSettingsPath = path.join(packageRoot, "settings.json");
166
- const pluginManifestPath = path.join(packageRoot, ".claude-plugin", "plugin.json");
167
- const monitorsPath = path.join(packageRoot, "monitors", "monitors.json");
168
- const packageJsonPath = path.join(packageRoot, "package.json");
169
-
170
- const state = {
171
- exists: false,
172
- packageVersion: null,
173
- pluginVersion: null,
174
- sourceRepo: {
175
- isGitRepo: false,
176
- branch: null,
177
- shortSha: null,
178
- exactTag: null,
179
- dirty: false,
180
- },
181
- defaultAgent: null,
182
- subagentStatusLineCommand: null,
183
- monitorCount: 0,
184
- monitors: [],
185
- userConfig: [],
186
- };
187
-
188
- let pluginSettings = null;
189
- let pluginManifest = null;
190
- let monitors = null;
191
-
192
- try {
193
- pluginSettings = JSON.parse(await fs.readFile(pluginSettingsPath, "utf-8"));
194
- } catch {
195
- pluginSettings = null;
196
- }
197
-
198
- try {
199
- pluginManifest = JSON.parse(await fs.readFile(pluginManifestPath, "utf-8"));
200
- } catch {
201
- pluginManifest = null;
202
- }
203
-
204
- try {
205
- const pkg = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
206
- state.packageVersion = typeof pkg?.version === "string" ? pkg.version : null;
207
- } catch {
208
- state.packageVersion = null;
209
- }
210
-
211
- const gitRepoCheck = runSync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: packageRoot });
212
- if (gitRepoCheck.code === 0 && gitRepoCheck.stdout.trim() === "true") {
213
- state.sourceRepo.isGitRepo = true;
214
-
215
- const branch = runSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: packageRoot });
216
- if (branch.code === 0) {
217
- state.sourceRepo.branch = branch.stdout.trim() || null;
218
- }
219
-
220
- const shortSha = runSync("git", ["rev-parse", "--short", "HEAD"], { cwd: packageRoot });
221
- if (shortSha.code === 0) {
222
- state.sourceRepo.shortSha = shortSha.stdout.trim() || null;
223
- }
224
-
225
- const exactTag = runSync("git", ["describe", "--tags", "--exact-match", "HEAD"], { cwd: packageRoot });
226
- if (exactTag.code === 0) {
227
- state.sourceRepo.exactTag = exactTag.stdout.trim() || null;
228
- }
229
-
230
- const status = runSync("git", ["status", "--short"], { cwd: packageRoot });
231
- if (status.code === 0) {
232
- state.sourceRepo.dirty = status.stdout.trim().length > 0;
233
- }
234
- }
235
-
236
- try {
237
- monitors = JSON.parse(await fs.readFile(monitorsPath, "utf-8"));
238
- } catch {
239
- monitors = null;
240
- }
241
-
242
- if (!pluginSettings && !pluginManifest && !monitors) {
243
- return state;
244
- }
245
-
246
- state.exists = true;
247
- state.pluginVersion = typeof pluginManifest?.version === "string" ? pluginManifest.version : null;
248
- state.defaultAgent = typeof pluginSettings?.agent === "string" ? pluginSettings.agent : null;
249
- state.subagentStatusLineCommand =
250
- typeof pluginSettings?.subagentStatusLine?.command === "string"
251
- ? pluginSettings.subagentStatusLine.command
252
- : null;
253
-
254
- if (Array.isArray(monitors)) {
255
- state.monitorCount = monitors.length;
256
- state.monitors = monitors
257
- .filter((entry) => entry && typeof entry === "object")
258
- .map((entry) => ({
259
- name: typeof entry.name === "string" ? entry.name : null,
260
- when: typeof entry.when === "string" ? entry.when : "always",
261
- }))
262
- .filter((entry) => entry.name);
263
- }
264
-
265
- if (pluginManifest?.userConfig && typeof pluginManifest.userConfig === "object") {
266
- state.userConfig = Object.entries(pluginManifest.userConfig)
267
- .filter(([, value]) => value && typeof value === "object" && !Array.isArray(value))
268
- .map(([key, value]) => ({
269
- key,
270
- type: value.type ?? null,
271
- default: Object.prototype.hasOwnProperty.call(value, "default") ? value.default : undefined,
272
- sensitive: value.sensitive === true,
273
- }));
274
- }
275
-
276
- return state;
277
- }
278
-
279
- export async function readProjectState(cwd = process.cwd()) {
280
- const flowDir = path.join(cwd, ".flow");
281
- try {
282
- const stat = await fs.stat(flowDir);
283
- if (!stat.isDirectory()) {
284
- return { exists: false, activeSpec: null };
285
- }
286
-
287
- try {
288
- const activeSpec = await fs.readFile(path.join(flowDir, ".active-spec"), "utf-8");
289
- return { exists: true, activeSpec: activeSpec.trim() };
290
- } catch {
291
- return { exists: true, activeSpec: null };
292
- }
293
- } catch {
294
- return { exists: false, activeSpec: null };
295
- }
296
- }
297
-
298
- export async function collectDoctorData(
299
- {
300
- cwd = process.cwd(),
301
- } = {},
302
- {
303
- claudeVersionImpl = claudeVersion,
304
- listPluginsImpl = listPlugins,
305
- listPluginMarketplacesImpl = listPluginMarketplaces,
306
- listMcpsImpl = listMcps,
307
- readUserMcpConfigImpl = readUserMcpConfig,
308
- inspectClaudeMemRuntimesImpl = inspectClaudeMemRuntimes,
309
- inspectRuntimeEnvironmentImpl = inspectRuntimeEnvironment,
310
- readProjectStateImpl = readProjectState,
311
- readProjectMcpConfigImpl = readProjectMcpConfig,
312
- readProjectTeamConfigImpl = readProjectTeamConfig,
313
- readProjectClaudeSettingsImpl = readProjectClaudeSettings,
314
- readBundledPluginRuntimeDefaultsImpl = readBundledPluginRuntimeDefaults,
315
- readConfigImpl = readConfig,
316
- } = {}
317
- ) {
318
- const claudeVersionValue = claudeVersionImpl();
319
- const plugins = claudeVersionValue ? listPluginsImpl() : [];
320
- const marketplaces = claudeVersionValue ? listPluginMarketplacesImpl() : [];
321
- const mcps = claudeVersionValue ? listMcpsImpl() : [];
322
- const userMcpConfig = claudeVersionValue ? readUserMcpConfigImpl() : new Map();
323
- const runtimeStatus = plugins.some(
324
- (plugin) => plugin.name === "claude-mem" && plugin.status === "enabled"
325
- )
326
- ? inspectClaudeMemRuntimesImpl()
327
- : null;
328
-
329
- return {
330
- claudeVersionValue,
331
- nodeVersion: process.version,
332
- plugins,
333
- marketplaces,
334
- mcps,
335
- userMcpConfig,
336
- runtimeStatus,
337
- runtimeEnvironment: inspectRuntimeEnvironmentImpl(),
338
- cwd,
339
- projectState: await readProjectStateImpl(cwd),
340
- projectMcpConfig: await readProjectMcpConfigImpl(cwd),
341
- projectTeamConfig: await readProjectTeamConfigImpl(cwd),
342
- projectClaudeSettings: await readProjectClaudeSettingsImpl(cwd),
343
- bundledPluginRuntimeDefaults: await readBundledPluginRuntimeDefaultsImpl(),
344
- legacyInstallState: {
345
- configPath: CONFIG_FILE,
346
- hasLegacyContext7ApiKey: Object.prototype.hasOwnProperty.call(readConfigImpl(), "context7ApiKey"),
347
- },
348
- };
349
- }
350
-
351
- export async function applyDoctorFixes(
352
- doctorData,
353
- {
354
- ensureClaudeMemRuntimesImpl = ensureClaudeMemRuntimes,
355
- removeMcpImpl = removeMcp,
356
- readConfigImpl = readConfig,
357
- writeConfigImpl = writeConfig,
358
- } = {}
359
- ) {
360
- const fixes = [];
361
- const context7PluginOwnsMcp = doctorData.mcps.some(
362
- (entry) => entry.name === "context7" && entry.plugin === "context7-plugin"
363
- );
364
- const hasLegacyUserContext7Mcp =
365
- doctorData.userMcpConfig instanceof Map && doctorData.userMcpConfig.has("context7");
366
-
367
- if (context7PluginOwnsMcp && hasLegacyUserContext7Mcp) {
368
- const result = await removeMcpImpl({ name: "context7" });
369
- if (result.code === 0) {
370
- doctorData.userMcpConfig.delete("context7");
371
- doctorData.mcps = doctorData.mcps.filter(
372
- (entry) => !(entry.name === "context7" && entry.plugin == null)
373
- );
374
- fixes.push({
375
- kind: "legacy-context7-user-mcp-removed",
376
- });
377
- }
378
- }
379
-
380
- if (doctorData.legacyInstallState?.hasLegacyContext7ApiKey) {
381
- const config = readConfigImpl();
382
- if (Object.prototype.hasOwnProperty.call(config, "context7ApiKey")) {
383
- delete config.context7ApiKey;
384
- writeConfigImpl(config);
385
- doctorData.legacyInstallState = {
386
- ...doctorData.legacyInstallState,
387
- hasLegacyContext7ApiKey: false,
388
- };
389
- fixes.push({
390
- kind: "legacy-context7-api-key-removed",
391
- configPath: CONFIG_FILE,
392
- });
393
- }
394
- }
395
-
396
- const claudeMemEnabled = doctorData.plugins.some(
397
- (plugin) => plugin.name === "claude-mem" && plugin.status === "enabled"
398
- );
399
-
400
- if (!claudeMemEnabled) {
401
- return fixes;
402
- }
403
-
404
- const runtimeStatus = ensureClaudeMemRuntimesImpl();
405
- doctorData.runtimeStatus = runtimeStatus;
406
- fixes.push({
407
- kind: "claude-mem-runtimes",
408
- runtimeStatus,
409
- });
410
- return fixes;
411
- }
412
-
413
- export function renderReportLines(lines, { logImpl = log } = {}) {
414
- for (const line of lines) {
415
- if (line.level === "ok") {
416
- logImpl.ok(line.text);
417
- } else if (line.level === "warn") {
418
- logImpl.warn(line.text);
419
- } else if (line.level === "err") {
420
- logImpl.err(line.text);
421
- } else {
422
- logImpl.info(line.text);
423
- }
424
-
425
- for (const detail of line.details || []) {
426
- console.log(color.dim(` → ${detail}`));
427
- }
428
- }
429
- }
430
-
431
- export function buildDoctorJsonPayload({
432
- context = {},
433
- doctorData,
434
- fixes = [],
435
- report,
436
- } = {}) {
437
- return {
438
- contractVersion: DOCTOR_JSON_CONTRACT_VERSION,
439
- generatedAt: new Date().toISOString(),
440
- context: {
441
- fix: context.fix === true,
442
- json: context.json === true,
443
- verbose: context.verbose === true,
444
- },
445
- summary: {
446
- errors: report?.errors || 0,
447
- warnings: report?.warnings || 0,
448
- healthy: (report?.errors || 0) === 0,
449
- },
450
- metadata: {
451
- appliedFixes: fixes,
452
- settingsInspection: DOCTOR_SETTINGS_INSPECTION,
453
- },
454
- doctorData,
455
- report,
456
- };
457
- }
458
-
459
- export function printDoctorSummary(
460
- report,
461
- { logImpl = log, exitImpl = process.exit } = {}
462
- ) {
463
- console.log();
464
- if (report.errors > 0) {
465
- console.log(color.red(`Summary: ${report.errors} error(s), ${report.warnings} warning(s)`));
466
- console.log(color.dim("Fix errors and re-run curdx-flow doctor"));
467
- exitImpl(1);
468
- return;
469
- }
470
-
471
- if (report.warnings > 0) {
472
- console.log(color.yellow(`Summary: ${report.warnings} warning(s). Usable, but worth addressing.`));
473
- return;
474
- }
475
-
476
- console.log(color.green("Summary: all healthy ✓"));
477
- }
478
-
479
- export function printVerboseDoctorDetails({ runSyncImpl = runSync } = {}) {
480
- console.log(`\n${color.bold("Details:")}`);
481
- console.log(color.dim(" Plugins raw:"));
482
- console.log(runSyncImpl("claude", ["plugin", "list"]).stdout);
483
- }
package/cli/doctor.js DELETED
@@ -1,73 +0,0 @@
1
- /**
2
- * doctor command — external health check (no need to enter Claude Code).
3
- */
4
-
5
- import {
6
- color,
7
- log,
8
- } from "./utils.js";
9
- import { buildDoctorReport } from "./lib/doctor-report.js";
10
- import {
11
- applyDoctorFixes,
12
- buildDoctorJsonPayload,
13
- collectDoctorData,
14
- createDoctorContext,
15
- printDoctorSummary,
16
- printVerboseDoctorDetails,
17
- renderReportLines,
18
- } from "./doctor-workflow.js";
19
-
20
- export async function doctor(
21
- args = [],
22
- {
23
- applyDoctorFixesImpl = applyDoctorFixes,
24
- buildDoctorJsonPayloadImpl = buildDoctorJsonPayload,
25
- buildDoctorReportImpl = buildDoctorReport,
26
- collectDoctorDataImpl = collectDoctorData,
27
- createDoctorContextImpl = createDoctorContext,
28
- printDoctorSummaryImpl = printDoctorSummary,
29
- printVerboseDoctorDetailsImpl = printVerboseDoctorDetails,
30
- renderReportLinesImpl = renderReportLines,
31
- logImpl = log,
32
- colorImpl = color,
33
- consoleImpl = console,
34
- processImpl = process,
35
- } = {}
36
- ) {
37
- const context = createDoctorContextImpl(args);
38
- let fixes = [];
39
-
40
- if (!context.json) {
41
- logImpl.title("🏥 CurdX-Flow Health Check");
42
- }
43
-
44
- const doctorData = await collectDoctorDataImpl();
45
- if (context.fix) {
46
- if (!context.json) {
47
- logImpl.info("Applying safe fixes...");
48
- }
49
- fixes = await applyDoctorFixesImpl(doctorData);
50
- if (fixes.length === 0 && !context.json) {
51
- logImpl.info("No automatic fixes available for the current environment");
52
- }
53
- }
54
- const report = buildDoctorReportImpl(doctorData);
55
-
56
- if (context.json) {
57
- const payload = buildDoctorJsonPayloadImpl({ context, doctorData, fixes, report });
58
- consoleImpl.log(JSON.stringify(payload, null, 2));
59
- processImpl.exitCode = report.errors > 0 ? 1 : 0;
60
- return;
61
- }
62
-
63
- renderReportLinesImpl(report.lines, { logImpl });
64
- for (const section of report.sections) {
65
- consoleImpl.log(`\n${colorImpl.bold(section.title)}`);
66
- renderReportLinesImpl(section.lines, { logImpl });
67
- }
68
-
69
- printDoctorSummaryImpl(report, { logImpl });
70
- if (context.verbose && doctorData.claudeVersionValue) {
71
- printVerboseDoctorDetailsImpl();
72
- }
73
- }
package/cli/help.js DELETED
@@ -1,59 +0,0 @@
1
- import { VERSION, color } from "./utils.js";
2
-
3
- export function printHelp() {
4
- console.log(`
5
- ${color.bold("curdx-flow")} ${color.dim(`v${VERSION}`)}
6
- CurdX-Flow installer & helper for Claude Code
7
-
8
- ${color.bold("USAGE")}
9
- npx @curdx/flow <command> [options]
10
-
11
- ${color.bold("COMMANDS")}
12
- ${color.cyan("install")} Install curdx-flow plugin + optional recommended plugins
13
- --all Install all recommended (skip prompt)
14
- --no-deps Only install curdx-flow, skip recommendations
15
- --online Fetch plugin from GitHub instead of using the
16
- local npm package (slower; default is offline
17
- when the plugin body is bundled)
18
-
19
- ${color.cyan("doctor")} Check health (claude CLI, plugin, MCPs, recommended)
20
- --fix Apply safe runtime fixes (bun/uv PATH symlinks)
21
- --json Emit machine-readable health report JSON
22
- --verbose Show raw plugin list details
23
-
24
- ${color.cyan("upgrade")} Update curdx-flow and recommended plugins to latest
25
-
26
- ${color.cyan("uninstall")} Remove curdx-flow plugin (and optionally recommended / artifacts)
27
- -y, --yes Skip confirmation, keep recommended + .flow/
28
- --keep-recommended Don't ask about pua/claude-mem/frontend-design
29
- --purge Also remove ~/.local/bin/bun, ~/.local/bin/uv symlinks
30
-
31
- ${color.bold("OPTIONS")}
32
- -v, --version Print version
33
- -h, --help Show this CLI usage summary
34
-
35
- ${color.dim("For the full command / workflow reference (including all slash")}
36
- ${color.dim("commands like /curdx-flow:start, /curdx-flow:spec, …) run:")}
37
- ${color.cyan("/curdx-flow:help")} ${color.dim("(inside Claude Code)")}
38
-
39
- ${color.bold("EXAMPLES")}
40
- ${color.dim("# First-time install with recommended plugins")}
41
- npx @curdx/flow install --all
42
-
43
- ${color.dim("# Check what's installed")}
44
- npx @curdx/flow doctor
45
-
46
- ${color.dim("# Update everything")}
47
- npx @curdx/flow upgrade
48
-
49
- ${color.bold("INITIALIZING A PROJECT")}
50
- Once curdx-flow is installed, initialize your project inside Claude Code:
51
-
52
- ${color.cyan("claude")}
53
- ${color.cyan("/curdx-flow:init")}
54
- ${color.cyan("/curdx-flow:start my-feature \"<description>\"")}
55
-
56
- ${color.bold("LEARN MORE")}
57
- https://github.com/curdx/curdx-flow
58
- `);
59
- }
@@ -1,37 +0,0 @@
1
- /**
2
- * Register MCP servers that curdx-flow depends on at user level via
3
- * `claude mcp add`. Source-of-truth list: cli/registry.js BUNDLED_MCPS.
4
- * Preserves existing user-level entries when mcp.preserveExisting is set.
5
- */
6
-
7
- import { addMcp } from "./lib/claude-ops.js";
8
- import { BUNDLED_MCPS } from "./registry.js";
9
- import { color, log, readUserMcpConfig, resultLastLine } from "./utils.js";
10
-
11
- export async function registerBundledMcps() {
12
- log.blank();
13
- log.info("Registering required MCP servers (user-level)...");
14
- const existingUserMcps = readUserMcpConfig();
15
- for (const mcp of BUNDLED_MCPS) {
16
- if (mcp.preserveExisting && existingUserMcps.has(mcp.name)) {
17
- const existing = existingUserMcps.get(mcp.name);
18
- log.info(
19
- ` ${mcp.name.padEnd(22)} ${color.dim(`already registered (${(existing.args || []).join(" ")}) — preserving`)}`
20
- );
21
- continue;
22
- }
23
- const r = await addMcp(mcp);
24
- if (r.code === 0) {
25
- log.ok(` ${mcp.name.padEnd(22)} ${color.dim("registered")}`);
26
- } else if (r.stderr.includes("already exists")) {
27
- log.info(` ${mcp.name.padEnd(22)} ${color.dim("already exists — skipped")}`);
28
- } else {
29
- log.warn(
30
- ` ${mcp.name.padEnd(22)} registration failed: ${resultLastLine(r)}`
31
- );
32
- log.info(
33
- ` Run manually: claude mcp add --scope user ${mcp.name} -- ${mcp.command} ${mcp.args.join(" ")}`
34
- );
35
- }
36
- }
37
- }
@@ -1,19 +0,0 @@
1
- /**
2
- * Re-export barrel preserving the stable import surface. New callers should
3
- * import directly from the concern-specific modules below instead of going
4
- * through this barrel. Kept in place so existing imports in cli/install.js
5
- * and cli/install-workflow.js keep working unchanged.
6
- *
7
- * Concern split:
8
- * install-required-plugins.js — required Claude Code companion plugins
9
- * install-bundled-mcps.js — user-level MCP registration
10
- * install-recommended-plugins.js — optional recommended plugins
11
- * install-context7-config.js — legacy Context7 state reconciliation (private to required)
12
- */
13
-
14
- export {
15
- addRequiredPluginMarketplaces,
16
- installRequiredPlugins,
17
- } from "./install-required-plugins.js";
18
- export { registerBundledMcps } from "./install-bundled-mcps.js";
19
- export { installRecommendedPlugins } from "./install-recommended-plugins.js";