@curdx/flow 7.1.2 → 7.1.4

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/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import * as p10 from "@clack/prompts";
5
- import { defineCommand, runMain } from "citty";
5
+ import { defineCommand as defineCommand2, runMain } from "citty";
6
6
 
7
7
  // src/ui/language.ts
8
8
  import * as p from "@clack/prompts";
@@ -84,7 +84,17 @@ var messages = {
84
84
  "claudeMd.unchanged": "CLAUDE.md \u5DF2\u662F\u6700\u65B0",
85
85
  "claudeMd.removed": "\u5DF2\u4ECE CLAUDE.md \u79FB\u9664 @curdx/flow \u533A\u5757",
86
86
  "claudeMd.skipped": "\u5DF2\u8DF3\u8FC7 CLAUDE.md \u540C\u6B65\uFF08--no-claude-md\uFF09",
87
- "claudeMd.failed": "CLAUDE.md \u540C\u6B65\u5931\u8D25\uFF1A{error}"
87
+ "claudeMd.failed": "CLAUDE.md \u540C\u6B65\u5931\u8D25\uFF1A{error}",
88
+ "analyze.description": "\u89E3\u6790 Claude Code session jsonl + curdx-flow errors.jsonl\uFF0C\u8F93\u51FA markdown \u62A5\u544A",
89
+ "analyze.helpSummary": "analyze \u2014 \u672C\u5730\u89C2\u6D4B\uFF1A\u5408\u5E76 ~/.claude/projects/<cwd-encoded>/<sessionId>.jsonl \u4E0E ~/.claude/curdx-flow/errors.jsonl\uFF0C\u6E32\u67D3 7 \u6BB5 markdown\uFF08hook \u5931\u8D25 / slash command \u9891\u6B21 / subagent \u8C03\u5EA6 / spec \u6F0F\u6597 / hook \u65F6\u5EF6 P50/P95/P99 / schema \u6F02\u79FB / parentUuid \u94FE\u5B8C\u6574\u6027\uFF09",
90
+ "analyze.flags.json": "\u8F93\u51FA JSON \u800C\u975E markdown\uFF08CI \u53CB\u597D\uFF1B\u4E0E --out \u4E92\u65A5\u8BED\u4E49\uFF1AJSON \u4E0D\u5199\u6587\u4EF6\uFF09",
91
+ "analyze.flags.out": "\u628A markdown \u62A5\u544A\u5199\u5165\u6307\u5B9A\u6587\u4EF6\uFF08\u7F3A\u7701\u5199\u5230 stdout\uFF09",
92
+ "analyze.flags.limit": "\u8868\u683C\u6BB5 Top-N \u622A\u65AD\uFF08\u9ED8\u8BA4 10\uFF1B\u4F20 0 \u89C6\u4E3A\u65E0\u610F\u4E49\u56DE\u843D 10\uFF09",
93
+ "analyze.flags.since": "\u53EA\u7EDF\u8BA1\u76F8\u5BF9\u7A97\u53E3\u5185\u7684\u4E8B\u4EF6\uFF0C\u4F8B\u5982 `7d` / `24h` / `30m`\uFF08\u9ED8\u8BA4\u5168\u91CF\uFF1B--since \u4E0E\u589E\u91CF offset \u7F13\u5B58\u5171\u5B58\uFF0C\u7F13\u5B58\u547D\u4E2D\u65F6\u76F4\u63A5 replay \u4E0A\u6B21\u62A5\u544A\uFF09",
94
+ "analyze.flags.project": "\u6307\u5B9A ~/.claude/projects/ \u4E0B\u7684 encoded-cwd \u5B50\u76EE\u5F55\uFF1B\u7F3A\u7701\u6309\u5F53\u524D git \u4ED3\u5E93\u6839\u76EE\u5F55\u63A8\u65AD\uFF08\u975E git \u76EE\u5F55\u9000\u5316\u4E3A\u7A7A\u62A5\u544A + warning\uFF09",
95
+ "analyze.flags.includePrompts": "\u5173\u95ED\u9ED8\u8BA4 redact\uFF0C\u628A\u539F\u59CB prompt \u6587\u672C\u900F\u51FA\uFF08\u4EC5\u672C\u5730\u8C03\u8BD5\uFF0C\u8C28\u614E\u4F7F\u7528\uFF1BD-9 \u767D\u540D\u5355\u9ED8\u8BA4\u88C1\u526A\u6240\u6709\u672A\u5728\u767D\u540D\u5355\u5B57\u6BB5\uFF09",
96
+ "analyze.warning.noProject": "\u672A\u80FD\u4ECE cwd \u63A8\u65AD\u5230 ~/.claude/projects/ \u5B50\u76EE\u5F55\uFF08\u975E git \u4ED3\u5E93\u6216\u65E0\u5BF9\u5E94 session\uFF09\uFF1B\u8F93\u51FA\u7A7A\u62A5\u544A\uFF0C\u8BF7\u7528 --project \u663E\u5F0F\u6307\u5B9A",
97
+ "analyze.warning.schemaFallback": "plugins/curdx-flow/schemas/transcript-events.json \u672A\u627E\u5230\uFF0C\u56DE\u843D\u5230\u5185\u7F6E\u6700\u5C0F\u767D\u540D\u5355\u2014\u2014schema \u6F02\u79FB\u8BCA\u65AD\u53EF\u80FD\u6F0F\u62A5"
88
98
  };
