@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
@@ -1,667 +0,0 @@
1
- /* global process */
2
- import { existsSync, readFileSync, readdirSync, statSync } from "fs"
3
- import { join } from "path"
4
- import { execFileSync } from "child_process"
5
- import { platform } from "os"
6
- import { debugLog } from "./trellis-context.js"
7
-
8
- const PYTHON_CMD = platform() === "win32" ? "python" : "python3"
9
-
10
- const FIRST_REPLY_NOTICE = `<first-reply-notice>
11
- First visible reply: say once in Chinese that Trellis SessionStart context is loaded, then answer directly.
12
- This notice is one-shot: do not repeat it after the first assistant reply in the same session.
13
- </first-reply-notice>`
14
-
15
- function hasCuratedJsonlEntry(jsonlPath) {
16
- try {
17
- const content = readFileSync(jsonlPath, "utf-8")
18
- for (const rawLine of content.split(/\r?\n/)) {
19
- const line = rawLine.trim()
20
- if (!line) continue
21
- try {
22
- const row = JSON.parse(line)
23
- if (row && typeof row === "object" && typeof row.file === "string" && row.file) {
24
- return true
25
- }
26
- } catch {
27
- // Ignore malformed line
28
- }
29
- }
30
- } catch {
31
- return false
32
- }
33
- return false
34
- }
35
-
36
- function getTaskStatus(ctx, platformInput = null) {
37
- const active = ctx.getActiveTask(platformInput)
38
- const taskRef = active.taskPath
39
- if (!taskRef) {
40
- return (
41
- "Trellis framework: active\n" +
42
- "Selected task: none\n" +
43
- "Next-Action: Use the Task Dashboard to choose select/create/inspect/continue-without-task. " +
44
- "Do not auto-select an existing task."
45
- )
46
- }
47
-
48
- const taskDir = ctx.resolveTaskDir(taskRef)
49
-
50
- if (active.stale || !taskDir || !existsSync(taskDir)) {
51
- return (
52
- `Trellis framework: active\nSelected task: ${taskRef}\n` +
53
- "Status: STALE SELECTION\n" +
54
- "Next-Action: Task directory not found. Run: python3 ./.trellis/scripts/task.py exit"
55
- )
56
- }
57
-
58
- let taskData = {}
59
- const taskJsonPath = join(taskDir, "task.json")
60
- if (existsSync(taskJsonPath)) {
61
- try {
62
- taskData = JSON.parse(readFileSync(taskJsonPath, "utf-8"))
63
- } catch {
64
- // Ignore parse errors
65
- }
66
- }
67
-
68
- const taskTitle = taskData.title || taskRef
69
- const taskStatus = taskData.status || "unknown"
70
-
71
- if (taskStatus === "completed") {
72
- return `Status: COMPLETED\nTask: ${taskTitle}\nNext-Action: Run /trellis:finish-work. If the working tree is dirty, return to Phase 3.4 first.`
73
- }
74
-
75
- const hasPrd = existsSync(join(taskDir, "prd.md"))
76
- const hasDesign = existsSync(join(taskDir, "design.md"))
77
- const hasImplementPlan = existsSync(join(taskDir, "implement.md"))
78
- const artifactNames = ["prd.md", "design.md", "implement.md", "implement.jsonl", "check.jsonl"]
79
- const present = artifactNames.filter(name => existsSync(join(taskDir, name)))
80
- if (existsSync(join(taskDir, "research"))) present.push("research/")
81
- const presentLine = present.length > 0 ? present.join(", ") : "(none)"
82
- const implementJsonl = join(taskDir, "implement.jsonl")
83
- const checkJsonl = join(taskDir, "check.jsonl")
84
- const jsonlReady =
85
- (!existsSync(implementJsonl) || hasCuratedJsonlEntry(implementJsonl)) &&
86
- (!existsSync(checkJsonl) || hasCuratedJsonlEntry(checkJsonl))
87
-
88
- if (taskStatus === "planning" && !hasPrd) {
89
- return `Status: PLANNING\nTask: ${taskTitle}\nPresent: ${presentLine}\nNext-Action: Load trellis-brainstorm and write prd.md. Stay in planning.`
90
- }
91
-
92
- if (taskStatus === "planning") {
93
- const missingComplex = []
94
- if (!hasDesign) missingComplex.push("design.md")
95
- if (!hasImplementPlan) missingComplex.push("implement.md")
96
- const nextBits = []
97
- if (missingComplex.length > 0) {
98
- nextBits.push(
99
- `Lightweight task can request execution readiness review with PRD-only; complex task must add ${missingComplex.join(", ")} before start-execution --check`,
100
- )
101
- } else {
102
- nextBits.push("Planning artifacts are present; run `task.py start-execution <task> --check`, report PASS, then ask for explicit execution approval")
103
- }
104
- if (!jsonlReady) {
105
- nextBits.push("curate `implement.jsonl` and `check.jsonl` before sub-agent mode start")
106
- }
107
- return `Status: PLANNING\nTask: ${taskTitle}\nPresent: ${presentLine}\nNext-Action: ${nextBits.join("; ")}. Do not enter implementation until explicit execution approval is granted.`
108
- }
109
-
110
- return (
111
- `Status: ${String(taskStatus).toUpperCase()}\nTask: ${taskTitle}\n` +
112
- `Present: ${presentLine}\n` +
113
- "Next-Action: Follow the matching per-turn workflow-state. " +
114
- "Implementation/check context order is jsonl entries -> `prd.md` -> `design.md if present` -> `implement.md if present`."
115
- )
116
- }
117
-
118
- function loadTrellisConfig(directory, contextKey = null) {
119
- const scriptPath = join(directory, ".trellis", "scripts", "get_context.py")
120
- if (!existsSync(scriptPath)) {
121
- return { isMonorepo: false, packages: {}, specScope: null, activeTaskPackage: null, defaultPackage: null }
122
- }
123
- try {
124
- const output = execFileSync(PYTHON_CMD, [scriptPath, "--mode", "packages", "--json"], {
125
- cwd: directory,
126
- timeout: 5000,
127
- encoding: "utf-8",
128
- stdio: ["pipe", "pipe", "pipe"],
129
- env: {
130
- ...process.env,
131
- ...(contextKey ? { TRELLIS_CONTEXT_ID: contextKey } : {}),
132
- },
133
- })
134
- const data = JSON.parse(output)
135
- if (data.mode !== "monorepo") {
136
- return { isMonorepo: false, packages: {}, specScope: null, activeTaskPackage: null, defaultPackage: null }
137
- }
138
- const pkgDict = {}
139
- for (const pkg of (data.packages || [])) {
140
- pkgDict[pkg.name] = pkg
141
- }
142
- return {
143
- isMonorepo: true,
144
- packages: pkgDict,
145
- specScope: data.specScope || null,
146
- activeTaskPackage: data.activeTaskPackage || null,
147
- defaultPackage: data.defaultPackage || null,
148
- }
149
- } catch (e) {
150
- debugLog("session", "loadTrellisConfig error:", e.message)
151
- return { isMonorepo: false, packages: {}, specScope: null, activeTaskPackage: null, defaultPackage: null }
152
- }
153
- }
154
-
155
- function checkLegacySpec(directory, config) {
156
- if (!config.isMonorepo || Object.keys(config.packages).length === 0) {
157
- return null
158
- }
159
-
160
- const specDir = join(directory, ".trellis", "spec")
161
- if (!existsSync(specDir)) return null
162
-
163
- let hasLegacy = false
164
- for (const name of ["backend", "frontend"]) {
165
- if (existsSync(join(specDir, name, "index.md"))) {
166
- hasLegacy = true
167
- break
168
- }
169
- }
170
- if (!hasLegacy) return null
171
-
172
- const pkgNames = Object.keys(config.packages).sort()
173
- const missing = pkgNames.filter(name => !existsSync(join(specDir, name)))
174
-
175
- if (missing.length === 0) return null
176
-
177
- if (missing.length === pkgNames.length) {
178
- return (
179
- `[!] Legacy spec structure detected: found \`spec/backend/\` or \`spec/frontend/\` ` +
180
- `but no package-scoped \`spec/<package>/\` directories.\n` +
181
- `Monorepo packages: ${pkgNames.join(", ")}\n` +
182
- `Please reorganize: \`spec/backend/\` -> \`spec/<package>/backend/\``
183
- )
184
- }
185
- return (
186
- `[!] Partial spec migration detected: packages ${missing.join(", ")} ` +
187
- `still missing \`spec/<pkg>/\` directory.\n` +
188
- `Please complete migration for all packages.`
189
- )
190
- }
191
-
192
- function resolveSpecScope(config) {
193
- if (!config.isMonorepo || Object.keys(config.packages).length === 0) {
194
- return null
195
- }
196
-
197
- const { specScope, activeTaskPackage, defaultPackage, packages } = config
198
- if (specScope == null) return null
199
-
200
- if (specScope === "active_task") {
201
- if (activeTaskPackage && activeTaskPackage in packages) return new Set([activeTaskPackage])
202
- if (defaultPackage && defaultPackage in packages) return new Set([defaultPackage])
203
- return null
204
- }
205
-
206
- if (Array.isArray(specScope)) {
207
- const valid = new Set()
208
- for (const entry of specScope) {
209
- if (entry in packages) {
210
- valid.add(entry)
211
- }
212
- }
213
- if (valid.size > 0) return valid
214
- if (activeTaskPackage && activeTaskPackage in packages) return new Set([activeTaskPackage])
215
- if (defaultPackage && defaultPackage in packages) return new Set([defaultPackage])
216
- return null
217
- }
218
-
219
- return null
220
- }
221
-
222
- function collectSpecIndexPaths(directory, allowedPkgs) {
223
- const specDir = join(directory, ".trellis", "spec")
224
- const paths = []
225
-
226
- const guidesIndex = join(specDir, "guides", "index.md")
227
- if (existsSync(guidesIndex)) {
228
- paths.push(".trellis/spec/guides/index.md")
229
- }
230
-
231
- if (!existsSync(specDir)) return paths
232
-
233
- try {
234
- const subs = readdirSync(specDir).filter(name => {
235
- if (name.startsWith(".") || name === "guides") return false
236
- try {
237
- return statSync(join(specDir, name)).isDirectory()
238
- } catch {
239
- return false
240
- }
241
- }).sort()
242
-
243
- for (const sub of subs) {
244
- const indexFile = join(specDir, sub, "index.md")
245
- if (existsSync(indexFile)) {
246
- paths.push(`.trellis/spec/${sub}/index.md`)
247
- } else {
248
- if (allowedPkgs !== null && !allowedPkgs.has(sub)) continue
249
- try {
250
- const nested = readdirSync(join(specDir, sub)).filter(name => {
251
- try {
252
- return statSync(join(specDir, sub, name)).isDirectory()
253
- } catch {
254
- return false
255
- }
256
- }).sort()
257
- for (const layer of nested) {
258
- const nestedIndex = join(specDir, sub, layer, "index.md")
259
- if (existsSync(nestedIndex)) {
260
- paths.push(`.trellis/spec/${sub}/${layer}/index.md`)
261
- }
262
- }
263
- } catch {
264
- // Ignore directory read errors
265
- }
266
- }
267
- }
268
- } catch {
269
- // Ignore spec directory read errors
270
- }
271
-
272
- return paths
273
- }
274
-
275
- function readDeveloper(directory) {
276
- try {
277
- const content = readFileSync(join(directory, ".trellis", ".developer"), "utf-8")
278
- for (const line of content.split(/\r?\n/)) {
279
- if (line.startsWith("name=")) return line.slice("name=".length).trim()
280
- }
281
- } catch {
282
- // Ignore missing developer file
283
- }
284
- return "(not initialized)"
285
- }
286
-
287
- function runGit(directory, args) {
288
- try {
289
- return execFileSync("git", args, {
290
- cwd: directory,
291
- timeout: 3000,
292
- encoding: "utf-8",
293
- stdio: ["pipe", "pipe", "pipe"],
294
- }).trim()
295
- } catch {
296
- return ""
297
- }
298
- }
299
-
300
- function buildCompactCurrentState(ctx, platformInput, specIndexPaths) {
301
- const directory = ctx.directory
302
- const lines = []
303
- lines.push(`Developer: ${readDeveloper(directory)}`)
304
-
305
- const branch = runGit(directory, ["branch", "--show-current"]) || "(detached)"
306
- const dirtyCount = runGit(directory, ["status", "--porcelain"])
307
- .split(/\r?\n/)
308
- .filter(line => line.trim()).length
309
- lines.push(`Git: branch ${branch}; ${dirtyCount === 0 ? "clean" : `dirty ${dirtyCount} paths`}.`)
310
-
311
- const active = ctx.getActiveTask(platformInput)
312
- lines.push("Trellis framework: active")
313
- if (active.taskPath) {
314
- const taskDir = ctx.resolveTaskDir(active.taskPath)
315
- let status = "unknown"
316
- if (taskDir) {
317
- try {
318
- const data = JSON.parse(readFileSync(join(taskDir, "task.json"), "utf-8"))
319
- status = data.status || "unknown"
320
- } catch {
321
- // Ignore parse errors
322
- }
323
- }
324
- lines.push(`Selected task: ${active.taskPath}; status=${status}.`)
325
- } else {
326
- lines.push("Selected task: none.")
327
- }
328
-
329
- const tasksDir = join(directory, ".trellis", "tasks")
330
- if (existsSync(tasksDir)) {
331
- try {
332
- const activeTasks = readdirSync(tasksDir, { withFileTypes: true })
333
- .filter(entry => entry.isDirectory() && entry.name !== "archive" && existsSync(join(tasksDir, entry.name, "task.json")))
334
- lines.push(`Active tasks: ${activeTasks.length} total. Use the Task Dashboard for routing; use \`python3 ./.trellis/scripts/task.py list --mine\` only for raw inspection.`)
335
- } catch {
336
- // Ignore task list errors
337
- }
338
- }
339
-
340
- const developer = readDeveloper(directory)
341
- const workspaceDir = join(directory, ".trellis", "workspace", developer)
342
- if (developer !== "(not initialized)" && existsSync(workspaceDir)) {
343
- try {
344
- const journals = readdirSync(workspaceDir)
345
- .filter(name => /^journal-\d+\.md$/.test(name))
346
- .sort((a, b) => Number(a.match(/\d+/)?.[0] || 0) - Number(b.match(/\d+/)?.[0] || 0))
347
- const journal = journals[journals.length - 1]
348
- if (journal) {
349
- const journalPath = join(workspaceDir, journal)
350
- const lineCount = readFileSync(journalPath, "utf-8").split(/\r?\n/).length
351
- lines.push(`Journal: .trellis/workspace/${developer}/${journal}, ${lineCount} / 2000 lines.`)
352
- }
353
- } catch {
354
- // Ignore journal errors
355
- }
356
- }
357
-
358
- if (specIndexPaths.length > 0) {
359
- lines.push(`Spec indexes: ${specIndexPaths.length} available.`)
360
- }
361
-
362
- return lines.join("\n")
363
- }
364
-
365
- function readTaskData(taskDir) {
366
- try {
367
- return JSON.parse(readFileSync(join(taskDir, "task.json"), "utf-8"))
368
- } catch {
369
- return null
370
- }
371
- }
372
-
373
- function readActiveTasks(directory) {
374
- const tasksDir = join(directory, ".trellis", "tasks")
375
- const tasks = new Map()
376
- if (!existsSync(tasksDir)) return tasks
377
-
378
- try {
379
- const entries = readdirSync(tasksDir, { withFileTypes: true })
380
- .filter(entry => entry.isDirectory() && entry.name !== "archive")
381
- .sort((a, b) => a.name.localeCompare(b.name))
382
- for (const entry of entries) {
383
- const taskDir = join(tasksDir, entry.name)
384
- const data = readTaskData(taskDir)
385
- if (!data || typeof data !== "object") continue
386
- tasks.set(entry.name, {
387
- dirName: entry.name,
388
- status: data.status || "unknown",
389
- assignee: data.assignee || "-",
390
- parent: data.parent || null,
391
- children: Array.isArray(data.children) ? data.children : [],
392
- })
393
- }
394
- } catch {
395
- // Ignore task directory read errors
396
- }
397
- return tasks
398
- }
399
-
400
- function childrenProgress(children, statuses) {
401
- if (!Array.isArray(children) || children.length === 0) return ""
402
- const done = children.filter(
403
- child => !statuses.has(child) || ["completed", "done"].includes(statuses.get(child)),
404
- ).length
405
- return ` [${done}/${children.length} done]`
406
- }
407
-
408
- function appendDashboardTask(lines, name, tasks, statuses, printed, indent = 0) {
409
- const task = tasks.get(name)
410
- if (!task) return
411
- printed.add(name)
412
- const prefix = " ".repeat(indent) + " - "
413
- const progress = childrenProgress(task.children, statuses)
414
- lines.push(`${prefix}.trellis/tasks/${name} (${task.status})${progress} [${task.assignee || "-"}]`)
415
- for (const childName of task.children) {
416
- if (tasks.has(childName)) {
417
- appendDashboardTask(lines, childName, tasks, statuses, printed, indent + 1)
418
- }
419
- }
420
- }
421
-
422
- function buildFallbackTaskDashboard(ctx, platformInput) {
423
- const active = ctx.getActiveTask(platformInput)
424
- const lines = [
425
- "Task Dashboard",
426
- "Trellis framework: active",
427
- active.taskPath
428
- ? `Selected task: ${active.taskPath}${active.source ? ` (${active.source})` : ""}`
429
- : "Selected task: none",
430
- "",
431
- ]
432
-
433
- const tasks = readActiveTasks(ctx.directory)
434
- const statuses = new Map([...tasks.entries()].map(([name, task]) => [name, task.status]))
435
- if (tasks.size === 0) {
436
- lines.push("Tasks: none")
437
- } else {
438
- const printed = new Set()
439
- for (const status of ["planning", "in_progress", "review", "blocked"]) {
440
- const names = [...tasks.keys()]
441
- .filter(name => tasks.get(name)?.status === status && !tasks.get(name)?.parent)
442
- .sort()
443
- if (names.length === 0) continue
444
- lines.push(`${status.replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase())}:`)
445
- for (const name of names) {
446
- appendDashboardTask(lines, name, tasks, statuses, printed)
447
- }
448
- lines.push("")
449
- }
450
-
451
- const otherNames = [...tasks.keys()]
452
- .filter(name => !printed.has(name) && !tasks.get(name)?.parent)
453
- .sort()
454
- if (otherNames.length > 0) {
455
- lines.push("Other:")
456
- for (const name of otherNames) {
457
- appendDashboardTask(lines, name, tasks, statuses, printed)
458
- }
459
- lines.push("")
460
- }
461
- }
462
-
463
- lines.push("Suggested actions:")
464
- lines.push(" - Select a task: python3 ./.trellis/scripts/task.py select <task>")
465
- lines.push(" - Create a task: python3 ./.trellis/scripts/task.py create \"<title>\" --slug <slug>")
466
- lines.push(" - Inspect raw list: python3 ./.trellis/scripts/task.py list")
467
- lines.push(" - Continue without a task only for No Task or Micro-Grill work")
468
-
469
- const developer = readDeveloper(ctx.directory)
470
- if (developer !== "(not initialized)") {
471
- lines.push(`Developer: ${developer}`)
472
- }
473
-
474
- return lines.map(line => line.trimEnd()).join("\n").trimEnd()
475
- }
476
-
477
- function buildPythonTaskDashboard(directory, contextKey) {
478
- const scriptPath = join(directory, ".trellis", "scripts", "task.py")
479
- if (!existsSync(scriptPath)) return ""
480
-
481
- try {
482
- return execFileSync(PYTHON_CMD, [scriptPath, "dashboard"], {
483
- cwd: directory,
484
- timeout: 5000,
485
- encoding: "utf-8",
486
- stdio: ["pipe", "pipe", "pipe"],
487
- env: {
488
- ...process.env,
489
- ...(contextKey ? { TRELLIS_CONTEXT_ID: contextKey } : {}),
490
- },
491
- }).trim()
492
- } catch {
493
- return ""
494
- }
495
- }
496
-
497
- function buildTaskDashboard(ctx, platformInput, contextKey) {
498
- return buildPythonTaskDashboard(ctx.directory, contextKey) ||
499
- buildFallbackTaskDashboard(ctx, platformInput)
500
- }
501
-
502
- export function buildSessionContext(ctx, platformInput = null) {
503
- const directory = ctx.directory
504
- const contextKey = typeof ctx.getContextKey === "function"
505
- ? ctx.getContextKey(platformInput)
506
- : null
507
-
508
- const config = loadTrellisConfig(directory, contextKey)
509
- const allowedPkgs = resolveSpecScope(config)
510
- const paths = collectSpecIndexPaths(directory, allowedPkgs)
511
-
512
- const parts = []
513
-
514
- parts.push(`<session-context>
515
- Trellis compact SessionStart context. Use it to orient the session; load details on demand.
516
- </session-context>`)
517
- parts.push(FIRST_REPLY_NOTICE)
518
-
519
- const legacyWarning = checkLegacySpec(directory, config)
520
- if (legacyWarning) {
521
- parts.push(`<migration-warning>\n${legacyWarning}\n</migration-warning>`)
522
- }
523
-
524
- parts.push("<current-state>")
525
- parts.push(buildCompactCurrentState(ctx, platformInput, paths))
526
- parts.push("</current-state>")
527
-
528
- parts.push("<task-dashboard>")
529
- parts.push(buildTaskDashboard(ctx, platformInput, contextKey))
530
- parts.push("</task-dashboard>")
531
-
532
- const workflowContent = ctx.readProjectFile(".trellis/workflow.md")
533
- if (workflowContent) {
534
- const allLines = workflowContent.split("\n")
535
- const overviewLines = [
536
- "# Development Workflow - Session Summary",
537
- "Full guide: .trellis/workflow.md. Step detail: `python3 ./.trellis/scripts/get_context.py --mode phase --step <X.Y>`.",
538
- "",
539
- ]
540
-
541
- let rangeStart = -1
542
- let rangeEnd = allLines.length
543
- for (let i = 0; i < allLines.length; i++) {
544
- const stripped = allLines[i].trim()
545
- if (rangeStart === -1 && stripped === "## Phase Index") {
546
- rangeStart = i
547
- } else if (rangeStart !== -1 && stripped === "## Phase 1: Plan") {
548
- rangeEnd = i
549
- break
550
- }
551
- }
552
- if (rangeStart !== -1) {
553
- const strippedStateBlocks = allLines
554
- .slice(rangeStart, rangeEnd)
555
- .join("\n")
556
- .replace(/\[workflow-state:([A-Za-z0-9_-]+)\]\s*\n[\s\S]*?\n\s*\[\/workflow-state:\1\]\n?/g, "")
557
- .replace(/<!--[\s\S]*?-->/g, "")
558
- .replace(/^\[(?!\/?workflow-state:)\/?[^\]\n]+\]\s*\n?/gm, "")
559
- .replace(/\n{3,}/g, "\n\n")
560
- overviewLines.push(strippedStateBlocks.trimEnd())
561
- }
562
-
563
- parts.push("<trellis-workflow>")
564
- parts.push(overviewLines.join("\n").trimEnd())
565
- parts.push("</trellis-workflow>")
566
- }
567
-
568
- parts.push("<guidelines>")
569
- parts.push(
570
- "Task context order for implementation/check: jsonl entries -> `prd.md` -> " +
571
- "`design.md if present` -> `implement.md if present`. Missing optional artifacts " +
572
- "are skipped for lightweight tasks.\n"
573
- )
574
-
575
- if (paths.length > 0) {
576
- parts.push("## Available indexes (read on demand)")
577
- for (const p of paths) {
578
- parts.push(`- ${p}`)
579
- }
580
- parts.push("")
581
- }
582
-
583
- parts.push(
584
- "Discover more via: " +
585
- "`python3 ./.trellis/scripts/get_context.py --mode packages`"
586
- )
587
- parts.push("</guidelines>")
588
-
589
- const taskStatus = getTaskStatus(ctx, platformInput)
590
- parts.push(`<task-status>\n${taskStatus}\n</task-status>`)
591
-
592
- parts.push(`<ready>
593
- Context loaded. Follow <task-status>. Load workflow/spec/task details only when needed.
594
- </ready>`)
595
-
596
- return parts.join("\n\n")
597
- }
598
-
599
- function getTrellisMetadata(metadata) {
600
- if (!metadata || typeof metadata !== "object") {
601
- return {}
602
- }
603
-
604
- const trellis = metadata.trellis
605
- if (!trellis || typeof trellis !== "object") {
606
- return {}
607
- }
608
-
609
- return trellis
610
- }
611
-
612
- function markPartAsSessionStart(part) {
613
- const metadata = part.metadata && typeof part.metadata === "object"
614
- ? part.metadata
615
- : {}
616
- part.metadata = {
617
- ...metadata,
618
- trellis: {
619
- ...getTrellisMetadata(metadata),
620
- sessionStart: true,
621
- },
622
- }
623
- }
624
-
625
- function hasSessionStartMarker(part) {
626
- if (!part || part.type !== "text" || typeof part.text !== "string") {
627
- return false
628
- }
629
-
630
- return getTrellisMetadata(part.metadata).sessionStart === true
631
- }
632
-
633
- export function hasInjectedTrellisContext(messages) {
634
- if (!Array.isArray(messages)) {
635
- return false
636
- }
637
-
638
- return messages.some(message => {
639
- if (!message?.info || message.info.role !== "user" || !Array.isArray(message.parts)) {
640
- return false
641
- }
642
-
643
- return message.parts.some(hasSessionStartMarker)
644
- })
645
- }
646
-
647
- export async function hasPersistedInjectedContext(client, directory, sessionID) {
648
- try {
649
- const response = await client.session.messages({
650
- path: { id: sessionID },
651
- query: { directory },
652
- throwOnError: true,
653
- })
654
- return hasInjectedTrellisContext(response.data || [])
655
- } catch (error) {
656
- debugLog(
657
- "session",
658
- "Failed to read session history for dedupe:",
659
- error instanceof Error ? error.message : String(error),
660
- )
661
- return false
662
- }
663
- }
664
-
665
- export function markContextInjected(part) {
666
- markPartAsSessionStart(part)
667
- }