@curdx/flow 2.3.6 → 2.3.8

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.6"
9
+ "version": "2.3.8"
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.6",
19
+ "version": "2.3.8",
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.6",
3
+ "version": "2.3.8",
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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.3.8
4
+
5
+ - taught `doctor` to detect dirty CurDX-Flow source checkouts, so plugin developers immediately see when Claude cannot possibly be running their latest local edits yet
6
+ - surfaced bundled source repo metadata (`branch`, `shortSha`, `exactTag`, `dirty`) alongside bundled plugin body version in diagnostics and JSON output
7
+ - documented the reinstall workflow for “same version, but local source changed” plugin-development scenarios
8
+
9
+ ## 2.3.7
10
+
11
+ - taught `doctor` to detect source/package-vs-installed plugin version drift so local plugin development and release validation no longer silently run against stale Claude plugin cache state
12
+ - exposed bundled plugin body version in the runtime report and machine-readable doctor payload for automation consumers
13
+ - documented the reinstall/restart recovery path when Claude is still loading an older CurDX-Flow build
14
+
3
15
  ## 2.3.6
4
16
 
5
17
  - taught `doctor` to inspect file-based Claude Code managed settings and apply them at the correct highest-precedence layer for CurDX-Flow plugin options
package/cli/README.md CHANGED
@@ -44,6 +44,10 @@ External diagnostics: claude CLI / curdx-flow / required MCPs / recommended plug
44
44
 
45
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, file-based managed settings, and runtime env projection.
46
46
 
47
+ `doctor` also compares the plugin body shipped with the current CLI/package against the `curdx-flow` version Claude actually has installed, so local development and release validation do not silently run against stale plugin cache state.
48
+
49
+ When the CLI is running from a git checkout, `doctor` also reports whether that source repo is dirty. This catches the common plugin-development trap where Claude is still running the previously installed cache while your local checkout has uninstalled edits.
50
+
47
51
  ### Project initialization (not a CLI command)
48
52
 
49
53
  Project initialization is a Claude Code slash command, not a CLI one. After `install`, open your project in Claude Code and run:
