@curdx/flow 7.1.4 → 7.1.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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to `@curdx/flow` are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/) and the project follows [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## 7.1.5 — 2026-05-06
6
+
7
+ ### Fixed
8
+
9
+ - **Prevent local source checkouts from silently running a stale CLI bundle.** A repo-local execution path could still write the old `~/.claude/CLAUDE.md` block even after `7.1.4` was published correctly, because `.gitignore` excludes `dist/` and `npx @curdx/flow` run from the source checkout may execute the checkout's local `bin` (`dist/index.mjs`) instead of the freshly published npm tarball. If `src/` had newer changes but `dist/` had not been rebuilt, the user would unknowingly run old installer logic and keep re-injecting the pre-7.1.4 managed block. Added `src/runner/buildFreshness.ts` and wired it into `src/index.ts` startup so source checkouts now fail fast with a clear error when `src/**/*.ts` is newer than `dist/index.mjs`, instructing the user to run `npm run build` or execute the published package explicitly. New tests in `tests/runner/buildFreshness.test.ts` cover both stale and fresh build states.
10
+
5
11
  ## 7.1.4 — 2026-05-06
6
12
 
7
13
  ### Changed
package/dist/index.mjs CHANGED
@@ -1711,6 +1711,58 @@ var analyzeCmd = defineCommand({
1711
1711
  });
1712
1712
  var analyze_default = analyzeCmd;
1713
1713
 
1714
+ // src/runner/buildFreshness.ts
1715
+ import { readdirSync, statSync, existsSync as existsSync3 } from "fs";
1716
+ import path5 from "path";
1717
+ import { fileURLToPath } from "url";
1718
+ var SELF_PATH = fileURLToPath(import.meta.url);
1719
+ var RUNNER_DIR = path5.dirname(SELF_PATH);
1720
+ var PROJECT_ROOT = path5.resolve(RUNNER_DIR, "..", "..");
1721
+ var SRC_DIR = path5.join(PROJECT_ROOT, "src");
1722
+ var DIST_ENTRY = path5.join(PROJECT_ROOT, "dist", "index.mjs");
1723
+ var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git"]);
1724
+ function newestTsMtimeMs(dir) {
1725
+ let newest = 0;
1726
+ const entries = readdirSync(dir, { withFileTypes: true });
1727
+ for (const entry of entries) {
1728
+ if (SKIP_DIRS.has(entry.name)) continue;
1729
+ const full = path5.join(dir, entry.name);
1730
+ if (entry.isDirectory()) {
1731
+ newest = Math.max(newest, newestTsMtimeMs(full));
1732
+ continue;
1733
+ }
1734
+ if (!entry.isFile() || !entry.name.endsWith(".ts")) continue;
1735
+ newest = Math.max(newest, statSync(full).mtimeMs);
1736
+ }
1737
+ return newest;
1738
+ }
1739
+ function assertFreshLocalBuild() {
1740
+ assertFreshBuild({ projectRoot: PROJECT_ROOT, srcDir: SRC_DIR, distEntry: DIST_ENTRY });
1741
+ }
1742
+ function assertFreshBuild(opts) {
1743
+ const { projectRoot, srcDir, distEntry } = opts;
1744
+ if (!existsSync3(srcDir) || !existsSync3(distEntry)) return;
1745
+ let distMtimeMs = 0;
1746
+ let newestSrcMtimeMs = 0;
1747
+ try {
1748
+ distMtimeMs = statSync(distEntry).mtimeMs;
1749
+ newestSrcMtimeMs = newestTsMtimeMs(srcDir);
1750
+ } catch {
1751
+ return;
1752
+ }
1753
+ if (newestSrcMtimeMs <= distMtimeMs) return;
1754
+ const relDist = path5.relative(projectRoot, distEntry);
1755
+ const relSrc = path5.relative(projectRoot, srcDir);
1756
+ throw new Error(
1757
+ [
1758
+ "Local build is stale: source files are newer than the bundled CLI entry.",
1759
+ `Detected source checkout at ${projectRoot}.`,
1760
+ `Run \`npm run build\` to refresh ${relDist}, or execute the published package explicitly with \`npx --package @curdx/flow@$(node -p "require('./package.json').version") @curdx/flow\`.`,
1761
+ `This guard only applies when running from a local checkout that still contains ${relSrc}/.`
1762
+ ].join(" ")
1763
+ );
1764
+ }
1765
+
1714
1766
  // src/index.ts
1715
1767
  function parseLang(v) {
1716
1768
  return v === "zh" || v === "en" ? v : void 0;
@@ -1846,6 +1898,7 @@ async function runInteractive(argv2) {
1846
1898
  }
1847
1899
  var argv = process.argv.slice(2);
1848
1900
  var first = firstNonFlag(argv);
1901
+ assertFreshLocalBuild();
1849
1902
  if (first === void 0 || first !== void 0 && !SUBCOMMANDS.has(first) && first !== "--help" && first !== "-h") {
1850
1903
  if (first === void 0) {
1851
1904
  runInteractive(argv).catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curdx/flow",
3
- "version": "7.1.4",
3
+ "version": "7.1.5",
4
4
  "description": "Interactive installer for Claude Code plugins and MCP servers",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.mjs",