@curdx/flow 2.3.3 → 2.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +6 -0
- package/README.md +2 -1
- package/cli/README.md +3 -1
- package/cli/doctor-workflow.js +34 -0
- package/cli/doctor.js +43 -14
- package/cli/help.js +1 -0
- package/cli/lib/doctor-claude-settings.js +57 -0
- package/cli/lib/doctor-report.js +24 -0
- package/knowledge/claude-code-runtime-contracts.md +1 -0
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Claude Code Discipline Layer — spec-driven workflow + goal-backward verification + Karpathy 4 principles enforced via gates. Stops Claude from faking \"done\" on non-trivial features.",
|
|
9
|
-
"version": "2.3.
|
|
9
|
+
"version": "2.3.5"
|
|
10
10
|
},
|
|
11
11
|
"allowCrossMarketplaceDependenciesOn": [
|
|
12
12
|
"context7-marketplace"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"name": "curdx-flow",
|
|
17
17
|
"source": "./",
|
|
18
18
|
"description": "Claude Code Discipline Layer — spec-driven workflow + goal-backward verification + Karpathy 4 principles enforced via gates. Stops Claude from faking \"done\" on non-trivial features.",
|
|
19
|
-
"version": "2.3.
|
|
19
|
+
"version": "2.3.5",
|
|
20
20
|
"author": {
|
|
21
21
|
"name": "wdx",
|
|
22
22
|
"email": "bydongxin@gmail.com"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "curdx-flow",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.5",
|
|
4
4
|
"description": "Claude Code Discipline Layer — spec-driven workflow + goal-backward verification + Karpathy 4 principles enforced via gates. Stops Claude from faking \"done\" on non-trivial features.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "wdx",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.3.5
|
|
4
|
+
|
|
5
|
+
- added a versioned `doctor --json` contract for CI/wrappers, including applied-fix metadata and explicit settings-inspection scope metadata
|
|
6
|
+
- added CLI-level regression coverage so `doctor --json` stays silent except for JSON stdout and exit code
|
|
7
|
+
- locked runtime env consumer drift checks against manifest `userConfig` keys and the actual bundled hook/monitor scripts
|
|
8
|
+
|
|
3
9
|
## 2.3.1
|
|
4
10
|
|
|
5
11
|
- expanded `doctor` to report CurDX-Flow’s bundled main-thread agent, monitor surface, and plugin option defaults
|
package/README.md
CHANGED
|
@@ -20,7 +20,8 @@ npx @curdx/flow install --all
|
|
|
20
20
|
|
|
21
21
|
Requires modern Claude Code and Node 18+. The install flow registers the plugin,
|
|
22
22
|
required reasoning/doc tools, and recommended companion plugins. Run
|
|
23
|
-
`npx @curdx/flow doctor` after install if anything looks off.
|
|
23
|
+
`npx @curdx/flow doctor` after install if anything looks off. For CI or wrapper
|
|
24
|
+
automation, use `npx @curdx/flow doctor --json`.
|
|
24
25
|
|
|
25
26
|
After restart, CurDX-Flow routes the main thread through `flow-orchestrator`
|
|
26
27
|
by default and starts the bundled `.flow` progress monitor in interactive
|
package/cli/README.md
CHANGED
|
@@ -36,12 +36,14 @@ Steps:
|
|
|
36
36
|
| `--all` | Install all recommended plugins, no prompt |
|
|
37
37
|
| `--no-deps` | Install only curdx-flow itself |
|
|
38
38
|
|
|
39
|
-
### `doctor [--verbose] [--fix]`
|
|
39
|
+
### `doctor [--verbose] [--fix] [--json]`
|
|
40
40
|
|
|
41
41
|
External diagnostics: claude CLI / curdx-flow / required MCPs / recommended plugins / current directory `.flow/` state.
|
|
42
42
|
|
|
43
43
|
`--fix` applies the safe automatic repairs the CLI can perform without guessing — currently the `bun` / `uv` PATH symlinks used by `claude-mem`. Everything else remains diagnostic-only.
|
|
44
44
|
|
|
45
|
+
`--json` emits the full health result as machine-readable JSON for CI, wrappers, or external diagnostics. It includes `contractVersion`, `metadata.appliedFixes`, settings inspection scope metadata, the rendered report structure, and raw `doctorData`, including CurDX-Flow plugin option precedence and runtime env projection.
|
|
46
|
+
|
|
45
47
|
### Project initialization (not a CLI command)
|
|
46
48
|
|
|
47
49
|
Project initialization is a Claude Code slash command, not a CLI one. After `install`, open your project in Claude Code and run:
|
package/cli/doctor-workflow.js
CHANGED
|
@@ -21,10 +21,16 @@ export { readProjectClaudeSettings };
|
|
|
21
21
|
export { inspectRuntimeEnvironment };
|
|
22
22
|
|
|
23
23
|
const PACKAGE_ROOT = fileURLToPath(new URL("../", import.meta.url));
|
|
24
|
+
export const DOCTOR_JSON_CONTRACT_VERSION = 1;
|
|
25
|
+
export const DOCTOR_SETTINGS_INSPECTION = Object.freeze({
|
|
26
|
+
pluginOptionScopesInspected: ["user", "project", "local"],
|
|
27
|
+
pluginOptionScopesNotInspected: ["managed", "cli"],
|
|
28
|
+
});
|
|
24
29
|
|
|
25
30
|
export function createDoctorContext(args = []) {
|
|
26
31
|
return {
|
|
27
32
|
fix: args.includes("--fix"),
|
|
33
|
+
json: args.includes("--json"),
|
|
28
34
|
verbose: args.includes("--verbose") || args.includes("-v"),
|
|
29
35
|
};
|
|
30
36
|
}
|
|
@@ -334,6 +340,34 @@ export function renderReportLines(lines, { logImpl = log } = {}) {
|
|
|
334
340
|
}
|
|
335
341
|
}
|
|
336
342
|
|
|
343
|
+
export function buildDoctorJsonPayload({
|
|
344
|
+
context = {},
|
|
345
|
+
doctorData,
|
|
346
|
+
fixes = [],
|
|
347
|
+
report,
|
|
348
|
+
} = {}) {
|
|
349
|
+
return {
|
|
350
|
+
contractVersion: DOCTOR_JSON_CONTRACT_VERSION,
|
|
351
|
+
generatedAt: new Date().toISOString(),
|
|
352
|
+
context: {
|
|
353
|
+
fix: context.fix === true,
|
|
354
|
+
json: context.json === true,
|
|
355
|
+
verbose: context.verbose === true,
|
|
356
|
+
},
|
|
357
|
+
summary: {
|
|
358
|
+
errors: report?.errors || 0,
|
|
359
|
+
warnings: report?.warnings || 0,
|
|
360
|
+
healthy: (report?.errors || 0) === 0,
|
|
361
|
+
},
|
|
362
|
+
metadata: {
|
|
363
|
+
appliedFixes: fixes,
|
|
364
|
+
settingsInspection: DOCTOR_SETTINGS_INSPECTION,
|
|
365
|
+
},
|
|
366
|
+
doctorData,
|
|
367
|
+
report,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
337
371
|
export function printDoctorSummary(
|
|
338
372
|
report,
|
|
339
373
|
{ logImpl = log, exitImpl = process.exit } = {}
|
package/cli/doctor.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { buildDoctorReport } from "./lib/doctor-report.js";
|
|
10
10
|
import {
|
|
11
11
|
applyDoctorFixes,
|
|
12
|
+
buildDoctorJsonPayload,
|
|
12
13
|
collectDoctorData,
|
|
13
14
|
createDoctorContext,
|
|
14
15
|
printDoctorSummary,
|
|
@@ -16,29 +17,57 @@ import {
|
|
|
16
17
|
renderReportLines,
|
|
17
18
|
} from "./doctor-workflow.js";
|
|
18
19
|
|
|
19
|
-
export async function doctor(
|
|
20
|
-
|
|
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 = [];
|
|
21
39
|
|
|
22
|
-
|
|
40
|
+
if (!context.json) {
|
|
41
|
+
logImpl.title("🏥 CurdX-Flow Health Check");
|
|
42
|
+
}
|
|
23
43
|
|
|
24
|
-
const doctorData = await
|
|
44
|
+
const doctorData = await collectDoctorDataImpl();
|
|
25
45
|
if (context.fix) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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");
|
|
30
52
|
}
|
|
31
53
|
}
|
|
32
|
-
const report =
|
|
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
|
+
}
|
|
33
62
|
|
|
34
|
-
|
|
63
|
+
renderReportLinesImpl(report.lines, { logImpl });
|
|
35
64
|
for (const section of report.sections) {
|
|
36
|
-
|
|
37
|
-
|
|
65
|
+
consoleImpl.log(`\n${colorImpl.bold(section.title)}`);
|
|
66
|
+
renderReportLinesImpl(section.lines, { logImpl });
|
|
38
67
|
}
|
|
39
68
|
|
|
40
|
-
|
|
69
|
+
printDoctorSummaryImpl(report, { logImpl });
|
|
41
70
|
if (context.verbose && doctorData.claudeVersionValue) {
|
|
42
|
-
|
|
71
|
+
printVerboseDoctorDetailsImpl();
|
|
43
72
|
}
|
|
44
73
|
}
|
package/cli/help.js
CHANGED
|
@@ -18,6 +18,7 @@ ${color.bold("COMMANDS")}
|
|
|
18
18
|
|
|
19
19
|
${color.cyan("doctor")} Check health (claude CLI, plugin, MCPs, recommended)
|
|
20
20
|
--fix Apply safe runtime fixes (bun/uv PATH symlinks)
|
|
21
|
+
--json Emit machine-readable health report JSON
|
|
21
22
|
--verbose Show raw plugin list details
|
|
22
23
|
|
|
23
24
|
${color.cyan("upgrade")} Update curdx-flow and recommended plugins to latest
|
|
@@ -121,6 +121,23 @@ const CURDX_FLOW_REQUIRED_PLUGIN_IDS = ["context7-plugin@context7-marketplace"];
|
|
|
121
121
|
const HTTP_HOOK_SETTINGS = ["allowedHttpHookUrls", "httpHookAllowedEnvVars"];
|
|
122
122
|
const PERSISTED_EFFORT_LEVELS = ["low", "medium", "high", "xhigh"];
|
|
123
123
|
const ENV_EFFORT_LEVELS = [...PERSISTED_EFFORT_LEVELS, "max", "auto"];
|
|
124
|
+
export const CURDX_FLOW_RUNTIME_CONSUMERS = {
|
|
125
|
+
autonomous_blocking: {
|
|
126
|
+
envVar: "CLAUDE_PLUGIN_OPTION_AUTONOMOUS_BLOCKING",
|
|
127
|
+
consumer: "hooks/scripts/stop-watcher.sh",
|
|
128
|
+
summary: "controls whether the Stop hook blocks Claude from stopping while execute work remains",
|
|
129
|
+
},
|
|
130
|
+
daily_dependency_check: {
|
|
131
|
+
envVar: "CLAUDE_PLUGIN_OPTION_DAILY_DEPENDENCY_CHECK",
|
|
132
|
+
consumer: "hooks/scripts/session-start.sh",
|
|
133
|
+
summary: "controls the once-per-day recommended companion plugin reminder",
|
|
134
|
+
},
|
|
135
|
+
monitor_interval_seconds: {
|
|
136
|
+
envVar: "CLAUDE_PLUGIN_OPTION_MONITOR_INTERVAL_SECONDS",
|
|
137
|
+
consumer: "monitors/scripts/flow-state-monitor.sh",
|
|
138
|
+
summary: "controls the polling interval for the interactive flow-state monitor",
|
|
139
|
+
},
|
|
140
|
+
};
|
|
124
141
|
|
|
125
142
|
function envFlagEnabled(value) {
|
|
126
143
|
if (value === true || value === 1) return true;
|
|
@@ -258,6 +275,43 @@ function applyCurdxFlowPluginOptionOverride(pluginOptionsState, key, value, scop
|
|
|
258
275
|
}
|
|
259
276
|
}
|
|
260
277
|
|
|
278
|
+
function buildCurdxFlowRuntimeProjection(pluginOptionsState) {
|
|
279
|
+
return pluginOptionsState.definitions.map((definition) => {
|
|
280
|
+
const effective = pluginOptionsState.machineEffective[definition.key] || {
|
|
281
|
+
value: definition.default,
|
|
282
|
+
source: "default",
|
|
283
|
+
};
|
|
284
|
+
const runtime = CURDX_FLOW_RUNTIME_CONSUMERS[definition.key] || {};
|
|
285
|
+
const details = [];
|
|
286
|
+
|
|
287
|
+
if (definition.key === "autonomous_blocking") {
|
|
288
|
+
details.push(
|
|
289
|
+
effective.value === false
|
|
290
|
+
? "stop-hook continuation is disabled; Claude may stop at turn end even when execute tasks remain"
|
|
291
|
+
: "stop-hook continuation is enabled; CurDX-Flow can block turn end while execute tasks remain"
|
|
292
|
+
);
|
|
293
|
+
} else if (definition.key === "daily_dependency_check") {
|
|
294
|
+
details.push(
|
|
295
|
+
effective.value === false
|
|
296
|
+
? "SessionStart plugin reminder is disabled on this machine"
|
|
297
|
+
: "SessionStart plugin reminder runs at most once per day on this machine"
|
|
298
|
+
);
|
|
299
|
+
} else if (definition.key === "monitor_interval_seconds") {
|
|
300
|
+
details.push(`flow-state monitor polls every ${effective.value} second(s) when Monitor is available`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
key: definition.key,
|
|
305
|
+
envVar: runtime.envVar || `CLAUDE_PLUGIN_OPTION_${definition.key.toUpperCase()}`,
|
|
306
|
+
consumer: runtime.consumer || "plugin subprocess",
|
|
307
|
+
summary: runtime.summary || "runtime consumer",
|
|
308
|
+
value: effective.value,
|
|
309
|
+
source: effective.source,
|
|
310
|
+
details,
|
|
311
|
+
};
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
261
315
|
function auditCurdxFlowPluginOptions(parsed, warnings, pluginOptionsState, scope = "project") {
|
|
262
316
|
if (!isNonArrayObject(parsed) || !("pluginConfigs" in parsed)) {
|
|
263
317
|
return;
|
|
@@ -593,6 +647,7 @@ export async function readProjectClaudeSettings(cwd = process.cwd(), { homeDir =
|
|
|
593
647
|
localParseError: null,
|
|
594
648
|
localWarnings: [],
|
|
595
649
|
pluginOptions: createCurdxFlowPluginOptionsState(),
|
|
650
|
+
pluginRuntimeProjection: [],
|
|
596
651
|
};
|
|
597
652
|
|
|
598
653
|
try {
|
|
@@ -972,5 +1027,7 @@ export async function readProjectClaudeSettings(cwd = process.cwd(), { homeDir =
|
|
|
972
1027
|
}
|
|
973
1028
|
}
|
|
974
1029
|
|
|
1030
|
+
state.pluginRuntimeProjection = buildCurdxFlowRuntimeProjection(state.pluginOptions);
|
|
1031
|
+
|
|
975
1032
|
return state;
|
|
976
1033
|
}
|
package/cli/lib/doctor-report.js
CHANGED
|
@@ -598,6 +598,30 @@ export function buildDoctorReport({
|
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
+
if ((projectClaudeSettings?.pluginRuntimeProjection || []).length > 0) {
|
|
602
|
+
const runtimeProjectionSection = createSection("CurDX-Flow runtime projection:");
|
|
603
|
+
|
|
604
|
+
for (const entry of projectClaudeSettings.pluginRuntimeProjection) {
|
|
605
|
+
const sourceLabel = entry.source === "local"
|
|
606
|
+
? "local"
|
|
607
|
+
: entry.source === "project"
|
|
608
|
+
? "project"
|
|
609
|
+
: entry.source === "user"
|
|
610
|
+
? "user"
|
|
611
|
+
: "bundled default";
|
|
612
|
+
pushSectionLine(
|
|
613
|
+
runtimeProjectionSection,
|
|
614
|
+
"info",
|
|
615
|
+
`${entry.envVar.padEnd(36)} ${formatInlineValue(entry.value)} (${sourceLabel})`,
|
|
616
|
+
[
|
|
617
|
+
`consumer: ${entry.consumer}`,
|
|
618
|
+
entry.summary,
|
|
619
|
+
...(entry.details || []),
|
|
620
|
+
]
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
601
625
|
const localProjectSection = createSection("Local project:");
|
|
602
626
|
if (projectState?.exists) {
|
|
603
627
|
pushSectionLine(localProjectSection, "ok", `.flow/ ${cwd}`);
|
|
@@ -88,6 +88,7 @@ Guarded artifact targets:
|
|
|
88
88
|
- `autonomous_blocking`: lets users disable stop-hook continuation without editing plugin files.
|
|
89
89
|
- `daily_dependency_check`: silences or enables the once-per-day recommended-plugin reminder.
|
|
90
90
|
- `monitor_interval_seconds`: controls plugin monitor polling cadence.
|
|
91
|
+
- `doctor` should explain both the machine-effective config value and the projected plugin subprocess env var for these knobs, since hook/monitor behavior depends on the env projection rather than direct JSON parsing.
|
|
91
92
|
|
|
92
93
|
## Plugin Dependency Constraints
|
|
93
94
|
|