@curdx/flow 2.3.4 → 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.
@@ -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.4"
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.4",
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.4",
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:
@@ -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(args = []) {
20
- const context = createDoctorContext(args);
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
- log.title("🏥 CurdX-Flow Health Check");
40
+ if (!context.json) {
41
+ logImpl.title("🏥 CurdX-Flow Health Check");
42
+ }
23
43
 
24
- const doctorData = await collectDoctorData();
44
+ const doctorData = await collectDoctorDataImpl();
25
45
  if (context.fix) {
26
- log.info("Applying safe fixes...");
27
- const fixes = await applyDoctorFixes(doctorData);
28
- if (fixes.length === 0) {
29
- log.info("No automatic fixes available for the current environment");
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 = buildDoctorReport(doctorData);
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
- renderReportLines(report.lines);
63
+ renderReportLinesImpl(report.lines, { logImpl });
35
64
  for (const section of report.sections) {
36
- console.log(`\n${color.bold(section.title)}`);
37
- renderReportLines(section.lines);
65
+ consoleImpl.log(`\n${colorImpl.bold(section.title)}`);
66
+ renderReportLinesImpl(section.lines, { logImpl });
38
67
  }
39
68
 
40
- printDoctorSummary(report);
69
+ printDoctorSummaryImpl(report, { logImpl });
41
70
  if (context.verbose && doctorData.claudeVersionValue) {
42
- printVerboseDoctorDetails();
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,7 +121,7 @@ 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
- const CURDX_FLOW_RUNTIME_CONSUMERS = {
124
+ export const CURDX_FLOW_RUNTIME_CONSUMERS = {
125
125
  autonomous_blocking: {
126
126
  envVar: "CLAUDE_PLUGIN_OPTION_AUTONOMOUS_BLOCKING",
127
127
  consumer: "hooks/scripts/stop-watcher.sh",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curdx/flow",
3
- "version": "2.3.4",
3
+ "version": "2.3.5",
4
4
  "description": "Skill-first discipline layer and CLI installer for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {