@blxzer/cursor-trellis 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/README.md +124 -5
  2. package/README.zh-CN.md +170 -0
  3. package/dist/cli/index.d.ts.map +1 -1
  4. package/dist/cli/index.js +1 -33
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/commands/init.d.ts +0 -13
  7. package/dist/commands/init.d.ts.map +1 -1
  8. package/dist/commands/init.js +7 -14
  9. package/dist/commands/init.js.map +1 -1
  10. package/dist/commands/uninstall.d.ts.map +1 -1
  11. package/dist/commands/uninstall.js +3 -32
  12. package/dist/commands/uninstall.js.map +1 -1
  13. package/dist/commands/update.d.ts.map +1 -1
  14. package/dist/commands/update.js +7 -84
  15. package/dist/commands/update.js.map +1 -1
  16. package/dist/configurators/index.d.ts +7 -8
  17. package/dist/configurators/index.d.ts.map +1 -1
  18. package/dist/configurators/index.js +11 -236
  19. package/dist/configurators/index.js.map +1 -1
  20. package/dist/configurators/workflow.d.ts.map +1 -1
  21. package/dist/configurators/workflow.js +5 -1
  22. package/dist/configurators/workflow.js.map +1 -1
  23. package/dist/templates/common/bundled-skills/smart-search-cli/SKILL.md +3 -3
  24. package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +4 -2
  25. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +8 -15
  26. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +7 -7
  27. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +18 -21
  28. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +2 -2
  29. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +10 -7
  30. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +4 -4
  31. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +20 -31
  32. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +20 -31
  33. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +24 -40
  34. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +28 -59
  35. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +12 -28
  36. package/dist/templates/common/bundled-skills/trellis-skill-creator/references/trellis-skill-locations.md +2 -2
  37. package/dist/templates/cursor/hooks.json +6 -0
  38. package/dist/templates/cursor/rules/retrieval-routing.mdc +57 -0
  39. package/dist/templates/extract.d.ts +0 -14
  40. package/dist/templates/extract.d.ts.map +1 -1
  41. package/dist/templates/extract.js +0 -34
  42. package/dist/templates/extract.js.map +1 -1
  43. package/dist/templates/markdown/agents.md +2 -6
  44. package/dist/templates/markdown/index.d.ts +1 -0
  45. package/dist/templates/markdown/index.d.ts.map +1 -1
  46. package/dist/templates/markdown/index.js +1 -0
  47. package/dist/templates/markdown/index.js.map +1 -1
  48. package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +41 -0
  49. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +14 -14
  50. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +8 -20
  51. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +15 -14
  52. package/dist/templates/markdown/spec/guides/cursor-context-injection-guide.md.txt +2 -1
  53. package/dist/templates/markdown/spec/guides/cursor-semantic-compliance.md.txt +49 -0
  54. package/dist/templates/markdown/spec/guides/cursor-subagent-policy.md.txt +2 -2
  55. package/dist/templates/markdown/spec/guides/retrieval-daily-guide.md.txt +68 -20
  56. package/dist/templates/shared-hooks/index.d.ts +1 -1
  57. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  58. package/dist/templates/shared-hooks/index.js +1 -0
  59. package/dist/templates/shared-hooks/index.js.map +1 -1
  60. package/dist/templates/shared-hooks/inject-retrieval-plan.py +163 -0
  61. package/dist/templates/shared-hooks/research-end-retrieval-pack.py +2 -11
  62. package/dist/templates/trellis/index.d.ts +11 -0
  63. package/dist/templates/trellis/index.d.ts.map +1 -1
  64. package/dist/templates/trellis/index.js +22 -0
  65. package/dist/templates/trellis/index.js.map +1 -1
  66. package/dist/templates/trellis/scripts/aggregate_retrieval_telemetry.py +342 -0
  67. package/dist/templates/trellis/scripts/batch_plan_envelope.py +105 -0
  68. package/dist/templates/trellis/scripts/codegraph_session_smoke.py +76 -0
  69. package/dist/templates/trellis/scripts/common/active_task.py +116 -147
  70. package/dist/templates/trellis/scripts/common/cli_adapter.py +34 -710
  71. package/dist/templates/trellis/scripts/common/codebase_retrieval_router.py +49 -106
  72. package/dist/templates/trellis/scripts/common/git_context.py +17 -2
  73. package/dist/templates/trellis/scripts/common/project_file_stats.py +91 -0
  74. package/dist/templates/trellis/scripts/common/retrieval_adapter_metadata.py +9 -11
  75. package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +313 -0
  76. package/dist/templates/trellis/scripts/common/retrieval_pack.py +0 -6
  77. package/dist/templates/trellis/scripts/common/retrieval_pack_context.py +0 -4
  78. package/dist/templates/trellis/scripts/common/retrieval_plan_gate.py +76 -0
  79. package/dist/templates/trellis/scripts/common/retrieval_result_ranking.py +253 -0
  80. package/dist/templates/trellis/scripts/common/retrieval_tool_classification.py +157 -0
  81. package/dist/templates/trellis/scripts/common/semantic_plan_gate.py +52 -0
  82. package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -24
  83. package/dist/templates/trellis/scripts/rank_retrieval_candidates.py +80 -0
  84. package/dist/templates/trellis/scripts/route_codebase_retrieval.py +38 -11
  85. package/dist/templates/trellis/scripts/score_evidence.py +112 -0
  86. package/dist/templates/trellis/workflow.md +861 -960
  87. package/dist/types/ai-tools.d.ts +13 -16
  88. package/dist/types/ai-tools.d.ts.map +1 -1
  89. package/dist/types/ai-tools.js +5 -238
  90. package/dist/types/ai-tools.js.map +1 -1
  91. package/dist/utils/codebase-retrieval-router.d.ts +1 -8
  92. package/dist/utils/codebase-retrieval-router.d.ts.map +1 -1
  93. package/dist/utils/codebase-retrieval-router.js +39 -180
  94. package/dist/utils/codebase-retrieval-router.js.map +1 -1
  95. package/dist/utils/project-capabilities.d.ts.map +1 -1
  96. package/dist/utils/project-capabilities.js +10 -24
  97. package/dist/utils/project-capabilities.js.map +1 -1
  98. package/dist/utils/retrieval-agent-instructions.d.ts +14 -0
  99. package/dist/utils/retrieval-agent-instructions.d.ts.map +1 -0
  100. package/dist/utils/retrieval-agent-instructions.js +221 -0
  101. package/dist/utils/retrieval-agent-instructions.js.map +1 -0
  102. package/dist/utils/retrieval-execution-telemetry.d.ts +43 -85
  103. package/dist/utils/retrieval-execution-telemetry.d.ts.map +1 -1
  104. package/dist/utils/retrieval-execution-telemetry.js +289 -22
  105. package/dist/utils/retrieval-execution-telemetry.js.map +1 -1
  106. package/dist/utils/retrieval-result-ranking.js +1 -1
  107. package/dist/utils/retrieval-result-ranking.js.map +1 -1
  108. package/dist/utils/retrieval-tool-classification.d.ts +32 -0
  109. package/dist/utils/retrieval-tool-classification.d.ts.map +1 -0
  110. package/dist/utils/retrieval-tool-classification.js +113 -0
  111. package/dist/utils/retrieval-tool-classification.js.map +1 -0
  112. package/dist/utils/uninstall-scrubbers.d.ts +0 -36
  113. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  114. package/dist/utils/uninstall-scrubbers.js +0 -184
  115. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  116. package/package.json +4 -2
  117. package/dist/commands/mem.d.ts +0 -30
  118. package/dist/commands/mem.d.ts.map +0 -1
  119. package/dist/commands/mem.js +0 -424
  120. package/dist/commands/mem.js.map +0 -1
  121. package/dist/configurators/antigravity.d.ts +0 -7
  122. package/dist/configurators/antigravity.d.ts.map +0 -1
  123. package/dist/configurators/antigravity.js +0 -19
  124. package/dist/configurators/antigravity.js.map +0 -1
  125. package/dist/configurators/claude.d.ts +0 -9
  126. package/dist/configurators/claude.d.ts.map +0 -1
  127. package/dist/configurators/claude.js +0 -72
  128. package/dist/configurators/claude.js.map +0 -1
  129. package/dist/configurators/codebuddy.d.ts +0 -10
  130. package/dist/configurators/codebuddy.d.ts.map +0 -1
  131. package/dist/configurators/codebuddy.js +0 -30
  132. package/dist/configurators/codebuddy.js.map +0 -1
  133. package/dist/configurators/codex.d.ts +0 -8
  134. package/dist/configurators/codex.d.ts.map +0 -1
  135. package/dist/configurators/codex.js +0 -87
  136. package/dist/configurators/codex.js.map +0 -1
  137. package/dist/configurators/copilot.d.ts +0 -10
  138. package/dist/configurators/copilot.d.ts.map +0 -1
  139. package/dist/configurators/copilot.js +0 -51
  140. package/dist/configurators/copilot.js.map +0 -1
  141. package/dist/configurators/droid.d.ts +0 -10
  142. package/dist/configurators/droid.d.ts.map +0 -1
  143. package/dist/configurators/droid.js +0 -30
  144. package/dist/configurators/droid.js.map +0 -1
  145. package/dist/configurators/gemini.d.ts +0 -16
  146. package/dist/configurators/gemini.d.ts.map +0 -1
  147. package/dist/configurators/gemini.js +0 -38
  148. package/dist/configurators/gemini.js.map +0 -1
  149. package/dist/configurators/kilo.d.ts +0 -7
  150. package/dist/configurators/kilo.d.ts.map +0 -1
  151. package/dist/configurators/kilo.js +0 -19
  152. package/dist/configurators/kilo.js.map +0 -1
  153. package/dist/configurators/kiro.d.ts +0 -8
  154. package/dist/configurators/kiro.d.ts.map +0 -1
  155. package/dist/configurators/kiro.js +0 -24
  156. package/dist/configurators/kiro.js.map +0 -1
  157. package/dist/configurators/opencode.d.ts +0 -14
  158. package/dist/configurators/opencode.d.ts.map +0 -1
  159. package/dist/configurators/opencode.js +0 -96
  160. package/dist/configurators/opencode.js.map +0 -1
  161. package/dist/configurators/pi.d.ts +0 -3
  162. package/dist/configurators/pi.d.ts.map +0 -1
  163. package/dist/configurators/pi.js +0 -45
  164. package/dist/configurators/pi.js.map +0 -1
  165. package/dist/configurators/qoder.d.ts +0 -11
  166. package/dist/configurators/qoder.d.ts.map +0 -1
  167. package/dist/configurators/qoder.js +0 -31
  168. package/dist/configurators/qoder.js.map +0 -1
  169. package/dist/configurators/windsurf.d.ts +0 -7
  170. package/dist/configurators/windsurf.d.ts.map +0 -1
  171. package/dist/configurators/windsurf.js +0 -19
  172. package/dist/configurators/windsurf.js.map +0 -1
  173. package/dist/templates/claude/agents/trellis-check.md +0 -124
  174. package/dist/templates/claude/agents/trellis-implement.md +0 -110
  175. package/dist/templates/claude/agents/trellis-research.md +0 -137
  176. package/dist/templates/claude/index.d.ts +0 -22
  177. package/dist/templates/claude/index.d.ts.map +0 -1
  178. package/dist/templates/claude/index.js +0 -46
  179. package/dist/templates/claude/index.js.map +0 -1
  180. package/dist/templates/claude/settings.json +0 -84
  181. package/dist/templates/codebuddy/agents/trellis-check.md +0 -115
  182. package/dist/templates/codebuddy/agents/trellis-implement.md +0 -110
  183. package/dist/templates/codebuddy/agents/trellis-research.md +0 -137
  184. package/dist/templates/codebuddy/index.d.ts +0 -15
  185. package/dist/templates/codebuddy/index.d.ts.map +0 -1
  186. package/dist/templates/codebuddy/index.js +0 -15
  187. package/dist/templates/codebuddy/index.js.map +0 -1
  188. package/dist/templates/codebuddy/settings.json +0 -70
  189. package/dist/templates/codex/agents/trellis-check.toml +0 -67
  190. package/dist/templates/codex/agents/trellis-implement.toml +0 -40
  191. package/dist/templates/codex/agents/trellis-research.toml +0 -73
  192. package/dist/templates/codex/config.toml +0 -28
  193. package/dist/templates/codex/hooks/session-start.py +0 -575
  194. package/dist/templates/codex/hooks.json +0 -15
  195. package/dist/templates/codex/index.d.ts +0 -39
  196. package/dist/templates/codex/index.d.ts.map +0 -1
  197. package/dist/templates/codex/index.js +0 -85
  198. package/dist/templates/codex/index.js.map +0 -1
  199. package/dist/templates/codex/skills/before-dev/SKILL.md +0 -40
  200. package/dist/templates/codex/skills/brainstorm/SKILL.md +0 -112
  201. package/dist/templates/codex/skills/break-loop/SKILL.md +0 -130
  202. package/dist/templates/codex/skills/check/SKILL.md +0 -98
  203. package/dist/templates/codex/skills/check-cross-layer/SKILL.md +0 -158
  204. package/dist/templates/codex/skills/create-command/SKILL.md +0 -101
  205. package/dist/templates/codex/skills/finish-work/SKILL.md +0 -90
  206. package/dist/templates/codex/skills/improve-ut/SKILL.md +0 -69
  207. package/dist/templates/codex/skills/integrate-skill/SKILL.md +0 -221
  208. package/dist/templates/codex/skills/onboard/SKILL.md +0 -363
  209. package/dist/templates/codex/skills/record-session/SKILL.md +0 -67
  210. package/dist/templates/codex/skills/start/SKILL.md +0 -66
  211. package/dist/templates/codex/skills/update-spec/SKILL.md +0 -335
  212. package/dist/templates/copilot/hooks/session-start.py +0 -557
  213. package/dist/templates/copilot/hooks.json +0 -19
  214. package/dist/templates/copilot/index.d.ts +0 -23
  215. package/dist/templates/copilot/index.d.ts.map +0 -1
  216. package/dist/templates/copilot/index.js +0 -54
  217. package/dist/templates/copilot/index.js.map +0 -1
  218. package/dist/templates/copilot/prompts/before-dev.prompt.md +0 -39
  219. package/dist/templates/copilot/prompts/brainstorm.prompt.md +0 -111
  220. package/dist/templates/copilot/prompts/break-loop.prompt.md +0 -129
  221. package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +0 -157
  222. package/dist/templates/copilot/prompts/check.prompt.md +0 -97
  223. package/dist/templates/copilot/prompts/create-command.prompt.md +0 -116
  224. package/dist/templates/copilot/prompts/finish-work.prompt.md +0 -99
  225. package/dist/templates/copilot/prompts/integrate-skill.prompt.md +0 -223
  226. package/dist/templates/copilot/prompts/onboard.prompt.md +0 -362
  227. package/dist/templates/copilot/prompts/parallel.prompt.md +0 -204
  228. package/dist/templates/copilot/prompts/record-session.prompt.md +0 -66
  229. package/dist/templates/copilot/prompts/start.prompt.md +0 -63
  230. package/dist/templates/copilot/prompts/update-spec.prompt.md +0 -358
  231. package/dist/templates/droid/droids/trellis-check.md +0 -107
  232. package/dist/templates/droid/droids/trellis-implement.md +0 -102
  233. package/dist/templates/droid/droids/trellis-research.md +0 -137
  234. package/dist/templates/droid/index.d.ts +0 -15
  235. package/dist/templates/droid/index.d.ts.map +0 -1
  236. package/dist/templates/droid/index.js +0 -15
  237. package/dist/templates/droid/index.js.map +0 -1
  238. package/dist/templates/droid/settings.json +0 -70
  239. package/dist/templates/gemini/agents/trellis-check.md +0 -107
  240. package/dist/templates/gemini/agents/trellis-implement.md +0 -102
  241. package/dist/templates/gemini/agents/trellis-research.md +0 -136
  242. package/dist/templates/gemini/index.d.ts +0 -13
  243. package/dist/templates/gemini/index.d.ts.map +0 -1
  244. package/dist/templates/gemini/index.js +0 -13
  245. package/dist/templates/gemini/index.js.map +0 -1
  246. package/dist/templates/gemini/settings.json +0 -28
  247. package/dist/templates/kiro/agents/trellis-check.json +0 -26
  248. package/dist/templates/kiro/agents/trellis-implement.json +0 -26
  249. package/dist/templates/kiro/agents/trellis-research.json +0 -30
  250. package/dist/templates/kiro/index.d.ts +0 -18
  251. package/dist/templates/kiro/index.d.ts.map +0 -1
  252. package/dist/templates/kiro/index.js +0 -18
  253. package/dist/templates/kiro/index.js.map +0 -1
  254. package/dist/templates/opencode/agents/trellis-check.md +0 -122
  255. package/dist/templates/opencode/agents/trellis-implement.md +0 -118
  256. package/dist/templates/opencode/agents/trellis-research.md +0 -145
  257. package/dist/templates/opencode/lib/session-utils.js +0 -667
  258. package/dist/templates/opencode/lib/trellis-context.js +0 -336
  259. package/dist/templates/opencode/package.json +0 -5
  260. package/dist/templates/opencode/plugins/inject-subagent-context.js +0 -495
  261. package/dist/templates/opencode/plugins/inject-workflow-state.js +0 -159
  262. package/dist/templates/opencode/plugins/session-start.js +0 -101
  263. package/dist/templates/pi/agents/trellis-check.md +0 -37
  264. package/dist/templates/pi/agents/trellis-implement.md +0 -42
  265. package/dist/templates/pi/agents/trellis-research.md +0 -25
  266. package/dist/templates/pi/extensions/trellis/index.ts.txt +0 -1600
  267. package/dist/templates/pi/index.d.ts +0 -5
  268. package/dist/templates/pi/index.d.ts.map +0 -1
  269. package/dist/templates/pi/index.js +0 -12
  270. package/dist/templates/pi/index.js.map +0 -1
  271. package/dist/templates/pi/settings.json +0 -12
  272. package/dist/templates/qoder/agents/trellis-check.md +0 -108
  273. package/dist/templates/qoder/agents/trellis-implement.md +0 -103
  274. package/dist/templates/qoder/agents/trellis-research.md +0 -137
  275. package/dist/templates/qoder/index.d.ts +0 -15
  276. package/dist/templates/qoder/index.d.ts.map +0 -1
  277. package/dist/templates/qoder/index.js +0 -15
  278. package/dist/templates/qoder/index.js.map +0 -1
  279. package/dist/templates/qoder/settings.json +0 -47
