@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.
- package/CHANGELOG.md +21 -34
- package/LICENSE +1 -1
- package/README.md +28 -79
- package/dist/index.mjs +995 -0
- package/package.json +33 -42
- package/.claude-plugin/marketplace.json +0 -48
- package/.claude-plugin/plugin.json +0 -70
- package/agent-preamble/preamble.md +0 -314
- package/agents/flow-adversary.md +0 -202
- package/agents/flow-architect.md +0 -197
- package/agents/flow-brownfield-analyst.md +0 -142
- package/agents/flow-debugger.md +0 -321
- package/agents/flow-edge-hunter.md +0 -288
- package/agents/flow-executor.md +0 -269
- package/agents/flow-orchestrator.md +0 -145
- package/agents/flow-planner.md +0 -246
- package/agents/flow-product-designer.md +0 -159
- package/agents/flow-qa-engineer.md +0 -282
- package/agents/flow-researcher.md +0 -165
- package/agents/flow-reviewer.md +0 -303
- package/agents/flow-security-auditor.md +0 -401
- package/agents/flow-triage-analyst.md +0 -272
- package/agents/flow-ui-researcher.md +0 -229
- package/agents/flow-ux-designer.md +0 -221
- package/agents/flow-verifier.md +0 -349
- package/bin/curdx-flow +0 -5
- package/bin/curdx-flow.js +0 -54
- package/cli/README.md +0 -104
- package/cli/doctor-workflow.js +0 -483
- package/cli/doctor.js +0 -73
- package/cli/help.js +0 -59
- package/cli/install-bundled-mcps.js +0 -37
- package/cli/install-companions.js +0 -19
- package/cli/install-context7-config.js +0 -80
- package/cli/install-curdx-plugin.js +0 -96
- package/cli/install-language.js +0 -35
- package/cli/install-next-steps.js +0 -29
- package/cli/install-options.js +0 -9
- package/cli/install-paths.js +0 -52
- package/cli/install-recommended-plugins.js +0 -104
- package/cli/install-required-plugins.js +0 -57
- package/cli/install-self-update.js +0 -62
- package/cli/install-workflow.js +0 -209
- package/cli/install.js +0 -101
- package/cli/lib/claude-commands.js +0 -41
- package/cli/lib/claude-ops.js +0 -47
- package/cli/lib/claude.js +0 -183
- package/cli/lib/config.js +0 -24
- package/cli/lib/doctor-claude-settings.js +0 -1186
- package/cli/lib/doctor-report.js +0 -978
- package/cli/lib/doctor-runtime-environment.js +0 -196
- package/cli/lib/frontmatter.js +0 -44
- package/cli/lib/json-schema.js +0 -57
- package/cli/lib/logging.js +0 -25
- package/cli/lib/process.js +0 -60
- package/cli/lib/prompts.js +0 -135
- package/cli/lib/runtime.js +0 -107
- package/cli/lib/semver.js +0 -109
- package/cli/lib/version.js +0 -12
- package/cli/protocols-body.md +0 -22
- package/cli/protocols.js +0 -162
- package/cli/registry.js +0 -123
- package/cli/router.js +0 -49
- package/cli/uninstall-actions.js +0 -360
- package/cli/uninstall-workflow.js +0 -146
- package/cli/uninstall.js +0 -42
- package/cli/upgrade-workflow.js +0 -80
- package/cli/upgrade.js +0 -91
- package/cli/utils.js +0 -40
- package/gates/adversarial-review-gate.md +0 -219
- package/gates/coverage-audit-gate.md +0 -182
- package/gates/devex-gate.md +0 -254
- package/gates/edge-case-gate.md +0 -194
- package/gates/karpathy-gate.md +0 -130
- package/gates/security-gate.md +0 -218
- package/gates/tdd-gate.md +0 -182
- package/gates/test-quality-gate.md +0 -59
- package/gates/verification-gate.md +0 -179
- package/hooks/hooks.json +0 -58
- package/hooks/scripts/common.sh +0 -46
- package/hooks/scripts/inject-karpathy.sh +0 -53
- package/hooks/scripts/quick-mode-guard.sh +0 -68
- package/hooks/scripts/session-start.sh +0 -90
- package/hooks/scripts/stop-watcher.sh +0 -230
- package/hooks/scripts/subagent-artifact-guard.sh +0 -159
- package/hooks/scripts/subagent-statusline.sh +0 -105
- package/knowledge/artifact-output-discipline.md +0 -24
- package/knowledge/artifact-summary-contracts.md +0 -50
- package/knowledge/atomic-commits.md +0 -262
- package/knowledge/claude-code-runtime-contracts.md +0 -219
- package/knowledge/epic-decomposition.md +0 -307
- package/knowledge/execution-strategies.md +0 -303
- package/knowledge/karpathy-guidelines.md +0 -219
- package/knowledge/planning-reviews.md +0 -211
- package/knowledge/poc-first-workflow.md +0 -223
- package/knowledge/review-feedback-intake.md +0 -57
- package/knowledge/spec-driven-development.md +0 -180
- package/knowledge/systematic-debugging.md +0 -378
- package/knowledge/two-stage-review.md +0 -249
- package/knowledge/wave-execution.md +0 -403
- package/monitors/monitors.json +0 -8
- package/monitors/scripts/flow-state-monitor.sh +0 -99
- package/output-styles/curdx-evidence-first.md +0 -34
- package/schemas/agent-frontmatter.schema.json +0 -63
- package/schemas/config.schema.json +0 -134
- package/schemas/gate-frontmatter.schema.json +0 -30
- package/schemas/hooks.schema.json +0 -115
- package/schemas/output-style-frontmatter.schema.json +0 -22
- package/schemas/plugin-manifest.schema.json +0 -436
- package/schemas/plugin-settings.schema.json +0 -29
- package/schemas/skill-frontmatter.schema.json +0 -177
- package/schemas/spec-frontmatter.schema.json +0 -42
- package/schemas/spec-state.schema.json +0 -147
- package/settings.json +0 -7
- package/skills/brownfield-index/SKILL.md +0 -53
- package/skills/brownfield-index/references/applicability.md +0 -12
- package/skills/brownfield-index/references/handoff.md +0 -8
- package/skills/brownfield-index/references/index-contract.md +0 -10
- package/skills/browser-qa/SKILL.md +0 -39
- package/skills/browser-qa/references/handoff.md +0 -6
- package/skills/browser-qa/references/prerequisites.md +0 -10
- package/skills/browser-qa/references/qa-contract.md +0 -20
- package/skills/cancel/SKILL.md +0 -41
- package/skills/cancel/references/destructive-mode.md +0 -17
- package/skills/cancel/references/reporting.md +0 -18
- package/skills/cancel/references/state-recovery.md +0 -30
- package/skills/cancel/references/target-resolution.md +0 -7
- package/skills/debug/SKILL.md +0 -45
- package/skills/debug/references/context-gathering.md +0 -11
- package/skills/debug/references/failure-guard.md +0 -25
- package/skills/debug/references/intake.md +0 -12
- package/skills/debug/references/phase-workflow.md +0 -34
- package/skills/debug/references/reporting.md +0 -20
- package/skills/epic/SKILL.md +0 -39
- package/skills/epic/references/epic-artifacts.md +0 -20
- package/skills/epic/references/epic-intake.md +0 -9
- package/skills/epic/references/slice-handoff.md +0 -16
- package/skills/fast/SKILL.md +0 -62
- package/skills/fast/references/applicability.md +0 -25
- package/skills/fast/references/clarification.md +0 -20
- package/skills/fast/references/execution-contract.md +0 -56
- package/skills/help/SKILL.md +0 -55
- package/skills/help/references/dispatch.md +0 -20
- package/skills/help/references/overview.md +0 -39
- package/skills/help/references/troubleshoot.md +0 -47
- package/skills/help/references/workflow.md +0 -37
- package/skills/implement/SKILL.md +0 -96
- package/skills/implement/references/error-recovery.md +0 -36
- package/skills/implement/references/linear-execution.md +0 -32
- package/skills/implement/references/preflight.md +0 -43
- package/skills/implement/references/progress-contract.md +0 -32
- package/skills/implement/references/state-init.md +0 -33
- package/skills/implement/references/stop-hook-execution.md +0 -36
- package/skills/implement/references/strategy-router.md +0 -38
- package/skills/implement/references/subagent-execution.md +0 -43
- package/skills/implement/references/wave-execution.md +0 -162
- package/skills/init/SKILL.md +0 -49
- package/skills/init/references/gitignore-and-health.md +0 -26
- package/skills/init/references/next-steps.md +0 -22
- package/skills/init/references/preflight.md +0 -15
- package/skills/init/references/scaffold-contract.md +0 -27
- package/skills/review/SKILL.md +0 -82
- package/skills/review/references/optional-passes.md +0 -48
- package/skills/review/references/preflight.md +0 -38
- package/skills/review/references/report-contract.md +0 -49
- package/skills/review/references/reporting.md +0 -20
- package/skills/review/references/stage-execution.md +0 -32
- package/skills/security-audit/SKILL.md +0 -47
- package/skills/security-audit/references/audit-contract.md +0 -21
- package/skills/security-audit/references/gate-handoff.md +0 -8
- package/skills/security-audit/references/scope-and-depth.md +0 -9
- package/skills/spec/SKILL.md +0 -100
- package/skills/spec/references/artifact-landing.md +0 -31
- package/skills/spec/references/phase-execution.md +0 -50
- package/skills/spec/references/planning-review.md +0 -31
- package/skills/spec/references/preflight-and-routing.md +0 -46
- package/skills/spec/references/reporting.md +0 -21
- package/skills/start/SKILL.md +0 -84
- package/skills/start/references/branch-routing.md +0 -51
- package/skills/start/references/mode-semantics.md +0 -12
- package/skills/start/references/preflight.md +0 -13
- package/skills/start/references/reporting.md +0 -20
- package/skills/start/references/state-seeding.md +0 -44
- package/skills/start/references/workflow-handoff.md +0 -26
- package/skills/status/SKILL.md +0 -41
- package/skills/status/references/gather-contract.md +0 -27
- package/skills/status/references/health-rules.md +0 -27
- package/skills/status/references/output-contract.md +0 -24
- package/skills/status/references/preflight.md +0 -10
- package/skills/status/references/recovery-hints.md +0 -18
- package/skills/ui-sketch/SKILL.md +0 -39
- package/skills/ui-sketch/references/brief-intake.md +0 -10
- package/skills/ui-sketch/references/iteration-handoff.md +0 -5
- package/skills/ui-sketch/references/variant-contract.md +0 -15
- package/skills/verify/SKILL.md +0 -56
- package/skills/verify/references/evidence-workflow.md +0 -39
- package/skills/verify/references/output-contract.md +0 -23
- package/skills/verify/references/preflight.md +0 -11
- package/skills/verify/references/report-handoff.md +0 -35
- package/skills/verify/references/strict-mode.md +0 -12
- package/templates/CONTEXT.md.tmpl +0 -53
- package/templates/PROJECT.md.tmpl +0 -59
- package/templates/ROADMAP.md.tmpl +0 -50
- package/templates/STATE.md.tmpl +0 -49
- package/templates/config.json.tmpl +0 -51
- package/templates/design.md.tmpl +0 -83
- package/templates/progress.md.tmpl +0 -77
- package/templates/requirements.md.tmpl +0 -76
- package/templates/research.md.tmpl +0 -83
- package/templates/tasks.md.tmpl +0 -107
package/cli/doctor-workflow.js
DELETED
|
@@ -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";
|