89
99
  var zh_default = messages;
90
100
 
@@ -165,7 +175,17 @@ var messages2 = {
165
175
  "claudeMd.unchanged": "CLAUDE.md already up to date",
166
176
  "claudeMd.removed": "Removed @curdx/flow block from CLAUDE.md",
167
177
  "claudeMd.skipped": "Skipped CLAUDE.md sync (--no-claude-md)",
168
- "claudeMd.failed": "CLAUDE.md sync failed: {error}"
178
+ "claudeMd.failed": "CLAUDE.md sync failed: {error}",
179
+ "analyze.description": "Analyze Claude Code session jsonl + curdx-flow errors.jsonl, output markdown report",
180
+ "analyze.helpSummary": "analyze \u2014 local observability: merge ~/.claude/projects/<cwd-encoded>/<sessionId>.jsonl with ~/.claude/curdx-flow/errors.jsonl into 7 markdown sections (hook failures / slash command frequency / subagent dispatch / spec funnel / hook duration P50/P95/P99 / schema drift / parentUuid chain integrity)",
181
+ "analyze.flags.json": "Emit JSON instead of markdown (CI-friendly; --out is ignored when --json is set)",
182
+ "analyze.flags.out": "Write the markdown report to the given file path (defaults to stdout)",
183
+ "analyze.flags.limit": "Top-N truncation for tabular sections (default 10; 0 falls back to 10)",
184
+ "analyze.flags.since": "Only count events within a relative window such as `7d` / `24h` / `30m` (default: full history; --since coexists with the incremental offset cache, replays the last report when cache hits)",
185
+ "analyze.flags.project": "Pin to a specific encoded-cwd directory under ~/.claude/projects/; defaults to inferring from the current git repository root (non-git directories degrade to an empty report with a warning)",
186
+ "analyze.flags.includePrompts": "Skip default redaction and pass raw prompt text through (local debugging only; D-9 white-list redacts every non-whitelisted field by default)",
187
+ "analyze.warning.noProject": "Could not infer a ~/.claude/projects/ subdirectory from cwd (not a git repo or no matching session); emitting an empty report \u2014 pass --project to override",
188
+ "analyze.warning.schemaFallback": "plugins/curdx-flow/schemas/transcript-events.json not found, falling back to the builtin minimal whitelist \u2014 schema drift diagnostics may underreport"
169
189
  };
170
190
  var en_default = messages2;
171
191
 
@@ -175,6 +195,9 @@ var currentLang = "zh";
175
195
  function setLang(lang) {
176
196
  currentLang = lang;
177
197
  }