@@ -0,0 +1,157 @@
1
+ """Classify agent tool names for retrieval execution telemetry (Cursor-first)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from dataclasses import dataclass
7
+
8
+ CODEGRAPH_PATTERNS = (
9
+ re.compile(r"^codegraph_", re.I),
10
+ re.compile(r"^project-0-.*-codegraph-", re.I),
11
+ re.compile(r"codegraph_search", re.I),
12
+ re.compile(r"codegraph_explore", re.I),
13
+ re.compile(r"codegraph_callers", re.I),
14
+ re.compile(r"codegraph_node", re.I),
15
+ )
16
+
17
+ PLATFORM_SEMANTIC_PATTERNS = (
18
+ re.compile(r"@codebase", re.I),
19
+ re.compile(r"semantic.?search", re.I),
20
+ re.compile(r"DEEP_SEARCH", re.I),
21
+ re.compile(r"codebase.?search", re.I),
22
+ re.compile(r"SemanticSearch", re.I),
23
+ re.compile(r"Instant Search", re.I),
24
+ re.compile(r"Cursor.*semantic", re.I),
25
+ re.compile(r"built-?in.*codebase", re.I),
26
+ )
27
+
28
+ FAST_CONTEXT_PATTERNS = (
29
+ re.compile(r"fast_context_search", re.I),
30
+ re.compile(r"fast-context", re.I),
31
+ re.compile(r"fast_context", re.I),
32
+ )
33
+
34
+ GREP_PATTERNS = (
35
+ re.compile(r"^grep$", re.I),
36
+ re.compile(r"^Grep$", re.I),
37
+ re.compile(r"^rg$", re.I),
38
+ re.compile(r"ripgrep", re.I),
39
+ re.compile(r"Instant Grep", re.I),
40
+ )
41
+
42
+ READ_PATTERNS = (
43
+ re.compile(r"^read$", re.I),
44
+ re.compile(r"^Read$", re.I),
45
+ re.compile(r"ReadFile", re.I),
46
+ re.compile(r"Get-Content", re.I),
47
+ )
48
+
49
+ ROUTER_CLI_PATTERNS = (
50
+ re.compile(r"route_codebase_retrieval", re.I),
51
+ re.compile(r"retrieval-routing", re.I),
52
+ )
53
+
54
+ STRUCTURAL_ROUTE_IDS = frozenset(
55
+ {
56
+ "caller-chain-ast",
57
+ "trap-demote-codegraph",
58
+ "extension-codegraph",
59
+ "ast-codegraph",
60
+ }
61
+ )
62
+
63
+
64
+ def _matches(name: str, patterns: tuple[re.Pattern[str], ...]) -> bool:
65
+ return any(p.search(name) for p in patterns)
66
+
67
+
68
+ def is_platform_semantic_tool_name(name: str) -> bool:
69
+ return _matches(name.strip(), PLATFORM_SEMANTIC_PATTERNS)
70
+
71
+
72
+ def is_fast_context_tool_name(name: str) -> bool:
73
+ return _matches(name.strip(), FAST_CONTEXT_PATTERNS)
74
+
75
+
76
+ @dataclass(frozen=True)
77
+ class ClassifiedToolCalls:
78
+ tools_called: list[str]
79
+ grep_count: int
80
+ read_count: int
81
+ codegraph_attempted: bool
82
+ codegraph_executed: bool
83
+ semantic_attempted: bool
84
+ semantic_executed: bool
85
+ router_cli_invoked: bool
86
+ platform_semantic_executed: bool = False
87
+ fast_context_count: int = 0
88
+ cursor_fast_context_misuse: bool = False
89
+
90
+
91
+ def classify_tool_calls(raw: list[str], *, platform: str = "cursor") -> ClassifiedToolCalls:
92
+ tools_called = list(raw)
93
+ grep_count = 0
94
+ read_count = 0
95
+ codegraph_executed = False
96
+ router_cli_invoked = False
97
+ platform_semantic_executed = False
98
+ fast_context_count = 0
99
+ plat = (platform or "cursor").lower()
100
+
101
+ for name in raw:
102
+ trimmed = name.strip()
103
+ if not trimmed:
104
+ continue
105
+ if _matches(trimmed, GREP_PATTERNS):
106
+ grep_count += 1
107
+ if _matches(trimmed, READ_PATTERNS):
108
+ read_count += 1
109
+ if _matches(trimmed, CODEGRAPH_PATTERNS):
110
+ codegraph_executed = True
111
+ if _matches(trimmed, ROUTER_CLI_PATTERNS):
112
+ router_cli_invoked = True
113
+ if is_fast_context_tool_name(trimmed):
114
+ fast_context_count += 1
115
+ if is_platform_semantic_tool_name(trimmed):
116
+ platform_semantic_executed = True
117
+
118
+ if plat == "cursor":
119
+ semantic_executed = platform_semantic_executed
120
+ else:
121
+ semantic_executed = platform_semantic_executed or fast_context_count > 0
122
+
123
+ semantic_attempted = semantic_executed or fast_context_count > 0
124
+ misuse = plat == "cursor" and fast_context_count > 0
125
+
126
+ return ClassifiedToolCalls(
127
+ tools_called=tools_called,
128
+ grep_count=grep_count,
129
+ read_count=read_count,
130
+ codegraph_attempted=codegraph_executed,
131
+ codegraph_executed=codegraph_executed,
132
+ semantic_attempted=semantic_attempted,
133
+ semantic_executed=semantic_executed,
134
+ router_cli_invoked=router_cli_invoked,
135
+ platform_semantic_executed=platform_semantic_executed,
136
+ fast_context_count=fast_context_count,
137
+ cursor_fast_context_misuse=misuse,
138
+ )
139
+
140
+
141
+ def structural_routes_in_plan(route_ids: list[str]) -> bool:
142
+ return any(
143
+ "codegraph" in rid or rid in STRUCTURAL_ROUTE_IDS for rid in route_ids
144
+ )
145
+
146
+
147
+ def semantic_routes_in_plan(route_ids: list[str]) -> bool:
148
+ return any(rid in ("platform-semantic", "semantic-fast-context") for rid in route_ids)
149
+
150
+
151
+ def platform_semantic_route_order(routes: list[dict]) -> int | None:
152
+ for route in routes:
153
+ if isinstance(route, dict) and route.get("id") == "platform-semantic":
154
+ order = route.get("order")
155
+ if isinstance(order, int):
156
+ return order
157
+ return None
@@ -0,0 +1,52 @@
1
+ """REC-11: post-plan hints when platform-semantic is first-class in the router envelope."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ def platform_semantic_order_from_envelope(envelope: dict[str, Any]) -> int | None:
9
+ routes = envelope.get("routes")
10
+ if not isinstance(routes, list):
11
+ return None
12
+ for route in routes:
13
+ if not isinstance(route, dict):
14
+ continue
15
+ if route.get("id") == "platform-semantic":
16
+ order = route.get("order")
17
+ if isinstance(order, int):
18
+ return order
19
+ return None
20
+
21
+
22
+ def semantic_compliance_gate_hint(
23
+ envelope: dict[str, Any],
24
+ *,
25
+ locale: str = "zh",
26
+ ) -> str:
27
+ """
28
+ When platform-semantic is order 1 (or 2 on policy-first routes), append a
29
+ hard compliance strip for eval / hook-injected plans (REC-06 + REC-11).
30
+ """
31
+ order = platform_semantic_order_from_envelope(envelope)
32
+ if order is None or order > 2:
33
+ return ""
34
+ routes = envelope.get("routes") or []
35
+ if not isinstance(routes, list):
36
+ return ""
37
+ if not any(isinstance(r, dict) and r.get("id") == "platform-semantic" for r in routes):
38
+ return ""
39
+
40
+ if locale != "zh":
41
+ return (
42
+ "**Plan gate (REC-11):** `platform-semantic` is step "
43
+ f"#{order}. Before Top-1 you MUST run one Cursor built-in codebase "
44
+ "semantic search and log the exact tool name. Do not use fast-context MCP. "
45
+ "If semantic returns paths, corroborate with Read on candidate ranges."
46
+ )
47
+ return (
48
+ "**计划门控(REC-11):** 本问 `platform-semantic` 为第 "
49
+ f"{order} 步。定 Top-1 前 **必须** 执行 1 次 Cursor **内置代码库语义搜索**,"
50
+ "并在记录中写下宿主工具名;**禁止** fast-context MCP。"
51
+ "语义命中路径后须 **Read** 验证候选片段(verified 层)。"
52
+ )
@@ -132,7 +132,7 @@ def get_step(step_id: str) -> str:
132
132
 
