@curdx/flow 2.3.7 → 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.7"
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.7",
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.7",
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,11 @@
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
+
3
9
  ## 2.3.7
4
10
 
5
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
package/cli/README.md CHANGED
@@ -46,6 +46,8 @@ External diagnostics: claude CLI / curdx-flow / required MCPs / recommended plug
46
46
 
47
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
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
+
49
51
  ### Project initialization (not a CLI command)
50
52
 
51
53
  Project initialization is a Claude Code slash command, not a CLI one. After `install`, open your project in Claude Code and run:
@@ -169,6 +169,13 @@ export async function readBundledPluginRuntimeDefaults(packageRoot = PACKAGE_ROO
169
169
  exists: false,
170
170
  packageVersion: null,
171
171
  pluginVersion: null,
172
+ sourceRepo: {
173
+ isGitRepo: false,
174
+ branch: null,
175
+ shortSha: null,
176
+ exactTag: null,
177
+ dirty: false,
178
+ },
172
179
  defaultAgent: null,
173
180
  subagentStatusLineCommand: null,
174
181
  monitorCount: 0,
@@ -199,6 +206,31 @@ export async function readBundledPluginRuntimeDefaults(packageRoot = PACKAGE_ROO
199
206
  state.packageVersion = null;
200
207
  }
201
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
+
202
234
  try {
203
235
  monitors = JSON.parse(await fs.readFile(monitorsPath, "utf-8"));
204
236
  } catch {
@@ -265,6 +265,7 @@ export function buildDoctorReport({
265
265
  const curdx = plugins.find((plugin) => plugin.name === "curdx-flow");
266
266
  const bundledVersion =
267
267
  bundledPluginRuntimeDefaults?.pluginVersion || bundledPluginRuntimeDefaults?.packageVersion || null;
268
+ const bundledSourceRepo = bundledPluginRuntimeDefaults?.sourceRepo || {};
268
269
  if (curdx) {
269
270
  if (curdx.status === "enabled") {
270
271
  pushLine(lines, "ok", `curdx-flow v${curdx.version} (enabled)`);
@@ -280,6 +281,18 @@ export function buildDoctorReport({
280
281
  ]
281
282
  );
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
+ }
283
296
  } else {
284
297
  pushLine(
285
298
  lines,
@@ -464,6 +477,28 @@ export function buildDoctorReport({
464
477
  );
465
478
  }
466
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
+
467
502
  if (bundledPluginRuntimeDefaults.defaultAgent) {
468
503
  pushSectionLine(
469
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.7",
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": {