198
+ function getLang() {
199
+ return currentLang;
200
+ }
178
201
  function t(key, vars) {
179
202
  const raw = tables[currentLang][key] ?? tables.en[key] ?? key;
180
203
  if (!vars) return raw;
@@ -828,44 +851,111 @@ var BLOCK_RE = /<!-- BEGIN @curdx\/flow v\d+[^>]*-->[\s\S]*?<!-- END @curdx\/flo
828
851
  function claudeMdPath() {
829
852
  return path4.join(os2.homedir(), ".claude", "CLAUDE.md");
830
853
  }
854
+ function isZh() {
855
+ return getLang() === "zh";
856
+ }
831
857
  function buildCombinationPatterns(ids) {
832
858
  const has = (k) => ids.has(k);
833
- const out = ["\u6309\u573A\u666F\u4E32\u8054\uFF0C\u4E0D\u8981\u4E00\u4E2A\u4E2A\u5B64\u7ACB\u8C03\u7528\uFF1A", ""];
859
+ const out = [
860
+ isZh() ? "\u6309\u573A\u666F\u4E32\u8054\uFF0C\u4F18\u5148\u6309\u80FD\u529B\u8FB9\u754C\u8C03\u7528\uFF1Aslash command\u3001MCP\u3001\u63D2\u4EF6 skill \u4E0D\u8981\u6DF7\u5199\u3002" : "Combine tools by capability. Keep slash commands, MCP tools, and plugin skills distinct.",
861
+ ""
862
+ ];
834
863
  if (has("claude-mem") || has("context7") || has("curdx-flow")) {
835
- out.push("- **\u63A5\u5230\u65B0\u9700\u6C42 / \u65B0 feature \u8D77\u624B\u5F0F**");
864
+ out.push(isZh() ? "- **\u63A5\u5230\u65B0\u9700\u6C42 / \u65B0 feature**" : "- **Starting a new feature**");
836
865
  let step = 1;
837
- if (has("claude-mem")) out.push(` ${step++}. \`claude-mem:mem-search\` \u67E5\u5386\u53F2\u2014\u2014"\u4EE5\u524D\u6709\u6CA1\u6709\u7C7B\u4F3C\u7684\u6D3B/\u5751"`);
838
- if (has("context7")) out.push(` ${step++}. \u6D89\u53CA\u5916\u90E8\u5E93 \u2192 \`context7\` \u62C9\u6700\u65B0\u6587\u6863`);
866
+ if (has("claude-mem")) {
867
+ out.push(
868
+ isZh() ? ` ${step++}. \u5148\u7528 \`/claude-mem:mem-search\` \u67E5\u5386\u53F2\uFF0C\u786E\u8BA4\u4E4B\u524D\u6709\u6CA1\u6709\u7C7B\u4F3C\u5B9E\u73B0\u3001\u8E29\u5751\u6216\u51B3\u7B56\u3002` : ` ${step++}. Start with \`/claude-mem:mem-search\` to check whether this work, decision, or pitfall already exists in memory.`
869
+ );
870
+ }
871
+ if (has("context7")) {
872
+ out.push(
873
+ isZh() ? ` ${step++}. \u6D89\u53CA\u5916\u90E8\u5E93\u3001SDK\u3001\u6846\u67B6\u6216 API \u65F6\uFF0C\u4F7F\u7528 Context7 MCP \u62C9\u5B98\u65B9\u6700\u65B0\u6587\u6863\u3002` : ` ${step++}. If external libraries, SDKs, frameworks, or APIs are involved, use the Context7 MCP to pull current official docs.`
874
+ );
875
+ }
839
876
  const planners = [];
840
- if (has("claude-mem")) planners.push("`claude-mem:make-plan` \u51FA phased plan");
841
- if (has("curdx-flow")) planners.push("`/curdx-flow:new` \u8D77 spec");
842
- if (planners.length > 0) out.push(` ${step++}. \u590D\u6742\u591A\u6B65 \u2192 ${planners.join("\uFF0C\u6216 ")}`);
843
- out.push(` ${step++}. \u7B80\u5355\u4E00\u6B21\u6027\u6539\u52A8 \u2192 \u76F4\u63A5\u52A8\u624B\uFF0C\u8DF3\u8FC7\u4E0A\u9762\u51E0\u6B65`);
877
+ if (has("claude-mem")) {
878
+ planners.push(
879
+ isZh() ? "`/claude-mem:make-plan` \u4EA7\u51FA\u5206\u9636\u6BB5\u8BA1\u5212" : "`/claude-mem:make-plan` for a phased plan"
880
+ );
881
+ }
882
+ if (has("curdx-flow")) {
883
+ planners.push(
884
+ isZh() ? "`/curdx-flow:new` \u6216\u76F8\u5173 spec flow \u8D77\u5B8C\u6574\u89C4\u683C" : "`/curdx-flow:new` or the spec flow for a full specification"
885
+ );
886
+ }
887
+ if (planners.length > 0) {
888
+ out.push(
889
+ isZh() ? ` ${step++}. \u591A\u6B65\u9AA4\u3001\u9AD8\u4E0D\u786E\u5B9A\u6027\u3001\u8DE8\u6A21\u5757\u65F6\uFF0C\u518D\u8FDB\u5165 ${planners.join("\uFF0C\u6216 ")}\u3002` : ` ${step++}. Only move into ${planners.join(" or ")} when the work is multi-step, cross-cutting, or uncertain.`
890
+ );
891
+ }
892
+ out.push(
893
+ isZh() ? ` ${step++}. \u7B80\u5355\u3001\u8303\u56F4\u660E\u786E\u7684\u4E00\u6B21\u6027\u6539\u52A8\uFF0C\u76F4\u63A5\u505A\uFF0C\u4E0D\u8981\u5148\u628A\u6D41\u7A0B\u62C9\u6EE1\u3002` : ` ${step++}. For small, clear one-shot changes, implement directly instead of forcing the full workflow.`
894
+ );
844
895
  out.push("");
845
896
  }
846
897
  const stuckLines = [];
847
898
  let s = 1;
848
- if (has("claude-mem")) stuckLines.push(` ${s++}. \u5148\u770B \`claude-mem:mem-search\`\u2014\u2014\u4EE5\u524D\u662F\u5426\u89E3\u8FC7\u540C\u6837\u7684 bug`);
849
- if (has("chrome-devtools-mcp")) stuckLines.push(` ${s++}. \u6D4F\u89C8\u5668\u4FA7 bug \u2192 \`chrome-devtools-mcp\`\uFF08network / console / perf trace\uFF09`);
850
- if (has("context7")) stuckLines.push(` ${s++}. \u5E93 / API \u884C\u4E3A\u4E0D\u7B26\u9884\u671F \u2192 \`context7\` \u67E5\u5B98\u65B9 doc\uFF0C\u4E0D\u8981\u51ED\u8BB0\u5FC6`);
899
+ if (has("claude-mem")) {
900
+ stuckLines.push(
901
+ isZh() ? ` ${s++}. \u5148\u7528 \`/claude-mem:mem-search\` \u67E5\u8BB0\u5FC6\uFF0C\u786E\u8BA4\u662F\u4E0D\u662F\u4EE5\u524D\u89E3\u8FC7\u540C\u7C7B bug\u3002` : ` ${s++}. Check \`/claude-mem:mem-search\` first to see whether the same bug was solved before.`
902
+ );
903
+ }
904
+ if (has("chrome-devtools-mcp")) {
905
+ stuckLines.push(
906
+ isZh() ? ` ${s++}. \u6D4F\u89C8\u5668\u4FA7\u95EE\u9898\u4F7F\u7528 Chrome DevTools MCP\uFF1A\u770B network\u3001console\u3001performance\u3001DOM snapshot\u3002` : ` ${s++}. For browser-side issues, use the Chrome DevTools MCP for network, console, performance, and DOM snapshots.`
907
+ );
908
+ }
909
+ if (has("context7")) {
910
+ stuckLines.push(
911
+ isZh() ? ` ${s++}. \u5982\u679C\u6000\u7591\u662F\u5E93 / API \u884C\u4E3A\u53D8\u5316\uFF0C\u4F7F\u7528 Context7 MCP \u67E5\u5B98\u65B9\u6587\u6863\uFF0C\u4E0D\u8981\u51ED\u8BB0\u5FC6\u3002` : ` ${s++}. If the issue may come from library or API behavior, use the Context7 MCP instead of relying on memory.`
912
+ );
913
+ }
851
914
  const stillStuck = [];
852
- if (has("sequential-thinking")) stillStuck.push("`sequential-thinking` \u62C6\u5047\u8BBE");
853
- if (has("pua")) stillStuck.push("`/pua:pua-loop` \u81EA\u52A8\u8FED\u4EE3");
854
- if (stillStuck.length > 0) stuckLines.push(` ${s++}. \u8FD8\u5361 \u2192 ${stillStuck.join("\uFF0C\u6216 ")}`);
915
+ if (has("sequential-thinking")) {
916
+ stillStuck.push(
917
+ isZh() ? "\u4F7F\u7528 sequential-thinking MCP \u62C6\u5047\u8BBE" : "use the sequential-thinking MCP to break down hypotheses"
918
+ );
919
+ }
920
+ if (has("pua")) {
921
+ stillStuck.push(
922
+ isZh() ? "\u518D\u8FDB\u5165 `/pua:pua-loop` \u8FED\u4EE3" : "then enter `/pua:pua-loop` for structured retries"
923
+ );
924
+ }
925
+ if (stillStuck.length > 0) {
926
+ stuckLines.push(
927
+ isZh() ? ` ${s++}. \u4E24\u8F6E\u4EE5\u4E0A\u4ECD\u5361\u4F4F\uFF0C\u518D ${stillStuck.join("\uFF0C\u6216 ")}\u3002` : ` ${s++}. If you are still stuck after multiple attempts, ${stillStuck.join(" or ")}.`
928
+ );
929
+ }
855
930
  if (stuckLines.length > 0) {
856
- out.push("- **\u9047\u5230 bug / \u5361\u4F4F 2 \u6B21\u4EE5\u4E0A**", ...stuckLines, "");
931
+ out.push(isZh() ? "- **\u9047\u5230 bug / \u8FDE\u7EED\u5361\u4F4F**" : "- **Debugging and repeated failures**", ...stuckLines, "");
857
932
  }
858
933
  if (has("frontend-design") || has("chrome-devtools-mcp")) {
859
- out.push("- **\u505A UI / \u524D\u7AEF\u9875\u9762**");
860
- if (has("frontend-design")) out.push(" - `frontend-design` \u81EA\u52A8 fire\uFF0C\u65E0\u9700\u624B\u52A8\u8C03");
861
- if (has("chrome-devtools-mcp")) out.push(" - \u6E32\u67D3\u5F02\u5E38\u6216\u4EA4\u4E92 bug \u2192 `chrome-devtools-mcp` \u9A8C\u8BC1\uFF0C\u4E0D\u9760\u8089\u773C");
934
+ out.push(isZh() ? "- **\u505A UI / \u524D\u7AEF\u9875\u9762**" : "- **UI and frontend work**");
935
+ if (has("frontend-design")) {
936
+ out.push(
937
+ isZh() ? " - \u4F18\u5148\u4F7F\u7528 `frontend-design` \u63D2\u4EF6\u7684 UI skills\uFF1B\u82E5\u672A\u81EA\u52A8\u89E6\u53D1\uFF0C\u518D\u663E\u5F0F\u8C03\u7528\u5BF9\u5E94 skill\u3002" : " - Prioritize the `frontend-design` plugin skills for UI work; if they do not trigger automatically, invoke the relevant skill explicitly."
938
+ );
939
+ }
940
+ if (has("chrome-devtools-mcp")) {
941
+ out.push(
942
+ isZh() ? " - \u6E32\u67D3\u5F02\u5E38\u3001\u4EA4\u4E92\u95EE\u9898\u6216\u89C6\u89C9\u56DE\u5F52\uFF0C\u4F7F\u7528 Chrome DevTools MCP \u9A8C\u8BC1\uFF0C\u4E0D\u8981\u53EA\u9760\u8089\u773C\u731C\u3002" : " - For rendering issues, interaction bugs, or visual regressions, verify with the Chrome DevTools MCP instead of relying on visual guesswork alone."
943
+ );
944
+ }
862
945
  out.push("");
863
946
  }
864
947
  if (has("pua") || has("curdx-flow")) {
865
- out.push("- **\u5927\u578B / \u8DE8\u6A21\u5757 / \u591A agent \u534F\u4F5C**");
866
- if (has("pua")) out.push(" - `/pua:p9` \u62C6 task prompt + \u7BA1 P8 \u56E2\u961F");
867
- if (has("curdx-flow")) out.push(" - `/curdx-flow:triage` \u628A\u5927 feature \u62C6\u6210\u591A\u4E2A spec");
868
- if (has("pua")) out.push(" - \u6218\u7565\u7EA7 \u2192 `/pua:p10`");
948
+ out.push(isZh() ? "- **\u5927\u578B / \u8DE8\u6A21\u5757 / \u591A agent \u534F\u4F5C**" : "- **Large, cross-cutting, or multi-agent work**");
949
+ if (has("pua")) {
950
+ out.push(
951
+ isZh() ? " - \u9700\u8981\u5E76\u884C\u62C6\u89E3\u4E0E\u56E2\u961F\u534F\u4F5C\u65F6\uFF0C\u7528 `/pua:p9`\uFF1B\u66F4\u9AD8\u5C42\u6218\u7565\u89C4\u5212\u518D\u8003\u8651 `/pua:p10`\u3002" : " - Use `/pua:p9` for parallel task decomposition and team coordination; reserve `/pua:p10` for higher-level strategy work."
952
+ );
953
+ }
954
+ if (has("curdx-flow")) {
955
+ out.push(
956
+ isZh() ? " - \u4E00\u4E2A\u5927\u529F\u80FD\u9700\u8981\u62C6\u6210\u591A\u4E2A\u76F8\u4E92\u4F9D\u8D56\u7684\u89C4\u683C\u65F6\uFF0C\u4F7F\u7528 `/curdx-flow:triage`\u3002" : " - Use `/curdx-flow:triage` when one large feature needs to be split into multiple dependent specs."
957
+ );
958
+ }
869
959
  }
870
960
  while (out.length > 0 && out[out.length - 1] === "") out.pop();
871
961
  return out;
@@ -873,48 +963,76 @@ function buildCombinationPatterns(ids) {
873
963
  function buildSkipRules(ids) {
874
964
  const has = (k) => ids.has(k);
875
965
  const out = [];
876
- out.push("- \u4E00\u884C\u6539\u52A8 / typo / \u91CD\u547D\u540D\u53D8\u91CF \u2014\u2014 \u4E0D\u8981 plan\uFF0C\u4E0D\u8981 mem-search\uFF0C\u76F4\u63A5 Edit");
966
+ out.push(
967
+ isZh() ? "- \u4E00\u884C\u6539\u52A8\u3001typo\u3001\u7EAF\u91CD\u547D\u540D\u53D8\u91CF\uFF1A\u4E0D\u8981\u5148 plan\uFF0C\u4E0D\u8981\u5148\u5F00 spec\uFF0C\u76F4\u63A5\u6539\u3002" : "- For one-line changes, typos, or pure renames, skip planning and spec flow. Just make the edit."
968
+ );
877
969
  const skips = [];
878
970
  if (has("pua")) skips.push("`/pua:pua`");
879
971
  if (has("sequential-thinking")) skips.push("`sequential-thinking`");
880
972
  if (skips.length > 0) {
881
- out.push(`- \u5DF2\u77E5\u786E\u5B9A\u7684 fix \u2014\u2014 \u4E0D\u8981 ${skips.join("\u3001")}`);
973
+ out.push(
974
+ isZh() ? `- \u5DF2\u77E5\u786E\u5B9A\u7684 fix\uFF1A\u4E0D\u8981\u5148\u4E0A ${skips.join("\u3001")}\u3002` : `- For a known, deterministic fix, do not reach for ${skips.join(" or ")} first.`
975
+ );
882
976
  }
883
- out.push('- \u7528\u6237\u95EE"\u8FD9\u662F\u4EC0\u4E48\u610F\u601D"\u7C7B\u7684\u89E3\u91CA\u9898 \u2014\u2014 \u4E0D\u8C03\u4EFB\u4F55\u5DE5\u5177\uFF0C\u76F4\u63A5\u7B54');
977
+ out.push(
978
+ isZh() ? "- \u7EAF\u6982\u5FF5\u89E3\u91CA\u9898\u53EF\u4EE5\u76F4\u63A5\u7B54\uFF1B\u5982\u679C\u662F\u5728\u95EE\u5F53\u524D\u4ED3\u5E93\u91CC\u7684\u4EE3\u7801\u542B\u4E49\uFF0C\u5148\u8BFB\u76F8\u5173\u6587\u4EF6\u518D\u89E3\u91CA\u3002" : "- Answer pure conceptual explanation questions directly. If the question is about code in this repository, read the relevant files first."
979
+ );
884
980
  if (has("curdx-flow")) {
885
- out.push("- \u5355\u6587\u4EF6\u5C40\u90E8\u91CD\u6784 \u2014\u2014 \u4E0D\u8D77 spec\uFF0C\u4E0D\u8FDB curdx-flow");
981
+ out.push(
982
+ isZh() ? "- \u5355\u6587\u4EF6\u5C40\u90E8\u91CD\u6784\u6216\u5F88\u5C0F\u8303\u56F4\u7684\u6574\u7406\uFF1A\u901A\u5E38\u4E0D\u8981\u8FDB\u5165 curdx-flow spec \u6D41\u3002" : "- For a single-file refactor or a very local cleanup, usually do not enter the curdx-flow spec workflow."
983
+ );
886
984
  }
887
985
  return out;
888
986
  }
889
987
  function buildDecisionTree(ids) {
890
988
  const has = (k) => ids.has(k);
891
989
  const out = [];
892
- out.push("1. \u80FD 1\u20132 \u6B65\u641E\u5B9A\uFF1F\u2192 \u76F4\u63A5\u505A");
893
- out.push("2. \u591A\u6B65\u9AA4\u4F46\u8DEF\u5F84\u6E05\u6670\uFF1F\u2192 TaskCreate \u62C6\u4EFB\u52A1\uFF0C\u4E0D\u8FDB spec");
990
+ out.push(isZh() ? "1. \u80FD 1\u20132 \u6B65\u641E\u5B9A\uFF1F\u2192 \u76F4\u63A5\u505A\u3002" : "1. Can it be finished in 1-2 steps? -> Do it directly.");
991
+ out.push(
992
+ isZh() ? "2. \u591A\u6B65\u9AA4\u4F46\u8DEF\u5F84\u6E05\u6670\uFF1F\u2192 \u62C6\u6210\u7B80\u77ED\u4EFB\u52A1\u5217\u8868\u9010\u4E2A\u63A8\u8FDB\uFF0C\u4E0D\u8981\u9ED8\u8BA4\u8FDB\u5165\u5B8C\u6574 spec \u6D41\u3002" : "2. Is it multi-step but still clear? -> Break it into a short task list and execute without defaulting to the full spec flow."
993
+ );
894
994
  const planners = [];
895
995
  if (has("curdx-flow")) planners.push("`/curdx-flow:new`");
896
- if (has("claude-mem")) planners.push("`claude-mem:make-plan`");
996
+ if (has("claude-mem")) planners.push("`/claude-mem:make-plan`");
897
997
  if (planners.length > 0) {
898
- out.push(`3. \u9700\u6C42\u6A21\u7CCA / \u8DE8\u6A21\u5757 / \u8981\u5206\u9636\u6BB5\u4EA4\u4ED8\uFF1F\u2192 ${planners.join(" \u6216 ")}`);
998
+ out.push(
999
+ isZh() ? `3. \u9700\u6C42\u6A21\u7CCA\u3001\u8DE8\u6A21\u5757\u3001\u9700\u8981\u5206\u9636\u6BB5\u4EA4\u4ED8\uFF1F\u2192 ${planners.join(" \u6216 ")}\u3002` : `3. Is the request ambiguous, cross-cutting, or phase-based? -> ${planners.join(" or ")}.`
1000
+ );
899
1001
  }
900
1002
  if (has("claude-mem")) {
901
- out.push("4. \u540C\u6837\u7684\u6D3B\u4EE5\u524D\u53EF\u80FD\u5E72\u8FC7\uFF1F\u2192 \u5148 `claude-mem:mem-search`");
1003
+ out.push(
1004
+ isZh() ? "4. \u8FD9\u7C7B\u6D3B\u4EE5\u524D\u53EF\u80FD\u505A\u8FC7\uFF1F\u2192 \u5148 `/claude-mem:mem-search`\u3002" : "4. Might this work have been done before? -> Start with `/claude-mem:mem-search`."
1005
+ );
902
1006
  }
903
1007
  return out;
904
1008
  }
1009
+ function buildLanguagePolicy() {
1010
+ if (getLang() !== "zh") return [];
1011
+ return [
1012
+ "- Tool and model interaction must be in English.",
1013
+ "- All user-facing responses must be in Simplified Chinese."
1014
+ ];
1015
+ }
905
1016
  function renderBlock(items) {
906
1017
  const installedIds = new Set(items.map((i) => i.id));
907
1018
  const sections = [
908
- ["## Tool Combination Patterns\uFF08\u7EC4\u5408\u5DE5\u4F5C\u6D41\uFF09", buildCombinationPatterns(installedIds)],
909
- ["## Skip Rules\uFF08\u9632\u8FC7\u5EA6\u5DE5\u5177\u5316\uFF09", buildSkipRules(installedIds)],
910
- ["## Decision Tree\uFF08\u9047\u5230\u6A21\u7CCA\u8BF7\u6C42\u65F6\uFF09", buildDecisionTree(installedIds)]
1019
+ ["## Language Policy\uFF08\u8BED\u8A00\u89C4\u5219\uFF09", buildLanguagePolicy()],
1020
+ [
1021
+ isZh() ? "## Tool Combination Patterns\uFF08\u7EC4\u5408\u5DE5\u4F5C\u6D41\uFF09" : "## Tool Combination Patterns",
1022
+ buildCombinationPatterns(installedIds)
1023
+ ],
1024
+ [isZh() ? "## Skip Rules\uFF08\u9632\u8FC7\u5EA6\u5DE5\u5177\u5316\uFF09" : "## Skip Rules", buildSkipRules(installedIds)],
1025
+ [isZh() ? "## Decision Tree\uFF08\u9047\u5230\u6A21\u7CCA\u8BF7\u6C42\u65F6\uFF09" : "## Decision Tree", buildDecisionTree(installedIds)]
911
1026
  ];
912
1027
  const lines = [BEGIN_MARKER];
913
1028
  for (const [heading, body] of sections) {
914
1029
  if (body.length === 0) continue;
915
1030
  lines.push(heading, "", ...body, "");
916
1031
  }
917
- lines.push("Run `npx @curdx/flow` to install / update / uninstall.", END_MARKER);
1032
+ lines.push(
1033
+ isZh() ? "\u8FD0\u884C `npx @curdx/flow` \u4EE5 install / update / uninstall\u3002" : "Run `npx @curdx/flow` to install / update / uninstall.",
1034
+ END_MARKER
1035
+ );
918
1036
  return lines.join("\n");
919
1037
  }
920
1038
  function withEol(s, eol) {
@@ -1554,6 +1672,45 @@ async function mainMenu() {
1554
1672
  }
1555
1673
  }
1556
1674
 
1675
+ // src/flows/analyze.ts
1676
+ import { defineCommand } from "citty";
1677
+ var analyzeCmd = defineCommand({
1678
+ meta: {
1679
+ name: "analyze",
1680
+ description: "Analyze Claude Code session jsonl + curdx-flow errors.jsonl into a markdown report"
1681
+ },
1682
+ args: {
1683
+ out: {
1684
+ type: "string",
1685
+ description: "Output file path (default: stdout)"
1686
+ },
1687
+ json: {
1688
+ type: "boolean",
1689
+ description: "Emit JSON instead of markdown"
1690
+ },
1691
+ limit: {
1692
+ type: "string",
1693
+ description: "Top-N truncation for tabular sections (default: 10)"
1694
+ },
1695
+ "include-prompts": {
1696
+ type: "boolean",
1697
+ description: "Skip prompt redaction (D-9 white-list passthrough disabled \u2014 local debugging only)"
1698
+ }
1699
+ },
1700
+ async run({ args }) {
1701
+ const limitRaw = args.limit;
1702
+ const limit = typeof limitRaw === "string" && limitRaw.length > 0 ? Number(limitRaw) : void 0;
1703
+ const { runAnalyze } = await import("./analyze-4DE3HVCA.mjs");
1704
+ await runAnalyze({
1705
+ out: typeof args.out === "string" ? args.out : void 0,
1706
+ json: Boolean(args.json),
1707
+ limit: Number.isFinite(limit) ? limit : void 0,
1708
+ includePrompts: Boolean(args["include-prompts"])
1709
+ });
1710
+ }
1711
+ });
1712
+ var analyze_default = analyzeCmd;
1713
+
1557
1714
  // src/index.ts
1558
1715
  function parseLang(v) {
1559
1716
  return v === "zh" || v === "en" ? v : void 0;
@@ -1569,7 +1726,7 @@ var sharedArgs = {
1569
1726
  description: "Skip syncing the @curdx/flow block in ~/.claude/CLAUDE.md"
1570
1727
  }
1571
1728
  };
1572
- var installCmd = defineCommand({
1729
+ var installCmd = defineCommand2({
1573
1730
  meta: { name: "install", description: "Install, reinstall, or update plugins / MCP servers" },
1574
1731
  args: {
1575
1732
  ...sharedArgs,
@@ -1592,7 +1749,7 @@ var installCmd = defineCommand({
1592
1749
  p10.outro(t("app.outro"));
1593
1750
  }
1594
1751
  });
1595
- var uninstallCmd = defineCommand({
1752
+ var uninstallCmd = defineCommand2({
1596
1753
  meta: { name: "uninstall", description: "Uninstall installed plugins / MCP servers" },
1597
1754
  args: {
1598
1755
  ...sharedArgs,
@@ -1611,7 +1768,7 @@ var uninstallCmd = defineCommand({
1611
1768
  p10.outro(t("app.outro"));
1612
1769
  }
1613
1770
  });
1614
- var updateCmd = defineCommand({
1771
+ var updateCmd = defineCommand2({
1615
1772
  meta: { name: "update", description: "Update installed plugins" },
1616
1773
  args: {
1617
1774
  ...sharedArgs,
@@ -1630,7 +1787,7 @@ var updateCmd = defineCommand({
1630
1787
  p10.outro(t("app.outro"));
1631
1788
  }
1632
1789
  });
1633
- var statusCmd = defineCommand({
1790
+ var statusCmd = defineCommand2({
1634
1791
  meta: { name: "status", description: "Show install status" },
1635
1792
  args: {
1636
1793
  ...sharedArgs,
@@ -1643,8 +1800,8 @@ var statusCmd = defineCommand({
1643
1800
  if (!args.json) p10.outro(t("app.outro"));
1644
1801
  }
1645
1802
  });
1646
- var SUBCOMMANDS = /* @__PURE__ */ new Set(["install", "uninstall", "update", "status"]);
1647
- var root = defineCommand({
1803
+ var SUBCOMMANDS = /* @__PURE__ */ new Set(["install", "uninstall", "update", "status", "analyze"]);
1804
+ var root = defineCommand2({
1648
1805
  meta: {
1649
1806
  name: "@curdx/flow",
1650
1807
  version: "3.3.2",
@@ -1655,7 +1812,8 @@ var root = defineCommand({
1655
1812
  install: installCmd,
1656
1813
  uninstall: uninstallCmd,
1657
1814
  update: updateCmd,
1658
- status: statusCmd
1815
+ status: statusCmd,
1816
+ analyze: analyze_default
1659
1817
  }
1660
1818
  // No root run() — citty 0.1.6 calls parent.run AFTER a matching subcommand,
1661
1819
  // which would render the menu after a subcommand finishes. We dispatch the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curdx/flow",
3
- "version": "7.1.2",
3
+ "version": "7.1.4",
4
4
  "description": "Interactive installer for Claude Code plugins and MCP servers",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.mjs",
@@ -15,11 +15,13 @@
15
15
  "build": "tsup",
16
16
  "build:hooks": "node scripts/build-hooks.mjs",
17
17
  "check:hooks-fresh": "node scripts/check-hooks-fresh.mjs",
18
+ "check:bundle": "node scripts/check-bundle-size.mjs",
18
19
  "dev": "tsup --watch",
19
20
  "test:hooks": "npm run build:hooks && vitest run tests/hooks --passWithNoTests",
21
+ "test:analyze": "vitest run tests/analyze",
20
22
  "start": "node ./dist/index.mjs",
21
23
  "typecheck": "tsc --noEmit",
22
- "verify": "npm run typecheck && npm run check-versions && npm run check:hooks-fresh && npm run test:hooks",
24
+ "verify": "npm run typecheck && npm run check-versions && npm run check:hooks-fresh && npm run build && npm run check:bundle && npm run test:hooks && npm run test:analyze",
23
25
  "check-versions": "node scripts/check-versions.mjs",
24
26
  "bump-version": "node scripts/bump-version.mjs",
25
27
  "prepublishOnly": "node scripts/check-versions.mjs && npm run typecheck && npm run check:hooks-fresh && npm run build"