133
133
 
134
134
  def _platform_matches(platform: str, block_names: list[str]) -> bool:
135
- """Case-insensitive fuzzy match: accept 'cursor', 'Cursor', 'claude-code', 'Claude Code'."""
135
+ """Case-insensitive fuzzy match: accept 'cursor' or 'Cursor'."""
136
136
  needle = platform.lower().replace("-", "").replace("_", "").replace(" ", "")
137
137
  for name in block_names:
138
138
  hay = name.lower().replace("-", "").replace("_", "").replace(" ", "")
@@ -142,29 +142,8 @@ def _platform_matches(platform: str, block_names: list[str]) -> bool:
142
142
 
143
143
 
144
144
  def resolve_effective_platform(platform: str, config: dict) -> str:
145
- """Map ``codex`` to a dispatch-mode-namespaced virtual platform name.
146
-
147
- When ``--platform codex`` is passed, return ``"codex-inline"`` (default)
148
- or ``"codex-sub-agent"`` based on ``.trellis/config.yaml`` ``codex.dispatch_mode``.
149
- ``filter_platform`` then surfaces blocks whose marker lists include the
150
- namespaced name (e.g. ``[codex-sub-agent, ...]`` or ``[codex-inline, Kilo,
151
- Antigravity, Windsurf]``).
152
-
153
- Default is ``inline`` because Codex sub-agents run with ``fork_turns="none"``
154
- isolation and can't inherit the parent session's task context — inline
155
- keeps the main agent in charge so context isn't lost. Invalid / missing
156
- values also fall back to inline.
157
-
158
- Other platforms are returned unchanged.
159
- """
160
- if platform == "codex":
161
- mode = "inline"
162
- codex_cfg = config.get("codex") if isinstance(config, dict) else None
163
- if isinstance(codex_cfg, dict):
164
- cfg_mode = codex_cfg.get("dispatch_mode")
165
- if cfg_mode in ("inline", "sub-agent"):
166
- mode = cfg_mode
167
- return f"codex-{mode}"
145
+ """Return the platform name unchanged (Cursor-only fork)."""
146
+ _ = config
168
147
  return platform
