@curdx/flow 2.0.0-beta.9 → 2.0.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/.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
package/cli/registry.js
CHANGED
|
@@ -9,58 +9,107 @@
|
|
|
9
9
|
* or removing a plugin is a one-file change.
|
|
10
10
|
*
|
|
11
11
|
* Every consumer pulls what it needs via property access:
|
|
12
|
-
* - install.js →
|
|
13
|
-
* - uninstall.js → uninstallSpec
|
|
14
|
-
* - upgrade.js →
|
|
15
|
-
* - doctor.js →
|
|
12
|
+
* - install.js → marketplaceSource + installSpec + hint (+ optional postInstall)
|
|
13
|
+
* - uninstall.js → uninstallSpec + uninstallArgs + marketplaceId
|
|
14
|
+
* - upgrade.js → updateSpec + marketplaceId
|
|
15
|
+
* - doctor.js → id + installSpec (for health checks and recovery hints)
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
export const RECOMMENDED_PLUGINS = [
|
|
19
19
|
{
|
|
20
20
|
name: "pua",
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
id: "pua@pua-skills",
|
|
22
|
+
marketplaceSource: "tanweai/pua",
|
|
23
|
+
marketplaceId: "pua-skills",
|
|
23
24
|
installSpec: "pua@pua-skills",
|
|
24
25
|
uninstallSpec: "pua@pua-skills",
|
|
26
|
+
updateSpec: "pua@pua-skills",
|
|
27
|
+
scope: "user",
|
|
25
28
|
hint: "no-give-up + three red lines",
|
|
26
29
|
},
|
|
27
30
|
{
|
|
28
31
|
name: "claude-mem",
|
|
29
|
-
|
|
32
|
+
id: "claude-mem@thedotmack",
|
|
33
|
+
marketplaceSource: "thedotmack/claude-mem",
|
|
30
34
|
marketplaceId: "thedotmack",
|
|
31
35
|
installSpec: "claude-mem@thedotmack",
|
|
32
36
|
uninstallSpec: "claude-mem@thedotmack",
|
|
37
|
+
updateSpec: "claude-mem@thedotmack",
|
|
38
|
+
uninstallArgs: ["--keep-data"],
|
|
39
|
+
scope: "user",
|
|
33
40
|
hint: "automatic cross-session memory",
|
|
34
41
|
postInstall: "claude-mem-runtimes",
|
|
35
42
|
},
|
|
36
43
|
{
|
|
37
44
|
name: "frontend-design",
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
id: "frontend-design@claude-plugins-official",
|
|
46
|
+
marketplaceSource: "anthropics/claude-plugins-official",
|
|
40
47
|
marketplaceId: "claude-plugins-official",
|
|
41
48
|
installSpec: "frontend-design@claude-plugins-official",
|
|
42
49
|
uninstallSpec: "frontend-design@claude-plugins-official",
|
|
50
|
+
updateSpec: "frontend-design@claude-plugins-official",
|
|
51
|
+
scope: "user",
|
|
43
52
|
hint: "Anthropic official UI skill",
|
|
44
53
|
},
|
|
45
54
|
{
|
|
46
55
|
name: "chrome-devtools-mcp",
|
|
47
|
-
|
|
56
|
+
id: "chrome-devtools-mcp@chrome-devtools-plugins",
|
|
57
|
+
marketplaceSource: "ChromeDevTools/chrome-devtools-mcp",
|
|
48
58
|
marketplaceId: "chrome-devtools-plugins",
|
|
49
59
|
installSpec: "chrome-devtools-mcp@chrome-devtools-plugins",
|
|
50
60
|
uninstallSpec: "chrome-devtools-mcp@chrome-devtools-plugins",
|
|
61
|
+
updateSpec: "chrome-devtools-mcp@chrome-devtools-plugins",
|
|
62
|
+
scope: "user",
|
|
51
63
|
hint: "Chrome DevTools + Puppeteer (Google official)",
|
|
52
64
|
},
|
|
53
65
|
];
|
|
54
66
|
|
|
67
|
+
export const REQUIRED_PLUGINS = [
|
|
68
|
+
{
|
|
69
|
+
name: "context7-plugin",
|
|
70
|
+
id: "context7-plugin@context7-marketplace",
|
|
71
|
+
marketplaceSource: "upstash/context7",
|
|
72
|
+
marketplaceId: "context7-marketplace",
|
|
73
|
+
installSpec: "context7-plugin@context7-marketplace",
|
|
74
|
+
uninstallSpec: "context7-plugin@context7-marketplace",
|
|
75
|
+
updateSpec: "context7-plugin@context7-marketplace",
|
|
76
|
+
scope: "user",
|
|
77
|
+
hint: "official Context7 plugin (MCP + skill + docs-researcher agent + /context7:docs)",
|
|
78
|
+
requiresConfig: true,
|
|
79
|
+
configType: "apiKey",
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* MCP servers that curdx-flow depends on for its core discipline rules and
|
|
85
|
+
* still registers directly. Starting beta.12 these are registered at
|
|
86
|
+
* USER-LEVEL via `claude mcp add` instead of plugin.json bundling, so:
|
|
87
|
+
*
|
|
88
|
+
* - Tool names stay standard (mcp__sequential-thinking__*)
|
|
89
|
+
* — matching every agent's and knowledge doc's hardcoded references.
|
|
90
|
+
*
|
|
91
|
+
* Context7 is installed via Upstash's official Claude Code plugin instead
|
|
92
|
+
* of direct `claude mcp add`: context7-plugin@context7-marketplace includes
|
|
93
|
+
* the MCP server, skill, docs-researcher agent, and /context7:docs command.
|
|
94
|
+
*/
|
|
95
|
+
export const BUNDLED_MCPS = [
|
|
96
|
+
{
|
|
97
|
+
name: "sequential-thinking",
|
|
98
|
+
command: "npx",
|
|
99
|
+
args: ["-y", "@modelcontextprotocol/server-sequential-thinking"],
|
|
100
|
+
purpose: "structured reasoning for design / review (L2 Mandatory Tool)",
|
|
101
|
+
preserveExisting: true,
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
|
|
55
105
|
/**
|
|
56
106
|
* Marketplaces to refresh during `upgrade`. Derived from RECOMMENDED_PLUGINS
|
|
57
107
|
* plus the curdx-flow marketplace itself.
|
|
58
108
|
*/
|
|
59
109
|
export const MARKETPLACES_TO_REFRESH = [
|
|
60
110
|
"curdx-flow-marketplace",
|
|
61
|
-
...
|
|
62
|
-
|
|
63
|
-
.map((p) => p.marketplaceId),
|
|
111
|
+
...REQUIRED_PLUGINS.map((p) => p.marketplaceId),
|
|
112
|
+
...RECOMMENDED_PLUGINS.map((p) => p.marketplaceId),
|
|
64
113
|
];
|
|
65
114
|
|
|
66
115
|
/**
|
|
@@ -69,5 +118,6 @@ export const MARKETPLACES_TO_REFRESH = [
|
|
|
69
118
|
*/
|
|
70
119
|
export const PLUGINS_TO_UPDATE = [
|
|
71
120
|
"curdx-flow@curdx-flow-marketplace",
|
|
72
|
-
...
|
|
121
|
+
...REQUIRED_PLUGINS.map((p) => p.updateSpec),
|
|
122
|
+
...RECOMMENDED_PLUGINS.map((p) => p.updateSpec),
|
|
73
123
|
];
|
package/cli/uninstall.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { existsSync, lstatSync, unlinkSync, rmSync, readlinkSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
+
import { homedir } from "node:os";
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
10
|
color,
|
|
@@ -15,14 +16,24 @@ import {
|
|
|
15
16
|
listPlugins,
|
|
16
17
|
} from "./utils.js";
|
|
17
18
|
import { removeGlobalProtocols, GLOBAL_CLAUDE_MD } from "./protocols.js";
|
|
18
|
-
import { RECOMMENDED_PLUGINS } from "./registry.js";
|
|
19
|
+
import { REQUIRED_PLUGINS, RECOMMENDED_PLUGINS, BUNDLED_MCPS } from "./registry.js";
|
|
19
20
|
|
|
20
|
-
const HOME =
|
|
21
|
+
const HOME = homedir();
|
|
21
22
|
|
|
22
23
|
// Pull uninstall-relevant subset from the single registry. See registry.js.
|
|
23
|
-
const RECOMMENDED = RECOMMENDED_PLUGINS.map(({ name, uninstallSpec }) => ({
|
|
24
|
+
const RECOMMENDED = RECOMMENDED_PLUGINS.map(({ name, uninstallSpec, uninstallArgs, marketplaceId, scope }) => ({
|
|
24
25
|
name,
|
|
25
26
|
uninstallSpec,
|
|
27
|
+
uninstallArgs: uninstallArgs || [],
|
|
28
|
+
marketplaceId,
|
|
29
|
+
scope,
|
|
30
|
+
}));
|
|
31
|
+
const REQUIRED = REQUIRED_PLUGINS.map(({ name, uninstallSpec, uninstallArgs, marketplaceId, scope }) => ({
|
|
32
|
+
name,
|
|
33
|
+
uninstallSpec,
|
|
34
|
+
uninstallArgs: uninstallArgs || [],
|
|
35
|
+
marketplaceId,
|
|
36
|
+
scope,
|
|
26
37
|
}));
|
|
27
38
|
|
|
28
39
|
// Symlinks created by install.js (only cleaned with --purge)
|
|
@@ -67,7 +78,7 @@ export async function uninstall(args = []) {
|
|
|
67
78
|
} else {
|
|
68
79
|
const r = await run(
|
|
69
80
|
"claude",
|
|
70
|
-
["plugin", "uninstall", "curdx-flow@curdx-flow-marketplace"],
|
|
81
|
+
["plugin", "uninstall", "--scope", "user", "curdx-flow@curdx-flow-marketplace"],
|
|
71
82
|
{ silent: true }
|
|
72
83
|
);
|
|
73
84
|
if (r.code === 0) {
|
|
@@ -113,10 +124,10 @@ export async function uninstall(args = []) {
|
|
|
113
124
|
for (const name of toRemove) {
|
|
114
125
|
const rec = presentRecs.find((r) => r.name === name);
|
|
115
126
|
log.blank();
|
|
116
|
-
console.log(` ${color.cyan("
|
|
127
|
+
console.log(` ${color.cyan("▸")} Uninstalling ${color.bold(rec.name)}...`);
|
|
117
128
|
const r = await run(
|
|
118
129
|
"claude",
|
|
119
|
-
["plugin", "uninstall", rec.uninstallSpec],
|
|
130
|
+
["plugin", "uninstall", "--scope", rec.scope, ...rec.uninstallArgs, rec.uninstallSpec],
|
|
120
131
|
{ silent: true }
|
|
121
132
|
);
|
|
122
133
|
if (r.code === 0) {
|
|
@@ -130,9 +141,71 @@ export async function uninstall(args = []) {
|
|
|
130
141
|
}
|
|
131
142
|
}
|
|
132
143
|
|
|
144
|
+
// ---------- Step 4.5: optionally remove user-level MCPs ----------
|
|
145
|
+
// Starting beta.12, the install command registers context7 +
|
|
146
|
+
// sequential-thinking at user-level (not plugin-bundled). Ask before
|
|
147
|
+
// removing because the user may have customised args (e.g. --api-key)
|
|
148
|
+
// or still be using these MCPs outside curdx-flow.
|
|
149
|
+
log.blank();
|
|
150
|
+
log.info("Required MCP servers (context7, sequential-thinking)");
|
|
151
|
+
if (keepRecommended || yes) {
|
|
152
|
+
log.info(
|
|
153
|
+
color.dim("--yes or --keep-recommended: keeping user-level MCPs (remove manually with `claude mcp remove <name>`)")
|
|
154
|
+
);
|
|
155
|
+
} else {
|
|
156
|
+
const removeMcps = await confirm(
|
|
157
|
+
`Remove user-level MCPs registered by install (${BUNDLED_MCPS.map((m) => m.name).join(", ")})? ${color.dim("(keeps them if other tools depend on them)")}`,
|
|
158
|
+
false
|
|
159
|
+
);
|
|
160
|
+
if (removeMcps) {
|
|
161
|
+
for (const mcp of BUNDLED_MCPS) {
|
|
162
|
+
const r = await run("claude", ["mcp", "remove", mcp.name], {
|
|
163
|
+
silent: true,
|
|
164
|
+
});
|
|
165
|
+
if (r.code === 0) {
|
|
166
|
+
log.ok(` ${mcp.name.padEnd(22)} removed`);
|
|
167
|
+
} else {
|
|
168
|
+
log.info(` ${mcp.name.padEnd(22)} ${color.dim("not present or already removed")}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
log.info("Keeping user-level MCPs");
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ---------- Step 4.75: uninstall required companion plugins ----------
|
|
177
|
+
log.blank();
|
|
178
|
+
log.info("Required companion plugins");
|
|
179
|
+
if (yes) {
|
|
180
|
+
log.info(
|
|
181
|
+
color.dim("--yes mode: keeping required companion plugins (use --purge to remove them)")
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
const removeRequired = await confirm(
|
|
185
|
+
`Remove required companion plugins (${REQUIRED.map((p) => p.name).join(", ")})? ${color.dim("(keeps shared tools available if other workflows depend on them)")}`,
|
|
186
|
+
false
|
|
187
|
+
);
|
|
188
|
+
if (removeRequired) {
|
|
189
|
+
for (const plugin of REQUIRED) {
|
|
190
|
+
const r = await run(
|
|
191
|
+
"claude",
|
|
192
|
+
["plugin", "uninstall", "--scope", plugin.scope, ...plugin.uninstallArgs, plugin.uninstallSpec],
|
|
193
|
+
{ silent: true }
|
|
194
|
+
);
|
|
195
|
+
if (r.code === 0) {
|
|
196
|
+
log.ok(` ${plugin.name.padEnd(22)} uninstalled`);
|
|
197
|
+
} else {
|
|
198
|
+
log.info(` ${plugin.name.padEnd(22)} ${color.dim("not present or already removed")}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
log.info("Keeping required companion plugins");
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
133
206
|
// ---------- Step 5: cleanup symlinks (only with --purge) ----------
|
|
134
207
|
log.blank();
|
|
135
|
-
log.step(3, 4, "Runtime symlinks");
|
|
208
|
+
log.step(3, 4, "Runtime symlinks and marketplaces");
|
|
136
209
|
if (!purge) {
|
|
137
210
|
log.info(
|
|
138
211
|
color.dim("Keeping ~/.local/bin/bun, ~/.local/bin/uv (use --purge to remove)")
|
|
@@ -141,6 +214,27 @@ export async function uninstall(args = []) {
|
|
|
141
214
|
color.dim("Reason: these bun/uv binaries may be used by other tools — confirm before deleting")
|
|
142
215
|
);
|
|
143
216
|
} else {
|
|
217
|
+
const marketplaceIds = [
|
|
218
|
+
...new Set(
|
|
219
|
+
RECOMMENDED
|
|
220
|
+
.concat(REQUIRED)
|
|
221
|
+
.map((r) => r.marketplaceId)
|
|
222
|
+
.filter((id) => id && id !== "claude-plugins-official")
|
|
223
|
+
),
|
|
224
|
+
];
|
|
225
|
+
for (const marketplaceId of marketplaceIds) {
|
|
226
|
+
const r = await run(
|
|
227
|
+
"claude",
|
|
228
|
+
["plugin", "marketplace", "remove", marketplaceId],
|
|
229
|
+
{ silent: true }
|
|
230
|
+
);
|
|
231
|
+
if (r.code === 0) {
|
|
232
|
+
log.ok(`Removed marketplace ${marketplaceId}`);
|
|
233
|
+
} else if (!r.stderr.includes("not found")) {
|
|
234
|
+
log.warn(`Failed to remove marketplace ${marketplaceId}: ${r.stderr.trim().split("\n").pop()}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
144
238
|
for (const link of MANAGED_SYMLINKS) {
|
|
145
239
|
if (!existsSync(link) && !isBrokenSymlink(link)) {
|
|
146
240
|
continue;
|
package/cli/upgrade.js
CHANGED
|
@@ -47,7 +47,7 @@ export async function upgrade(args = []) {
|
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
const r = await run("claude", ["plugin", "update", spec], { silent: true });
|
|
50
|
+
const r = await run("claude", ["plugin", "update", "--scope", "user", spec], { silent: true });
|
|
51
51
|
if (r.code === 0) {
|
|
52
52
|
const updated = r.stdout.includes("updated from");
|
|
53
53
|
if (updated) {
|