@blxzer/cursor-trellis 0.4.2 → 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 (315) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +23 -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 +137 -40
  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 +2 -4
  33. package/dist/configurators/workflow.js.map +1 -1
  34. package/dist/constants/paths.d.ts +9 -0
  35. package/dist/constants/paths.d.ts.map +1 -1
  36. package/dist/constants/paths.js +13 -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-meta/references/platform-files/skills-and-commands.md +2 -4
  40. package/dist/templates/common/bundled-skills/cstl-skill-creator/SKILL.md +10 -7
  41. package/dist/templates/common/bundled-skills/cstl-skill-creator/references/authoring-rules.md +93 -19
  42. package/dist/templates/common/bundled-skills/cstl-skill-creator/references/general-authoring.md +189 -0
  43. package/dist/templates/common/bundled-skills/cstl-skill-creator/references/review-checklist.md +10 -5
  44. package/dist/templates/common/commands/continue.md +5 -4
  45. package/dist/templates/common/index.d.ts +20 -0
  46. package/dist/templates/common/index.d.ts.map +1 -1
  47. package/dist/templates/common/index.js +21 -2
  48. package/dist/templates/common/index.js.map +1 -1
  49. package/dist/templates/common/optional-skills/chrome-cdp/SKILL.md +179 -0
  50. package/dist/templates/common/optional-skills/chrome-cdp/examples/fetch-hook-api-capture.md +149 -0
  51. package/dist/templates/common/optional-skills/chrome-cdp/scripts/cdp.mjs +903 -0
  52. package/dist/templates/cursor/agents/cstl-research.md +1 -1
  53. package/dist/templates/cursor/fixtures/expected-rules.d.ts +1 -1
  54. package/dist/templates/cursor/fixtures/expected-rules.d.ts.map +1 -1
  55. package/dist/templates/cursor/fixtures/expected-rules.js +7 -24
  56. package/dist/templates/cursor/fixtures/expected-rules.js.map +1 -1
  57. package/dist/templates/cursor/hooks.json +4 -0
  58. package/dist/templates/cursor/index.d.ts +1 -1
  59. package/dist/templates/cursor/index.js +1 -1
  60. package/dist/templates/cursor/rules/cstl-bootstrap.mdc +17 -0
  61. package/dist/templates/markdown/agents.md +15 -10
  62. package/dist/templates/markdown/framework/cursor-native-modes-guide.md.txt +12 -9
  63. package/dist/templates/markdown/framework/cursor-subagent-policy.md.txt +62 -126
  64. package/dist/templates/markdown/framework/dogfood-only-surfaces.md.txt +4 -6
  65. package/dist/templates/markdown/framework/execution-strategy.md.txt +2 -0
  66. package/dist/templates/markdown/framework/index.md.txt +4 -0
  67. package/dist/templates/markdown/framework/internal-skills-cursor-reachability.md.txt +4 -3
  68. package/dist/templates/markdown/framework/middleware-protocol.md.txt +83 -0
  69. package/dist/templates/markdown/framework/parallel-first-execution.md.txt +78 -0
  70. package/dist/templates/markdown/framework/release-boundary.md.txt +30 -0
  71. package/dist/templates/markdown/framework/retrieval-daily-guide.md.txt +1 -1
  72. package/dist/templates/markdown/framework/upgrade.md.txt +15 -0
  73. package/dist/templates/markdown/index.d.ts +4 -0
  74. package/dist/templates/markdown/index.d.ts.map +1 -1
  75. package/dist/templates/markdown/index.js +17 -0
  76. package/dist/templates/markdown/index.js.map +1 -1
  77. package/dist/templates/markdown/spec/guides/index.md.txt +0 -6
  78. package/dist/templates/shared-hooks/event-bridge.py +60 -0
  79. package/dist/templates/shared-hooks/index.d.ts +1 -1
  80. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  81. package/dist/templates/shared-hooks/index.js +1 -0
  82. package/dist/templates/shared-hooks/index.js.map +1 -1
  83. package/dist/templates/shared-hooks/session-start.py +18 -1
  84. package/dist/templates/trellis/CONTEXT.md +63 -3
  85. package/dist/templates/trellis/gitignore.txt +39 -39
  86. package/dist/templates/trellis/index.d.ts +12 -0
  87. package/dist/templates/trellis/index.d.ts.map +1 -1
  88. package/dist/templates/trellis/index.js +73 -15
  89. package/dist/templates/trellis/index.js.map +1 -1
  90. package/dist/templates/trellis/pool/README.md +12 -3
  91. package/dist/templates/trellis/pool/plan.md +24 -5
  92. package/dist/templates/trellis/scripts/common/adapter_middleware.py +158 -0
  93. package/dist/templates/trellis/scripts/common/artifact_locale.py +12 -3
  94. package/dist/templates/trellis/scripts/common/cursor_retrieval_env.py +5 -2
  95. package/dist/templates/trellis/scripts/common/full_quality.py +237 -0
  96. package/dist/templates/trellis/scripts/common/git.py +6 -0
  97. package/dist/templates/trellis/scripts/common/git_context.py +17 -5
  98. package/dist/templates/trellis/scripts/common/kernel_command.py +367 -0
  99. package/dist/templates/trellis/scripts/common/lite_context.py +280 -0
  100. package/dist/templates/trellis/scripts/common/ondemand_topology.py +225 -0
  101. package/dist/templates/trellis/scripts/common/parent_orchestration.py +1 -1
  102. package/dist/templates/trellis/scripts/common/pool_store.py +16 -4
  103. package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +2 -2
  104. package/dist/templates/trellis/scripts/common/session_context.py +28 -2
  105. package/dist/templates/trellis/scripts/common/task_gates.py +73 -12
  106. package/dist/templates/trellis/scripts/common/task_map.py +42 -9
  107. package/dist/templates/trellis/scripts/common/task_store.py +286 -56
  108. package/dist/templates/trellis/scripts/common/test_adapter_middleware.py +56 -0
  109. package/dist/templates/trellis/scripts/common/test_depends_mode_block.py +9 -0
  110. package/dist/templates/trellis/scripts/common/test_full_quality.py +197 -0
  111. package/dist/templates/trellis/scripts/common/test_kernel_command.py +326 -0
  112. package/dist/templates/trellis/scripts/common/test_lite_path.py +190 -0
  113. package/dist/templates/trellis/scripts/common/test_ondemand_topology.py +122 -0
  114. package/dist/templates/trellis/scripts/common/test_pool_store.py +17 -0
  115. package/dist/templates/trellis/scripts/common/test_task_store_kernel_patch.py +163 -0
  116. package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -0
  117. package/dist/templates/trellis/scripts/get_context.py +1 -0
  118. package/dist/templates/trellis/scripts/pool.py +5 -0
  119. package/dist/templates/trellis/scripts/task.py +83 -7
  120. package/dist/templates/trellis/workflow.md +100 -18
  121. package/dist/utils/cursor-retrieval-env.d.ts +2 -1
  122. package/dist/utils/cursor-retrieval-env.d.ts.map +1 -1
  123. package/dist/utils/cursor-retrieval-env.js +3 -2
  124. package/dist/utils/cursor-retrieval-env.js.map +1 -1
  125. package/dist/utils/cursor2plus-residue-cleanup.d.ts +38 -0
  126. package/dist/utils/cursor2plus-residue-cleanup.d.ts.map +1 -0
  127. package/dist/utils/cursor2plus-residue-cleanup.js +145 -0
  128. package/dist/utils/cursor2plus-residue-cleanup.js.map +1 -0
  129. package/dist/utils/manifest-prune.d.ts.map +1 -1
  130. package/dist/utils/manifest-prune.js +7 -2
  131. package/dist/utils/manifest-prune.js.map +1 -1
  132. package/dist/utils/p36-upgrade.d.ts +62 -0
  133. package/dist/utils/p36-upgrade.d.ts.map +1 -0
  134. package/dist/utils/p36-upgrade.js +160 -0
  135. package/dist/utils/p36-upgrade.js.map +1 -0
  136. package/dist/utils/project-capabilities.d.ts +1 -12
  137. package/dist/utils/project-capabilities.d.ts.map +1 -1
  138. package/dist/utils/project-capabilities.js +3 -100
  139. package/dist/utils/project-capabilities.js.map +1 -1
  140. package/dist/utils/readiness.d.ts +10 -0
  141. package/dist/utils/readiness.d.ts.map +1 -1
  142. package/dist/utils/readiness.js +58 -26
  143. package/dist/utils/readiness.js.map +1 -1
  144. package/dist/utils/retrieval-agent-instructions.js +1 -1
  145. package/dist/utils/retrieval-agent-instructions.js.map +1 -1
  146. package/dist/utils/template-hash.d.ts.map +1 -1
  147. package/dist/utils/template-hash.js +11 -1
  148. package/dist/utils/template-hash.js.map +1 -1
  149. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  150. package/dist/utils/uninstall-scrubbers.js +52 -14
  151. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  152. package/dist/utils/update-rollout-report.d.ts +14 -0
  153. package/dist/utils/update-rollout-report.d.ts.map +1 -1
  154. package/dist/utils/update-rollout-report.js +1 -0
  155. package/dist/utils/update-rollout-report.js.map +1 -1
  156. package/dist/utils/workflow-ownership.d.ts +1 -1
  157. package/dist/utils/workflow-ownership.js +4 -4
  158. package/dist/utils/workflow-ownership.js.map +1 -1
  159. package/package.json +5 -4
  160. package/scripts/postinstall.js +6 -7
  161. package/dist/commands/campaign/canvas-render.d.ts +0 -68
  162. package/dist/commands/campaign/canvas-render.d.ts.map +0 -1
  163. package/dist/commands/campaign/canvas-render.js +0 -414
  164. package/dist/commands/campaign/canvas-render.js.map +0 -1
  165. package/dist/commands/campaign/compose.d.ts +0 -15
  166. package/dist/commands/campaign/compose.d.ts.map +0 -1
  167. package/dist/commands/campaign/compose.js +0 -110
  168. package/dist/commands/campaign/compose.js.map +0 -1
  169. package/dist/commands/campaign/index.d.ts +0 -13
  170. package/dist/commands/campaign/index.d.ts.map +0 -1
  171. package/dist/commands/campaign/index.js +0 -134
  172. package/dist/commands/campaign/index.js.map +0 -1
  173. package/dist/commands/campaign/kind-map.d.ts +0 -6
  174. package/dist/commands/campaign/kind-map.d.ts.map +0 -1
  175. package/dist/commands/campaign/kind-map.js +0 -21
  176. package/dist/commands/campaign/kind-map.js.map +0 -1
  177. package/dist/commands/campaign/mcp-server.d.ts +0 -6
  178. package/dist/commands/campaign/mcp-server.d.ts.map +0 -1
  179. package/dist/commands/campaign/mcp-server.js +0 -167
  180. package/dist/commands/campaign/mcp-server.js.map +0 -1
  181. package/dist/commands/campaign/render.d.ts +0 -5
  182. package/dist/commands/campaign/render.d.ts.map +0 -1
  183. package/dist/commands/campaign/render.js +0 -103
  184. package/dist/commands/campaign/render.js.map +0 -1
  185. package/dist/commands/campaign/trellis-load.d.ts +0 -13
  186. package/dist/commands/campaign/trellis-load.d.ts.map +0 -1
  187. package/dist/commands/campaign/trellis-load.js +0 -122
  188. package/dist/commands/campaign/trellis-load.js.map +0 -1
  189. package/dist/commands/campaign/types.d.ts +0 -61
  190. package/dist/commands/campaign/types.d.ts.map +0 -1
  191. package/dist/commands/campaign/types.js +0 -3
  192. package/dist/commands/campaign/types.js.map +0 -1
  193. package/dist/commands/goal/index.d.ts +0 -3
  194. package/dist/commands/goal/index.d.ts.map +0 -1
  195. package/dist/commands/goal/index.js +0 -159
  196. package/dist/commands/goal/index.js.map +0 -1
  197. package/dist/commands/goal/review.d.ts +0 -6
  198. package/dist/commands/goal/review.d.ts.map +0 -1
  199. package/dist/commands/goal/review.js +0 -28
  200. package/dist/commands/goal/review.js.map +0 -1
  201. package/dist/commands/rpc/client.d.ts +0 -51
  202. package/dist/commands/rpc/client.d.ts.map +0 -1
  203. package/dist/commands/rpc/client.js +0 -147
  204. package/dist/commands/rpc/client.js.map +0 -1
  205. package/dist/commands/rpc/index.d.ts +0 -10
  206. package/dist/commands/rpc/index.d.ts.map +0 -1
  207. package/dist/commands/rpc/index.js +0 -157
  208. package/dist/commands/rpc/index.js.map +0 -1
  209. package/dist/commands/rpc/serve.d.ts +0 -23
  210. package/dist/commands/rpc/serve.d.ts.map +0 -1
  211. package/dist/commands/rpc/serve.js +0 -60
  212. package/dist/commands/rpc/serve.js.map +0 -1
  213. package/dist/commands/rpc/smoke.d.ts +0 -16
  214. package/dist/commands/rpc/smoke.d.ts.map +0 -1
  215. package/dist/commands/rpc/smoke.js +0 -92
  216. package/dist/commands/rpc/smoke.js.map +0 -1
  217. package/dist/commands/sdk/index.d.ts +0 -9
  218. package/dist/commands/sdk/index.d.ts.map +0 -1
  219. package/dist/commands/sdk/index.js +0 -58
  220. package/dist/commands/sdk/index.js.map +0 -1
  221. package/dist/commands/sdk/run.d.ts +0 -42
  222. package/dist/commands/sdk/run.d.ts.map +0 -1
  223. package/dist/commands/sdk/run.js +0 -220
  224. package/dist/commands/sdk/run.js.map +0 -1
  225. package/dist/commands/sdk/status.d.ts +0 -14
  226. package/dist/commands/sdk/status.d.ts.map +0 -1
  227. package/dist/commands/sdk/status.js +0 -69
  228. package/dist/commands/sdk/status.js.map +0 -1
  229. package/dist/configurators/cursor2plus-local.d.ts +0 -6
  230. package/dist/configurators/cursor2plus-local.d.ts.map +0 -1
  231. package/dist/configurators/cursor2plus-local.js +0 -21
  232. package/dist/configurators/cursor2plus-local.js.map +0 -1
  233. package/dist/goal/action-packet.d.ts +0 -89
  234. package/dist/goal/action-packet.d.ts.map +0 -1
  235. package/dist/goal/action-packet.js +0 -113
  236. package/dist/goal/action-packet.js.map +0 -1
  237. package/dist/goal/audit.d.ts +0 -14
  238. package/dist/goal/audit.d.ts.map +0 -1
  239. package/dist/goal/audit.js +0 -12
  240. package/dist/goal/audit.js.map +0 -1
  241. package/dist/goal/constants.d.ts +0 -26
  242. package/dist/goal/constants.d.ts.map +0 -1
  243. package/dist/goal/constants.js +0 -24
  244. package/dist/goal/constants.js.map +0 -1
  245. package/dist/goal/paths.d.ts +0 -8
  246. package/dist/goal/paths.d.ts.map +0 -1
  247. package/dist/goal/paths.js +0 -36
  248. package/dist/goal/paths.js.map +0 -1
  249. package/dist/goal/preflight.d.ts +0 -21
  250. package/dist/goal/preflight.d.ts.map +0 -1
  251. package/dist/goal/preflight.js +0 -97
  252. package/dist/goal/preflight.js.map +0 -1
  253. package/dist/goal/review-seam.d.ts +0 -44
  254. package/dist/goal/review-seam.d.ts.map +0 -1
  255. package/dist/goal/review-seam.js +0 -153
  256. package/dist/goal/review-seam.js.map +0 -1
  257. package/dist/goal/reviewer-rules.d.ts +0 -13
  258. package/dist/goal/reviewer-rules.d.ts.map +0 -1
  259. package/dist/goal/reviewer-rules.js +0 -153
  260. package/dist/goal/reviewer-rules.js.map +0 -1
  261. package/dist/goal/reviewer.d.ts +0 -9
  262. package/dist/goal/reviewer.d.ts.map +0 -1
  263. package/dist/goal/reviewer.js +0 -54
  264. package/dist/goal/reviewer.js.map +0 -1
  265. package/dist/goal/runtime.d.ts +0 -32
  266. package/dist/goal/runtime.d.ts.map +0 -1
  267. package/dist/goal/runtime.js +0 -242
  268. package/dist/goal/runtime.js.map +0 -1
  269. package/dist/goal/sdk-client.d.ts +0 -10
  270. package/dist/goal/sdk-client.d.ts.map +0 -1
  271. package/dist/goal/sdk-client.js +0 -34
  272. package/dist/goal/sdk-client.js.map +0 -1
  273. package/dist/goal/state.d.ts +0 -40
  274. package/dist/goal/state.d.ts.map +0 -1
  275. package/dist/goal/state.js +0 -37
  276. package/dist/goal/state.js.map +0 -1
  277. package/dist/goal/task-triggers.d.ts +0 -15
  278. package/dist/goal/task-triggers.d.ts.map +0 -1
  279. package/dist/goal/task-triggers.js +0 -23
  280. package/dist/goal/task-triggers.js.map +0 -1
  281. package/dist/goal/walls.d.ts +0 -12
  282. package/dist/goal/walls.d.ts.map +0 -1
  283. package/dist/goal/walls.js +0 -65
  284. package/dist/goal/walls.js.map +0 -1
  285. package/dist/goal/worker-prompt.d.ts +0 -13
  286. package/dist/goal/worker-prompt.d.ts.map +0 -1
  287. package/dist/goal/worker-prompt.js +0 -41
  288. package/dist/goal/worker-prompt.js.map +0 -1
  289. package/dist/goal/worker.d.ts +0 -42
  290. package/dist/goal/worker.d.ts.map +0 -1
  291. package/dist/goal/worker.js +0 -180
  292. package/dist/goal/worker.js.map +0 -1
  293. package/dist/templates/common/bundled-skills/cstl-cursor2plus-setup/SKILL.md +0 -63
  294. package/dist/templates/cursor/commands/cursor2plus-setup.md +0 -82
  295. package/dist/templates/cursor/rules/cstl-cursor-modes.mdc +0 -32
  296. package/dist/templates/cursor/rules/cstl-session-rename.mdc +0 -31
  297. package/dist/templates/cursor/rules/cstl-subagent-dispatch.mdc +0 -34
  298. package/dist/templates/cursor/rules/cstl-triage.mdc +0 -36
  299. package/dist/templates/cursor/rules/retrieval-routing.mdc +0 -78
  300. package/dist/templates/trellis/local/README.md +0 -85
  301. package/dist/templates/trellis/local/config.local.json.example +0 -6
  302. package/dist/templates/trellis/local/index.d.ts +0 -8
  303. package/dist/templates/trellis/local/index.d.ts.map +0 -1
  304. package/dist/templates/trellis/local/index.js +0 -15
  305. package/dist/templates/trellis/local/index.js.map +0 -1
  306. package/dist/templates/trellis/local/patch_wpelc8.py +0 -421
  307. package/dist/templates/trellis/local/smoke.py +0 -94
  308. package/dist/templates/trellis/local/subagent-models.json.example +0 -4
  309. package/dist/templates/trellis/local/trellis-task-models.json.example +0 -10
  310. package/dist/templates/trellis/local/trellis-task-models.json5.example +0 -45
  311. package/dist/templates/trellis/local/trellis_task_models_config.py +0 -200
  312. package/dist/utils/cursor-sdk-gate.d.ts +0 -10
  313. package/dist/utils/cursor-sdk-gate.d.ts.map +0 -1
  314. package/dist/utils/cursor-sdk-gate.js +0 -32
  315. package/dist/utils/cursor-sdk-gate.js.map +0 -1
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env python3
2
+ """Stage 3 Personal Lite: no-Git Close, dual surfaces, budgeted context pack."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ import pytest
12
+
13
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
14
+
15
+ from common import kernel_command as kernel_command_mod
16
+ from common.kernel_command import kernel_start, kernel_expected_revision
17
+ from common.lite_context import (
18
+ LITE_BASELINE_MODULES,
19
+ LITE_PACK_SOURCE,
20
+ LiteContextPackError,
21
+ build_lite_context_pack,
22
+ )
23
+ from common.task_gates import validate_archive, validate_start_execution_check
24
+ from common.task_store import cmd_archive, cmd_create
25
+ from common.test_kernel_command import FAKE_KERNEL, _record
26
+
27
+
28
+ LITE_VERIFY = """# Verification Evidence
29
+
30
+ - validation: python -c "print('ok')"
31
+ - acceptance: Lite path completed without Parent or Git
32
+ - durable learning: no durable learning
33
+ """
34
+
35
+ PLACEHOLDER_VERIFY = """# Verification Evidence
36
+
37
+ - validation: TBD
38
+ - acceptance: TODO
39
+ - durable learning: TBD
40
+ """
41
+
42
+
43
+ @pytest.fixture
44
+ def lite_repo(tmp_path, monkeypatch):
45
+ repo = tmp_path / "repo"
46
+ (repo / ".cstl" / "tasks").mkdir(parents=True)
47
+ (repo / ".cstl" / ".developer").write_text("tester\n", encoding="utf-8")
48
+ script = tmp_path / "fake_kernel.py"
49
+ script.write_text(FAKE_KERNEL, encoding="utf-8")
50
+ monkeypatch.setattr("common.task_store.get_repo_root", lambda: repo)
51
+ monkeypatch.setattr("common.task_store.get_developer", lambda _repo=None: "tester")
52
+ monkeypatch.setattr("common.task_store.is_monorepo", lambda _repo: False)
53
+ monkeypatch.setattr("common.task_store._has_subagent_platform", lambda _repo: False)
54
+ monkeypatch.setattr("common.paths.get_repo_root", lambda: repo)
55
+ monkeypatch.setattr("common.artifact_locale.get_repo_root", lambda: repo)
56
+ monkeypatch.setattr(
57
+ kernel_command_mod,
58
+ "kernel_cli_argv",
59
+ lambda: [sys.executable, str(script)],
60
+ )
61
+ assert not (repo / ".git").exists()
62
+ return repo
63
+
64
+
65
+ def _only_task_dir(repo: Path) -> Path:
66
+ tasks = [
67
+ p
68
+ for p in (repo / ".cstl" / "tasks").iterdir()
69
+ if p.is_dir() and p.name != "archive"
70
+ ]
71
+ assert len(tasks) == 1
72
+ return tasks[0]
73
+
74
+
75
+ def test_lite_context_pack_budget_and_exclusions() -> None:
76
+ pack = build_lite_context_pack(
77
+ phase="verify",
78
+ artifacts=[
79
+ {
80
+ "role": "definition",
81
+ "path": "prd.md",
82
+ "content": "# Lite\n\n## Acceptance Criteria\n\n- [x] Close without Git\n",
83
+ },
84
+ {
85
+ "role": "evidence",
86
+ "path": "verify.md",
87
+ "content": "- validation: core test\n- acceptance: done\n",
88
+ },
89
+ ],
90
+ )
91
+ assert pack["source"] == LITE_PACK_SOURCE
92
+ assert pack["modules"]["baseline"] == list(LITE_BASELINE_MODULES)
93
+ assert pack["budget"]["estimatedTokens"] <= pack["budget"]["maxEstimatedTokens"]
94
+ assert any(item["role"] == "retrieval-router" for item in pack["selected"])
95
+ assert not any(
96
+ item["module"]
97
+ in (
98
+ "parent-child",
99
+ "vcs-integration",
100
+ "personal-memory",
101
+ "retention-storage",
102
+ "retrieval-extended",
103
+ )
104
+ for item in pack["selected"]
105
+ )
106
+
107
+ with pytest.raises(LiteContextPackError) as dump:
108
+ build_lite_context_pack(phase="define", include_full_workflow=True)
109
+ assert dump.value.code == "WORKFLOW_DUMP"
110
+
111
+ with pytest.raises(LiteContextPackError) as parent:
112
+ build_lite_context_pack(phase="execute", activated_modules=["parent-child"])
113
+ assert parent.value.code == "ON_DEMAND_INACTIVE"
114
+
115
+ tight = build_lite_context_pack(
116
+ phase="verify",
117
+ max_items=1,
118
+ max_estimated_tokens=80,
119
+ artifacts=[
120
+ {"role": "definition", "path": "prd.md", "content": "x" * 400},
121
+ {"role": "evidence", "path": "verify.md", "content": "y" * 400},
122
+ ],
123
+ )
124
+ assert tight["budget"]["itemsUsed"] == 1
125
+ assert tight["omitted"]
126
+ assert "budget limits caused Lite pack omission" in tight["warnings"]
127
+
128
+
129
+ def test_create_start_check_and_no_git_archive(lite_repo: Path) -> None:
130
+ rc = cmd_create(
131
+ argparse.Namespace(
132
+ title="Personal Lite Slice",
133
+ slug="personal-lite-slice",
134
+ description="no parent no git",
135
+ assignee="tester",
136
+ priority="P2",
137
+ parent=None,
138
+ package=None,
139
+ )
140
+ )
141
+ assert rc == 0
142
+ task_dir = _only_task_dir(lite_repo)
143
+ assert (task_dir / "prd.md").is_file()
144
+ assert (task_dir / "verify.md").is_file()
145
+ assert not (task_dir / "task-map.md").is_file()
146
+ data = json.loads((task_dir / "task.json").read_text(encoding="utf-8"))
147
+ assert data["status"] == "planning"
148
+ assert data["parent"] is None
149
+ assert data["children"] == []
150
+
151
+ check = validate_start_execution_check(task_dir, data)
152
+ assert check.ok
153
+ assert data.get("execution_approval") is None
154
+
155
+ (task_dir / "verify.md").write_text(PLACEHOLDER_VERIFY, encoding="utf-8")
156
+ fake = validate_archive(task_dir, data)
157
+ assert not fake.ok
158
+ assert any("verify.md" in err for err in fake.errors)
159
+
160
+ (task_dir / "verify.md").write_text(LITE_VERIFY, encoding="utf-8")
161
+ started = kernel_start(
162
+ task_dir,
163
+ _record(
164
+ id=data["id"],
165
+ name=data["name"],
166
+ title=data["title"],
167
+ status="in_progress",
168
+ ),
169
+ {"execution_approval": {"approved_by": "user"}},
170
+ expected_revision=kernel_expected_revision(task_dir),
171
+ actor="task.py start-execution --approved",
172
+ idempotency_key="start:personal-lite-slice",
173
+ )
174
+ assert started["legacy"]["status"] == "in_progress"
175
+
176
+ rc = cmd_archive(
177
+ argparse.Namespace(
178
+ name=task_dir.name,
179
+ check=False,
180
+ no_commit=False,
181
+ archive_integrated_children=False,
182
+ )
183
+ )
184
+ assert rc == 0
185
+ assert not (lite_repo / ".git").exists()
186
+ archived_root = lite_repo / ".cstl" / "tasks" / "archive"
187
+ archived = list(archived_root.rglob("task.json")) if archived_root.is_dir() else []
188
+ assert archived, "Lite Close should still move or keep Outcome on disk"
189
+ closed = json.loads(archived[0].read_text(encoding="utf-8"))
190
+ assert closed["status"] == "completed"
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env python3
2
+ """Stage 5 Topology / On-demand 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.ondemand_topology import (
14
+ ONDEMAND_OWNERS,
15
+ STAGE5_ONDEMAND_MODULES,
16
+ TopologyError,
17
+ apply_kernel_graph_projection,
18
+ apply_retention,
19
+ assert_integration_authority,
20
+ assign_parent,
21
+ capture_candidate,
22
+ confirm_decompose,
23
+ default_topology,
24
+ expand_depends_on_to_requires,
25
+ project_task_map_graph,
26
+ propose_decompose,
27
+ resident_on_demand_modules,
28
+ unmet_requires,
29
+ )
30
+ from common.task_map import ensure_task_map
31
+
32
+
33
+ def test_capture_and_decompose_do_not_create() -> None:
34
+ candidate = capture_candidate("later")
35
+ assert candidate["task_created"] is False
36
+ proposal = propose_decompose("parent-a", ["child-a"])
37
+ assert proposal["confirmed"] is False
38
+ assert proposal["children_created"] == []
39
+ confirmed = confirm_decompose(proposal)
40
+ assert confirmed["confirmed"] is True
41
+ assert confirmed["children_created"] == ["child-a"]
42
+
43
+
44
+ def test_default_topology_parent_id_alone_is_single() -> None:
45
+ linked = default_topology(parent="parent-a", children=[])
46
+ assert linked["kind"] == "single"
47
+ assert linked["parent_id"] == "parent-a"
48
+ controller = default_topology(parent=None, children=["child-a"])
49
+ assert controller["kind"] == "parent-child"
50
+
51
+
52
+ def test_assign_parent_keeps_ordinary_child_single() -> None:
53
+ linked = assign_parent({"parent_id": None, "children": []}, "parent-a")
54
+ assert linked["kind"] == "single"
55
+ assert linked["parent_id"] == "parent-a"
56
+ nested = assign_parent({"parent_id": None, "children": ["child-a"]}, "grand")
57
+ assert nested["kind"] == "parent-child"
58
+ assert nested["children"] == ["child-a"]
59
+
60
+
61
+ def test_second_parent_and_child_integrate_rejected() -> None:
62
+ topology = {"parent_id": "parent-a", "children": []}
63
+ with pytest.raises(TopologyError, match="second parent"):
64
+ assign_parent(topology, "parent-b")
65
+ with pytest.raises(TopologyError, match="Integration authority"):
66
+ assert_integration_authority("child")
67
+ assert_integration_authority("parent")
68
+
69
+
70
+ def test_requires_blocks_advisory_does_not() -> None:
71
+ graph = expand_depends_on_to_requires(
72
+ {"edges": [{"from": "here", "to": "hint", "type": "advisory"}]},
73
+ "here",
74
+ ["upstream"],
75
+ )
76
+ assert unmet_requires(graph, [], from_id="here") == ["upstream"]
77
+ assert unmet_requires(graph, ["upstream"], from_id="here") == []
78
+ assert unmet_requires(graph, [], from_id="other") == []
79
+
80
+
81
+ def test_task_map_is_kernel_graph_projection(tmp_path: Path) -> None:
82
+ parent_dir = tmp_path / "parent"
83
+ parent_dir.mkdir()
84
+ extras = {
85
+ "topology": {
86
+ "kind": "parent-child",
87
+ "parent_id": "parent-a",
88
+ "children": ["child-a"],
89
+ },
90
+ "dependency_graph": {
91
+ "edges": [{"from": "child-a", "to": "upstream", "type": "requires"}],
92
+ },
93
+ }
94
+ projection = project_task_map_graph(extras["topology"], extras["dependency_graph"])
95
+ assert projection["graph_authority"] == "kernel-extras"
96
+ assert projection["children"] == [{"id": "child-a", "depends_on": ["upstream"]}]
97
+
98
+ data = ensure_task_map(
99
+ parent_dir,
100
+ {"id": "parent-a", **extras},
101
+ ["child-a"],
102
+ )
103
+ assert data["graph_authority"] == "kernel-extras"
104
+ assert data["topology_kind"] == "parent-child"
105
+ child = next(item for item in data["children"] if item["id"] == "child-a")
106
+ assert child["depends_on"] == ["upstream"]
107
+ apply_kernel_graph_projection(data, extras)
108
+ assert data["graph_authority"] == "kernel-extras"
109
+
110
+
111
+ def test_ondemand_defaults_and_retention_outcome() -> None:
112
+ extras = {
113
+ "ondemand_modules": {
114
+ "registered": list(STAGE5_ONDEMAND_MODULES),
115
+ "active": [],
116
+ "owners": dict(ONDEMAND_OWNERS),
117
+ }
118
+ }
119
+ assert resident_on_demand_modules(extras) == []
120
+ assert ONDEMAND_OWNERS["integration-handoff"] == "parent-child"
121
+ assert ONDEMAND_OWNERS["session-transfer"] == "session-transfer"
122
+ assert apply_retention("completed") == "completed"
@@ -11,6 +11,7 @@ import pytest
11
11
 