169
148
 
170
149
 
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env python3
2
+ """CLI: rank codebase path candidates for B/E/D intents (eval / dogfood)."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ from common.retrieval_result_ranking import rank_retrieval_result_candidates
12
+
13
+
14
+ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
15
+ parser = argparse.ArgumentParser(
16
+ description="Rank retrieval path candidates (caller / trap / env intents).",
17
+ )
18
+ parser.add_argument(
19
+ "--candidates",
20
+ help="Path to JSON array of candidate objects, or '-' for stdin.",
21
+ )
22
+ parser.add_argument(
23
+ "--intents",
24
+ required=True,
25
+ help="Comma-separated intent ids (e.g. caller-chain,env-config-literal).",
26
+ )
27
+ parser.add_argument("--top-k", type=int, default=5)
28
+ parser.add_argument("--expanded-pool-size", type=int, default=None)
29
+ parser.add_argument(
30
+ "--caller-pool-expansion",
31
+ action="store_true",
32
+ help="Enable caller pool expansion (caller-chain intent).",
33
+ )
34
+ parser.add_argument("--min-concrete-callers", type=int, default=3)
35
+ parser.add_argument("--json", action="store_true", help="Emit JSON (default).")
36
+ parser.add_argument("--pretty", action="store_true")
37
+ return parser.parse_args(argv)
38
+
39
+
40
+ def load_candidates(source: str | None) -> list[dict]:
41
+ if source is None or source == "-":
42
+ raw = sys.stdin.read()
43
+ else:
44
+ raw = Path(source).read_text(encoding="utf-8")
45
+ parsed = json.loads(raw)
46
+ if not isinstance(parsed, list):
47
+ raise ValueError("candidates must be a JSON array")
48
+ return [item for item in parsed if isinstance(item, dict)]
49
+
50
+
51
+ def main(argv: list[str] | None = None) -> int:
52
+ args = parse_args(argv)
53
+ try:
54
+ candidates = load_candidates(args.candidates)
55
+ except (OSError, json.JSONDecodeError, ValueError) as error:
56
+ print(f"rank_retrieval_candidates: {error}", file=sys.stderr)
57
+ return 2
58
+
59
+ intents = [part.strip() for part in args.intents.split(",") if part.strip()]
60
+ expansion = None
61
+ if args.caller_pool_expansion:
62
+ expansion = {
63
+ "enabled": True,
64
+ "minConcreteCallers": args.min_concrete_callers,
65
+ }
66
+
67
+ result = rank_retrieval_result_candidates(
68
+ candidates,
69
+ intents=intents,
70
+ top_k=args.top_k,
71
+ expanded_pool_size=args.expanded_pool_size,
72
+ caller_pool_expansion=expansion,
73
+ )
74
+ indent = 2 if args.pretty else None
75
+ print(json.dumps(result, indent=indent, ensure_ascii=False))
76
+ return 0
77
+
78
+
79
+ if __name__ == "__main__":
80
+ raise SystemExit(main())
@@ -7,12 +7,16 @@ from __future__ import annotations
7
7
 
8
8
  import argparse
9
9
  import json
10
+ import sys
10
11
  from pathlib import Path
11
12
 
12
13
  from common.codebase_retrieval_router import (
13
14
  codebase_retrieval_selected_from_capabilities,
14
15
  route_codebase_retrieval,
15
16
  )
17
+ from common.paths import get_repo_root
18
+ from common.project_file_stats import resolve_project_file_count_arg
19
+ from common.retrieval_agent_instructions import render_agent_instructions
16
20
 
17
21
 
18
22
  def load_capabilities(path: Path | None) -> dict[str, object] | None:
@@ -38,16 +42,24 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
38
42
  help="Treat codebase-retrieval as unselected (omit optional adapter routes).",
39
43
  )
40
44
  parser.add_argument(
41
- "--platform",
42
- default="generic",
43
- choices=["cursor", "claude-code", "codex", "generic"],
44
- help="Host platform for platform-adaptive routing (default: generic).",
45
+ "--project-file-count",
46
+ default="auto",
47
+ metavar="N|auto",
48
+ help=(
49
+ "File count for large-repo routing (>2000 promotes codegraph). "
50
+ "Default auto: git ls-files or walk from repo root. Example: 5000."
51
+ ),
45
52
  )
46
53
  parser.add_argument(
47
- "--project-file-count",
48
- type=int,
49
- default=None,
50
- help="Total file count in project for token economy signals (e.g. 5000).",
54
+ "--locale",
55
+ default="zh",
56
+ choices=["zh", "en"],
57
+ help="Language for agent instructions (default: zh).",
58
+ )
59
+ parser.add_argument(
60
+ "--instructions",
61
+ action="store_true",
62
+ help="Print agent-executable instructions only (no JSON).",
51
63
  )
52
64
  parser.add_argument("--json", action="store_true", help="Emit JSON to stdout (default).")
53
65
  parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON.")
@@ -56,6 +68,14 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
56
68
 
57
69
  def main(argv: list[str] | None = None) -> int:
58
70
  args = parse_args(argv)
71
+ try:
72
+ project_file_count = resolve_project_file_count_arg(
73
+ args.project_file_count,
74
+ repo_root=get_repo_root(),
75
+ )
76
+ except ValueError as error:
77
+ print(f"route_codebase_retrieval: {error}", file=sys.stderr)
78
+ return 2
59
79
  caps = load_capabilities(Path(args.capabilities) if args.capabilities else None)
60
80
  selected = (
61
81
  False
@@ -65,11 +85,18 @@ def main(argv: list[str] | None = None) -> int:
65
85
  plan = route_codebase_retrieval(
66
86
  args.query,
67
87
  codebase_retrieval_selected=selected,
68
- platform=args.platform,
69
- project_file_count=args.project_file_count,
88
+ project_file_count=project_file_count,
89
+ )
90
+ instructions = render_agent_instructions(
91
+ plan,
92
+ locale=args.locale,
70
93
  )
94
+ if args.instructions:
95
+ sys.stdout.write(instructions)
96
+ return 0
97
+ payload: dict[str, object] = {**plan, "agentInstructions": instructions}
71
98
  indent = 2 if args.pretty else None
72
- print(json.dumps(plan, indent=indent, ensure_ascii=False))
99
+ print(json.dumps(payload, indent=indent, ensure_ascii=False))
73
100
  return 0
74
101
 
75
102
 
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env python3
2
+ """REC-11: derive evidence_score (0-2) from telemetry + optional rubric row."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ _SCRIPT_DIR = Path(__file__).resolve().parent
13
+ if str(_SCRIPT_DIR) not in sys.path:
14
+ sys.path.insert(0, str(_SCRIPT_DIR))
15
+
16
+ from common.retrieval_tool_classification import classify_tool_calls # noqa: E402
17
+
18
+
19
+ def evidence_score_from_record(record: dict[str, Any]) -> int:
20
+ """
21
+ Trellis verified layer proxy for eval (R-CR-014):
22
+ 0 = no Read on candidates
23
+ 1 = Read used but no corroborated_files / weak verify
24
+ 2 = read_verification_done and (corroborated_files or read_count >= 1 with top1)
25
+ """
26
+ if not record.get("read_verification_done") and int(record.get("read_count") or 0) <= 0:
27
+ return 0
28
+ corroborated = record.get("corroborated_files") or []
29
+ if isinstance(corroborated, list) and len(corroborated) > 0:
30
+ return 2
31
+ if record.get("read_verification_done") or int(record.get("read_count") or 0) > 0:
32
+ top1 = str(record.get("top1") or record.get("top_1") or "").strip()
33
+ if top1:
34
+ return 2
35
+ return 1
36
+ return 0
37
+
38
+
39
+ def enrich_record(raw: dict[str, Any]) -> dict[str, Any]:
40
+ platform = str(raw.get("platform", "cursor"))
41
+ tools = raw.get("tools_called") or []
42
+ if not isinstance(tools, list):
43
+ tools = []
44
+ classified = classify_tool_calls([str(t) for t in tools], platform=platform)
45
+ out = dict(raw)
46
+ out["platform_semantic_executed"] = bool(
47
+ raw.get("platform_semantic_executed", classified.platform_semantic_executed)
48
+ )
49
+ out["semantic_executed"] = bool(raw.get("semantic_executed", classified.semantic_executed))
50
+ out["read_count"] = int(raw.get("read_count", classified.read_count))
51
+ if "read_verification_done" not in out:
52
+ out["read_verification_done"] = classified.read_count > 0
53
+ out["evidence_score"] = evidence_score_from_record(out)
54
+ ans = raw.get("answer_score")
55
+ if isinstance(ans, (int, float)):
56
+ out["combined_score"] = float(ans) + float(out["evidence_score"])
57
+ return out
58
+
59
+
60
+ def main(argv: list[str] | None = None) -> int:
61
+ parser = argparse.ArgumentParser(description=__doc__)
62
+ parser.add_argument("jsonl", type=Path, help="Per-query telemetry JSONL")
63
+ parser.add_argument("--pretty", action="store_true")
64
+ parser.add_argument("--markdown", action="store_true")
65
+ args = parser.parse_args(argv)
66
+
67
+ if not args.jsonl.is_file():
68
+ print(f"error: not found: {args.jsonl}", file=sys.stderr)
69
+ return 1
70
+
71
+ rows: list[dict[str, Any]] = []
72
+ for line in args.jsonl.read_text(encoding="utf-8").splitlines():
73
+ stripped = line.strip()
74
+ if not stripped:
75
+ continue
76
+ raw = json.loads(stripped)
77
+ if isinstance(raw, dict):
78
+ rows.append(enrich_record(raw))
79
+
80
+ evidence_total = sum(int(r.get("evidence_score", 0)) for r in rows)
81
+ combined: list[float] = []
82
+ for r in rows:
83
+ c = r.get("combined_score")
84
+ if isinstance(c, (int, float)):
85
+ combined.append(float(c))
86
+
87
+ summary = {
88
+ "n": len(rows),
89
+ "evidence_score_total": evidence_total,
90
+ "evidence_score_max": len(rows) * 2,
91
+ "avg_evidence_score": 0.0 if not rows else evidence_total / len(rows),
92
+ "avg_combined_score": 0.0 if not combined else sum(combined) / len(combined),
93
+ }
94
+
95
+ if args.markdown:
96
+ print("## Evidence scores (REC-11)\n")
97
+ print("| query_id | evidence_score | read_verify | semantic_exec |")
98
+ print("| --- | ---: | --- | --- |")
99
+ for r in rows:
100
+ print(
101
+ f"| {r.get('query_id','')} | {r.get('evidence_score',0)} | "
102
+ f"{r.get('read_verification_done')} | {r.get('semantic_executed')} |"
103
+ )
104
+ print(f"\nTotal evidence: **{evidence_total}** / {summary['evidence_score_max']}")
105
+ else:
106
+ payload = {"summary": summary, "records": rows}
107
+ print(json.dumps(payload, ensure_ascii=False, indent=2 if args.pretty else None))
108
+ return 0
109
+
110
+
111
+ if __name__ == "__main__":
112
+ raise SystemExit(main())