@curdx/flow 2.0.0-beta.9 → 2.0.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +4 -20
- package/CHANGELOG.md +81 -0
- package/README.md +6 -3
- package/README.zh.md +18 -18
- package/bin/curdx-flow.js +30 -1
- package/cli/README.md +8 -6
- package/cli/doctor.js +90 -15
- package/cli/install.js +425 -32
- package/cli/protocols-body.md +21 -0
- package/cli/protocols.js +20 -29
- package/cli/registry.js +64 -14
- package/cli/uninstall.js +101 -7
- package/cli/upgrade.js +1 -1
- package/cli/utils.js +321 -61
- package/commands/implement.md +3 -3
- package/commands/init.md +14 -3
- package/commands/start.md +34 -12
- package/hooks/hooks.json +2 -3
- package/hooks/scripts/inject-karpathy.sh +8 -5
- package/package.json +8 -4
- package/skills/brownfield-index/SKILL.md +1 -1
- package/skills/browser-qa/SKILL.md +1 -1
- package/skills/epic/SKILL.md +1 -1
- package/skills/security-audit/SKILL.md +1 -1
- package/skills/ui-sketch/SKILL.md +1 -1
|
@@ -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.0.0-beta.
|
|
9
|
+
"version": "2.0.0-beta.18"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "curdx-flow",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.18",
|
|
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",
|
|
7
7
|
"email": "bydongxin@gmail.com"
|
|
8
8
|
},
|
|
9
|
-
"homepage": "https://github.com/
|
|
10
|
-
"repository": "https://github.com/
|
|
9
|
+
"homepage": "https://github.com/curdx/curdx-flow",
|
|
10
|
+
"repository": "https://github.com/curdx/curdx-flow",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"keywords": [
|
|
13
13
|
"workflow",
|
|
@@ -16,21 +16,5 @@
|
|
|
16
16
|
"orchestration",
|
|
17
17
|
"karpathy",
|
|
18
18
|
"claude-code"
|
|
19
|
-
]
|
|
20
|
-
"mcpServers": {
|
|
21
|
-
"context7": {
|
|
22
|
-
"command": "npx",
|
|
23
|
-
"args": [
|
|
24
|
-
"-y",
|
|
25
|
-
"@upstash/context7-mcp@latest"
|
|
26
|
-
]
|
|
27
|
-
},
|
|
28
|
-
"sequential-thinking": {
|
|
29
|
-
"command": "npx",
|
|
30
|
-
"args": [
|
|
31
|
-
"-y",
|
|
32
|
-
"@modelcontextprotocol/server-sequential-thinking"
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
19
|
+
]
|
|
36
20
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,83 @@ All notable changes to CurDX-Flow will be documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `hooks/hooks.json` + `hooks/scripts/inject-karpathy.sh` — migrated the L1 baseline injector from the `InstructionsLoaded` event to `SessionStart` with `matcher: "startup|clear|compact"`. Per the Claude Code hooks docs (code.claude.com/docs/en/hooks), `InstructionsLoaded` is an observability-only event: its hook schema has no `hookSpecificOutput` field, so the injector's `{"hookSpecificOutput":{"hookEventName":"InstructionsLoaded","additionalContext":…}}` payload was rejected at session boot with `Hook JSON output validation failed — (root): Invalid input`, producing the `SessionStart:startup hook error` banner on every Claude Code launch. The `startup|clear|compact` matcher preserves the original "baseline survives compaction" intent. Also updated `docs/architecture.md` and `README.zh.md` hook-event inventories.
|
|
10
|
+
|
|
11
|
+
### BREAKING
|
|
12
|
+
|
|
13
|
+
- **`context7` and `sequential-thinking` moved from plugin-bundled MCPs to user-level MCPs.** Previously `.claude-plugin/plugin.json` declared both in `mcpServers`, so Claude Code auto-registered them as `plugin:curdx-flow:context7` and `plugin:curdx-flow:sequential-thinking` when the plugin installed. This is no longer the case — the `mcpServers` block is gone. Instead, `curdx-flow install` now runs `claude mcp add context7 …` + `claude mcp add sequential-thinking …` against the user's `~/.claude.json`, which keeps them as standard user-level registrations named `context7` and `sequential-thinking`.
|
|
14
|
+
|
|
15
|
+
**Why**: every early adopter who ran `claude mcp add context7 -- npx -y @upstash/context7-mcp --api-key ctx7sk-…` before installing curdx-flow ended up with *both* entries side-by-side — doubling MCP processes, making API-key routing unpredictable (random between free-tier plugin copy and paid user copy), and forcing an awkward env-var migration path. User-level registration matches the way every other MCP in the ecosystem is installed, keeps tool names standard (`mcp__context7__*` instead of `mcp__plugin_curdx-flow_context7__*`), and lets users put an `--api-key` directly in their own entry without any env-var indirection. Every agent / knowledge doc / command in the repo already calls the standard tool-name form, so this is a **zero-change-for-callers** migration.
|
|
16
|
+
|
|
17
|
+
**Migration for existing users**:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Upgrade the plugin — this removes the plugin-bundled MCPs and
|
|
21
|
+
# registers them at user-level (preserving any existing user-level entry
|
|
22
|
+
# with a custom --api-key).
|
|
23
|
+
npx @curdx/flow@latest upgrade
|
|
24
|
+
|
|
25
|
+
# Restart Claude Code so the plugin manifest reloads.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
After upgrade, `claude mcp list` will show `context7` and
|
|
29
|
+
`sequential-thinking` (user-level) but NOT `plugin:curdx-flow:context7` etc.
|
|
30
|
+
`npx @curdx/flow doctor` confirms with "user-level (standard)" in the
|
|
31
|
+
"MCP Servers" section.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- `cli/registry.js` exports a new `BUNDLED_MCPS` constant — the source-of-truth list of MCPs that `install` registers at user-level and `uninstall` optionally removes.
|
|
36
|
+
- `cli/install.js` Step 3.5 — registers the required MCPs via `claude mcp add`. Detects pre-existing user-level entries (e.g. your hand-configured context7 with an API key) and preserves them instead of overwriting.
|
|
37
|
+
- `cli/uninstall.js` Step 4.5 — asks whether to `claude mcp remove` the registered MCPs (default: no, because other tools may depend on them).
|
|
38
|
+
- `cli/doctor.js` — now reports "user-level (standard)" for each required MCP when it's registered the right way, and "(legacy)" with a migration hint when the old plugin-bundled form is still active.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- The "Duplicate MCP" warning in `doctor` (added in beta.11) is now framed as "Legacy plugin-bundled MCPs still present" with a concrete migration command, since the new architecture reserves duplication strictly for the upgrade-transition window.
|
|
43
|
+
- `docs/getting-started.md` "Optional: use your paid context7 API key" section rewritten around the user-level path (add `--api-key` to your `claude mcp add` command) since env-var indirection is no longer the only way to route a key to the plugin copy.
|
|
44
|
+
|
|
45
|
+
## [2.0.0-beta.11] - 2026-04-22
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- `cli/doctor.js` detects when a user-level MCP in `~/.claude.json` (typically `context7` added via `claude mcp add …`) duplicates a plugin-bundled MCP from `plugin.json` (`plugin:curdx-flow:context7`). Backed by `cli/utils.js:readUserMcpConfig()` + `findDuplicateMcps()` and 3 new tests in `test/utils.test.js`.
|
|
50
|
+
- `docs/getting-started.md` "Optional: use your paid context7 API key" section documenting the env-var path.
|
|
51
|
+
|
|
52
|
+
## [2.0.0-beta.10] - 2026-04-21
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- `cli/utils.js` — `listMcps` rewritten to handle the actual `claude mcp list` format captured from claude 2.1.117. The previous regex matched only a single kebab-case token before the first colon, so `plugin:curdx-flow:context7: npx ...` parsed as name=`plugin` and silently dropped the rest. New parser exports `{ name, plugin, fullName, status, command }` and is fixture-tested in `test/utils.test.js`.
|
|
57
|
+
- `cli/doctor.js` — MCP presence check now accepts both standalone (`context7`) and plugin-bundled (`plugin:curdx-flow:context7`) registrations, with source in the status line. Fixes the same class of false-positive that bit `chrome-devtools` in beta.7. Also gated `--verbose` raw-plugin dump behind `claude` being on PATH, so it no longer runs a meaningless empty child when the CLI is absent.
|
|
58
|
+
- `cli/install.js` — step counter was `1/4`..`4/4` but there are five steps; `Step 5: inject global protocols` was emitted via bare `console.log` so the progress display lied. All five steps now use `log.step(N, 5, ...)`. Also switched `⏳ Installing` and `✅ Install complete` glyphs to the `▸` / `✓` symbols used elsewhere in the project's `log.*` helpers.
|
|
59
|
+
- `cli/uninstall.js` — same `⏳` → `▸` glyph normalisation.
|
|
60
|
+
- `cli/protocols.js` + `cli/utils.js` + `cli/uninstall.js` — switched from `process.env.HOME || ""` to `os.homedir()`. `$HOME` is only guaranteed in interactive login shells; CI containers, some `docker exec` invocations, and non-login spawns can leave it empty, which resolved `GLOBAL_CLAUDE_MD` to `/.claude/CLAUDE.md` and broke `ensureRuntimeInPath` runtime candidate lookup.
|
|
61
|
+
- `bin/curdx-flow.js` — `main()` was called unconditionally at module scope, so `import()` from a test would spawn the CLI, parse the test runner's argv, and `exit(1)`. Now guarded by the ESM direct-invocation idiom (`import.meta.url === pathToFileURL(process.argv[1]).href`). Added one real-import test.
|
|
62
|
+
- `.claude-plugin/plugin.json` — `homepage` and `repository` pointed at `github.com/wdx/curdx-flow` but the authoritative remote is `github.com/curdx/curdx-flow`. Plugin-marketplace UI clicks previously 404'd. Aligned to the real owner.
|
|
63
|
+
- `.github/workflows/npm-publish.yml` — bumped `actions/setup-node` from Node 20 to Node 22 LTS ahead of the 2026-06-02 Node 20 removal.
|
|
64
|
+
- `scripts/release.sh` — lockstep bump of `plugin.json` + `marketplace.json` now parses both files in memory before writing either, with `git checkout -- package.json` auto-revert on failure. Previously the second file could fail to write while the first was already disk-committed.
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
|
|
68
|
+
- `commands/start.md` — replaced the brittle `xargs`/`awk`/`sed` flag-parsing block with a model-directed parse that tolerates quoted strings in `$ARGUMENTS` (e.g. `my-feature "Fix user's login bug"` no longer hits `xargs: unmatched quote`).
|
|
69
|
+
- `commands/init.md` — Step 5 used to say "Run `npx @curdx/flow doctor`" but the slash command runs inside Claude Code where a spawned CLI's output doesn't render cleanly. Reframed as "verify inline + suggest the user run the CLI in a separate terminal if they want the full report."
|
|
70
|
+
- `commands/implement.md` — replaced `❌` emoji with `✗` to match the project's own `log.err` helper.
|
|
71
|
+
- `docs/architecture.md` — Hook System section and CLI layout were **entirely fabricated** (listed non-existent hooks `pre-spec.sh` / `post-implement.sh` / `pre-verify.sh` / `post-review.sh` / `on-gate-fail.sh` and bogus paths `cli/bin/flow` / `cli/commands/install.js` / `cli/lib/…`). Rewritten to match the real `hooks/scripts/` layout (4 hooks: session-start / inject-karpathy / quick-mode-guard / stop-watcher) and real `bin/` + `cli/` paths including `cli/registry.js` and the `test/` directory.
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- `test/utils.test.js` grew 5 fixture tests for the new `parseMcpList` against a captured `claude mcp list` output.
|
|
76
|
+
- `test/cli-entrypoints.test.js` — 5 smoke tests that each dynamically-import `cli/doctor.js` / `cli/install.js` / `cli/upgrade.js` / `cli/uninstall.js` and assert the expected top-level function exports. Guards against the "deleted an import but forgot the consumer" class of regression at CI time. Plus one test that imports `bin/curdx-flow.js` now that it no longer runs `main()` at module load.
|
|
77
|
+
|
|
78
|
+
### Removed (docs compliance)
|
|
79
|
+
|
|
80
|
+
- Chinese trigger phrases from `skills/*/SKILL.md` descriptions (5 files). Keeping bilingual triggers violated the project's own language-separation rule (`CLAUDE.md`: "Documentation layer = English"). Semantic matching on the English phrases plus the model's own bilingual understanding covers the same invocation surface.
|
|
81
|
+
|
|
82
|
+
## [2.0.0-beta.9] - 2026-04-21
|
|
83
|
+
|
|
7
84
|
### Fixed (P0)
|
|
8
85
|
|
|
9
86
|
- `cli/utils.js` — `findRuntime()` referenced `existsSync` without importing it; any user whose `bun`/`uv` was not on PATH hit `ReferenceError` during install or doctor.
|
|
@@ -18,6 +95,10 @@ All notable changes to CurDX-Flow will be documented here.
|
|
|
18
95
|
- `commands/start.md` and `commands/spec.md` now produce `.state.json` files that match `schemas/spec-state.schema.json` (field names: `spec_name` / `created` / `updated` / `version`; initial phase is `research`, not the undefined `created`).
|
|
19
96
|
- All python heredocs inside hook scripts use quoted delimiters (`<<'PY'`) and read `STATE_FILE` via `os.environ`, closing a shell→python code-injection surface triggered by unusual spec names.
|
|
20
97
|
|
|
98
|
+
### Added
|
|
99
|
+
|
|
100
|
+
- First real test suite — `node --test`-based, 18 regression tests covering `cli/protocols.js`, `cli/registry.js`, and `cli/utils.js`. Wired into `package.json` `scripts.test` and the CI `publish` job so a failing test blocks `npm publish`.
|
|
101
|
+
|
|
21
102
|
### Removed
|
|
22
103
|
|
|
23
104
|
- `hooks/scripts/fail-tracker.sh` and its `PostToolUseFailure` registration — the counter was written but never read by any consumer (the intended pua escalation was never implemented). Can be reintroduced when the consumer exists.
|
package/README.md
CHANGED
|
@@ -28,7 +28,9 @@ Not a framework. Not a methodology library. A discipline layer.
|
|
|
28
28
|
npx @curdx/flow install --all
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
This installs the Claude Code plugin (fully offline from the npm package — no GitHub fetch), the
|
|
31
|
+
This installs the Claude Code plugin (fully offline from the npm package — no GitHub fetch), the official Context7 plugin, the required sequential-thinking MCP server, and four recommended companion plugins (pua, claude-mem, frontend-design, chrome-devtools-mcp).
|
|
32
|
+
|
|
33
|
+
**Note:** If you're running this command inside the `curdx-flow` project directory itself, use `npx --ignore-existing @curdx/flow install --all` to avoid npx trying to use the local package without dependencies installed.
|
|
32
34
|
|
|
33
35
|
## 9 slash commands, that's it
|
|
34
36
|
|
|
@@ -97,7 +99,8 @@ npm i -g @curdx/flow@^1.1
|
|
|
97
99
|
- **8 composable gates** — Karpathy / Verification / TDD / Coverage / Adversarial / Edge-Case / Security / DevEx
|
|
98
100
|
- **4 execution strategies** for `/curdx-flow:implement` (linear / subagent / stop-hook / wave, auto-routed)
|
|
99
101
|
- **5 hook events** that enforce the discipline without user action
|
|
100
|
-
- **
|
|
102
|
+
- **Required docs/reasoning tools** — Context7 official plugin (MCP + skill + docs agent) and sequential-thinking MCP
|
|
103
|
+
- **4 recommended companion plugins** — pua, claude-mem, frontend-design, chrome-devtools-mcp
|
|
101
104
|
- **Offline-capable install** — the npm package ships the full plugin body; zero GitHub round-trips during install
|
|
102
105
|
|
|
103
106
|
## Documentation
|
|
@@ -123,7 +126,7 @@ CurDX-Flow v2 is a distillation, not an invention. Ideas we depend on:
|
|
|
123
126
|
- [**superpowers**](https://github.com/obra/superpowers) — subagent discipline + TDD + two-stage review
|
|
124
127
|
- [**pua**](https://github.com/tanweai/pua) — the three red lines
|
|
125
128
|
- [**claude-mem**](https://github.com/thedotmack/claude-mem) — cross-session memory
|
|
126
|
-
- **
|
|
129
|
+
- **MCP / plugin ecosystem** — context7 (Upstash), sequential-thinking, chrome-devtools-mcp (Chrome DevTools team), frontend-design skill
|
|
127
130
|
|
|
128
131
|
## License
|
|
129
132
|
|
package/README.zh.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **Claude Code 的 AI 工程工作流元框架**
|
|
4
4
|
> 把 Claude Code 变成有工程纪律的 AI 团队 — 编排 MCP 和插件,强制 Karpathy 4 原则,用规格驱动工作流交付高质量软件。
|
|
5
5
|
|
|
6
|
-
[](https://www.npmjs.com/package/@curdx/flow)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
[](https://code.claude.com)
|
|
9
9
|
[](./README.md)
|
|
@@ -16,15 +16,15 @@ CurDX-Flow 是一个 Claude Code 插件,把 6 个验证过的 AI 工程工作
|
|
|
16
16
|
|
|
17
17
|
**不重造轮子。编排好轮子。**
|
|
18
18
|
|
|
19
|
-
## 一览(
|
|
19
|
+
## 一览(v2)
|
|
20
20
|
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
21
|
+
- **9 个命令** — 初始化 / 启动规格 / 规格 / 执行 / 验证 / 审查 / 调试 / fast / 帮助
|
|
22
|
+
- **15 个内部代理** — 由命令调度,不再暴露 v1 的人格角色
|
|
23
23
|
- **8 个可组合 Gate** — Karpathy / Verification / TDD / Coverage / Adversarial / Edge-Case / Security / DevEx
|
|
24
24
|
- **4 种执行策略** — linear / subagent / stop-hook / wave(自动路由)
|
|
25
25
|
- **10 个知识文档** — 规格驱动 / POC-First / 原子提交 / 执行策略 / ...
|
|
26
|
-
- **
|
|
27
|
-
-
|
|
26
|
+
- **5 个 hook 事件** — SessionStart / InstructionsLoaded / PostToolUseFailure / Stop / PreToolUse
|
|
27
|
+
- **必需文档/推理工具 + 4 个推荐插件** — Context7 官方插件 / sequential-thinking MCP + pua / claude-mem / frontend-design / chrome-devtools-mcp
|
|
28
28
|
- **优雅降级** — 依赖缺失时进入 fallback 模式并清晰告知
|
|
29
29
|
|
|
30
30
|
## 为什么用
|
|
@@ -41,23 +41,23 @@ CurDX-Flow 是一个 Claude Code 插件,把 6 个验证过的 AI 工程工作
|
|
|
41
41
|
|
|
42
42
|
## 安装
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/plugin marketplace add wdx/curdx-flow
|
|
47
|
-
/plugin install curdx-flow
|
|
44
|
+
```bash
|
|
45
|
+
npx @curdx/flow install --all
|
|
48
46
|
```
|
|
49
47
|
|
|
48
|
+
这会用 `claude plugin ...` 非交互 CLI 安装 CurDX-Flow 插件、Context7 官方插件、必需 MCP,并安装推荐插件。
|
|
49
|
+
|
|
50
|
+
**注意:** 如果你在 `curdx-flow` 项目目录内运行此命令,请使用 `npx --ignore-existing @curdx/flow install --all` 避免 npx 尝试使用本地未安装依赖的包。
|
|
51
|
+
|
|
50
52
|
### 本地 dev
|
|
51
53
|
```bash
|
|
52
|
-
git clone https://github.com/
|
|
54
|
+
git clone https://github.com/curdx/curdx-flow
|
|
53
55
|
claude --plugin-dir ./curdx-flow
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
安装后在 Claude Code 内运行:
|
|
57
59
|
|
|
58
60
|
```
|
|
59
|
-
/curdx-flow:install-deps # 交互式安装 pua / claude-mem / frontend-design
|
|
60
|
-
/curdx-flow:doctor # 验证健康
|
|
61
61
|
/curdx-flow:init # 初始化你的项目
|
|
62
62
|
```
|
|
63
63
|
|
|
@@ -102,8 +102,8 @@ claude --plugin-dir ./curdx-flow
|
|
|
102
102
|
| 文档 | 何时读 |
|
|
103
103
|
|-----|------|
|
|
104
104
|
| [`docs/getting-started.md`](./docs/getting-started.md) | 首次使用,5 分钟上手 |
|
|
105
|
-
| [`docs/command-reference.md`](./docs/command-reference.md) |
|
|
106
|
-
| [`docs/agent-reference.md`](./docs/agent-reference.md) |
|
|
105
|
+
| [`docs/command-reference.md`](./docs/command-reference.md) | 9 个命令完整参考 |
|
|
106
|
+
| [`docs/agent-reference.md`](./docs/agent-reference.md) | 15 个内部代理 |
|
|
107
107
|
| [`docs/workflows.md`](./docs/workflows.md) | 5 种典型场景(greenfield/brownfield/epic/fast/UI) |
|
|
108
108
|
| [`docs/architecture.md`](./docs/architecture.md) | 内部设计(给扩展者) |
|
|
109
109
|
| [`docs/ethos.md`](./docs/ethos.md) | 设计决策的理由 |
|
|
@@ -132,7 +132,7 @@ CurDX-Flow 是蒸馏,不是原创。深深致谢:
|
|
|
132
132
|
- [**pua**](https://github.com/tanweai/pua) — 持续性 + 三条红线
|
|
133
133
|
- [**claude-mem**](https://github.com/thedotmack/claude-mem) — 自动跨会话记忆
|
|
134
134
|
- [**frontend-design skill**](https://claude.ai/skills/frontend-design) — distinctive UI(Anthropic 官方)
|
|
135
|
-
- **
|
|
135
|
+
- **Context7**(Upstash)+ **sequential-thinking**(Anthropic)+ **chrome-devtools-mcp**(Chrome 团队)
|
|
136
136
|
|
|
137
137
|
## 许可
|
|
138
138
|
|
|
@@ -140,7 +140,7 @@ MIT。见 [`LICENSE`](./LICENSE)。
|
|
|
140
140
|
|
|
141
141
|
## 贡献
|
|
142
142
|
|
|
143
|
-
- Issues: https://github.com/
|
|
143
|
+
- Issues: https://github.com/curdx/curdx-flow/issues
|
|
144
144
|
- 欢迎 PR,但请先用 `/curdx-flow:spec` 自己走一遍(吃自己的狗粮)
|
|
145
145
|
- 社区准则:友善 + 具体 + 不对着 LLM 发火
|
|
146
146
|
|
package/bin/curdx-flow.js
CHANGED
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
* for the full command/workflow reference)
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
import { realpathSync } from "node:fs";
|
|
25
|
+
|
|
23
26
|
import { install } from "../cli/install.js";
|
|
24
27
|
import { doctor } from "../cli/doctor.js";
|
|
25
28
|
import { upgrade } from "../cli/upgrade.js";
|
|
@@ -128,4 +131,30 @@ async function main() {
|
|
|
128
131
|
}
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
main()
|
|
134
|
+
// Only execute main() when invoked directly (`node bin/curdx-flow.js ...`
|
|
135
|
+
// or via the npm bin shim at node_modules/.bin/<name>). When the file is
|
|
136
|
+
// imported by tests or tooling, we want the module graph to load without
|
|
137
|
+
// side-effects.
|
|
138
|
+
//
|
|
139
|
+
// CRITICAL: compare RESOLVED real paths. npm installs the bin as a symlink
|
|
140
|
+
// (node_modules/.bin/curdx-flow → ../@curdx/flow/bin/curdx-flow.js), so
|
|
141
|
+
// process.argv[1] is the symlink path while import.meta.url resolves to
|
|
142
|
+
// the real file. Comparing them directly (the pre-beta.13 behavior)
|
|
143
|
+
// silently skipped main() for every single npx / global-install user,
|
|
144
|
+
// producing a completely broken CLI that exited with no output. Regression
|
|
145
|
+
// caught by user report + reproduced in CI via test/cli-entrypoints.test.js.
|
|
146
|
+
function isInvokedDirectly() {
|
|
147
|
+
if (!process.argv[1]) return false;
|
|
148
|
+
try {
|
|
149
|
+
return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
150
|
+
} catch {
|
|
151
|
+
// argv[1] is not a real filesystem path (e.g. `node -e` eval forms or
|
|
152
|
+
// a worker pipe). Treat as "not invoked directly" — the caller is
|
|
153
|
+
// doing something non-standard.
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (isInvokedDirectly()) {
|
|
159
|
+
main();
|
|
160
|
+
}
|
package/cli/README.md
CHANGED
|
@@ -24,9 +24,11 @@ npx @curdx/flow upgrade
|
|
|
24
24
|
|
|
25
25
|
Steps:
|
|
26
26
|
1. Verify the `claude` CLI is installed
|
|
27
|
-
2. `claude plugin marketplace add curdx/curdx-flow`
|
|
28
|
-
3. `claude plugin install curdx-flow@curdx-flow-marketplace`
|
|
29
|
-
4.
|
|
27
|
+
2. `claude plugin marketplace add --scope user curdx/curdx-flow`
|
|
28
|
+
3. `claude plugin install --scope user curdx-flow@curdx-flow-marketplace`
|
|
29
|
+
4. Install required companion plugin: **context7-plugin@context7-marketplace**
|
|
30
|
+
5. Register required user-level MCP: **sequential-thinking**
|
|
31
|
+
6. Interactively (or automatically) install recommended plugins: **pua**, **claude-mem**, **frontend-design**, **chrome-devtools-mcp**
|
|
30
32
|
|
|
31
33
|
| Flag | Purpose |
|
|
32
34
|
|------|---------|
|
|
@@ -35,7 +37,7 @@ Steps:
|
|
|
35
37
|
|
|
36
38
|
### `doctor [--verbose]`
|
|
37
39
|
|
|
38
|
-
External diagnostics: claude CLI / curdx-flow /
|
|
40
|
+
External diagnostics: claude CLI / curdx-flow / required MCPs / recommended plugins / current directory `.flow/` state.
|
|
39
41
|
|
|
40
42
|
### Project initialization (not a CLI command)
|
|
41
43
|
|
|
@@ -50,11 +52,11 @@ This keeps the CLI scoped to install-time and lifecycle operations only — anyt
|
|
|
50
52
|
|
|
51
53
|
### `upgrade`
|
|
52
54
|
|
|
53
|
-
`claude plugin marketplace update` + `claude plugin update` for every installed curdx-flow-related plugin.
|
|
55
|
+
`claude plugin marketplace update` + `claude plugin update --scope user` for every installed curdx-flow-related plugin.
|
|
54
56
|
|
|
55
57
|
### `uninstall [-y] [--keep-recommended] [--purge]`
|
|
56
58
|
|
|
57
|
-
Inverse of `install`. By default removes only the curdx-flow plugin. With `--purge`, also removes the `~/.local/bin/bun`
|
|
59
|
+
Inverse of `install`. By default removes only the curdx-flow plugin. Recommended plugins are kept unless selected interactively. With `--purge`, also removes third-party marketplaces and the `~/.local/bin/bun` / `~/.local/bin/uv` symlinks created by install.
|
|
58
60
|
|
|
59
61
|
## Why a CLI?
|
|
60
62
|
|
package/cli/doctor.js
CHANGED
|
@@ -10,10 +10,13 @@ import {
|
|
|
10
10
|
runSync,
|
|
11
11
|
claudeVersion,
|
|
12
12
|
listPlugins,
|
|
13
|
+
listPluginMarketplaces,
|
|
13
14
|
listMcps,
|
|
14
15
|
ensureClaudeMemRuntimes,
|
|
16
|
+
readUserMcpConfig,
|
|
17
|
+
findDuplicateMcps,
|
|
15
18
|
} from "./utils.js";
|
|
16
|
-
import { RECOMMENDED_PLUGINS } from "./registry.js";
|
|
19
|
+
import { BUNDLED_MCPS, REQUIRED_PLUGINS, RECOMMENDED_PLUGINS } from "./registry.js";
|
|
17
20
|
|
|
18
21
|
export async function doctor(args = []) {
|
|
19
22
|
const verbose = args.includes("--verbose") || args.includes("-v");
|
|
@@ -50,21 +53,58 @@ export async function doctor(args = []) {
|
|
|
50
53
|
warnings++;
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
const marketplaces = cv ? listPluginMarketplaces() : [];
|
|
57
|
+
const marketplaceNames = new Set(marketplaces.map((m) => m.name));
|
|
58
|
+
|
|
59
|
+
// ---------- Required plugins ----------
|
|
60
|
+
console.log(`\n${color.bold("Required plugins:")}`);
|
|
61
|
+
for (const r of REQUIRED_PLUGINS) {
|
|
62
|
+
const p = plugins.find((x) => x.id === r.id || x.name === r.name);
|
|
63
|
+
if (r.marketplaceSource && !marketplaceNames.has(r.marketplaceId)) {
|
|
64
|
+
log.warn(
|
|
65
|
+
`${r.marketplaceId.padEnd(22)} marketplace missing ${color.dim(`(run: claude plugin marketplace add --scope ${r.scope} ${r.marketplaceSource})`)}`
|
|
66
|
+
);
|
|
67
|
+
warnings++;
|
|
68
|
+
}
|
|
69
|
+
if (p && p.status === "enabled") {
|
|
70
|
+
log.ok(`${r.name.padEnd(22)} ${color.dim(`v${p.version || "unknown"}`)}`);
|
|
71
|
+
} else if (p && p.status === "failed") {
|
|
72
|
+
log.err(`${r.name.padEnd(22)} load failed`);
|
|
73
|
+
errors++;
|
|
74
|
+
} else {
|
|
75
|
+
log.warn(
|
|
76
|
+
`${r.name.padEnd(22)} not installed ${color.dim(`(run: claude plugin install --scope ${r.scope} ${r.installSpec})`)}`
|
|
77
|
+
);
|
|
78
|
+
warnings++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
53
82
|
// ---------- MCPs ----------
|
|
54
|
-
|
|
55
|
-
// chrome-devtools is NOT here anymore — it was extracted into its own
|
|
56
|
-
// recommended plugin (see below) to align with the "each MCP owned by one
|
|
57
|
-
// plugin" model and avoid double-spawning the chrome-devtools-mcp process.
|
|
58
|
-
console.log(`\n${color.bold("MCP Servers:")}`);
|
|
83
|
+
console.log(`\n${color.bold("MCP Servers (required by L2 mandatory tools):")}`);
|
|
59
84
|
const mcps = cv ? listMcps() : [];
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
85
|
+
for (const expected of BUNDLED_MCPS) {
|
|
86
|
+
const m = expected.name;
|
|
87
|
+
// Beta.12 onward: the required MCPs are registered at user-level
|
|
88
|
+
// (via `claude mcp add`), NOT plugin-bundled. Both still show up in
|
|
89
|
+
// `claude mcp list`. Accept a standalone user-level registration
|
|
90
|
+
// as the primary form, and warn if only a plugin-bundled copy exists
|
|
91
|
+
// (because that's the legacy layout that beta.11 had).
|
|
92
|
+
const userLevel = mcps.find((x) => x.name === m && x.plugin === null);
|
|
93
|
+
const pluginLevel = mcps.find((x) => x.name === m && x.plugin !== null);
|
|
94
|
+
|
|
95
|
+
if (userLevel) {
|
|
96
|
+
log.ok(`${m.padEnd(22)} ${color.dim("user-level (standard)")}`);
|
|
97
|
+
} else if (pluginLevel) {
|
|
98
|
+
log.warn(
|
|
99
|
+
`${m.padEnd(22)} registered via plugin:${pluginLevel.plugin} (legacy). ` +
|
|
100
|
+
`Run ${color.cyan("npx @curdx/flow install --all")} to migrate to user-level.`
|
|
101
|
+
);
|
|
102
|
+
warnings++;
|
|
65
103
|
} else {
|
|
66
104
|
if (curdx) {
|
|
67
|
-
log.warn(
|
|
105
|
+
log.warn(
|
|
106
|
+
`${m.padEnd(22)} missing. Run: ${color.cyan(`claude mcp add --scope user ${m} -- ${expected.command} ${expected.args.join(" ")}`)}`
|
|
107
|
+
);
|
|
68
108
|
warnings++;
|
|
69
109
|
} else {
|
|
70
110
|
log.info(`${m.padEnd(22)} waiting for curdx-flow install`);
|
|
@@ -76,7 +116,13 @@ export async function doctor(args = []) {
|
|
|
76
116
|
console.log(`\n${color.bold("Recommended plugins:")}`);
|
|
77
117
|
let claudeMemEnabled = false;
|
|
78
118
|
for (const r of RECOMMENDED_PLUGINS) {
|
|
79
|
-
const p = plugins.find((x) => x.name === r.name);
|
|
119
|
+
const p = plugins.find((x) => x.id === r.id || x.name === r.name);
|
|
120
|
+
if (r.marketplaceSource && !marketplaceNames.has(r.marketplaceId)) {
|
|
121
|
+
log.warn(
|
|
122
|
+
`${r.marketplaceId.padEnd(22)} marketplace missing ${color.dim(`(run: claude plugin marketplace add --scope ${r.scope} ${r.marketplaceSource})`)}`
|
|
123
|
+
);
|
|
124
|
+
warnings++;
|
|
125
|
+
}
|
|
80
126
|
if (p && p.status === "enabled") {
|
|
81
127
|
log.ok(`${r.name.padEnd(22)} ${color.dim(`v${p.version}`)}`);
|
|
82
128
|
if (r.postInstall === "claude-mem-runtimes") claudeMemEnabled = true;
|
|
@@ -85,12 +131,39 @@ export async function doctor(args = []) {
|
|
|
85
131
|
errors++;
|
|
86
132
|
} else {
|
|
87
133
|
log.warn(
|
|
88
|
-
`${r.name.padEnd(22)} not installed ${color.dim(`(run: claude plugin install ${r.installSpec})`)}`
|
|
134
|
+
`${r.name.padEnd(22)} not installed ${color.dim(`(run: claude plugin install --scope ${r.scope} ${r.installSpec})`)}`
|
|
89
135
|
);
|
|
90
136
|
warnings++;
|
|
91
137
|
}
|
|
92
138
|
}
|
|
93
139
|
|
|
140
|
+
// ---------- Legacy plugin-bundled MCP residue (beta.11 and earlier) ----------
|
|
141
|
+
// Beta.12 moved context7 + sequential-thinking to user-level registration.
|
|
142
|
+
// If both a user-level and a plugin-bundled copy are visible, the user
|
|
143
|
+
// was likely installed from an older beta.7-beta.11 that still had
|
|
144
|
+
// mcpServers in plugin.json and a `claude mcp update` hasn't refreshed
|
|
145
|
+
// the plugin cache yet. Point them at the migration command.
|
|
146
|
+
if (cv) {
|
|
147
|
+
const userCfg = readUserMcpConfig();
|
|
148
|
+
const duplicates = findDuplicateMcps(mcps, userCfg);
|
|
149
|
+
if (duplicates.length > 0) {
|
|
150
|
+
console.log(`\n${color.bold("Legacy plugin-bundled MCPs still present:")}`);
|
|
151
|
+
for (const d of duplicates) {
|
|
152
|
+
log.warn(
|
|
153
|
+
`${d.name.padEnd(22)} both user-level AND plugin:${d.pluginEntry.plugin} active`
|
|
154
|
+
);
|
|
155
|
+
console.log(
|
|
156
|
+
color.dim(
|
|
157
|
+
` → Migration: ${color.cyan(`claude plugin update curdx-flow@curdx-flow-marketplace`)}\n` +
|
|
158
|
+
` then restart Claude Code. Beta.12+ removes plugin-bundled\n` +
|
|
159
|
+
` versions in favor of the user-level entry you already have.`
|
|
160
|
+
)
|
|
161
|
+
);
|
|
162
|
+
warnings++;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
94
167
|
// ---------- Runtime PATH guards (only if claude-mem is installed) ----------
|
|
95
168
|
if (claudeMemEnabled) {
|
|
96
169
|
console.log(`\n${color.bold("Runtime (claude-mem dependencies):")}`);
|
|
@@ -149,7 +222,9 @@ export async function doctor(args = []) {
|
|
|
149
222
|
console.log(color.green("Summary: all healthy ✓"));
|
|
150
223
|
}
|
|
151
224
|
|
|
152
|
-
if (verbose) {
|
|
225
|
+
if (verbose && cv) {
|
|
226
|
+
// Only call claude when it is actually on PATH; otherwise we spawn a
|
|
227
|
+
// child that fails silently and print a blank block.
|
|
153
228
|
console.log(`\n${color.bold("Details:")}`);
|
|
154
229
|
console.log(color.dim(` Plugins raw:`));
|
|
155
230
|
console.log(runSync("claude", ["plugin", "list"]).stdout);
|