@curdx/flow 7.1.18 → 7.1.20

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,34 @@
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.20 — 2026-05-11
6
+
7
+ ### Changed
8
+
9
+ - **Companion capabilities are now the default required bundle.** `pua`, `claude-mem`, `chrome-devtools-mcp`, `frontend-design`, `sequential-thinking`, and `context7` are marked `required` in the installer alongside `curdx-flow`, so interactive installs show them as always installed and `--ids` installs auto-include missing required companions.
10
+ - **Official plugin dependency metadata added.** `curdx-flow` now declares plugin dependencies for `pua`, `claude-mem`, `chrome-devtools-mcp`, and `frontend-design`, and the root marketplace explicitly allows those cross-marketplace dependencies.
11
+ - **Capability routing marks bundled companions as `core-required`.** Smart-route recommendations still trigger only when relevant, but recommended bundled capabilities are no longer suppressed by narrow availability filters.
12
+
13
+ ### Tests
14
+
15
+ - Added registry and manifest regression coverage for the required bundle, expanded capability-router expectations, rebuilt hook bundles, and tightened `claudecc` smoke checks for `core-required` recommendations.
16
+
17
+ ## 7.1.19 — 2026-05-11
18
+
19
+ ### Added
20
+
21
+ - **Third-party capability graph for smart routing.** New `hooks/scripts/lib/tool-capabilities.mjs` maps installed companion capabilities (`claude-mem`, `context7`, `sequential-thinking`, `chrome-devtools-mcp`, `frontend-design`, and `pua`) to concrete AI-facing triggers, phases, skip rules, and invocations.
22
+ - **Capability recommendations in `smart-route`.** Route output now includes `recommendedCapabilities` so `/curdx-flow:start` can choose docs lookup, memory search, UI design, browser verification, structured reasoning, or retry tooling from goal/topology facts without forcing every task through every tool.
23
+
24
+ ### Changed
25
+
26
+ - **Global CLAUDE.md guidance is generated from the capability graph.** The managed block now emits concise installed-tool routing rules and a decision tree instead of hand-maintained duplicated plugin/MCP prose.
27
+ - **Start workflow stores tool hints with spec state.** New specs can persist compact `recommendedCapabilities` next to `projectTopology`, and the state schema/reference docs now declare both fields so later phases can reuse the original routing context without re-deriving it.
28
+
29
+ ### Tests
30
+
31
+ - Added capability-router unit coverage, smart-route capability filtering checks, CLAUDE.md rendering regression coverage, and claudecc smoke assertions for empty direct-change hints and frontend/browser/docs recommendations.
32
+
5
33
  ## 7.1.18 — 2026-05-11
6
34
 
7
35
  ### Added
package/README.md CHANGED
@@ -123,7 +123,7 @@ The same npm package delivers both products. The installer reads its descriptor
123
123
 