12
12
  sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
13
13
 
14
+ from common import kernel_command as kernel_command_mod
14
15
  from common.pool_store import (
15
16
  check_plan,
16
17
  find_item_path,
@@ -26,6 +27,19 @@ from common.pool_store import (
26
27
  validate_pool,
27
28
  write_item_frontmatter,
28
29
  )
30
+ from common.test_kernel_command import FAKE_KERNEL
31
+
32
+
33
+ @pytest.fixture(autouse=True)
34
+ def fake_kernel(tmp_path, monkeypatch):
35
+ script = tmp_path / "fake_kernel.py"
36
+ script.write_text(FAKE_KERNEL, encoding="utf-8")
37
+ monkeypatch.setattr(
38
+ kernel_command_mod,
39
+ "kernel_cli_argv",
40
+ lambda: [sys.executable, str(script)],
41
+ )
42
+ return script
29
43
 
30
44
  ITEM_TEMPLATE = """\
31
45
  ---
@@ -205,6 +219,9 @@ def test_link_item_task_writes_both_sides_idempotent(tmp_path: Path) -> None:
205
219
  assert get_linked_tasks(item) == ["08-09-some-task"]
206
220
  data = json.loads((task_dir / "task.json").read_text(encoding="utf-8"))
207
221
  assert get_pool_items(data) == ["P01"]
222
+ kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
223
+ assert kernel["revision"] >= 1
224
+ assert kernel["audit"][-1]["idempotencyKey"].startswith("patch:pool-link:")
208
225
 
209
226
  second = link_item_task(repo, "P01", "08-09-some-task")
210
227
  assert second.ok
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env python3
2
+ """Parent-Child / VCS task.json writers go through Kernel patch."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ import pytest
12
+
13
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
14
+
15
+ from common import kernel_command as kernel_command_mod
16
+ from common.kernel_command import KernelCliNotFound
17
+ from common.task_store import (
18
+ cmd_add_subtask,
19
+ cmd_remove_subtask,
20
+ cmd_set_base_branch,
21
+ cmd_set_branch,
22
+ cmd_set_depends_mode,
23
+ cmd_set_deps,
24
+ cmd_set_scope,
25
+ )
26
+ from common.test_kernel_command import FAKE_KERNEL
27
+
28
+
29
+ def _write_task(tasks_dir: Path, dir_name: str, **fields) -> Path:
30
+ task_dir = tasks_dir / dir_name
31
+ task_dir.mkdir(parents=True, exist_ok=True)
32
+ data = {
33
+ "id": dir_name,
34
+ "name": dir_name,
35
+ "title": dir_name,
36
+ "status": "planning",
37
+ "children": [],
38
+ "parent": None,
39
+ "meta": {},
40
+ }
41
+ data.update(fields)
42
+ (task_dir / "task.json").write_text(
43
+ json.dumps(data, indent=2, ensure_ascii=False),
44
+ encoding="utf-8",
45
+ )
46
+ return task_dir
47
+
48
+
49
+ def _read(task_dir: Path) -> dict:
50
+ return json.loads((task_dir / "task.json").read_text(encoding="utf-8"))
51
+
52
+
53
+ @pytest.fixture
54
+ def sandbox(tmp_path, monkeypatch):
55
+ repo = tmp_path / "repo"
56
+ tasks_dir = repo / ".cstl" / "tasks"
57
+ tasks_dir.mkdir(parents=True)
58
+ monkeypatch.setattr("common.task_store.get_repo_root", lambda: repo)
59
+ monkeypatch.setattr("common.task_dependencies.get_repo_root", lambda: repo)
60
+ script = tmp_path / "fake_kernel.py"
61
+ script.write_text(FAKE_KERNEL, encoding="utf-8")
62
+ monkeypatch.setattr(
63
+ kernel_command_mod,
64
+ "kernel_cli_argv",
65
+ lambda: [sys.executable, str(script)],
66
+ )
67
+ return repo, tasks_dir
68
+
69
+
70
+ def test_add_and_remove_subtask_go_through_kernel(sandbox) -> None:
71
+ _repo, tasks_dir = sandbox
72
+ parent_dir = _write_task(tasks_dir, "parent-x")
73
+ child_dir = _write_task(tasks_dir, "child-a")
74
+
75
+ rc = cmd_add_subtask(
76
+ argparse.Namespace(parent_dir="parent-x", child_dir="child-a")
77
+ )
78
+ assert rc == 0
79
+
80
+ parent = _read(parent_dir)
81
+ child = _read(child_dir)
82
+ assert parent["children"] == ["child-a"]
83
+ assert child["parent"] == "parent-x"
84
+ assert parent["status"] == "planning"
85
+ assert child["status"] == "planning"
86
+ assert (parent_dir / "kernel.json").is_file()
87
+ assert (child_dir / "kernel.json").is_file()
88
+ parent_kernel = json.loads((parent_dir / "kernel.json").read_text(encoding="utf-8"))
89
+ child_kernel = json.loads((child_dir / "kernel.json").read_text(encoding="utf-8"))
90
+ assert parent_kernel["revision"] >= 1
91
+ assert child_kernel["revision"] >= 1
92
+ assert (parent_dir / "task-map.md").is_file()
93
+
94
+ rc = cmd_remove_subtask(
95
+ argparse.Namespace(parent_dir="parent-x", child_dir="child-a")
96
+ )
97
+ assert rc == 0
98
+ parent = _read(parent_dir)
99
+ child = _read(child_dir)
100
+ assert parent["children"] == []
101
+ assert child["parent"] is None
102
+ assert parent["status"] == "planning"
103
+
104
+
105
+ def test_set_branch_base_and_scope_go_through_kernel(sandbox) -> None:
106
+ _repo, tasks_dir = sandbox
107
+ task_dir = _write_task(tasks_dir, "task-x")
108
+
109
+ assert cmd_set_branch(argparse.Namespace(dir="task-x", branch="feat/demo")) == 0
110
+ data = _read(task_dir)
111
+ assert data["branch"] == "feat/demo"
112
+ assert data["status"] == "planning"
113
+ kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
114
+ assert kernel["revision"] >= 1
115
+ first_revision = kernel["revision"]
116
+
117
+ assert cmd_set_base_branch(
118
+ argparse.Namespace(dir="task-x", base_branch="feat/stage0-clean-baseline")
119
+ ) == 0
120
+ data = _read(task_dir)
121
+ assert data["base_branch"] == "feat/stage0-clean-baseline"
122
+ assert data["branch"] == "feat/demo"
123
+ kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
124
+ assert kernel["revision"] > first_revision
125
+
126
+ assert cmd_set_scope(argparse.Namespace(dir="task-x", scope="cli")) == 0
127
+ data = _read(task_dir)
128
+ assert data["scope"] == "cli"
129
+ assert data["status"] == "planning"
130
+
131
+
132
+ def test_set_deps_and_depends_mode_go_through_kernel(sandbox) -> None:
133
+ _repo, tasks_dir = sandbox
134
+ task_dir = _write_task(tasks_dir, "task-x")
135
+
136
+ assert cmd_set_deps(argparse.Namespace(dir="task-x", dep=["dep-a", "pool:P28"])) == 0
137
+ data = _read(task_dir)
138
+ assert data["depends_on"] == ["dep-a", "pool:P28"]
139
+ assert data["status"] == "planning"
140
+ kernel = json.loads((task_dir / "kernel.json").read_text(encoding="utf-8"))
141
+ assert kernel["revision"] >= 1
142
+ assert kernel["audit"][-1]["idempotencyKey"].startswith("patch:set-deps:")
143
+
144
+ assert cmd_set_depends_mode(argparse.Namespace(dir="task-x", mode="block")) == 0
145
+ data = _read(task_dir)
146
+ assert data["meta"]["depends_mode"] == "block"
147
+ assert data["depends_on"] == ["dep-a", "pool:P28"]
148
+ assert data["status"] == "planning"
149
+
150
+
151
+ def test_set_branch_does_not_fallback_when_kernel_cli_missing(sandbox, monkeypatch) -> None:
152
+ _repo, tasks_dir = sandbox
153
+ task_dir = _write_task(tasks_dir, "task-x")
154
+
155
+ def _missing():
156
+ raise KernelCliNotFound("Kernel CLI not found")
157
+
158
+ monkeypatch.setattr(kernel_command_mod, "kernel_cli_argv", _missing)
159
+ rc = cmd_set_branch(argparse.Namespace(dir="task-x", branch="feat/demo"))
160
+ assert rc == 1
161
+ data = _read(task_dir)
162
+ assert "branch" not in data or data.get("branch") in (None, "")
163
+ assert not (task_dir / "kernel.json").is_file()
@@ -3,6 +3,9 @@
3
3
  """
4
4
  Workflow Phase Extraction.
5
5
 
6
+ Convenience reader for the human-overview copy of `.cstl/workflow.md`.
7
+ That file is not the runtime SSOT — Kernel extras and `task.json` are.
8
+
6
9
  Extracts step-level content from .cstl/workflow.md and optionally filters
7
10
  platform-specific blocks.
8
11
 
@@ -5,6 +5,7 @@ Get Session Context for AI Agent.
5
5
  Usage:
6
6
  python3 get_context.py Output context in text format
7
7
  python3 get_context.py --json Output context in JSON format
8
+ python3 get_context.py --mode lite --json Personal Lite budgeted pack
8
9
  python3 get_context.py --mode retrieval-pack --json Output scored retrieval pack JSON
9
10
  """
10
11
 
@@ -101,6 +101,11 @@ def cmd_show(args: argparse.Namespace) -> int:
101
101
  print(f"title: {item.title or '<missing>'}")
102
102
  print(f"status: {item.status or '<missing>'}")
103
103
  print(f"type: {item.type or '<missing>'}")
104
+ priority = item.frontmatter.get("priority")
105
+ if isinstance(priority, str) and priority.strip():
106
+ print(f"priority: {priority.strip()}")
107
+ else:
108
+ print("priority: <unlabeled>")
104
109
  print(f"path: {item.path}")
105
110
  if not item.linked_tasks:
106
111
  print("linked_tasks: []")