@@ -163,9 +163,19 @@ export async function readBundledPluginRuntimeDefaults(packageRoot = PACKAGE_ROO
163
163
  const pluginSettingsPath = path.join(packageRoot, "settings.json");
164
164
  const pluginManifestPath = path.join(packageRoot, ".claude-plugin", "plugin.json");
165
165
  const monitorsPath = path.join(packageRoot, "monitors", "monitors.json");
166
+ const packageJsonPath = path.join(packageRoot, "package.json");
166
167
 
167
168
  const state = {
168
169
  exists: false,
170
+ packageVersion: null,
171
+ pluginVersion: null,
172
+ sourceRepo: {
173
+ isGitRepo: false,
174
+ branch: null,
175
+ shortSha: null,
176
+ exactTag: null,
177
+ dirty: false,
178
+ },
169
179
  defaultAgent: null,
170
180
  subagentStatusLineCommand: null,
171
181
  monitorCount: 0,
@@ -189,6 +199,38 @@ export async function readBundledPluginRuntimeDefaults(packageRoot = PACKAGE_ROO
189
199
  pluginManifest = null;
190
200
  }
191
201
 
202
+ try {
203
+ const pkg = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
204
+ state.packageVersion = typeof pkg?.version === "string" ? pkg.version : null;
205
+ } catch {
206
+ state.packageVersion = null;
207
+ }
208
+
209
+ const gitRepoCheck = runSync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: packageRoot });
210
+ if (gitRepoCheck.code === 0 && gitRepoCheck.stdout.trim() === "true") {
211
+ state.sourceRepo.isGitRepo = true;
212
+
213
+ const branch = runSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: packageRoot });
214
+ if (branch.code === 0) {
215
+ state.sourceRepo.branch = branch.stdout.trim() || null;
216
+ }
217
+
218
+ const shortSha = runSync("git", ["rev-parse", "--short", "HEAD"], { cwd: packageRoot });
219
+ if (shortSha.code === 0) {
220
+ state.sourceRepo.shortSha = shortSha.stdout.trim() || null;
221
+ }
222
+
223
+ const exactTag = runSync("git", ["describe", "--tags", "--exact-match", "HEAD"], { cwd: packageRoot });
224
+ if (exactTag.code === 0) {
225
+ state.sourceRepo.exactTag = exactTag.stdout.trim() || null;
226
+ }
227
+
228
+ const status = runSync("git", ["status", "--short"], { cwd: packageRoot });
229
+ if (status.code === 0) {
230
+ state.sourceRepo.dirty = status.stdout.trim().length > 0;
231
+ }
232
+ }
233
+
192
234
  try {
193
235
  monitors = JSON.parse(await fs.readFile(monitorsPath, "utf-8"));
194
236
  } catch {
@@ -200,6 +242,7 @@ export async function readBundledPluginRuntimeDefaults(packageRoot = PACKAGE_ROO
200
242
  }
201
243
 
202
244
  state.exists = true;
245
+ state.pluginVersion = typeof pluginManifest?.version === "string" ? pluginManifest.version : null;
203
246
  state.defaultAgent = typeof pluginSettings?.agent === "string" ? pluginSettings.agent : null;
204
247
  state.subagentStatusLineCommand =
205
248
  typeof pluginSettings?.subagentStatusLine?.command === "string"
@@ -263,9 +263,36 @@ export function buildDoctorReport({
263
263
  pushLine(lines, "ok", `Node ${nodeVersion}`);
264
264
 
265
265
  const curdx = plugins.find((plugin) => plugin.name === "curdx-flow");
266
+ const bundledVersion =
267
+ bundledPluginRuntimeDefaults?.pluginVersion || bundledPluginRuntimeDefaults?.packageVersion || null;
268
+ const bundledSourceRepo = bundledPluginRuntimeDefaults?.sourceRepo || {};
266
269
  if (curdx) {
267
270
  if (curdx.status === "enabled") {
268
271
  pushLine(lines, "ok", `curdx-flow v${curdx.version} (enabled)`);
272
+ if (bundledVersion && curdx.version && curdx.version !== bundledVersion) {
273
+ pushLine(
274
+ lines,
275
+ "warn",
276
+ `curdx-flow source/body v${bundledVersion} differs from installed v${curdx.version}`,
277
+ [
278
+ "you are not validating the same CurDX-Flow build that Claude currently loads",
279
+ "reinstall the plugin from the current source/package, then restart Claude Code",
280
+ "run: npx @curdx/flow install --all",
281
+ ]
282
+ );
283
+ }
284
+ if (bundledSourceRepo.isGitRepo && bundledSourceRepo.dirty) {
285
+ pushLine(
286
+ lines,
287
+ "warn",
288
+ "curdx-flow source repo has uninstalled local changes",
289
+ [
290
+ "the current CLI/source checkout has git modifications that Claude's installed plugin cannot see until you reinstall it",
291
+ "re-run: npx @curdx/flow install --all",
292
+ "then fully restart Claude Code before validating plugin behavior",
293
+ ]
294
+ );
295
+ }
269
296
  } else {
270
297
  pushLine(
271
298
  lines,
@@ -442,6 +469,36 @@ export function buildDoctorReport({
442
469
  if (bundledPluginRuntimeDefaults?.exists) {
443
470
  const bundledRuntimeSection = createSection("CurDX-Flow bundled runtime:");
444
471
 
472
+ if (bundledVersion) {
473
+ pushSectionLine(
474
+ bundledRuntimeSection,
475
+ "info",
476
+ `Bundled plugin body v${bundledVersion}`
477
+ );
478
+ }
479
+
480
+ if (bundledSourceRepo.isGitRepo) {
481
+ const sourceSummary = [
482
+ bundledSourceRepo.branch,
483
+ bundledSourceRepo.shortSha,
484
+ ].filter(Boolean).join(" @ ");
485
+ const sourceDetails = [];
486
+ if (bundledSourceRepo.exactTag) {
487
+ sourceDetails.push(`exact tag: ${bundledSourceRepo.exactTag}`);
488
+ }
489
+ sourceDetails.push(
490
+ bundledSourceRepo.dirty
491
+ ? "git worktree dirty: local source changes are not reflected in Claude until reinstall"
492
+ : "git worktree clean"
493
+ );
494
+ pushSectionLine(
495
+ bundledRuntimeSection,
496
+ bundledSourceRepo.dirty ? "warn" : "info",
497
+ `Bundled source repo ${sourceSummary || "git checkout detected"}`,
498
+ sourceDetails
499
+ );
500
+ }
501
+
445
502
  if (bundledPluginRuntimeDefaults.defaultAgent) {
446
503
  pushSectionLine(
447
504
  bundledRuntimeSection,
@@ -29,8 +29,13 @@ export function run(cmd, args = [], opts = {}) {
29
29
  /**
30
30
  * Sync run — for quick checks (e.g. "which claude").
31
31
  */
32
- export function runSync(cmd, args = []) {
33
- const res = spawnSync(cmd, args, { encoding: "utf-8", shell: false });
32
+ export function runSync(cmd, args = [], opts = {}) {
33
+ const res = spawnSync(cmd, args, {
34
+ encoding: "utf-8",
35
+ shell: false,
36
+ cwd: opts.cwd,
37
+ env: opts.env ? { ...process.env, ...opts.env } : process.env,
38
+ });
34
39
  return {
35
40
  code: res.status ?? -1,
36
41
  stdout: res.stdout ?? "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curdx/flow",
3
- "version": "2.3.6",
3
+ "version": "2.3.8",
4
4
  "description": "Skill-first discipline layer and CLI installer for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {