@blxzer/cursor-trellis 0.4.1 → 0.4.3

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 (337) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +25 -14
  3. package/README.zh-CN.md +14 -10
  4. package/bin/smart-search.js +10 -2
  5. package/dist/cli/index.d.ts.map +1 -1
  6. package/dist/cli/index.js +36 -15
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/commands/init.d.ts +1 -1
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +42 -153
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/commands/migrate.d.ts +10 -0
  13. package/dist/commands/migrate.d.ts.map +1 -0
  14. package/dist/commands/migrate.js +38 -0
  15. package/dist/commands/migrate.js.map +1 -0
  16. package/dist/commands/update.d.ts +5 -0
  17. package/dist/commands/update.d.ts.map +1 -1
  18. package/dist/commands/update.js +144 -41
  19. package/dist/commands/update.js.map +1 -1
  20. package/dist/configurators/cursor.d.ts +2 -1
  21. package/dist/configurators/cursor.d.ts.map +1 -1
  22. package/dist/configurators/cursor.js +4 -2
  23. package/dist/configurators/cursor.js.map +1 -1
  24. package/dist/configurators/index.js +4 -4
  25. package/dist/configurators/index.js.map +1 -1
  26. package/dist/configurators/shared.d.ts +8 -0
  27. package/dist/configurators/shared.d.ts.map +1 -1
  28. package/dist/configurators/shared.js +27 -1
  29. package/dist/configurators/shared.js.map +1 -1
  30. package/dist/configurators/workflow.d.ts +0 -9
  31. package/dist/configurators/workflow.d.ts.map +1 -1
  32. package/dist/configurators/workflow.js +12 -45
  33. package/dist/configurators/workflow.js.map +1 -1
  34. package/dist/constants/paths.d.ts +13 -0
  35. package/dist/constants/paths.d.ts.map +1 -1
  36. package/dist/constants/paths.js +17 -0
  37. package/dist/constants/paths.js.map +1 -1
  38. package/dist/migrations/manifests/0.3.0.json +1 -1
  39. package/dist/templates/common/bundled-skills/cstl-check/SKILL.md +1 -1
  40. package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/hooks-and-settings.md +2 -2
  41. package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/overview.md +1 -1
  42. package/dist/templates/common/bundled-skills/cstl-meta/references/platform-files/skills-and-commands.md +2 -4
  43. package/dist/templates/common/bundled-skills/cstl-skill-creator/SKILL.md +10 -7
  44. package/dist/templates/common/bundled-skills/cstl-skill-creator/references/authoring-rules.md +93 -19
  45. package/dist/templates/common/bundled-skills/cstl-skill-creator/references/general-authoring.md +189 -0
  46. package/dist/templates/common/bundled-skills/cstl-skill-creator/references/review-checklist.md +10 -5
  47. package/dist/templates/common/commands/continue.md +6 -5
  48. package/dist/templates/common/index.d.ts +20 -0
  49. package/dist/templates/common/index.d.ts.map +1 -1
  50. package/dist/templates/common/index.js +21 -2
  51. package/dist/templates/common/index.js.map +1 -1
  52. package/dist/templates/common/optional-skills/chrome-cdp/SKILL.md +179 -0
  53. package/dist/templates/common/optional-skills/chrome-cdp/examples/fetch-hook-api-capture.md +149 -0
  54. package/dist/templates/common/optional-skills/chrome-cdp/scripts/cdp.mjs +903 -0
  55. package/dist/templates/common/skills/brainstorm.md +2 -2
  56. package/dist/templates/cursor/agents/cstl-check.md +2 -2
  57. package/dist/templates/cursor/agents/cstl-implement.md +1 -1
  58. package/dist/templates/cursor/agents/cstl-research.md +2 -2
  59. package/dist/templates/cursor/fixtures/expected-rules.d.ts +1 -1
  60. package/dist/templates/cursor/fixtures/expected-rules.d.ts.map +1 -1
  61. package/dist/templates/cursor/fixtures/expected-rules.js +7 -24
  62. package/dist/templates/cursor/fixtures/expected-rules.js.map +1 -1
  63. package/dist/templates/cursor/hooks.json +4 -0
  64. package/dist/templates/cursor/index.d.ts +1 -1
  65. package/dist/templates/cursor/index.js +1 -1
  66. package/dist/templates/cursor/rules/cstl-bootstrap.mdc +17 -0
  67. package/dist/templates/markdown/agents.md +36 -3
  68. package/dist/templates/markdown/{spec/guides → framework}/cursor-native-modes-guide.md.txt +13 -10
  69. package/dist/templates/markdown/{spec/guides → framework}/cursor-subagent-policy.md.txt +63 -127
  70. package/dist/templates/markdown/framework/dogfood-only-surfaces.md.txt +29 -0
  71. package/dist/templates/markdown/{spec/guides → framework}/execution-strategy.md.txt +2 -0
  72. package/dist/templates/markdown/framework/index.md.txt +31 -0
  73. package/dist/templates/markdown/framework/internal-skills-cursor-reachability.md.txt +45 -0
  74. package/dist/templates/markdown/framework/middleware-protocol.md.txt +83 -0
  75. package/dist/templates/markdown/framework/parallel-first-execution.md.txt +78 -0
  76. package/dist/templates/markdown/framework/prd-grill-frontier.md.txt +83 -0
  77. package/dist/templates/markdown/framework/release-boundary.md.txt +30 -0
  78. package/dist/templates/markdown/{spec/guides → framework}/retrieval-daily-guide.md.txt +1 -1
  79. package/dist/templates/markdown/framework/upgrade.md.txt +15 -0
  80. package/dist/templates/markdown/{spec/guides → framework}/verification-strength-guide.md.txt +2 -2
  81. package/dist/templates/markdown/index.d.ts +26 -10
  82. package/dist/templates/markdown/index.d.ts.map +1 -1
  83. package/dist/templates/markdown/index.js +87 -11
  84. package/dist/templates/markdown/index.js.map +1 -1
  85. package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +1 -1
  86. package/dist/templates/markdown/spec/guides/index.md.txt +5 -19
  87. package/dist/templates/markdown/spec/guides/prototype-guide.md.txt +10 -10
  88. package/dist/templates/markdown/spec/guides/test-discipline-guide.md.txt +1 -1
  89. package/dist/templates/shared-hooks/event-bridge.py +60 -0
  90. package/dist/templates/shared-hooks/index.d.ts +1 -1
  91. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  92. package/dist/templates/shared-hooks/index.js +1 -0
  93. package/dist/templates/shared-hooks/index.js.map +1 -1
  94. package/dist/templates/shared-hooks/session-start.py +19 -2
  95. package/dist/templates/trellis/CONTEXT.md +63 -3
  96. package/dist/templates/trellis/config.yaml +1 -1
  97. package/dist/templates/trellis/gitignore.txt +39 -39
  98. package/dist/templates/trellis/index.d.ts +12 -0
  99. package/dist/templates/trellis/index.d.ts.map +1 -1
  100. package/dist/templates/trellis/index.js +73 -15
  101. package/dist/templates/trellis/index.js.map +1 -1
  102. package/dist/templates/trellis/pool/README.md +12 -3
  103. package/dist/templates/trellis/pool/plan.md +24 -5
  104. package/dist/templates/trellis/scripts/common/adapter_middleware.py +158 -0
  105. package/dist/templates/trellis/scripts/common/artifact_locale.py +12 -3
  106. package/dist/templates/trellis/scripts/common/cursor_retrieval_env.py +5 -2
  107. package/dist/templates/trellis/scripts/common/full_quality.py +237 -0
  108. package/dist/templates/trellis/scripts/common/git.py +6 -0
  109. package/dist/templates/trellis/scripts/common/git_context.py +17 -5
  110. package/dist/templates/trellis/scripts/common/kernel_command.py +367 -0
  111. package/dist/templates/trellis/scripts/common/lite_context.py +280 -0
  112. package/dist/templates/trellis/scripts/common/ondemand_topology.py +225 -0
  113. package/dist/templates/trellis/scripts/common/parent_orchestration.py +1 -1
  114. package/dist/templates/trellis/scripts/common/pool_store.py +16 -4
  115. package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +2 -2
  116. package/dist/templates/trellis/scripts/common/session_context.py +28 -2
  117. package/dist/templates/trellis/scripts/common/task_gates.py +73 -12
  118. package/dist/templates/trellis/scripts/common/task_map.py +42 -9
  119. package/dist/templates/trellis/scripts/common/task_store.py +293 -61
  120. package/dist/templates/trellis/scripts/common/test_adapter_middleware.py +56 -0
  121. package/dist/templates/trellis/scripts/common/test_depends_mode_block.py +9 -0
  122. package/dist/templates/trellis/scripts/common/test_full_quality.py +197 -0
  123. package/dist/templates/trellis/scripts/common/test_kernel_command.py +326 -0
  124. package/dist/templates/trellis/scripts/common/test_lite_path.py +190 -0
  125. package/dist/templates/trellis/scripts/common/test_observable_defaults.py +10 -4
  126. package/dist/templates/trellis/scripts/common/test_ondemand_topology.py +122 -0
  127. package/dist/templates/trellis/scripts/common/test_pool_store.py +17 -0
  128. package/dist/templates/trellis/scripts/common/test_task_store_kernel_patch.py +163 -0
  129. package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -0
  130. package/dist/templates/trellis/scripts/cursor_retrieval_probe_prompt.md +4 -5
  131. package/dist/templates/trellis/scripts/get_context.py +1 -0
  132. package/dist/templates/trellis/scripts/pool.py +5 -0
  133. package/dist/templates/trellis/scripts/task.py +83 -7
  134. package/dist/templates/trellis/workflow.md +109 -23
  135. package/dist/utils/cursor-retrieval-env.d.ts +2 -1
  136. package/dist/utils/cursor-retrieval-env.d.ts.map +1 -1
  137. package/dist/utils/cursor-retrieval-env.js +3 -2
  138. package/dist/utils/cursor-retrieval-env.js.map +1 -1
  139. package/dist/utils/cursor2plus-residue-cleanup.d.ts +38 -0
  140. package/dist/utils/cursor2plus-residue-cleanup.d.ts.map +1 -0
  141. package/dist/utils/cursor2plus-residue-cleanup.js +145 -0
  142. package/dist/utils/cursor2plus-residue-cleanup.js.map +1 -0
  143. package/dist/utils/manifest-prune.d.ts.map +1 -1
  144. package/dist/utils/manifest-prune.js +7 -2
  145. package/dist/utils/manifest-prune.js.map +1 -1
  146. package/dist/utils/p36-upgrade.d.ts +62 -0
  147. package/dist/utils/p36-upgrade.d.ts.map +1 -0
  148. package/dist/utils/p36-upgrade.js +160 -0
  149. package/dist/utils/p36-upgrade.js.map +1 -0
  150. package/dist/utils/project-capabilities.d.ts +1 -12
  151. package/dist/utils/project-capabilities.d.ts.map +1 -1
  152. package/dist/utils/project-capabilities.js +3 -100
  153. package/dist/utils/project-capabilities.js.map +1 -1
  154. package/dist/utils/readiness.d.ts +10 -0
  155. package/dist/utils/readiness.d.ts.map +1 -1
  156. package/dist/utils/readiness.js +58 -26
  157. package/dist/utils/readiness.js.map +1 -1
  158. package/dist/utils/retrieval-agent-instructions.js +1 -1
  159. package/dist/utils/retrieval-agent-instructions.js.map +1 -1
  160. package/dist/utils/retrieval-execution-telemetry.js +1 -1
  161. package/dist/utils/retrieval-execution-telemetry.js.map +1 -1
  162. package/dist/utils/template-hash.d.ts.map +1 -1
  163. package/dist/utils/template-hash.js +11 -1
  164. package/dist/utils/template-hash.js.map +1 -1
  165. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  166. package/dist/utils/uninstall-scrubbers.js +52 -14
  167. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  168. package/dist/utils/update-rollout-report.d.ts +14 -0
  169. package/dist/utils/update-rollout-report.d.ts.map +1 -1
  170. package/dist/utils/update-rollout-report.js +1 -0
  171. package/dist/utils/update-rollout-report.js.map +1 -1
  172. package/dist/utils/workflow-ownership.d.ts +1 -1
  173. package/dist/utils/workflow-ownership.js +4 -4
  174. package/dist/utils/workflow-ownership.js.map +1 -1
  175. package/package.json +5 -4
  176. package/scripts/postinstall.js +6 -7
  177. package/dist/commands/campaign/canvas-render.d.ts +0 -68
  178. package/dist/commands/campaign/canvas-render.d.ts.map +0 -1
  179. package/dist/commands/campaign/canvas-render.js +0 -414
  180. package/dist/commands/campaign/canvas-render.js.map +0 -1
  181. package/dist/commands/campaign/compose.d.ts +0 -15
  182. package/dist/commands/campaign/compose.d.ts.map +0 -1
  183. package/dist/commands/campaign/compose.js +0 -110
  184. package/dist/commands/campaign/compose.js.map +0 -1
  185. package/dist/commands/campaign/index.d.ts +0 -13
  186. package/dist/commands/campaign/index.d.ts.map +0 -1
  187. package/dist/commands/campaign/index.js +0 -134
  188. package/dist/commands/campaign/index.js.map +0 -1
  189. package/dist/commands/campaign/kind-map.d.ts +0 -6
  190. package/dist/commands/campaign/kind-map.d.ts.map +0 -1
  191. package/dist/commands/campaign/kind-map.js +0 -21
  192. package/dist/commands/campaign/kind-map.js.map +0 -1
  193. package/dist/commands/campaign/mcp-server.d.ts +0 -6
  194. package/dist/commands/campaign/mcp-server.d.ts.map +0 -1
  195. package/dist/commands/campaign/mcp-server.js +0 -167
  196. package/dist/commands/campaign/mcp-server.js.map +0 -1
  197. package/dist/commands/campaign/render.d.ts +0 -5
  198. package/dist/commands/campaign/render.d.ts.map +0 -1
  199. package/dist/commands/campaign/render.js +0 -103
  200. package/dist/commands/campaign/render.js.map +0 -1
  201. package/dist/commands/campaign/trellis-load.d.ts +0 -13
  202. package/dist/commands/campaign/trellis-load.d.ts.map +0 -1
  203. package/dist/commands/campaign/trellis-load.js +0 -122
  204. package/dist/commands/campaign/trellis-load.js.map +0 -1
  205. package/dist/commands/campaign/types.d.ts +0 -61
  206. package/dist/commands/campaign/types.d.ts.map +0 -1
  207. package/dist/commands/campaign/types.js +0 -3
  208. package/dist/commands/campaign/types.js.map +0 -1
  209. package/dist/commands/goal/index.d.ts +0 -3
  210. package/dist/commands/goal/index.d.ts.map +0 -1
  211. package/dist/commands/goal/index.js +0 -159
  212. package/dist/commands/goal/index.js.map +0 -1
  213. package/dist/commands/goal/review.d.ts +0 -6
  214. package/dist/commands/goal/review.d.ts.map +0 -1
  215. package/dist/commands/goal/review.js +0 -28
  216. package/dist/commands/goal/review.js.map +0 -1
  217. package/dist/commands/rpc/client.d.ts +0 -51
  218. package/dist/commands/rpc/client.d.ts.map +0 -1
  219. package/dist/commands/rpc/client.js +0 -147
  220. package/dist/commands/rpc/client.js.map +0 -1
  221. package/dist/commands/rpc/index.d.ts +0 -10
  222. package/dist/commands/rpc/index.d.ts.map +0 -1
  223. package/dist/commands/rpc/index.js +0 -157
  224. package/dist/commands/rpc/index.js.map +0 -1
  225. package/dist/commands/rpc/serve.d.ts +0 -23
  226. package/dist/commands/rpc/serve.d.ts.map +0 -1
  227. package/dist/commands/rpc/serve.js +0 -60
  228. package/dist/commands/rpc/serve.js.map +0 -1
  229. package/dist/commands/rpc/smoke.d.ts +0 -16
  230. package/dist/commands/rpc/smoke.d.ts.map +0 -1
  231. package/dist/commands/rpc/smoke.js +0 -92
  232. package/dist/commands/rpc/smoke.js.map +0 -1
  233. package/dist/commands/sdk/index.d.ts +0 -9
  234. package/dist/commands/sdk/index.d.ts.map +0 -1
  235. package/dist/commands/sdk/index.js +0 -58
  236. package/dist/commands/sdk/index.js.map +0 -1
  237. package/dist/commands/sdk/run.d.ts +0 -42
  238. package/dist/commands/sdk/run.d.ts.map +0 -1
  239. package/dist/commands/sdk/run.js +0 -220
  240. package/dist/commands/sdk/run.js.map +0 -1
  241. package/dist/commands/sdk/status.d.ts +0 -14
  242. package/dist/commands/sdk/status.d.ts.map +0 -1
  243. package/dist/commands/sdk/status.js +0 -69
  244. package/dist/commands/sdk/status.js.map +0 -1
  245. package/dist/configurators/cursor2plus-local.d.ts +0 -6
  246. package/dist/configurators/cursor2plus-local.d.ts.map +0 -1
  247. package/dist/configurators/cursor2plus-local.js +0 -21
  248. package/dist/configurators/cursor2plus-local.js.map +0 -1
  249. package/dist/goal/action-packet.d.ts +0 -89
  250. package/dist/goal/action-packet.d.ts.map +0 -1
  251. package/dist/goal/action-packet.js +0 -113
  252. package/dist/goal/action-packet.js.map +0 -1
  253. package/dist/goal/audit.d.ts +0 -14
  254. package/dist/goal/audit.d.ts.map +0 -1
  255. package/dist/goal/audit.js +0 -12
  256. package/dist/goal/audit.js.map +0 -1
  257. package/dist/goal/constants.d.ts +0 -26
  258. package/dist/goal/constants.d.ts.map +0 -1
  259. package/dist/goal/constants.js +0 -24
  260. package/dist/goal/constants.js.map +0 -1
  261. package/dist/goal/paths.d.ts +0 -8
  262. package/dist/goal/paths.d.ts.map +0 -1
  263. package/dist/goal/paths.js +0 -36
  264. package/dist/goal/paths.js.map +0 -1
  265. package/dist/goal/preflight.d.ts +0 -21
  266. package/dist/goal/preflight.d.ts.map +0 -1
  267. package/dist/goal/preflight.js +0 -97
  268. package/dist/goal/preflight.js.map +0 -1
  269. package/dist/goal/review-seam.d.ts +0 -44
  270. package/dist/goal/review-seam.d.ts.map +0 -1
  271. package/dist/goal/review-seam.js +0 -153
  272. package/dist/goal/review-seam.js.map +0 -1
  273. package/dist/goal/reviewer-rules.d.ts +0 -13
  274. package/dist/goal/reviewer-rules.d.ts.map +0 -1
  275. package/dist/goal/reviewer-rules.js +0 -153
  276. package/dist/goal/reviewer-rules.js.map +0 -1
  277. package/dist/goal/reviewer.d.ts +0 -9
  278. package/dist/goal/reviewer.d.ts.map +0 -1
  279. package/dist/goal/reviewer.js +0 -54
  280. package/dist/goal/reviewer.js.map +0 -1
  281. package/dist/goal/runtime.d.ts +0 -32
  282. package/dist/goal/runtime.d.ts.map +0 -1
  283. package/dist/goal/runtime.js +0 -242
  284. package/dist/goal/runtime.js.map +0 -1
  285. package/dist/goal/sdk-client.d.ts +0 -10
  286. package/dist/goal/sdk-client.d.ts.map +0 -1
  287. package/dist/goal/sdk-client.js +0 -34
  288. package/dist/goal/sdk-client.js.map +0 -1
  289. package/dist/goal/state.d.ts +0 -40
  290. package/dist/goal/state.d.ts.map +0 -1
  291. package/dist/goal/state.js +0 -37
  292. package/dist/goal/state.js.map +0 -1
  293. package/dist/goal/task-triggers.d.ts +0 -15
  294. package/dist/goal/task-triggers.d.ts.map +0 -1
  295. package/dist/goal/task-triggers.js +0 -23
  296. package/dist/goal/task-triggers.js.map +0 -1
  297. package/dist/goal/walls.d.ts +0 -12
  298. package/dist/goal/walls.d.ts.map +0 -1
  299. package/dist/goal/walls.js +0 -65
  300. package/dist/goal/walls.js.map +0 -1
  301. package/dist/goal/worker-prompt.d.ts +0 -13
  302. package/dist/goal/worker-prompt.d.ts.map +0 -1
  303. package/dist/goal/worker-prompt.js +0 -41
  304. package/dist/goal/worker-prompt.js.map +0 -1
  305. package/dist/goal/worker.d.ts +0 -42
  306. package/dist/goal/worker.d.ts.map +0 -1
  307. package/dist/goal/worker.js +0 -180
  308. package/dist/goal/worker.js.map +0 -1
  309. package/dist/templates/common/bundled-skills/cstl-cursor2plus-setup/SKILL.md +0 -63
  310. package/dist/templates/cursor/commands/cursor2plus-setup.md +0 -82
  311. package/dist/templates/cursor/rules/cstl-cursor-modes.mdc +0 -32
  312. package/dist/templates/cursor/rules/cstl-session-rename.mdc +0 -31
  313. package/dist/templates/cursor/rules/cstl-subagent-dispatch.mdc +0 -34
  314. package/dist/templates/cursor/rules/cstl-triage.mdc +0 -36
  315. package/dist/templates/cursor/rules/retrieval-routing.mdc +0 -78
  316. package/dist/templates/markdown/spec/guides/cursor-trellis-release-coexistence-guide.md.txt +0 -166
  317. package/dist/templates/markdown/spec/guides/goal-release-regression-runbook.md.txt +0 -132
  318. package/dist/templates/trellis/local/README.md +0 -85
  319. package/dist/templates/trellis/local/config.local.json.example +0 -6
  320. package/dist/templates/trellis/local/index.d.ts +0 -8
  321. package/dist/templates/trellis/local/index.d.ts.map +0 -1
  322. package/dist/templates/trellis/local/index.js +0 -15
  323. package/dist/templates/trellis/local/index.js.map +0 -1
  324. package/dist/templates/trellis/local/patch_wpelc8.py +0 -421
  325. package/dist/templates/trellis/local/smoke.py +0 -94
  326. package/dist/templates/trellis/local/subagent-models.json.example +0 -4
  327. package/dist/templates/trellis/local/trellis-task-models.json.example +0 -10
  328. package/dist/templates/trellis/local/trellis-task-models.json5.example +0 -45
  329. package/dist/templates/trellis/local/trellis_task_models_config.py +0 -200
  330. package/dist/utils/cursor-sdk-gate.d.ts +0 -10
  331. package/dist/utils/cursor-sdk-gate.d.ts.map +0 -1
  332. package/dist/utils/cursor-sdk-gate.js +0 -32
  333. package/dist/utils/cursor-sdk-gate.js.map +0 -1
  334. /package/dist/templates/markdown/{spec/guides → framework}/artifact-locale-guide.md.txt +0 -0
  335. /package/dist/templates/markdown/{spec/guides → framework}/cursor-context-injection-guide.md.txt +0 -0
  336. /package/dist/templates/markdown/{spec/guides → framework}/cursor-semantic-compliance.md.txt +0 -0
  337. /package/dist/templates/markdown/{spec/guides → framework}/injection-budget-guide.md.txt +0 -0
@@ -40,8 +40,17 @@ from .config import (
40
40
  validate_package,
41
41
  )
42
42
  from .cli_environment import format_git_repo_errors, print_environment_repair_hints
43
- from .git import run_git
44
- from .io import read_json, write_json
43
+ from .git import is_git_worktree, run_git
44
+ from .io import read_json
45
+ from .kernel_command import (
46
+ KernelCliNotFound,
47
+ KernelCommandError,
48
+ kernel_archive,
49
+ kernel_create,
50
+ kernel_expected_revision,
51
+ kernel_patch,
52
+ print_kernel_error,
53
+ )
45
54
  from .log import Colors, colored
46
55
  from .paths import (
47
56
  DIR_ARCHIVE,
@@ -62,10 +71,13 @@ from .task_gates import (
62
71
  BASELINE_GATE,
63
72
  archive_repair_hints,
64
73
  build_spec_update_scaffold,
74
+ collect_kernel_projection_extras,
65
75
  prepare_archive_evidence,
76
+ task_closeout_profile,
66
77
  validate_archive,
67
78
  write_gate_record,
68
79
  )
80
+ from .ondemand_topology import TopologyError, assign_parent, default_topology
69
81
  from .task_map import (
70
82
  CHILD_STATES,
71
83
  CHILD_REPORT_STATES,
@@ -257,10 +269,12 @@ _SUBAGENT_CONFIG_DIRS: tuple[str, ...] = (
257
269
  ".pi", # Pi Agent
258
270
  )
259
271
 
260
- _STABLE_SPEC_SEED_PATHS: tuple[str, ...] = (
272
+ # Stable seed paths for jsonl create: one user-owned thinking-guide index plus
273
+ # framework-owned verification/injection docs (both always present after init).
274
+ _STABLE_SEED_PATHS: tuple[str, ...] = (
261
275
  ".cstl/spec/guides/index.md",
262
- ".cstl/spec/guides/verification-strength-guide.md",
263
- ".cstl/spec/guides/injection-budget-guide.md",
276
+ ".cstl/framework/verification-strength-guide.md",
277
+ ".cstl/framework/injection-budget-guide.md",
264
278
  )
265
279
 
266
280
 
@@ -289,7 +303,7 @@ def _resolve_seed_spec_paths(
289
303
  for path in suggest_spec_targets(repo_root, task_dir, task_data):
290
304
  if path not in candidates:
291
305
  candidates.append(path)
292
- for rel in _STABLE_SPEC_SEED_PATHS:
306
+ for rel in _STABLE_SEED_PATHS:
293
307
  if rel not in candidates:
294
308
  candidates.append(rel)
295
309
 
@@ -298,7 +312,7 @@ def _resolve_seed_spec_paths(
298
312
  return existing[:3]
299
313
 
300
314
  fallback = [
301
- rel for rel in _STABLE_SPEC_SEED_PATHS if (repo_root / rel).is_file()
315
+ rel for rel in _STABLE_SEED_PATHS if (repo_root / rel).is_file()
302
316
  ]
303
317
  return fallback[:3]
304
318
 
@@ -343,6 +357,35 @@ def _default_prd_content(
343
357
  return default_prd_content(title, description, locale, root)
344
358
 
345
359
 
360
+ def _kernel_patch_task_json(
361
+ task_dir: Path,
362
+ data: dict,
363
+ *,
364
+ actor: str,
365
+ op: str,
366
+ evidence: str,
367
+ ) -> bool:
368
+ """Persist mutated task.json fields through Kernel patch (not task-map.md)."""
369
+ extras = collect_kernel_projection_extras(data)
370
+ if "depends_on" in data:
371
+ extras["depends_on"] = data["depends_on"]
372
+ try:
373
+ expected = kernel_expected_revision(task_dir)
374
+ kernel_patch(
375
+ task_dir,
376
+ data,
377
+ extras,
378
+ expected_revision=expected,
379
+ actor=actor,
380
+ idempotency_key=f"patch:{op}:{task_dir.name}:r{expected}",
381
+ evidence=evidence,
382
+ )
383
+ return True
384
+ except (KernelCliNotFound, KernelCommandError) as err:
385
+ print_kernel_error(err)
386
+ return False
387
+
388
+
346
389
  # =============================================================================
347
390
  # Command: create
348
391
  # =============================================================================
@@ -443,7 +486,33 @@ def cmd_create(args: argparse.Namespace) -> int:
443
486
  "meta": {},
444
487
  }
445
488
 
446
- write_json(task_json_path, task_data)
489
+ parent_dir = None
490
+ parent_data = None
491
+ if args.parent:
492
+ parent_dir = resolve_task_dir(args.parent, repo_root)
493
+ parent_json_path = parent_dir / FILE_TASK_JSON
494
+ if not parent_json_path.is_file():
495
+ print(colored(f"Warning: Parent task.json not found: {args.parent}", Colors.YELLOW), file=sys.stderr)
496
+ else:
497
+ parent_data = read_json(parent_json_path)
498
+ if parent_data:
499
+ task_data["parent"] = parent_dir.name
500
+
501
+ try:
502
+ kernel_create(
503
+ task_dir,
504
+ task_data,
505
+ actor="task.py create",
506
+ idempotency_key=f"create:{slug}",
507
+ evidence="task.py create",
508
+ )
509
+ except (KernelCliNotFound, KernelCommandError) as err:
510
+ print_kernel_error(err)
511
+ return 1
512
+
513
+ persisted = read_json(task_json_path)
514
+ if persisted:
515
+ task_data = persisted
447
516
 
448
517
  prd_path = task_dir / "prd.md"
449
518
  if not prd_path.exists():
@@ -471,39 +540,35 @@ def cmd_create(args: argparse.Namespace) -> int:
471
540
  _write_seed_jsonl(jsonl_path, repo_root, task_dir, task_data)
472
541
  seeded_jsonl = True
473
542
 
474
- # Handle --parent: establish bidirectional link
475
- if args.parent:
476
- parent_dir = resolve_task_dir(args.parent, repo_root)
477
- parent_json_path = parent_dir / FILE_TASK_JSON
478
- if not parent_json_path.is_file():
479
- print(colored(f"Warning: Parent task.json not found: {args.parent}", Colors.YELLOW), file=sys.stderr)
480
- else:
481
- parent_data = read_json(parent_json_path)
482
- if parent_data:
483
- # Add child to parent's children list
484
- parent_children = parent_data.get("children", [])
485
- if dir_name not in parent_children:
486
- parent_children.append(dir_name)
487
- parent_data["children"] = parent_children
488
- write_json(parent_json_path, parent_data)
489
-
490
- # Set parent in child's task.json
491
- task_data["parent"] = parent_dir.name
492
- write_json(task_json_path, task_data)
493
- ensure_task_map(
494
- parent_dir,
495
- parent_data,
496
- list(parent_data.get("children", [])),
497
- f"Linked Child `{dir_name}`.",
498
- )
499
-
500
- print(colored(f"Linked as child of: {parent_dir.name}", Colors.GREEN), file=sys.stderr)
543
+ # Handle --parent: child's `parent` is in the Kernel create record above;
544
+ # parent `children[]` goes through Kernel patch. task-map.md stays Python.
545
+ if parent_dir is not None and parent_data:
546
+ parent_children = parent_data.get("children", [])
547
+ if dir_name not in parent_children:
548
+ parent_children.append(dir_name)
549
+ parent_data["children"] = parent_children
550
+ if not _kernel_patch_task_json(
551
+ parent_dir,
552
+ parent_data,
553
+ actor="task.py create",
554
+ op="create-parent-link",
555
+ evidence="children[]",
556
+ ):
557
+ return 1
558
+ ensure_task_map(
559
+ parent_dir,
560
+ parent_data,
561
+ list(parent_data.get("children", [])),
562
+ f"Linked Child `{dir_name}`.",
563
+ )
564
+ print(colored(f"Linked as child of: {parent_dir.name}", Colors.GREEN), file=sys.stderr)
501
565
 
502
566
  print(colored(f"Created task: {dir_name}", Colors.GREEN), file=sys.stderr)
503
567
  print("", file=sys.stderr)
504
568
  print(colored("Next steps:", Colors.BLUE), file=sys.stderr)
505
569
  print(" - Fill prd.md with requirements and acceptance criteria", file=sys.stderr)
506
570
  print(f" - Select it when ready: python ./.cstl/scripts/task.py select {DIR_WORKFLOW}/{DIR_TASKS}/{dir_name}", file=sys.stderr)
571
+ print(" - Personal Lite: Definition=prd.md, Evidence=verify.md; start-execution --check is not approval", file=sys.stderr)
507
572
  print(" - Lightweight task: PRD-only is valid", file=sys.stderr)
508
573
  print(" - Complex task: add design.md and implement.md before task.py start-execution --check", file=sys.stderr)
509
574
  if seeded_jsonl:
@@ -634,7 +699,21 @@ def _archive_one_task(
634
699
  write_gate_record(data, "full-task-complete", BASELINE_GATE, guard.baseline_record)
635
700
  data["status"] = "completed"
636
701
  data["completedAt"] = today
637
- write_json(task_json_path, data)
702
+ extras = collect_kernel_projection_extras(data)
703
+ try:
704
+ expected = kernel_expected_revision(task_dir)
705
+ kernel_archive(
706
+ task_dir,
707
+ data,
708
+ extras,
709
+ expected_revision=expected,
710
+ actor="task.py archive",
711
+ idempotency_key=f"archive:{dir_name}:{today}",
712
+ evidence="task.py archive",
713
+ )
714
+ except (KernelCliNotFound, KernelCommandError) as err:
715
+ print_kernel_error(err)
716
+ return False, [], None
638
717
 
639
718
  task_children = data.get("children", [])
640
719
  if task_children:
@@ -646,14 +725,32 @@ def _archive_one_task(
646
725
  child_data = read_json(child_json)
647
726
  if child_data:
648
727
  child_data["parent"] = None
649
- write_json(child_json, child_data)
728
+ if not _kernel_patch_task_json(
729
+ child_dir_path,
730
+ child_data,
731
+ actor="task.py archive",
732
+ op="archive-clear-parent",
733
+ evidence="parent",
734
+ ):
735
+ return False, modified_children, None
650
736
  modified_children.append(child_dir_path.name)
651
737
 
652
738
  from .active_task import clear_task_from_sessions
653
739
 
740
+ profile = task_closeout_profile(task_dir, task_data) if task_data else "lite"
654
741
  clear_task_from_sessions(str(task_dir), repo_root)
655
742
  result = archive_task_complete(task_dir, repo_root)
656
743
  if "archived_to" not in result:
744
+ if profile == "lite":
745
+ print(
746
+ colored(
747
+ "Close Outcome written; physical archive/retention skipped "
748
+ "(not a Lite completion condition).",
749
+ Colors.YELLOW,
750
+ ),
751
+ file=sys.stderr,
752
+ )
753
+ return True, modified_children, f"{DIR_WORKFLOW}/{DIR_TASKS}/{dir_name}"
657
754
  return False, modified_children, None
658
755
 
659
756
  archive_dest = Path(result["archived_to"])
@@ -665,15 +762,25 @@ def _archive_one_task(
665
762
 
666
763
  if not no_commit:
667
764
  if not _auto_commit_archive(dir_name, repo_root, modified_children):
668
- print(
669
- colored(
670
- "Archive moved on disk, but git auto-commit did not complete. "
671
- "Resolve `git status` before continuing.",
672
- Colors.RED,
673
- ),
674
- file=sys.stderr,
675
- )
676
- return False, modified_children, None
765
+ if profile == "lite":
766
+ print(
767
+ colored(
768
+ "Lite Close Outcome stands; git auto-commit skipped or failed "
769
+ "(VCS is On-demand, not a completion condition).",
770
+ Colors.YELLOW,
771
+ ),
772
+ file=sys.stderr,
773
+ )
774
+ else:
775
+ print(
776
+ colored(
777
+ "Archive moved on disk, but git auto-commit did not complete. "
778
+ "Resolve `git status` before continuing.",
779
+ Colors.RED,
780
+ ),
781
+ file=sys.stderr,
782
+ )
783
+ return False, modified_children, None
677
784
 
678
785
  rel = f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}/{year_month}/{dir_name}"
679
786
  archived_json = archive_dest / FILE_TASK_JSON
@@ -856,6 +963,14 @@ def _auto_commit_archive(
856
963
  set to ``false``, this function returns immediately without
857
964
  touching git (the archive directory move on disk is unaffected).
858
965
  """
966
+ if not is_git_worktree(repo_root):
967
+ print(
968
+ "[OK] no Git worktree — skipping archive auto-commit "
969
+ "(Close Outcome already written).",
970
+ file=sys.stderr,
971
+ )
972
+ return True
973
+
859
974
  if not get_session_auto_commit(repo_root):
860
975
  print(
861
976
  "[OK] session_auto_commit: false — skipping git stage/commit.",
@@ -965,9 +1080,49 @@ def cmd_add_subtask(args: argparse.Namespace) -> int:
965
1080
  # Set parent in child's task.json
966
1081
  child_data["parent"] = parent_dir.name
967
1082
 
968
- # Write both
969
- write_json(parent_json_path, parent_data)
970
- write_json(child_json_path, child_data)
1083
+ parent_id = str(parent_data.get("id") or parent_dir.name)
1084
+ parent_existing = (
1085
+ parent_data.get("topology")
1086
+ if isinstance(parent_data.get("topology"), dict)
1087
+ else {}
1088
+ )
1089
+ parent_data["topology"] = default_topology(
1090
+ parent=parent_existing.get("parent_id") or parent_data.get("parent"),
1091
+ children=parent_children,
1092
+ )
1093
+ child_existing = (
1094
+ child_data.get("topology")
1095
+ if isinstance(child_data.get("topology"), dict)
1096
+ else {}
1097
+ )
1098
+ child_children = list(
1099
+ child_existing.get("children") or child_data.get("children") or []
1100
+ )
1101
+ try:
1102
+ child_data["topology"] = assign_parent(
1103
+ default_topology(parent=None, children=child_children),
1104
+ parent_id,
1105
+ )
1106
+ except TopologyError as err:
1107
+ print(colored(f"Error: {err}", Colors.RED), file=sys.stderr)
1108
+ return 1
1109
+
1110
+ if not _kernel_patch_task_json(
1111
+ parent_dir,
1112
+ parent_data,
1113
+ actor="task.py add-subtask",
1114
+ op="add-subtask",
1115
+ evidence="children[]",
1116
+ ):
1117
+ return 1
1118
+ if not _kernel_patch_task_json(
1119
+ child_dir,
1120
+ child_data,
1121
+ actor="task.py add-subtask",
1122
+ op="add-subtask",
1123
+ evidence="parent",
1124
+ ):
1125
+ return 1
971
1126
  ensure_task_map(
972
1127
  parent_dir,
973
1128
  parent_data,
@@ -1018,9 +1173,41 @@ def cmd_remove_subtask(args: argparse.Namespace) -> int:
1018
1173
  # Clear parent in child's task.json
1019
1174
  child_data["parent"] = None
1020
1175
 
1021
- # Write both
1022
- write_json(parent_json_path, parent_data)
1023
- write_json(child_json_path, child_data)
1176
+ parent_existing = (
1177
+ parent_data.get("topology")
1178
+ if isinstance(parent_data.get("topology"), dict)
1179
+ else {}
1180
+ )
1181
+ parent_data["topology"] = default_topology(
1182
+ parent=parent_existing.get("parent_id") or parent_data.get("parent"),
1183
+ children=parent_children,
1184
+ )
1185
+ child_existing = (
1186
+ child_data.get("topology")
1187
+ if isinstance(child_data.get("topology"), dict)
1188
+ else {}
1189
+ )
1190
+ child_data["topology"] = default_topology(
1191
+ parent=None,
1192
+ children=list(child_existing.get("children") or child_data.get("children") or []),
1193
+ )
1194
+
1195
+ if not _kernel_patch_task_json(
1196
+ parent_dir,
1197
+ parent_data,
1198
+ actor="task.py remove-subtask",
1199
+ op="remove-subtask",
1200
+ evidence="children[]",
1201
+ ):
1202
+ return 1
1203
+ if not _kernel_patch_task_json(
1204
+ child_dir,
1205
+ child_data,
1206
+ actor="task.py remove-subtask",
1207
+ op="remove-subtask",
1208
+ evidence="parent",
1209
+ ):
1210
+ return 1
1024
1211
  remove_child_from_task_map(parent_dir, parent_data, child_dir_name)
1025
1212
 
1026
1213
  print(colored(f"Unlinked: {child_dir.name} from {parent_dir.name}", Colors.GREEN), file=sys.stderr)
@@ -1106,7 +1293,14 @@ def cmd_prepare_child_worktree(args: argparse.Namespace) -> int:
1106
1293
 
1107
1294
  child_data["branch"] = branch
1108
1295
  child_data["worktree_path"] = worktree_rel
1109
- write_json(child_json_path, child_data)
1296
+ if not _kernel_patch_task_json(
1297
+ child_dir,
1298
+ child_data,
1299
+ actor="task.py prepare-child-worktree",
1300
+ op="prepare-child-worktree",
1301
+ evidence="branch,worktree_path",
1302
+ ):
1303
+ return 1
1110
1304
 
1111
1305
  ok, map_errors = record_child_worktree(
1112
1306
  parent_dir,
@@ -1145,7 +1339,7 @@ def append_depends_ignore_event(
1145
1339
  """Append a depends-ignore audit event to meta.depends_ignore_events.
1146
1340
 
1147
1341
  Mutates task_data in memory; the caller persists it in the SAME
1148
- write_json as the mutation it accompanies (execution approval / child
1342
+ Kernel patch as the mutation it accompanies (execution approval / child
1149
1343
  state), so the event can never dangle as a separate stale write. The
1150
1344
  list is capped at MAX_IGNORE_EVENTS (FIFO drops the oldest entry).
1151
1345
  """
@@ -1234,8 +1428,13 @@ def _guard_child_working_deps(
1234
1428
  evidence=args.evidence,
1235
1429
  reason=getattr(args, "reason", None),
1236
1430
  )
1237
- child_json_path = child_dir / FILE_TASK_JSON
1238
- if not write_json(child_json_path, child_data):
1431
+ if not _kernel_patch_task_json(
1432
+ child_dir,
1433
+ child_data,
1434
+ actor="task.py set-child-state",
1435
+ op="depends-ignore",
1436
+ evidence=str(args.evidence or "ignore-deps"),
1437
+ ):
1239
1438
  print(
1240
1439
  colored("Error: failed to write task.json (ignore event)", Colors.RED),
1241
1440
  file=sys.stderr,
@@ -1770,7 +1969,14 @@ def cmd_set_branch(args: argparse.Namespace) -> int:
1770
1969
  return 1
1771
1970
 
1772
1971
  data["branch"] = branch
1773
- write_json(task_json, data)
1972
+ if not _kernel_patch_task_json(
1973
+ target_dir,
1974
+ data,
1975
+ actor="task.py set-branch",
1976
+ op="set-branch",
1977
+ evidence="branch",
1978
+ ):
1979
+ return 1
1774
1980
 
1775
1981
  print(colored(f"✓ Branch set to: {branch}", Colors.GREEN))
1776
1982
  return 0
@@ -1804,7 +2010,14 @@ def cmd_set_base_branch(args: argparse.Namespace) -> int:
1804
2010
  return 1
1805
2011
 
1806
2012
  data["base_branch"] = base_branch
1807
- write_json(task_json, data)
2013
+ if not _kernel_patch_task_json(
2014
+ target_dir,
2015
+ data,
2016
+ actor="task.py set-base-branch",
2017
+ op="set-base-branch",
2018
+ evidence="base_branch",
2019
+ ):
2020
+ return 1
1808
2021
 
1809
2022
  print(colored(f"✓ Base branch set to: {base_branch}", Colors.GREEN))
1810
2023
  print(f" PR will target: {base_branch}")
@@ -1836,7 +2049,14 @@ def cmd_set_scope(args: argparse.Namespace) -> int:
1836
2049
  return 1
1837
2050
 
1838
2051
  data["scope"] = scope
1839
- write_json(task_json, data)
2052
+ if not _kernel_patch_task_json(
2053
+ target_dir,
2054
+ data,
2055
+ actor="task.py set-scope",
2056
+ op="set-scope",
2057
+ evidence="scope",
2058
+ ):
2059
+ return 1
1840
2060
 
1841
2061
  print(colored(f"✓ Scope set to: {scope}", Colors.GREEN))
1842
2062
  return 0
@@ -1878,7 +2098,13 @@ def cmd_set_deps(args: argparse.Namespace) -> int:
1878
2098
  if resolve_dep_ref(ref, repo_root=repo_root).kind == KIND_MISSING
1879
2099
  ]
1880
2100
 
1881
- if not write_json(task_json, data):
2101
+ if not _kernel_patch_task_json(
2102
+ target_dir,
2103
+ data,
2104
+ actor="task.py set-deps",
2105
+ op="set-deps",
2106
+ evidence="depends_on",
2107
+ ):
1882
2108
  print(colored("Error: failed to write task.json", Colors.RED), file=sys.stderr)
1883
2109
  return 1
1884
2110
 
@@ -1948,7 +2174,13 @@ def cmd_set_depends_mode(args: argparse.Namespace) -> int:
1948
2174
  data["meta"] = meta
1949
2175
  meta["depends_mode"] = args.mode
1950
2176
 
1951
- if not write_json(task_json, data):
2177
+ if not _kernel_patch_task_json(
2178
+ target_dir,
2179
+ data,
2180
+ actor="task.py set-depends-mode",
2181
+ op="set-depends-mode",
2182
+ evidence="meta.depends_mode",
2183
+ ):
1952
2184
  print(colored("Error: failed to write task.json", Colors.RED), file=sys.stderr)
1953
2185
  return 1
1954
2186
 
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env python3
2
+ """Stage 6 Event Bridge / Middleware Python projection."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
12
+
13
+ from common.adapter_middleware import (
14
+ EXTERNAL_KNOWLEDGE_CAPABILITY,
15
+ RETRIEVAL_INTENTS,
16
+ AdapterMiddlewareError,
17
+ assert_external_knowledge,
18
+ dispatch_hook_event,
19
+ normalize_capability_router,
20
+ probe_smart_search_readiness,
21
+ )
22
+
23
+
24
+ def test_dispatch_skips_unsubscribed_modules() -> None:
25
+ last = dispatch_hook_event(
26
+ {
27
+ "subscriptions": [
28
+ {"event": "sessionStart", "module": "observability-local"},
29
+ {"event": "stop", "module": "retrieval-extended"},
30
+ ]
31
+ },
32
+ "sessionStart",
33
+ source="cursor-hooks",
34
+ )
35
+ assert last["delivered"] == ["observability-local"]
36
+ assert last["skipped"] == ["retrieval-extended"]
37
+
38
+
39
+ def test_missing_smart_search_is_not_ready() -> None:
40
+ readiness = probe_smart_search_readiness(available=False)
41
+ assert readiness["status"] == "missing"
42
+ assert readiness["capability"] == EXTERNAL_KNOWLEDGE_CAPABILITY
43
+ extras = {"required_capabilities": [EXTERNAL_KNOWLEDGE_CAPABILITY]}
44
+ with pytest.raises(AdapterMiddlewareError, match="not ready"):
45
+ assert_external_knowledge(extras, readiness, phase="start")
46
+ extras["external_knowledge_policy"] = "degrade"
47
+ assert_external_knowledge(extras, readiness, phase="start")
48
+ assert extras["profile_health"] == "degraded"
49
+ assert_external_knowledge({}, readiness, phase="archive")
50
+
51
+
52
+ def test_capability_router_rejects_optional_tool_names() -> None:
53
+ router = normalize_capability_router(None)
54
+ assert tuple(key for key in RETRIEVAL_INTENTS if router.get(key)) == RETRIEVAL_INTENTS
55
+ with pytest.raises(AdapterMiddlewareError, match="Optional tool"):
56
+ normalize_capability_router({"codegraph": True})
@@ -25,6 +25,8 @@ from common.task_dependencies import (
25
25
  read_depends_mode,
26
26
  )
27
27
  from common.task_gates import validate_start_execution, validate_start_execution_check
28
+ from common import kernel_command as kernel_command_mod
29
+ from common.test_kernel_command import FAKE_KERNEL
28
30
 
29
31
 
30
32
  # =============================================================================
@@ -69,6 +71,13 @@ def sandbox(tmp_path, monkeypatch):
69
71
  tasks_dir.mkdir(parents=True)
70
72
  monkeypatch.setattr("common.task_dependencies.get_repo_root", lambda: repo)
71
73
  monkeypatch.setattr("common.task_store.get_repo_root", lambda: repo)
74
+ script = tmp_path / "fake_kernel.py"
75
+ script.write_text(FAKE_KERNEL, encoding="utf-8")
76
+ monkeypatch.setattr(
77
+ kernel_command_mod,
78
+ "kernel_cli_argv",
79
+ lambda: [sys.executable, str(script)],
80
+ )
72
81
  return repo, tasks_dir
73
82
 
74
83