@blxzer/cursor-trellis 0.1.0 → 0.1.2

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 (285) 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/migrations/manifests/0.1.1.json +9 -0
  24. package/dist/migrations/manifests/0.1.2.json +9 -0
  25. package/dist/templates/common/bundled-skills/smart-search-cli/SKILL.md +3 -3
  26. package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +4 -2
  27. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +8 -15
  28. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +7 -7
  29. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +18 -21
  30. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +2 -2
  31. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +10 -7
  32. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +4 -4
  33. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +20 -31
  34. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +20 -31
  35. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +24 -40
  36. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +28 -59
  37. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +12 -28
  38. package/dist/templates/common/bundled-skills/trellis-skill-creator/references/trellis-skill-locations.md +2 -2
  39. package/dist/templates/cursor/hooks.json +6 -0
  40. package/dist/templates/cursor/rules/retrieval-routing.mdc +57 -0
  41. package/dist/templates/extract.d.ts +0 -14
  42. package/dist/templates/extract.d.ts.map +1 -1
  43. package/dist/templates/extract.js +0 -34
  44. package/dist/templates/extract.js.map +1 -1
  45. package/dist/templates/markdown/agents.md +2 -6
  46. package/dist/templates/markdown/index.d.ts +1 -0
  47. package/dist/templates/markdown/index.d.ts.map +1 -1
  48. package/dist/templates/markdown/index.js +1 -0
  49. package/dist/templates/markdown/index.js.map +1 -1
  50. package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +41 -0
  51. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +14 -14
  52. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +8 -20
  53. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +15 -14
  54. package/dist/templates/markdown/spec/guides/cursor-context-injection-guide.md.txt +4 -2
  55. package/dist/templates/markdown/spec/guides/cursor-semantic-compliance.md.txt +49 -0
  56. package/dist/templates/markdown/spec/guides/cursor-subagent-policy.md.txt +18 -5
  57. package/dist/templates/markdown/spec/guides/retrieval-daily-guide.md.txt +68 -20
  58. package/dist/templates/shared-hooks/index.d.ts +1 -1
  59. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  60. package/dist/templates/shared-hooks/index.js +1 -0
  61. package/dist/templates/shared-hooks/index.js.map +1 -1
  62. package/dist/templates/shared-hooks/inject-retrieval-plan.py +163 -0
  63. package/dist/templates/shared-hooks/inject-subagent-context.py +31 -567
  64. package/dist/templates/shared-hooks/research-end-retrieval-pack.py +2 -11
  65. package/dist/templates/trellis/index.d.ts +12 -0
  66. package/dist/templates/trellis/index.d.ts.map +1 -1
  67. package/dist/templates/trellis/index.js +24 -0
  68. package/dist/templates/trellis/index.js.map +1 -1
  69. package/dist/templates/trellis/scripts/aggregate_retrieval_telemetry.py +342 -0
  70. package/dist/templates/trellis/scripts/batch_plan_envelope.py +105 -0
  71. package/dist/templates/trellis/scripts/codegraph_session_smoke.py +76 -0
  72. package/dist/templates/trellis/scripts/common/active_task.py +116 -147
  73. package/dist/templates/trellis/scripts/common/cli_adapter.py +34 -710
  74. package/dist/templates/trellis/scripts/common/codebase_retrieval_router.py +49 -106
  75. package/dist/templates/trellis/scripts/common/git_context.py +17 -2
  76. package/dist/templates/trellis/scripts/common/project_file_stats.py +91 -0
  77. package/dist/templates/trellis/scripts/common/retrieval_adapter_metadata.py +9 -11
  78. package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +313 -0
  79. package/dist/templates/trellis/scripts/common/retrieval_pack.py +0 -6
  80. package/dist/templates/trellis/scripts/common/retrieval_pack_context.py +0 -4
  81. package/dist/templates/trellis/scripts/common/retrieval_plan_gate.py +76 -0
  82. package/dist/templates/trellis/scripts/common/retrieval_result_ranking.py +253 -0
  83. package/dist/templates/trellis/scripts/common/retrieval_tool_classification.py +157 -0
  84. package/dist/templates/trellis/scripts/common/semantic_plan_gate.py +52 -0
  85. package/dist/templates/trellis/scripts/common/subagent_dispatch.py +527 -0
  86. package/dist/templates/trellis/scripts/common/task_store.py +32 -0
  87. package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -24
  88. package/dist/templates/trellis/scripts/rank_retrieval_candidates.py +80 -0
  89. package/dist/templates/trellis/scripts/route_codebase_retrieval.py +38 -11
  90. package/dist/templates/trellis/scripts/score_evidence.py +112 -0
  91. package/dist/templates/trellis/scripts/task.py +26 -0
  92. package/dist/templates/trellis/workflow.md +844 -960
  93. package/dist/types/ai-tools.d.ts +13 -16
  94. package/dist/types/ai-tools.d.ts.map +1 -1
  95. package/dist/types/ai-tools.js +5 -238
  96. package/dist/types/ai-tools.js.map +1 -1
  97. package/dist/utils/codebase-retrieval-router.d.ts +1 -8
  98. package/dist/utils/codebase-retrieval-router.d.ts.map +1 -1
  99. package/dist/utils/codebase-retrieval-router.js +39 -180
  100. package/dist/utils/codebase-retrieval-router.js.map +1 -1
  101. package/dist/utils/project-capabilities.d.ts.map +1 -1
  102. package/dist/utils/project-capabilities.js +10 -24
  103. package/dist/utils/project-capabilities.js.map +1 -1
  104. package/dist/utils/retrieval-agent-instructions.d.ts +14 -0
  105. package/dist/utils/retrieval-agent-instructions.d.ts.map +1 -0
  106. package/dist/utils/retrieval-agent-instructions.js +221 -0
  107. package/dist/utils/retrieval-agent-instructions.js.map +1 -0
  108. package/dist/utils/retrieval-execution-telemetry.d.ts +43 -85
  109. package/dist/utils/retrieval-execution-telemetry.d.ts.map +1 -1
  110. package/dist/utils/retrieval-execution-telemetry.js +289 -22
  111. package/dist/utils/retrieval-execution-telemetry.js.map +1 -1
  112. package/dist/utils/retrieval-result-ranking.js +1 -1
  113. package/dist/utils/retrieval-result-ranking.js.map +1 -1
  114. package/dist/utils/retrieval-tool-classification.d.ts +32 -0
  115. package/dist/utils/retrieval-tool-classification.d.ts.map +1 -0
  116. package/dist/utils/retrieval-tool-classification.js +113 -0
  117. package/dist/utils/retrieval-tool-classification.js.map +1 -0
  118. package/dist/utils/uninstall-scrubbers.d.ts +0 -36
  119. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  120. package/dist/utils/uninstall-scrubbers.js +0 -184
  121. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  122. package/package.json +4 -2
  123. package/dist/commands/mem.d.ts +0 -30
  124. package/dist/commands/mem.d.ts.map +0 -1
  125. package/dist/commands/mem.js +0 -424
  126. package/dist/commands/mem.js.map +0 -1
  127. package/dist/configurators/antigravity.d.ts +0 -7
  128. package/dist/configurators/antigravity.d.ts.map +0 -1
  129. package/dist/configurators/antigravity.js +0 -19
  130. package/dist/configurators/antigravity.js.map +0 -1
  131. package/dist/configurators/claude.d.ts +0 -9
  132. package/dist/configurators/claude.d.ts.map +0 -1
  133. package/dist/configurators/claude.js +0 -72
  134. package/dist/configurators/claude.js.map +0 -1
  135. package/dist/configurators/codebuddy.d.ts +0 -10
  136. package/dist/configurators/codebuddy.d.ts.map +0 -1
  137. package/dist/configurators/codebuddy.js +0 -30
  138. package/dist/configurators/codebuddy.js.map +0 -1
  139. package/dist/configurators/codex.d.ts +0 -8
  140. package/dist/configurators/codex.d.ts.map +0 -1
  141. package/dist/configurators/codex.js +0 -87
  142. package/dist/configurators/codex.js.map +0 -1
  143. package/dist/configurators/copilot.d.ts +0 -10
  144. package/dist/configurators/copilot.d.ts.map +0 -1
  145. package/dist/configurators/copilot.js +0 -51
  146. package/dist/configurators/copilot.js.map +0 -1
  147. package/dist/configurators/droid.d.ts +0 -10
  148. package/dist/configurators/droid.d.ts.map +0 -1
  149. package/dist/configurators/droid.js +0 -30
  150. package/dist/configurators/droid.js.map +0 -1
  151. package/dist/configurators/gemini.d.ts +0 -16
  152. package/dist/configurators/gemini.d.ts.map +0 -1
  153. package/dist/configurators/gemini.js +0 -38
  154. package/dist/configurators/gemini.js.map +0 -1
  155. package/dist/configurators/kilo.d.ts +0 -7
  156. package/dist/configurators/kilo.d.ts.map +0 -1
  157. package/dist/configurators/kilo.js +0 -19
  158. package/dist/configurators/kilo.js.map +0 -1
  159. package/dist/configurators/kiro.d.ts +0 -8
  160. package/dist/configurators/kiro.d.ts.map +0 -1
  161. package/dist/configurators/kiro.js +0 -24
  162. package/dist/configurators/kiro.js.map +0 -1
  163. package/dist/configurators/opencode.d.ts +0 -14
  164. package/dist/configurators/opencode.d.ts.map +0 -1
  165. package/dist/configurators/opencode.js +0 -96
  166. package/dist/configurators/opencode.js.map +0 -1
  167. package/dist/configurators/pi.d.ts +0 -3
  168. package/dist/configurators/pi.d.ts.map +0 -1
  169. package/dist/configurators/pi.js +0 -45
  170. package/dist/configurators/pi.js.map +0 -1
  171. package/dist/configurators/qoder.d.ts +0 -11
  172. package/dist/configurators/qoder.d.ts.map +0 -1
  173. package/dist/configurators/qoder.js +0 -31
  174. package/dist/configurators/qoder.js.map +0 -1
  175. package/dist/configurators/windsurf.d.ts +0 -7
  176. package/dist/configurators/windsurf.d.ts.map +0 -1
  177. package/dist/configurators/windsurf.js +0 -19
  178. package/dist/configurators/windsurf.js.map +0 -1
  179. package/dist/templates/claude/agents/trellis-check.md +0 -124
  180. package/dist/templates/claude/agents/trellis-implement.md +0 -110
  181. package/dist/templates/claude/agents/trellis-research.md +0 -137
  182. package/dist/templates/claude/index.d.ts +0 -22
  183. package/dist/templates/claude/index.d.ts.map +0 -1
  184. package/dist/templates/claude/index.js +0 -46
  185. package/dist/templates/claude/index.js.map +0 -1
  186. package/dist/templates/claude/settings.json +0 -84
  187. package/dist/templates/codebuddy/agents/trellis-check.md +0 -115
  188. package/dist/templates/codebuddy/agents/trellis-implement.md +0 -110
  189. package/dist/templates/codebuddy/agents/trellis-research.md +0 -137
  190. package/dist/templates/codebuddy/index.d.ts +0 -15
  191. package/dist/templates/codebuddy/index.d.ts.map +0 -1
  192. package/dist/templates/codebuddy/index.js +0 -15
  193. package/dist/templates/codebuddy/index.js.map +0 -1
  194. package/dist/templates/codebuddy/settings.json +0 -70
  195. package/dist/templates/codex/agents/trellis-check.toml +0 -67
  196. package/dist/templates/codex/agents/trellis-implement.toml +0 -40
  197. package/dist/templates/codex/agents/trellis-research.toml +0 -73
  198. package/dist/templates/codex/config.toml +0 -28
  199. package/dist/templates/codex/hooks/session-start.py +0 -575
  200. package/dist/templates/codex/hooks.json +0 -15
  201. package/dist/templates/codex/index.d.ts +0 -39
  202. package/dist/templates/codex/index.d.ts.map +0 -1
  203. package/dist/templates/codex/index.js +0 -85
  204. package/dist/templates/codex/index.js.map +0 -1
  205. package/dist/templates/codex/skills/before-dev/SKILL.md +0 -40
  206. package/dist/templates/codex/skills/brainstorm/SKILL.md +0 -112
  207. package/dist/templates/codex/skills/break-loop/SKILL.md +0 -130
  208. package/dist/templates/codex/skills/check/SKILL.md +0 -98
  209. package/dist/templates/codex/skills/check-cross-layer/SKILL.md +0 -158
  210. package/dist/templates/codex/skills/create-command/SKILL.md +0 -101
  211. package/dist/templates/codex/skills/finish-work/SKILL.md +0 -90
  212. package/dist/templates/codex/skills/improve-ut/SKILL.md +0 -69
  213. package/dist/templates/codex/skills/integrate-skill/SKILL.md +0 -221
  214. package/dist/templates/codex/skills/onboard/SKILL.md +0 -363
  215. package/dist/templates/codex/skills/record-session/SKILL.md +0 -67
  216. package/dist/templates/codex/skills/start/SKILL.md +0 -66
  217. package/dist/templates/codex/skills/update-spec/SKILL.md +0 -335
  218. package/dist/templates/copilot/hooks/session-start.py +0 -557
  219. package/dist/templates/copilot/hooks.json +0 -19
  220. package/dist/templates/copilot/index.d.ts +0 -23
  221. package/dist/templates/copilot/index.d.ts.map +0 -1
  222. package/dist/templates/copilot/index.js +0 -54
  223. package/dist/templates/copilot/index.js.map +0 -1
  224. package/dist/templates/copilot/prompts/before-dev.prompt.md +0 -39
  225. package/dist/templates/copilot/prompts/brainstorm.prompt.md +0 -111
  226. package/dist/templates/copilot/prompts/break-loop.prompt.md +0 -129
  227. package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +0 -157
  228. package/dist/templates/copilot/prompts/check.prompt.md +0 -97
  229. package/dist/templates/copilot/prompts/create-command.prompt.md +0 -116
  230. package/dist/templates/copilot/prompts/finish-work.prompt.md +0 -99
  231. package/dist/templates/copilot/prompts/integrate-skill.prompt.md +0 -223
  232. package/dist/templates/copilot/prompts/onboard.prompt.md +0 -362
  233. package/dist/templates/copilot/prompts/parallel.prompt.md +0 -204
  234. package/dist/templates/copilot/prompts/record-session.prompt.md +0 -66
  235. package/dist/templates/copilot/prompts/start.prompt.md +0 -63
  236. package/dist/templates/copilot/prompts/update-spec.prompt.md +0 -358
  237. package/dist/templates/droid/droids/trellis-check.md +0 -107
  238. package/dist/templates/droid/droids/trellis-implement.md +0 -102
  239. package/dist/templates/droid/droids/trellis-research.md +0 -137
  240. package/dist/templates/droid/index.d.ts +0 -15
  241. package/dist/templates/droid/index.d.ts.map +0 -1
  242. package/dist/templates/droid/index.js +0 -15
  243. package/dist/templates/droid/index.js.map +0 -1
  244. package/dist/templates/droid/settings.json +0 -70
  245. package/dist/templates/gemini/agents/trellis-check.md +0 -107
  246. package/dist/templates/gemini/agents/trellis-implement.md +0 -102
  247. package/dist/templates/gemini/agents/trellis-research.md +0 -136
  248. package/dist/templates/gemini/index.d.ts +0 -13
  249. package/dist/templates/gemini/index.d.ts.map +0 -1
  250. package/dist/templates/gemini/index.js +0 -13
  251. package/dist/templates/gemini/index.js.map +0 -1
  252. package/dist/templates/gemini/settings.json +0 -28
  253. package/dist/templates/kiro/agents/trellis-check.json +0 -26
  254. package/dist/templates/kiro/agents/trellis-implement.json +0 -26
  255. package/dist/templates/kiro/agents/trellis-research.json +0 -30
  256. package/dist/templates/kiro/index.d.ts +0 -18
  257. package/dist/templates/kiro/index.d.ts.map +0 -1
  258. package/dist/templates/kiro/index.js +0 -18
  259. package/dist/templates/kiro/index.js.map +0 -1
  260. package/dist/templates/opencode/agents/trellis-check.md +0 -122
  261. package/dist/templates/opencode/agents/trellis-implement.md +0 -118
  262. package/dist/templates/opencode/agents/trellis-research.md +0 -145
  263. package/dist/templates/opencode/lib/session-utils.js +0 -667
  264. package/dist/templates/opencode/lib/trellis-context.js +0 -336
  265. package/dist/templates/opencode/package.json +0 -5
  266. package/dist/templates/opencode/plugins/inject-subagent-context.js +0 -495
  267. package/dist/templates/opencode/plugins/inject-workflow-state.js +0 -159
  268. package/dist/templates/opencode/plugins/session-start.js +0 -101
  269. package/dist/templates/pi/agents/trellis-check.md +0 -37
  270. package/dist/templates/pi/agents/trellis-implement.md +0 -42
  271. package/dist/templates/pi/agents/trellis-research.md +0 -25
  272. package/dist/templates/pi/extensions/trellis/index.ts.txt +0 -1600
  273. package/dist/templates/pi/index.d.ts +0 -5
  274. package/dist/templates/pi/index.d.ts.map +0 -1
  275. package/dist/templates/pi/index.js +0 -12
  276. package/dist/templates/pi/index.js.map +0 -1
  277. package/dist/templates/pi/settings.json +0 -12
  278. package/dist/templates/qoder/agents/trellis-check.md +0 -108
  279. package/dist/templates/qoder/agents/trellis-implement.md +0 -103
  280. package/dist/templates/qoder/agents/trellis-research.md +0 -137
  281. package/dist/templates/qoder/index.d.ts +0 -15
  282. package/dist/templates/qoder/index.d.ts.map +0 -1
  283. package/dist/templates/qoder/index.js +0 -15
  284. package/dist/templates/qoder/index.js.map +0 -1
  285. 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
- }