@curdx/flow 7.0.2 → 7.1.1
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 +27 -0
- package/dist/index.mjs +28 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
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.1 — 2026-05-04
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Windows Chrome detection in the installer's `chrome-devtools-mcp` pre-req check.** `src/registry/plugins/chrome-devtools-mcp.ts`'s `checkChrome()` previously ran `test -x /Applications/...` plus `which google-chrome` / `which chromium` on every platform — none of which work on Windows (`test` is a Unix builtin, `which` isn't on `cmd`/PowerShell PATH by default, and the macOS app-bundle path doesn't exist). Result: the installer rejected Windows machines with Chrome installed, reporting "需要本机已安装 Chrome / Requires Chrome installed locally". Detection is now per-platform, mirroring `GoogleChrome/chrome-launcher`'s `chrome-finder` strategy: on `win32`, scan `LOCALAPPDATA` / `PROGRAMFILES` / `PROGRAMFILES(X86)` for `Google\Chrome\Application\chrome.exe` and `Google\Chrome SxS\Application\chrome.exe` (Canary) via `fs.existsSync`; on `darwin`, check the canonical app-bundle path; on Linux, the existing `which` lookup. A `CHROME_PATH` env var now overrides on all platforms (matches chrome-launcher / Lighthouse convention).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`completed: boolean` and `completedAt: string` fields in `.curdx-state.json` schema.** New optional fields on the spec state file (`schemas/spec.schema.json`). `completed === true` flips the spec into "done, retained for audit" mode; `completedAt` carries an ISO 8601 timestamp (`new Date().toISOString()`, includes milliseconds, e.g. `2026-05-04T20:17:00.123Z`). Legacy v7.0.x state files with `completed === undefined` continue to be treated as in-progress (backwards-compat — see Migration).
|
|
16
|
+
- **`merge-state` `$unset` operator.** `plugins/curdx-flow/hooks/scripts/lib/merge-state.mjs` now accepts a JSON patch with `"$unset": ["key1", "key2"]` to remove specific fields atomically. Used by `/curdx-flow:refactor` to clear `completedAt` when a spec is intentionally re-opened. Patches without `$unset` behave exactly as before (zero-behavior-change for existing callers).
|
|
17
|
+
- **`ensure-gitignore` wire-in to `/curdx-flow:start`.** The `ensure-gitignore` lib utility (already shipped in v7.0.0 but not invoked) is now called from `commands/start.md` so first-spec creation guarantees `**/.progress.md` is gitignored. Closes the "working tree permanently dirty" footgun that motivated this spec.
|
|
18
|
+
- **Shared `CurdxState` interface in `src/hooks/_shared/types.ts`.** Single source of truth for the `.curdx-state.json` shape across all 4 reader hooks (`load-spec-context`, `quick-mode-guard`, `stop-watcher`, `update-spec-index`). Type-only export — esbuild erases at bundle time, zero runtime cost.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **`.curdx-state.json` is no longer deleted on `ALL_TASKS_COMPLETE`.** Coordinator and `commands/implement.md` Step 5 now write `{"completed":true,"completedAt":"<ISO>","awaitingApproval":false}` via `merge-state` instead of `rm -f .curdx-state.json`. The state file is **retained** as the structured source of truth for completed specs (audit trail: `discoveredSkills`, `granularity`, `commitSpec`, `quickMode` interview decisions all survive). Eliminates the test008-class regression where state-deletion left a permanently-dirty working tree, and lets `update-spec-index` short-circuit to `phase=completed` without falling back to fragile markdown reverse-parsing.
|
|
23
|
+
- **5 reader hooks now use strict `state.completed === true` equality.** `stop-watcher.ts:601`, `load-spec-context.ts:147`, `update-spec-index.ts:278` (plus `quick-mode-guard.ts` type-import sync) check `state.completed === true` (never `if (state.completed)`). This is the backwards-compat contract: legacy v7.0.x state files with `completed === undefined` falsy-evaluate and behave identically to pre-7.1.0. Lint-enforced via grep gate (≥3 strict-equality occurrences, 0 truthy-checks).
|
|
24
|
+
- **`update-spec-index` short-circuits to `phase=completed`** when `state.completed === true`, without invoking `inferPhaseFromFiles()`. The fallback path (markdown reverse-parse) remains as a second-tier safety net for human-deleted state files / third-party forks / pre-v7 residue.
|
|
25
|
+
- **`/curdx-flow:refactor` resets via `merge-state $unset` instead of state file deletion.** When a completed spec is re-opened for refactor, `commands/refactor.md` now runs `merge-state .curdx-state.json '{"$unset":["completedAt"],"completed":false}'` rather than `rm -f`. Preserves audit history; matches the v7.1.0 retention model end-to-end.
|
|
26
|
+
|
|
27
|
+
### Migration
|
|
28
|
+
|
|
29
|
+
- Backwards-compatible by design — `completed === undefined` (legacy v7.0.x state files) is treated as in-progress, no manual migration required.
|
|
30
|
+
- See [docs/MIGRATION-V7.md → v7.1.0](./docs/MIGRATION-V7.md#v710-state-retention--completion-marker) for the full upgrade note + a `jq`-style snippet to backfill `completed:true` on specs whose `.curdx-state.json` was deleted under v7.0.x (AC-8.3).
|
|
31
|
+
|
|
5
32
|
## 7.0.2 — 2026-05-04
|
|
6
33
|
|
|
7
34
|
### Fixed
|
package/dist/index.mjs
CHANGED
|
@@ -522,17 +522,38 @@ var claudeMem = {
|
|
|
522
522
|
var claude_mem_default = claudeMem;
|
|
523
523
|
|
|
524
524
|
// src/registry/plugins/chrome-devtools-mcp.ts
|
|
525
|
+
import { existsSync } from "fs";
|
|
526
|
+
import path2 from "path";
|
|
525
527
|
var PLUGIN_ID3 = "chrome-devtools-mcp@chrome-devtools-plugins";
|
|
526
528
|
var MARKETPLACE_NAME3 = "chrome-devtools-plugins";
|
|
527
529
|
var MARKETPLACE_SOURCE3 = "ChromeDevTools/chrome-devtools-mcp";
|
|
528
530
|
async function checkChrome() {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
531
|
+
if (process.env.CHROME_PATH && existsSync(process.env.CHROME_PATH)) return true;
|
|
532
|
+
if (process.platform === "win32") {
|
|
533
|
+
const suffixes = [
|
|
534
|
+
path2.join("Google", "Chrome SxS", "Application", "chrome.exe"),
|
|
535
|
+
path2.join("Google", "Chrome", "Application", "chrome.exe")
|
|
536
|
+
];
|
|
537
|
+
const prefixes = [
|
|
538
|
+
process.env.LOCALAPPDATA,
|
|
539
|
+
process.env.PROGRAMFILES,
|
|
540
|
+
process.env["PROGRAMFILES(X86)"]
|
|
541
|
+
].filter((p10) => Boolean(p10));
|
|
542
|
+
for (const prefix of prefixes) {
|
|
543
|
+
for (const suffix of suffixes) {
|
|
544
|
+
if (existsSync(path2.join(prefix, suffix))) return true;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
if (process.platform === "darwin") {
|
|
550
|
+
return existsSync("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
|
|
551
|
+
}
|
|
552
|
+
const [viaPath, viaPathChromium] = await Promise.all([
|
|
532
553
|
run("which", ["google-chrome"]),
|
|
533
554
|
run("which", ["chromium"])
|
|
534
555
|
]);
|
|
535
|
-
return
|
|
556
|
+
return viaPath.exitCode === 0 || viaPathChromium.exitCode === 0;
|
|
536
557
|
}
|
|
537
558
|
var chromeDevtoolsMcp = {
|
|
538
559
|
id: "chrome-devtools-mcp",
|
|
@@ -713,14 +734,14 @@ function findPkg(id) {
|
|
|
713
734
|
|
|
714
735
|
// src/runner/claudeMd.ts
|
|
715
736
|
import { promises as fs2 } from "fs";
|
|
716
|
-
import
|
|
737
|
+
import path3 from "path";
|
|
717
738
|
import os2 from "os";
|
|
718
739
|
import * as p3 from "@clack/prompts";
|
|
719
740
|
var BEGIN_MARKER = "<!-- BEGIN @curdx/flow v1 -->";
|
|
720
741
|
var END_MARKER = "<!-- END @curdx/flow v1 -->";
|
|
721
742
|
var BLOCK_RE = /<!-- BEGIN @curdx\/flow v\d+[^>]*-->[\s\S]*?<!-- END @curdx\/flow v\d+ -->/;
|
|
722
743
|
function claudeMdPath() {
|
|
723
|
-
return
|
|
744
|
+
return path3.join(os2.homedir(), ".claude", "CLAUDE.md");
|
|
724
745
|
}
|
|
725
746
|
function buildCombinationPatterns(ids) {
|
|
726
747
|
const has = (k) => ids.has(k);
|
|
@@ -896,7 +917,7 @@ async function syncClaudeMd(opts) {
|
|
|
896
917
|
if (next === existing) {
|
|
897
918
|
return { status: "unchanged", path: file };
|
|
898
919
|
}
|
|
899
|
-
await fs2.mkdir(
|
|
920
|
+
await fs2.mkdir(path3.dirname(file), { recursive: true });
|
|
900
921
|
const tmp = `${file}.tmp.${process.pid}`;
|
|
901
922
|
await fs2.writeFile(tmp, next, "utf8");
|
|
902
923
|
await fs2.rename(tmp, file);
|