124
124
  - **Node.js** ≥ 20.12 ([download](https://nodejs.org))
125
125
  - **Claude Code CLI** installed and on `PATH` ([install instructions](https://docs.anthropic.com/en/docs/claude-code))
126
- - *(Optional)* **Bun** ≥ 1.0 — auto-detected; the installer offers to install it if you choose `claude-mem`
126
+ - *(Optional)* **Bun** ≥ 1.0 — auto-detected; the installer offers to install it for the default `claude-mem` companion
127
127
 
128
128
  ### Install
129
129
 
@@ -131,7 +131,7 @@ The same npm package delivers both products. The installer reads its descriptor
131
131
  npx @curdx/flow
132
132
  ```
133
133
 
134
- On first run, you pick a language (中文 / English), then select what to install. The bundled `curdx-flow` plugin (the spec workflow itself) is always installed. Everything else is opt-in.
134
+ On first run, you pick a language (中文 / English). The full curdx-flow bundle is installed by default: `curdx-flow`, `pua`, `claude-mem`, `chrome-devtools-mcp`, `frontend-design`, `sequential-thinking`, and `context7`. If a companion has a local prerequisite that is missing, the installer reports the skip reason and continues so the core workflow remains usable.
135
135
 
136
136
  That language choice also controls the managed `~/.claude/CLAUDE.md` block that flow writes. The block is rendered in the selected language, and when you choose `zh` it additionally injects a language policy telling Claude to keep tool/model interaction in English while replying to the user in Simplified Chinese.
137
137
 
@@ -428,9 +428,9 @@ Most workflow frameworks address this by adding more agents, more orchestration,
428
428
 
429
429
  No. flow runs **inside** Claude Code as a plugin. You still use the Claude Code CLI / IDE extension to chat; flow adds the `/curdx-flow:*` commands, subagents, hooks, and the bundled marketplace.
430
430
 
431
- #### Can I use flow without installing the marketplace plugins?
431
+ #### Can I use flow without the companion capabilities?
432
432
 
433
- Yes. The bundled `curdx-flow` plugin is the spec workflow itself; everything else (claude-mem, chrome-devtools-mcp, …) is opt-in. `npx @curdx/flow install` lets you pick.
433
+ The default installer treats the companion capabilities as required because routing depends on them for memory, current docs, frontend design, browser verification, structured reasoning, and retry/parallel recovery. If a local prerequisite is missing, that item may be skipped with a visible reason, but the next `npx @curdx/flow install` run will try to restore it.
434
434
 
435
435
  #### Do I need to commit the spec files?
436
436
 
package/dist/index.mjs CHANGED
@@ -514,6 +514,7 @@ var pua = {
514
514
  name: "pua",
515
515
  description: "tanweai/pua \u2014 Chinese Claude Code skills bundle",
516
516
  type: "plugin",
517
+ required: true,
517
518
  slashNamespace: "/pua:*",
518
519
  whenToUse: "auto-fires on 2+ failures or user frustration; sub-modes p7 / p9 / pro / loop. Skip on first-attempt failures or when a known fix is executing.",
519
520
  marketplaces: () => [MARKETPLACE_NAME],
@@ -609,6 +610,7 @@ var claudeMem = {
609
610
  name: "claude-mem",
610
611
  description: "thedotmack/claude-mem \u2014 persistent cross-session memory for Claude Code",
611
612
  type: "plugin",
613
+ required: true,
612
614
  slashNamespace: "/claude-mem:*",
613
615
  whenToUse: 'for cross-session memory search ("did we solve this before?"), phased planning (`make-plan`), or phased execution (`do`).',
614
616
  marketplaces: () => [MARKETPLACE_NAME2],
@@ -668,6 +670,7 @@ var chromeDevtoolsMcp = {
668
670
  name: "chrome-devtools-mcp",
669
671
  description: "ChromeDevTools/chrome-devtools-mcp \u2014 drive a real Chrome from Claude Code",
670
672
  type: "plugin",
673
+ required: true,
671
674
  whenToUse: "when debugging code that runs in a browser: perf traces, network / console inspection, DOM / CSS issues. Prefer snapshot over screenshot.",
672
675
  prereqCheck: async (t2) => {
673
676
  const major = Number(process.versions.node.split(".")[0] ?? "0");
@@ -697,6 +700,7 @@ var frontendDesign = {
697
700
  name: "frontend-design",
698
701
  description: "Anthropic official \u2014 UI/frontend design helpers",
699
702
  type: "plugin",
703
+ required: true,
700
704
  whenToUse: "auto-fires when building UI / web components / pages. Best where visual personality matters (landing, marketing, portfolio).",
701
705
  isInstalled: () => isPluginInstalled(PLUGIN_ID4),
702
706
  install: (ctx) => installPluginById(PLUGIN_ID4, ctx),
@@ -742,6 +746,7 @@ var sequentialThinking = {
742
746
  name: "sequential-thinking",
743
747
  description: "modelcontextprotocol/server-sequential-thinking \u2014 structured reasoning helper",
744
748
  type: "mcp",
749
+ required: true,
745
750
  whenToUse: "for complex multi-step problems where assumptions may shift (architecture comparison, risk-assessed migrations, prod-only debugging). Skip for simple queries.",
746
751
  isInstalled: () => isMcpInstalled(MCP_NAME),
747
752
  install: async (ctx) => {
@@ -783,6 +788,7 @@ var context7 = {
783
788
  name: "context7",
784
789
  description: "upstash/context7 \u2014 up-to-date docs from any library (HTTP MCP, optional API key)",
785
790
  type: "mcp",
791
+ required: true,
786
792
  whenToUse: "for any library / SDK / framework / API / Claude Code docs lookup. Use instead of web search.",
787
793
  isInstalled: () => isMcpInstalled(MCP_NAME2),
788
794
  configPrompts: async ({ t: t2 }) => {
@@ -845,6 +851,274 @@ import { promises as fs2 } from "fs";
845
851
  import path4 from "path";
846
852
  import os2 from "os";
847
853
  import * as p4 from "@clack/prompts";
854
+
855
+ // src/hooks/lib/tool-capabilities.ts
856
+ import { basename } from "path";
857
+ import { fileURLToPath } from "url";
858
+ var CAPABILITIES = {
859
+ "context7": {
860
+ id: "context7",
861
+ name: "Context7",
862
+ type: "mcp",
863
+ invocation: "Context7 MCP",
864
+ summary: "current official docs for libraries, SDKs, APIs, and Claude Code",
865
+ useWhen: "use the Context7 MCP before implementation when external library, SDK, API, framework, or Claude Code behavior matters.",
866
+ skipWhen: "Skip for pure local logic, typos, and code paths fully understood from this repository."
867
+ },
868
+ "claude-mem": {
869
+ id: "claude-mem",
870
+ name: "claude-mem",
871
+ type: "plugin",
872
+ invocation: "/claude-mem:mem-search",
873
+ summary: "cross-session memory search and phased plan/execution commands",
874
+ useWhen: "Use /claude-mem:mem-search when similar work, prior decisions, or repeated failures may exist; use /claude-mem:make-plan only for genuinely phased work.",
875
+ skipWhen: "Skip when the task is new, obvious, and smaller than a short local edit."
876
+ },
877
+ "sequential-thinking": {
878
+ id: "sequential-thinking",
879
+ name: "sequential-thinking",
880
+ type: "mcp",
881
+ invocation: "sequential-thinking MCP",
882
+ summary: "structured hypothesis breakdown for hard architecture and debugging problems",
883
+ useWhen: "Use for architecture tradeoffs, migrations, security/data/release risk, or debugging where assumptions may change.",
884
+ skipWhen: "Skip for direct edits, simple lookups, and deterministic fixes."
885
+ },
886
+ "chrome-devtools-mcp": {
887
+ id: "chrome-devtools-mcp",
888
+ name: "Chrome DevTools MCP",
889
+ type: "plugin",
890
+ invocation: "Chrome DevTools MCP",
891
+ summary: "real browser console, network, DOM, performance, and screenshot/snapshot verification",
892
+ useWhen: "Use for browser runtime behavior, UI regressions, DOM/CSS issues, network failures, and frontend verification.",
893
+ skipWhen: "Skip for backend-only code with no browser-facing behavior."
894
+ },
895
+ "frontend-design": {
896
+ id: "frontend-design",
897
+ name: "frontend-design",
898
+ type: "plugin",
899
+ invocation: "frontend-design plugin skills",
900
+ summary: "frontend UX/design guidance for UI pages, components, and interaction polish",
901
+ useWhen: "Use when building or changing visible UI, interaction design, frontend layout, or visual quality.",
902
+ skipWhen: "Skip for backend-only changes, copy-only edits, and internal CLI/library work."
903
+ },
904
+ "pua": {
905
+ id: "pua",
906
+ name: "pua",
907
+ type: "plugin",
908
+ invocation: "/pua:pua-loop or /pua:p9",
909
+ summary: "structured retries and parallel task decomposition",
910
+ useWhen: "Use after multiple failed attempts or for truly independent parallel work slices.",
911
+ skipWhen: "Skip on first-attempt failures, known fixes, and work that is sequential by dependency."
912
+ }
913
+ };
914
+ var ORDER = [
915
+ "context7",
916
+ "claude-mem",
917
+ "frontend-design",
918
+ "chrome-devtools-mcp",
919
+ "sequential-thinking",
920
+ "pua"
921
+ ];
922
+ var CORE_REQUIRED = /* @__PURE__ */ new Set([
923
+ "context7",
924
+ "claude-mem",
925
+ "frontend-design",
926
+ "chrome-devtools-mcp",
927
+ "sequential-thinking",
928
+ "pua"
929
+ ]);
930
+ var EXTERNAL_DOCS_RE = /\b(api|sdk|library|libraries|framework|version|upgrade|dependency|dependencies|official docs?|latest docs?|claude code|plugin|mcp|hook|hooks|skill|skills|agent|agents|react|vue|spring|spring boot|spring cloud|next\.?js|vite|webpack|npm|node)\b|最新|依赖|框架|插件|官方|联网|搜索|文档.*(最新|官方|API|SDK|框架|插件|依赖)/i;
931
+ var MEMORY_RE = /\b(previous|before|again|remember|memory|history|similar|repeated|regression|already solved|same bug|past decision)\b|之前|上次|记得|历史|做过|又|重复|老问题/i;
932
+ var UI_RE = /\b(ui|ux|frontend|front-end|browser|chrome|dom|css|html|layout|component|page|form|modal|responsive|visual|render|react|vue|vite|next\.?js|screenshot|interaction)\b|前端|页面|浏览器|样式|交互|组件|布局|视觉|截图/i;
933
+ var BROWSER_VERIFY_RE = /\b(browser|chrome|dom|css|network|console|performance|render|screenshot|e2e|playwright|visual regression|interaction)\b|浏览器|控制台|网络|性能|渲染|截图|端到端/i;
934
+ var COMPLEX_RE = /\b(architecture|architect|migration|migrate|security|auth|authentication|authorization|permission|oauth|payment|billing|database|schema|release|publish|npm|tag|hook|subagent|multi[- ]?repo|monorepo|cross[- ]?system|concurrency|race|cache|rewrite|refactor)\b|架构|迁移|安全|权限|认证|数据库|发布|重写|并发|跨仓库|多仓库/i;
935
+ var STUCK_RE = /\b(stuck|failed|failure|fails|flaky|retry|debug|investigate|root cause|not working|broken|regression)\b|卡住|失败|报错|不行|修不好|定位|排查/i;
936
+ var PARALLEL_RE = /\b(parallel|multi-agent|team|decompose|split|epic|multiple subsystems|large refactor)\b|并行|多智能体|拆分|史诗|多模块/i;
937
+ var LOW_RISK_LOCAL_RE = /\b(typo|readme|docs?|comment|comments|copy|wording|rename label|format text)\b|错别字|注释|文案/i;
938
+ function normalize(input) {
939
+ return (input ?? "").trim().replace(/\s+/g, " ");
940
+ }
941
+ function hasAny(values, candidates) {
942
+ const set = new Set((values ?? []).map((v) => v.toLowerCase()));
943
+ return candidates.some((candidate) => set.has(candidate.toLowerCase()));
944
+ }
945
+ function capabilityAvailability(id, available) {
946
+ if (CORE_REQUIRED.has(id)) return "core-required";
947
+ if (available === null) return "check-if-installed";
948
+ return available.has(id) ? "known-available" : null;
949
+ }
950
+ function pushRecommendation(out, available, id, phase, reason, instruction) {
951
+ const availability = capabilityAvailability(id, available);
952
+ if (availability === null) return;
953
+ if (out.some((rec) => rec.id === id)) return;
954
+ const cap = CAPABILITIES[id];
955
+ out.push({
956
+ id,
957
+ name: cap.name,
958
+ type: cap.type,
959
+ invocation: cap.invocation,
960
+ phase,
961
+ availability,
962
+ reason,
963
+ instruction
964
+ });
965
+ }
966
+ function sortRecommendations(recs) {
967
+ return [...recs].sort((a, b) => ORDER.indexOf(a.id) - ORDER.indexOf(b.id));
968
+ }
969
+ function recommendToolCapabilities(input) {
970
+ const goal = normalize(input.goal);
971
+ const route = normalize(input.route);
972
+ const risk = normalize(input.risk);
973
+ const topologyKinds = input.topologyKinds ?? [];
974
+ const topologyFrameworks = input.topologyFrameworks ?? [];
975
+ const missingRoots = input.missingRoots ?? 0;
976
+ const available = input.availableCapabilities === void 0 ? null : new Set(input.availableCapabilities.filter(Boolean));
977
+ const recs = [];
978
+ if (missingRoots > 0) {
979
+ return recs;
980
+ }
981
+ const externalDocsRelevant = EXTERNAL_DOCS_RE.test(goal);
982
+ const localLowRisk = LOW_RISK_LOCAL_RE.test(goal) && route === "direct-change" && !externalDocsRelevant;
983
+ if (localLowRisk) {
984
+ return recs;
985
+ }
986
+ const hasFrontend = UI_RE.test(goal) || hasAny(topologyKinds, ["frontend-app"]) || hasAny(topologyFrameworks, ["react", "vue", "next.js", "vite"]);
987
+ const browserRuntime = BROWSER_VERIFY_RE.test(goal) || hasFrontend;
988
+ const complex = COMPLEX_RE.test(goal) && route !== "direct-change" || risk === "high" || risk === "critical" || route === "full-spec" || route === "epic-split";
989
+ const stuck = STUCK_RE.test(goal);
990
+ const parallel = PARALLEL_RE.test(goal) || route === "epic-split";
991
+ if (externalDocsRelevant) {
992
+ pushRecommendation(
993
+ recs,
994
+ available,
995
+ "context7",
996
+ "before-coding",
997
+ "external documentation or current API behavior is likely relevant",
998
+ "Use Context7 before editing so version-specific behavior is grounded in current docs."
999
+ );
1000
+ }
1001
+ if (MEMORY_RE.test(goal) || stuck || route === "full-spec" || route === "epic-split") {
1002
+ pushRecommendation(
1003
+ recs,
1004
+ available,
1005
+ "claude-mem",
1006
+ "planning",
1007
+ "similar prior work or longer-running plan may exist",
1008
+ "Search memory before planning; use make-plan only when the work is genuinely phased."
1009
+ );
1010
+ }
1011
+ if (hasFrontend) {
1012
+ pushRecommendation(
1013
+ recs,
1014
+ available,
1015
+ "frontend-design",
1016
+ "implementation",
1017
+ "visible frontend behavior or UI quality is in scope",
1018
+ "Use frontend-design guidance for UI structure, interaction, responsive behavior, and visual polish."
1019
+ );
1020
+ }
1021
+ if (browserRuntime) {
1022
+ pushRecommendation(
1023
+ recs,
1024
+ available,
1025
+ "chrome-devtools-mcp",
1026
+ "verification",
1027
+ "browser runtime behavior should be verified in a real browser",
1028
+ "Use Chrome DevTools MCP for console, network, DOM, performance, or visual proof after implementation."
1029
+ );
1030
+ }
1031
+ if (complex || stuck) {
1032
+ pushRecommendation(
1033
+ recs,
1034
+ available,
1035
+ "sequential-thinking",
1036
+ "planning",
1037
+ "risk or uncertainty requires explicit hypothesis management",
1038
+ "Use sequential-thinking to break assumptions before choosing the implementation path."
1039
+ );
1040
+ }
1041
+ if (stuck || parallel) {
1042
+ pushRecommendation(
1043
+ recs,
1044
+ available,
1045
+ "pua",
1046
+ stuck ? "recovery" : "planning",
1047
+ stuck ? "the goal indicates repeated failure or debugging difficulty" : "large work may contain independent parallel slices",
1048
+ stuck ? "Use /pua:pua-loop only after local triage confirms the first fix path is not working." : "Use /pua:p9 only after dependencies prove the slices can run independently."
1049
+ );
1050
+ }
1051
+ return sortRecommendations(recs);
1052
+ }
1053
+ function renderInstalledCapabilityRules(availableCapabilities) {
1054
+ const available = new Set(availableCapabilities);
1055
+ const lines = [
1056
+ "Use installed capabilities by trigger, not by habit. Prefer the first matching rule; skip absent capabilities."
1057
+ ];
1058
+ for (const id of ORDER) {
1059
+ if (!available.has(id)) continue;
1060
+ const cap = CAPABILITIES[id];
1061
+ lines.push(`- ${cap.invocation}: ${cap.useWhen} ${cap.skipWhen}`);
1062
+ }
1063
+ return lines;
1064
+ }
1065
+ function renderCapabilityDecisionTree(availableCapabilities) {
1066
+ const available = new Set(availableCapabilities);
1067
+ const rules = [
1068
+ "Can the edit be finished safely from local code in 1-2 steps? -> Do it directly."
1069
+ ];
1070
+ if (available.has("context7")) {
1071
+ rules.push("Does correctness depend on external docs, SDKs, APIs, or Claude Code behavior? -> use the Context7 MCP before editing.");
1072
+ }
1073
+ if (available.has("claude-mem")) {
1074
+ rules.push("Might similar work, a prior decision, or a repeated failure exist? -> Start with `/claude-mem:mem-search`.");
1075
+ }
1076
+ if (available.has("frontend-design") || available.has("chrome-devtools-mcp")) {
1077
+ rules.push("Is visible frontend behavior in scope? -> Use frontend-design for UI decisions and Chrome DevTools MCP for runtime proof when installed.");
1078
+ }
1079
+ if (available.has("sequential-thinking")) {
1080
+ rules.push("Is the work high-risk, architectural, or assumption-heavy? -> Use sequential-thinking after reading the relevant code.");
1081
+ }
1082
+ if (available.has("pua")) {
1083
+ rules.push("Are there multiple failed attempts or truly independent parallel slices? -> Use `/pua:pua-loop` for recovery or `/pua:p9` for bounded parallel planning.");
1084
+ }
1085
+ return rules.map((rule, idx) => `${idx + 1}. ${rule}`);
1086
+ }
1087
+ function parseList(value) {
1088
+ if (!value) return [];
1089
+ return value.split(/[,;\n]/).map((s) => s.trim()).filter(Boolean);
1090
+ }
1091
+ function readArg(name, argv2) {
1092
+ const idx = argv2.indexOf(name);
1093
+ if (idx === -1) return void 0;
1094
+ return argv2[idx + 1];
1095
+ }
1096
+ function main() {
1097
+ const argv2 = process.argv.slice(2);
1098
+ const recommendations = recommendToolCapabilities({
1099
+ goal: readArg("--goal", argv2),
1100
+ route: readArg("--route", argv2),
1101
+ risk: readArg("--risk", argv2),
1102
+ topologyKinds: parseList(readArg("--topology-kinds", argv2)),
1103
+ topologyFrameworks: parseList(readArg("--topology-frameworks", argv2)),
1104
+ missingRoots: Number(readArg("--missing-roots", argv2) ?? 0),
1105
+ availableCapabilities: readArg("--available-capabilities", argv2) ? parseList(readArg("--available-capabilities", argv2)) : void 0
1106
+ });
1107
+ process.stdout.write(JSON.stringify(recommendations, null, 2) + "\n");
1108
+ }
1109
+ function isDirectRun() {
1110
+ try {
1111
+ const entry = fileURLToPath(import.meta.url);
1112
+ return process.argv[1] === entry && basename(entry).startsWith("tool-capabilities.");
1113
+ } catch {
1114
+ return false;
1115
+ }
1116
+ }
1117
+ if (isDirectRun()) {
1118
+ main();
1119
+ }
1120
+
1121
+ // src/runner/claudeMd.ts
848
1122
  var BEGIN_MARKER = "<!-- BEGIN @curdx/flow v1 -->";
849
1123
  var END_MARKER = "<!-- END @curdx/flow v1 -->";
850
1124
  var BLOCK_RE = /<!-- BEGIN @curdx\/flow v\d+[^>]*-->[\s\S]*?<!-- END @curdx\/flow v\d+ -->/;
@@ -852,63 +1126,11 @@ function claudeMdPath() {
852
1126
  return path4.join(os2.homedir(), ".claude", "CLAUDE.md");
853
1127
  }
854
1128
  function buildCombinationPatterns(ids) {
855
- const has = (k) => ids.has(k);
856
- const out = [
857
- "Combine tools by capability. Keep slash commands, MCP tools, and plugin skills distinct.",
858
- ""
859
- ];
860
- if (has("context7") || has("curdx-flow") || has("claude-mem")) {
861
- out.push("- **Starting a new feature**");
862
- let step = 1;
863
- if (has("context7")) {
864
- out.push(` ${step++}. If external libraries, SDKs, frameworks, or APIs are involved, use the Context7 MCP to pull current official docs.`);
865
- }
866
- const planners = [];
867
- if (has("claude-mem")) planners.push("`/claude-mem:make-plan` for a phased plan");
868
- if (has("curdx-flow")) planners.push("`/curdx-flow:new` or the spec flow for a full specification");
869
- if (planners.length > 0) {
870
- out.push(` ${step++}. Only move into ${planners.join(" or ")} when the work is multi-step, cross-cutting, or uncertain.`);
871
- }
872
- out.push(` ${step++}. For small, clear one-shot changes, implement directly instead of forcing the full workflow.`);
873
- out.push("");
874
- }
875
- const stuckLines = [];
876
- let s = 1;
877
- if (has("chrome-devtools-mcp")) {
878
- stuckLines.push(` ${s++}. For browser-side issues, use the Chrome DevTools MCP for network, console, performance, and DOM snapshots.`);
879
- }
880
- if (has("context7")) {
881
- stuckLines.push(` ${s++}. If the issue may come from library or API behavior, use the Context7 MCP instead of relying on memory.`);
882
- }
883
- const stillStuck = [];
884
- if (has("sequential-thinking")) stillStuck.push("switch to the sequential-thinking MCP to break down hypotheses");
885
- if (has("pua")) stillStuck.push("enter `/pua:pua-loop` for structured retries");
886
- if (stillStuck.length > 0) {
887
- stuckLines.push(` ${s++}. If you are still stuck after multiple attempts, ${stillStuck.join(" or ")}.`);
888
- }
889
- if (stuckLines.length > 0) {
890
- out.push("- **Debugging and repeated failures**", ...stuckLines, "");
891
- }
892
- if (has("frontend-design") || has("chrome-devtools-mcp")) {
893
- out.push("- **UI and frontend work**");
894
- if (has("frontend-design")) {
895
- out.push(" - Prioritize the `frontend-design` plugin skills for UI work; if they do not trigger automatically, invoke the relevant skill explicitly.");
896
- }
897
- if (has("chrome-devtools-mcp")) {
898
- out.push(" - For rendering issues, interaction bugs, or visual regressions, verify with the Chrome DevTools MCP instead of relying on visual guesswork alone.");
899
- }
900
- out.push("");
1129
+ const out = renderInstalledCapabilityRules([...ids]);
1130
+ if (ids.has("curdx-flow")) {
1131
+ out.push("- /curdx-flow:start: Use for ambiguous, cross-cutting, phase-based, or multi-root work; skip for small direct edits.");
1132
+ out.push("- /curdx-flow:triage: Use when one request is too large for a single coherent spec.");
901
1133
  }
902
- if (has("pua") || has("curdx-flow")) {
903
- out.push("- **Large, cross-cutting, or multi-agent work**");
904
- if (has("pua")) {
905
- out.push(" - Use `/pua:p9` for parallel task decomposition and team coordination; reserve `/pua:p10` for higher-level strategy work.");
906
- }
907
- if (has("curdx-flow")) {
908
- out.push(" - Use `/curdx-flow:triage` when one large feature needs to be split into multiple dependent specs.");
909
- }
910
- }
911
- while (out.length > 0 && out[out.length - 1] === "") out.pop();
912
1134
  return out;
913
1135
  }
914
1136
  function buildSkipRules(ids) {
@@ -928,18 +1150,9 @@ function buildSkipRules(ids) {
928
1150
  return out;
929
1151
  }
930
1152
  function buildDecisionTree(ids) {
931
- const has = (k) => ids.has(k);
932
- const out = [];
933
- out.push("1. Can it be finished in 1-2 steps? -> Do it directly.");
934
- out.push("2. Is it multi-step but still clear? -> Break it into a short task list and execute without defaulting to the full spec flow.");
935
- const planners = [];
936
- if (has("curdx-flow")) planners.push("`/curdx-flow:new`");
937
- if (has("claude-mem")) planners.push("`/claude-mem:make-plan`");
938
- if (planners.length > 0) {
939
- out.push(`3. Is the request ambiguous, cross-cutting, or phase-based? -> ${planners.join(" or ")}.`);
940
- }
941
- if (has("claude-mem")) {
942
- out.push("4. Might this work have been done before? -> Start with `/claude-mem:mem-search`.");
1153
+ const out = renderCapabilityDecisionTree([...ids]);
1154
+ if (ids.has("curdx-flow")) {
1155
+ out.push(`${out.length + 1}. Is the request ambiguous, cross-cutting, phase-based, or multi-root? -> Run /curdx-flow:start.`);
943
1156
  }
944
1157
  return out;
945
1158
  }
@@ -1677,8 +1890,8 @@ var analyze_default = analyzeCmd;
1677
1890
  // src/runner/buildFreshness.ts
1678
1891
  import { readdirSync, statSync, existsSync as existsSync3 } from "fs";
1679
1892
  import path5 from "path";
1680
- import { fileURLToPath } from "url";
1681
- var SELF_PATH = fileURLToPath(import.meta.url);
1893
+ import { fileURLToPath as fileURLToPath2 } from "url";
1894
+ var SELF_PATH = fileURLToPath2(import.meta.url);
1682
1895
  var RUNNER_DIR = path5.dirname(SELF_PATH);
1683
1896
  var PROJECT_ROOT = path5.resolve(RUNNER_DIR, "..", "..");
1684
1897
  var SRC_DIR = path5.join(PROJECT_ROOT, "src");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curdx/flow",
3
- "version": "7.1.18",
3
+ "version": "7.1.20",
4
4
  "description": "Interactive installer for Claude Code plugins and MCP servers",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.mjs",