@chinhae/atw-cli 0.5.0 → 0.7.0

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 (257) hide show
  1. package/README.md +128 -451
  2. package/dist/cli/index.d.ts.map +1 -1
  3. package/dist/cli/index.js +24 -1
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/commands/channel/adapters/claude.d.ts +44 -2
  6. package/dist/commands/channel/adapters/claude.d.ts.map +1 -1
  7. package/dist/commands/channel/adapters/claude.js +124 -23
  8. package/dist/commands/channel/adapters/claude.js.map +1 -1
  9. package/dist/commands/channel/adapters/codex.d.ts +36 -6
  10. package/dist/commands/channel/adapters/codex.d.ts.map +1 -1
  11. package/dist/commands/channel/adapters/codex.js +150 -10
  12. package/dist/commands/channel/adapters/codex.js.map +1 -1
  13. package/dist/commands/channel/adapters/index.d.ts +33 -4
  14. package/dist/commands/channel/adapters/index.d.ts.map +1 -1
  15. package/dist/commands/channel/adapters/index.js +159 -6
  16. package/dist/commands/channel/adapters/index.js.map +1 -1
  17. package/dist/commands/channel/adapters/omp.d.ts +106 -0
  18. package/dist/commands/channel/adapters/omp.d.ts.map +1 -0
  19. package/dist/commands/channel/adapters/omp.js +405 -0
  20. package/dist/commands/channel/adapters/omp.js.map +1 -0
  21. package/dist/commands/channel/adapters/pi.d.ts +123 -0
  22. package/dist/commands/channel/adapters/pi.d.ts.map +1 -0
  23. package/dist/commands/channel/adapters/pi.js +387 -0
  24. package/dist/commands/channel/adapters/pi.js.map +1 -0
  25. package/dist/commands/channel/adapters/types.d.ts +16 -0
  26. package/dist/commands/channel/adapters/types.d.ts.map +1 -1
  27. package/dist/commands/channel/agent-loader.d.ts +1 -0
  28. package/dist/commands/channel/agent-loader.d.ts.map +1 -1
  29. package/dist/commands/channel/agent-loader.js +45 -5
  30. package/dist/commands/channel/agent-loader.js.map +1 -1
  31. package/dist/commands/channel/dev-parse-trace.d.ts +1 -1
  32. package/dist/commands/channel/dev-parse-trace.d.ts.map +1 -1
  33. package/dist/commands/channel/dev-parse-trace.js +25 -2
  34. package/dist/commands/channel/dev-parse-trace.js.map +1 -1
  35. package/dist/commands/channel/index.d.ts.map +1 -1
  36. package/dist/commands/channel/index.js +44 -12
  37. package/dist/commands/channel/index.js.map +1 -1
  38. package/dist/commands/channel/run.d.ts +39 -2
  39. package/dist/commands/channel/run.d.ts.map +1 -1
  40. package/dist/commands/channel/run.js +227 -68
  41. package/dist/commands/channel/run.js.map +1 -1
  42. package/dist/commands/channel/spawn.d.ts +7 -2
  43. package/dist/commands/channel/spawn.d.ts.map +1 -1
  44. package/dist/commands/channel/spawn.js +35 -1
  45. package/dist/commands/channel/spawn.js.map +1 -1
  46. package/dist/commands/channel/store/events.d.ts +2 -2
  47. package/dist/commands/channel/store/events.d.ts.map +1 -1
  48. package/dist/commands/channel/store/events.js +1 -1
  49. package/dist/commands/channel/store/events.js.map +1 -1
  50. package/dist/commands/channel/supervisor/shutdown.d.ts +2 -0
  51. package/dist/commands/channel/supervisor/shutdown.d.ts.map +1 -1
  52. package/dist/commands/channel/supervisor/shutdown.js +6 -1
  53. package/dist/commands/channel/supervisor/shutdown.js.map +1 -1
  54. package/dist/commands/channel/supervisor.d.ts +2 -2
  55. package/dist/commands/channel/supervisor.d.ts.map +1 -1
  56. package/dist/commands/channel/supervisor.js +26 -3
  57. package/dist/commands/channel/supervisor.js.map +1 -1
  58. package/dist/commands/init.d.ts.map +1 -1
  59. package/dist/commands/init.js +6 -1
  60. package/dist/commands/init.js.map +1 -1
  61. package/dist/commands/mem.d.ts +2 -1
  62. package/dist/commands/mem.d.ts.map +1 -1
  63. package/dist/commands/mem.js +162 -13
  64. package/dist/commands/mem.js.map +1 -1
  65. package/dist/commands/mode.d.ts.map +1 -1
  66. package/dist/commands/mode.js +5 -3
  67. package/dist/commands/mode.js.map +1 -1
  68. package/dist/commands/uninstall.d.ts +5 -3
  69. package/dist/commands/uninstall.d.ts.map +1 -1
  70. package/dist/commands/uninstall.js +40 -16
  71. package/dist/commands/uninstall.js.map +1 -1
  72. package/dist/commands/update.d.ts +34 -0
  73. package/dist/commands/update.d.ts.map +1 -1
  74. package/dist/commands/update.js +209 -11
  75. package/dist/commands/update.js.map +1 -1
  76. package/dist/commands/verify.d.ts +18 -0
  77. package/dist/commands/verify.d.ts.map +1 -0
  78. package/dist/commands/verify.js +75 -0
  79. package/dist/commands/verify.js.map +1 -0
  80. package/dist/configurators/index.d.ts.map +1 -1
  81. package/dist/configurators/index.js +3 -2
  82. package/dist/configurators/index.js.map +1 -1
  83. package/dist/configurators/omp.d.ts +22 -0
  84. package/dist/configurators/omp.d.ts.map +1 -1
  85. package/dist/configurators/omp.js +101 -2
  86. package/dist/configurators/omp.js.map +1 -1
  87. package/dist/configurators/shared.d.ts.map +1 -1
  88. package/dist/configurators/shared.js +39 -7
  89. package/dist/configurators/shared.js.map +1 -1
  90. package/dist/configurators/workflow.d.ts.map +1 -1
  91. package/dist/configurators/workflow.js +5 -1
  92. package/dist/configurators/workflow.js.map +1 -1
  93. package/dist/constants/paths.d.ts +4 -0
  94. package/dist/constants/paths.d.ts.map +1 -1
  95. package/dist/constants/paths.js +4 -0
  96. package/dist/constants/paths.js.map +1 -1
  97. package/dist/migrations/manifests/0.6.0.json +442 -0
  98. package/dist/migrations/manifests/0.7.0.json +1378 -0
  99. package/dist/templates/atw/definition-of-done.md +65 -0
  100. package/dist/templates/atw/gitignore.txt +7 -0
  101. package/dist/templates/atw/index.d.ts +11 -0
  102. package/dist/templates/atw/index.d.ts.map +1 -1
  103. package/dist/templates/atw/index.js +22 -0
  104. package/dist/templates/atw/index.js.map +1 -1
  105. package/dist/templates/atw/scripts/common/active_task.py +2 -2
  106. package/dist/templates/atw/scripts/common/workflow_phase.py +33 -0
  107. package/dist/templates/atw/scripts/cross_model_review.py +3312 -0
  108. package/dist/templates/atw/scripts/decision_log.py +2002 -0
  109. package/dist/templates/atw/scripts/floor_guard.py +642 -0
  110. package/dist/templates/atw/scripts/task.py +25 -6
  111. package/dist/templates/atw/scripts/tickets.py +480 -10
  112. package/dist/templates/atw/workflow-general.md +6 -1
  113. package/dist/templates/atw/workflow.md +346 -26
  114. package/dist/templates/claude/settings.json +12 -0
  115. package/dist/templates/codex/hooks/session-start.py +2 -2
  116. package/dist/templates/common/bundled-skills/atw-askme/SKILL.md +1 -1
  117. package/dist/templates/common/bundled-skills/atw-askme-with-docs/SKILL.md +1 -1
  118. package/dist/templates/common/bundled-skills/atw-channel/SKILL.md +5 -2
  119. package/dist/templates/common/bundled-skills/atw-channel/references/command-reference.md +44 -5
  120. package/dist/templates/common/bundled-skills/atw-channel/references/progress-debugging.md +9 -0
  121. package/dist/templates/common/bundled-skills/atw-channel/references/workers.md +48 -4
  122. package/dist/templates/common/bundled-skills/atw-code-review/SKILL.md +78 -3
  123. package/dist/templates/common/bundled-skills/atw-codebase-design/SKILL.md +2 -2
  124. package/dist/templates/common/bundled-skills/atw-codebase-design/{DESIGN-IT-TWICE.md → design-it-twice.md} +3 -3
  125. package/dist/templates/common/bundled-skills/atw-cross-model-review/SKILL.md +361 -0
  126. package/dist/templates/common/bundled-skills/atw-cross-model-review/agents/openai.yaml +5 -0
  127. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/four-tiers.md +42 -0
  128. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/log-review-questions.md +38 -0
  129. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/questions.md +54 -0
  130. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/recheck-questions.md +42 -0
  131. package/dist/templates/common/bundled-skills/atw-cross-model-review/references/report-format.md +22 -0
  132. package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/SKILL.md +13 -2
  133. package/dist/templates/common/bundled-skills/atw-domain-modeling/SKILL.md +2 -2
  134. package/dist/templates/common/bundled-skills/atw-handoff/SKILL.md +1 -1
  135. package/dist/templates/common/bundled-skills/atw-implement/SKILL.md +37 -1
  136. package/dist/templates/common/bundled-skills/atw-implement-all/SKILL.md +219 -24
  137. package/dist/templates/common/bundled-skills/atw-implement-spec/SKILL.md +237 -18
  138. package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/SKILL.md +2 -2
  139. package/dist/templates/common/bundled-skills/atw-init-repo/SKILL.md +1 -1
  140. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw-local.md +7 -1
  141. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw.md +7 -1
  142. package/dist/templates/common/bundled-skills/atw-map/SKILL.md +1 -1
  143. package/dist/templates/common/bundled-skills/atw-meta/SKILL.md +1 -1
  144. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/add-project-local-conventions.md +4 -3
  145. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-skills-or-commands.md +21 -16
  146. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-task-lifecycle.md +1 -1
  147. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/overview.md +1 -0
  148. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/task-system.md +2 -1
  149. package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/hooks-and-settings.md +1 -0
  150. package/dist/templates/common/bundled-skills/atw-noob-mode/SKILL.md +1 -1
  151. package/dist/templates/common/bundled-skills/atw-performance/SKILL.md +134 -0
  152. package/dist/templates/common/bundled-skills/atw-performance/agents/openai.yaml +3 -0
  153. package/dist/templates/common/bundled-skills/atw-performance/references/optimization-patterns.md +250 -0
  154. package/dist/templates/common/bundled-skills/atw-performance/references/performance-checklist.md +238 -0
  155. package/dist/templates/common/bundled-skills/atw-performance/references/performance-optimization.md +264 -0
  156. package/dist/templates/common/bundled-skills/atw-prototype/SKILL.md +3 -3
  157. package/dist/templates/common/bundled-skills/atw-prototype/{LOGIC.md → logic.md} +1 -1
  158. package/dist/templates/common/bundled-skills/atw-prototype/references/design-direction.md +91 -58
  159. package/dist/templates/common/bundled-skills/atw-prototype/references/direction-persuasion.md +25 -0
  160. package/dist/templates/common/bundled-skills/atw-prototype/references/style-explorer.md +1 -1
  161. package/dist/templates/common/bundled-skills/atw-prototype/ui.md +194 -0
  162. package/dist/templates/common/bundled-skills/atw-reflect/SKILL.md +77 -0
  163. package/dist/templates/common/bundled-skills/atw-reflect/agents/openai.yaml +5 -0
  164. package/dist/templates/common/bundled-skills/atw-reflect/references/divergent-reviewer.md +38 -0
  165. package/dist/templates/common/bundled-skills/atw-reflect/references/judgment-reviewer.md +37 -0
  166. package/dist/templates/common/bundled-skills/atw-reflect/references/synthesizer.md +63 -0
  167. package/dist/templates/common/bundled-skills/atw-reflect/references/tooling-reviewer.md +48 -0
  168. package/dist/templates/common/bundled-skills/atw-security/SKILL.md +248 -0
  169. package/dist/templates/common/bundled-skills/atw-security/agents/openai.yaml +3 -0
  170. package/dist/templates/common/bundled-skills/atw-security/references/hardening-patterns.md +324 -0
  171. package/dist/templates/common/bundled-skills/atw-security/references/security-checklist.md +248 -0
  172. package/dist/templates/common/bundled-skills/atw-session-insight/SKILL.md +1 -1
  173. package/dist/templates/common/bundled-skills/atw-session-insight/references/cli-quick-reference.md +11 -2
  174. package/dist/templates/common/bundled-skills/atw-spec/SKILL.md +1 -1
  175. package/dist/templates/common/bundled-skills/atw-tdd/SKILL.md +25 -0
  176. package/dist/templates/common/bundled-skills/atw-tickets/SKILL.md +1 -1
  177. package/dist/templates/common/bundled-skills/atw-triage/SKILL.md +5 -5
  178. package/dist/templates/common/bundled-skills/atw-ui/SKILL.md +99 -31
  179. package/dist/templates/common/bundled-skills/atw-ui/references/accessibility-checklist.md +160 -0
  180. package/dist/templates/common/bundled-skills/atw-ui/references/layout-and-viewport.md +7 -5
  181. package/dist/templates/common/bundled-skills/atw-ui/references/media.md +117 -20
  182. package/dist/templates/common/bundled-skills/atw-ui/references/motion.md +47 -23
  183. package/dist/templates/common/bundled-skills/atw-ui/references/play.md +18 -0
  184. package/dist/templates/common/bundled-skills/atw-ui/references/reviewer-manual.md +73 -0
  185. package/dist/templates/common/bundled-skills/atw-ui/references/scroll-narrative.md +98 -0
  186. package/dist/templates/common/bundled-skills/atw-ui/references/tools.md +46 -0
  187. package/dist/templates/common/bundled-skills/atw-ui/references/visual-language.md +40 -24
  188. package/dist/templates/common/bundled-skills/atw-ui/references/visual-review.md +26 -82
  189. package/dist/templates/common/bundled-skills/atw-ui/scripts/shoot.mjs +1721 -0
  190. package/dist/templates/common/bundled-skills/atw-verify-skill/SKILL.md +58 -0
  191. package/dist/templates/common/bundled-skills/atw-verify-skill/agents/openai.yaml +5 -0
  192. package/dist/templates/common/bundled-skills/atw-verify-skill/references/feature-map-example/README.md +47 -0
  193. package/dist/templates/common/bundled-skills/atw-verify-skill/references/feature-map-example/create-note.md +39 -0
  194. package/dist/templates/common/bundled-skills/atw-verify-skill/references/feature-map-example/search.md +45 -0
  195. package/dist/templates/common/bundled-skills/atw-verify-skill/references/generate.md +107 -0
  196. package/dist/templates/common/bundled-skills/atw-verify-skill/references/health-check.md +100 -0
  197. package/dist/templates/common/bundled-skills/atw-verify-skill/references/verify-skill-template.md +99 -0
  198. package/dist/templates/common/bundled-skills/atw-what-happened/SKILL.md +49 -0
  199. package/dist/templates/common/bundled-skills/atw-what-happened/agents/openai.yaml +5 -0
  200. package/dist/templates/common/commands/finish-work.md +10 -1
  201. package/dist/templates/common/commands/start.md +3 -1
  202. package/dist/templates/common/skills/update-spec.md +40 -4
  203. package/dist/templates/copilot/hooks/session-start.py +2 -2
  204. package/dist/templates/dsh/DSH.md +2 -2
  205. package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +10 -0
  206. package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +10 -0
  207. package/dist/templates/omp/config.yml +15 -0
  208. package/dist/templates/omp/extensions/atw/index.ts.txt +135 -18
  209. package/dist/templates/omp/index.d.ts +1 -0
  210. package/dist/templates/omp/index.d.ts.map +1 -1
  211. package/dist/templates/omp/index.js +3 -0
  212. package/dist/templates/omp/index.js.map +1 -1
  213. package/dist/templates/opencode/lib/session-utils.js +4 -2
  214. package/dist/templates/opencode/plugins/inject-workflow-state.js +5 -1
  215. package/dist/templates/pi/extensions/atw/index.ts.txt +80 -7
  216. package/dist/templates/shared-hooks/index.d.ts +8 -1
  217. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  218. package/dist/templates/shared-hooks/index.js +8 -0
  219. package/dist/templates/shared-hooks/index.js.map +1 -1
  220. package/dist/templates/shared-hooks/inject-workflow-state.py +131 -14
  221. package/dist/templates/shared-hooks/session-start.py +4 -2
  222. package/dist/templates/shared-hooks/show-notice.py +135 -0
  223. package/dist/templates/snow/SNOW.md +1 -1
  224. package/dist/utils/initialized.d.ts +9 -0
  225. package/dist/utils/initialized.d.ts.map +1 -0
  226. package/dist/utils/initialized.js +24 -0
  227. package/dist/utils/initialized.js.map +1 -0
  228. package/dist/utils/managed-removal.d.ts +2 -0
  229. package/dist/utils/managed-removal.d.ts.map +1 -1
  230. package/dist/utils/managed-removal.js +23 -3
  231. package/dist/utils/managed-removal.js.map +1 -1
  232. package/dist/utils/optional-skills.d.ts +2 -0
  233. package/dist/utils/optional-skills.d.ts.map +1 -1
  234. package/dist/utils/optional-skills.js +1 -1
  235. package/dist/utils/optional-skills.js.map +1 -1
  236. package/dist/utils/template-hash.d.ts.map +1 -1
  237. package/dist/utils/template-hash.js +3 -0
  238. package/dist/utils/template-hash.js.map +1 -1
  239. package/dist/utils/uninstall-scrubbers.d.ts +10 -0
  240. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  241. package/dist/utils/uninstall-scrubbers.js +50 -0
  242. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  243. package/dist/utils/verify-entries.d.ts +51 -0
  244. package/dist/utils/verify-entries.d.ts.map +1 -0
  245. package/dist/utils/verify-entries.js +399 -0
  246. package/dist/utils/verify-entries.js.map +1 -0
  247. package/package.json +2 -2
  248. package/dist/templates/common/bundled-skills/atw-prototype/UI.md +0 -174
  249. package/dist/templates/common/bundled-skills/atw-prototype/references/visual-language.md +0 -88
  250. package/dist/templates/common/bundled-skills/atw-prototype/references/visual-review.md +0 -63
  251. package/dist/templates/common/bundled-skills/atw-ui/references/imagery.md +0 -69
  252. /package/dist/templates/common/bundled-skills/atw-codebase-design/{DEEPENING.md → deepening.md} +0 -0
  253. /package/dist/templates/common/bundled-skills/atw-domain-modeling/{ADR-FORMAT.md → adr-format.md} +0 -0
  254. /package/dist/templates/common/bundled-skills/atw-domain-modeling/{GLOSSARY-FORMAT.md → glossary-format.md} +0 -0
  255. /package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/{HTML-REPORT.md → html-report.md} +0 -0
  256. /package/dist/templates/common/bundled-skills/atw-triage/{AGENT-BRIEF.md → agent-brief.md} +0 -0
  257. /package/dist/templates/common/bundled-skills/atw-triage/{OUT-OF-SCOPE.md → out-of-scope.md} +0 -0
@@ -51,10 +51,19 @@ Then route:
51
51
  {{PYTHON_CMD}} ./.atw/scripts/task.py archive <task-name>
52
52
  ```
53
53
 
54
- At minimum: the current active task (if any). Plus any extra tasks the user confirmed in Step 1. Each archive produces a `chore(task): archive ...` commit via the script's auto-commit.
54
+ At minimum: the current active task (if any). Plus any extra tasks the user confirmed in Step 1. Each archive produces a `chore(task): archive ...` commit via the script's auto-commit — unless the task's `standing-orders.md` has an order on commit messages: then pass `--no-commit` and commit the move yourself as the order says (`.atw/workflow.md` 3.2).
55
55
 
56
56
  If there is no active task and the user did not confirm any cleanup archives, skip this step.
57
57
 
58
+ Right after a `task.py archive` that moved a task under `archive/`, add one sentence that the user can look back over this conversation for what to improve (复盘), with the input for their current tool only — the one line below that names that tool:
59
+
60
+ - Claude Code: `/atw-reflect`
61
+ - Codex: `$atw-reflect`
62
+ - pi: `/skill:atw-reflect`
63
+ - omp: `/skill:atw-reflect`
64
+
65
+ You never start it yourself. Once per task: an archive moves a task only once, so this comes once per task; several tasks archived in this step share one sentence. Say it once in the reply that reports the archive, in the part about the archive, not again where the reply wraps up.
66
+
58
67
  ## Step 4: Record session journal
59
68
 
60
69
  ```bash
@@ -52,7 +52,9 @@ Load the step detail before acting on it:
52
52
 
53
53
  `{{CMD_REF:continue}}` carries the same six stages with their artifact checks and stop points — use it when you need more than the step number.
54
54
 
55
- **No active task** → classify first. For simple conversation / small task, ask only whether this turn should create an ATW task. For complex work, ask whether you may create an ATW task and enter `discover` — that ask is **stop ①**, and task creation is step **1.0**. If the user says no, skip ATW for this session.
55
+ **No active task, and the request is about a task that already exists** — the user names it, or asks to continue or accept and only one open task fits (Step 1 lists them) → make it this session's task first; do not ask whether to create a new one. Use `task.py resume <task>` at any stage, `implement` and `accept` included: it only bookmarks the task for this session and changes no file. `task.py start` is only for step 1.5, where a task leaves `slice` (or `specify`, when the work was not sliced) for `implement`; do not run it to pick up a task. Then follow its stage as above: `implement` → **2.1**, `accept` → **3.1**. Several open tasks fit and nothing tells which: ask which one.
56
+
57
+ **Any other request** → classify first. For simple conversation / small task, ask whether this turn should create an ATW task. In that ask, say what each answer means: without a task there is no requirements document (`prd.md`) and no formal acceptance (each requirement checked with evidence, the user signs off); a task adds writing the requirements, the user confirming the spec, implementing against it, and that acceptance before archiving. For complex work, ask whether you may create an ATW task and enter `discover` — that ask is **stop ①**, and task creation is step **1.0**. If the user says no, skip ATW for this session.
56
58
 
57
59
  ---
58
60
 
@@ -98,7 +98,30 @@ Answer these questions:
98
98
  2. **Why is it important?** (What problem does it prevent?)
99
99
  3. **Where does it belong?** (Which spec file?)
100
100
 
101
- ### Step 2: Classify the Update Type
101
+ ### Step 2: Ask Whether It Can Be Enforced
102
+
103
+ Before writing a single line of docs, fix the lesson at the highest level that works. Assume every contributor is an agent that sees only the files it opened, copies the nearest example, and takes the shortest path that compiles. Design the repo so a change that looks right from one file is right for the whole repo.
104
+
105
+ 1. **Eliminate it with architecture.** Give each piece of state one owner and each task one supported way. Hide internals so the wrong import fails. Replace hand-synced lists with one source of truth. Delete old ways and dead code an agent would copy.
106
+ 2. **Enforce it with types so the bad state can't be written.** If bad code still compiles, add a lint or CI check whose error names the file, type, or function to use instead. If the pattern is already common, fail only when a change adds more.
107
+ 3. **Test the behavior.** Fix or delete any test that still passes when the behavior it checks breaks, or that fails when only the internals change.
108
+ 4. **Write docs last, only for judgment calls.** Nothing fails when an agent skips them.
109
+
110
+ Tell the user the level you picked and why a higher level didn't work.
111
+
112
+ After a fix at levels 1–3, the docs entry is only a pointer — make the docs entry point at it: the rule in one sentence plus "enforced by `<test file or checker>`". Docs that only repeat what the test already enforces are noise. Steps 3–6 below apply when the rule is written as docs (level 4).
113
+
114
+ **When code may not change here** — called during the acceptance check, or anywhere else that is read-only — do not make a level 1–3 fix in place. Instead write it as a new ticket the way the project's tracker doc says (`docs/agents/issue-tracker.md`), and write only the rule's row and its docs now: "Docs only" under "Enforced by" and the ticket under "Where", until the ticket lands.
115
+
116
+ **Fix and prove.** Prove each new check fails on a real past mistake. Run the same command locally and in CI. Exceptions go on the offending line with a reason, an expiry date, and a human's approval — never your own. In an unattended run nobody can approve one: write no exception; log one decision-log row marked needs-you (`python3 .atw/scripts/decision_log.py add … --mark needs-you`) naming the line and why it needs one, and leave it for the user. Write each exception into the rule's row, in the rule table's `Expires` column, as its expiry date plus its `file:line` — several exceptions, several entries. If the project's table has no `Expires` column — tables written before it existed keep their old header, because `atw update` never touches `.atw/spec/` — add the column, with `—` in every existing row, the first time you write an exception.
117
+
118
+ **Drop a rule once its mistake can't happen** — when the thing it guarded no longer exists, delete its docs and its row in the rule table. A rule fixed at architecture or types is not dropped: its row stays, pointing at what enforces it.
119
+
120
+ **Find the mistake classes only when the correction repeats.** When the user says it goes this way from now on (以后都这样), or a choice of the same kind is overruled a second time, first read recent commits, reverts, review comments, agent instruction files, and comments that explain workarounds. Group the mistakes into classes. A class counts once it has happened twice. Fix the most frequent classes now, one commit each, each at the highest level that works. Otherwise skip this and fix only the lesson in front of you.
121
+
122
+ **Keep the rule table** — **every rule you write gets a row in the rule table** at the top of the layer's `quality-guidelines.md`: the rule, what enforces it, where that lives, which task or bug produced it, and the expiry date of each exception to it. When the user corrects you, fix the mistake and add the rule. If the rule was already there and nothing enforces it, that's a repeat, so fix it at the highest level in the same change. A row whose "Enforced by" reads "Docs only" is the signal that the next time this rule is broken you upgrade it to a test or lint instead of rewording the docs — it is not the end point.
123
+
124
+ ### Step 3: Classify the Update Type
102
125
 
103
126
  | Type | Description | Action |
104
127
  |------|-------------|--------|
@@ -110,7 +133,7 @@ Answer these questions:
110
133
  | **Convention** | Agreed-upon standard | Add to relevant section |
111
134
  | **Gotcha** | Non-obvious behavior | Add warning callout |
112
135
 
113
- ### Step 3: Read the Target Code-Spec
136
+ ### Step 4: Read the Target Code-Spec
114
137
 
115
138
  Before editing, read the current code-spec to:
116
139
  - Understand existing structure
@@ -121,7 +144,7 @@ Before editing, read the current code-spec to:
121
144
  cat .atw/spec/<category>/<file>.md
122
145
  ```
123
146
 
124
- ### Step 4: Make the Update
147
+ ### Step 5: Make the Update
125
148
 
126
149
  Follow these principles:
127
150
 
@@ -131,7 +154,7 @@ Follow these principles:
131
154
  4. **Show Code**: Add code snippets for key patterns
132
155
  5. **Keep it Short**: One concept per section
133
156
 
134
- ### Step 5: Update the Index (if needed)
157
+ ### Step 6: Update the Index (if needed)
135
158
 
136
159
  If you added a new section or the code-spec status changed, update the category's `index.md`.
137
160
 
@@ -321,6 +344,7 @@ Before finishing your code-spec update:
321
344
  - [ ] Did you include Good/Base/Bad cases?
322
345
  - [ ] Did you include required tests with assertion points?
323
346
  - [ ] Is it in the right code-spec file?
347
+ - [ ] Did you add a row to the rule table (and is "Docs only" really the only option)?
324
348
  - [ ] Does it duplicate existing content?
325
349
  - [ ] Would a new team member understand it?
326
350
 
@@ -350,3 +374,15 @@ The goal is **institutional memory**:
350
374
  - What one person learns, everyone benefits from
351
375
  - What AI learns in one session, persists to future sessions
352
376
  - Mistakes become documented guardrails
377
+
378
+ ---
379
+
380
+ ## Rationalizations specific to this skill
381
+
382
+ Same shape as the general table in `.atw/workflow.md`; these are the excuses that only show up while capturing lessons.
383
+
384
+ | Rationalization | Reality |
385
+ |---|---|
386
+ | Writing it into the docs is capturing it | What a test or lint can enforce becomes a test or lint first; the docs record only what cannot be written into code |
387
+ | This rule is too obvious to record | Obvious rules only arrive here after they have been broken |
388
+ | Note it down now, add the test later | "Docs only" in the rule table is the signal for the next upgrade, not the end point |
@@ -236,8 +236,8 @@ def _get_task_status(atw_dir: Path, hook_input: dict, general: bool = False) ->
236
236
  )
237
237
  return (
238
238
  "Status: NO ACTIVE TASK\n"
239
- "Next: Classify the current turn and ask for task-creation consent "
240
- "before creating any ATW task."
239
+ "Next: If the request is about a task that already exists — the user names it, or asks to continue or accept and only one open task fits — make it this session's task first, as the no-task breadcrumb says; do not ask whether to create a new one. "
240
+ "Otherwise classify the current turn and ask for task-creation consent before creating any ATW task."
241
241
  )
242
242
 
243
243
  task_ref = active.task_path
@@ -76,9 +76,9 @@ In dsh:
76
76
 
77
77
  ## File map
78
78
 
79
- - `.agents/skills/` — the six skills of `general` mode: `atw-interview`,
79
+ - `.agents/skills/` — the seven skills of `general` mode: `atw-interview`,
80
80
  `atw-research`, `atw-session-insight`, `atw-noob-mode`, `atw-askme`,
81
- `atw-handoff`.
81
+ `atw-handoff`, `atw-what-happened`.
82
82
  - `.dsh/skills/` — the dsh-private entry skill `atw-start`.
83
83
  - `.atw/` — tasks, the conventions file (`.atw/spec/conventions.md`),
84
84
  workspace memory, and the shared scripts the skills invoke
@@ -4,6 +4,16 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## Rule Table
8
+
9
+ Every rule in this file has a row here: the rule in one sentence, what enforces it (architecture / types / lint / test / script / docs only), where that enforcement lives (test file or checker name), the task or bug that produced it, and the expiry date of each exception to this rule with its `file:line` (`—` when there is none). Add a row whenever you write a rule. "Docs only" means nothing in code catches a violation yet — the next time that rule is broken, upgrade it to a test, lint or script instead of rewording the docs. Delete the row once the rule can no longer be broken. The `_Example:_` row below is a placeholder, not a rule — replace it with your first real rule.
10
+
11
+ | Rule | Enforced by | Where | Source | Expires |
12
+ |------|-------------|-------|--------|---------|
13
+ | _Example: no `console.log` left in committed code_ | lint | `eslint no-console` | _task or bug id_ | `—` |
14
+
15
+ ---
16
+
7
17
  ## Overview
8
18
 
9
19
  <!--
@@ -4,6 +4,16 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## Rule Table
8
+
9
+ Every rule in this file has a row here: the rule in one sentence, what enforces it (architecture / types / lint / test / script / docs only), where that enforcement lives (test file or checker name), the task or bug that produced it, and the expiry date of each exception to this rule with its `file:line` (`—` when there is none). Add a row whenever you write a rule. "Docs only" means nothing in code catches a violation yet — the next time that rule is broken, upgrade it to a test, lint or script instead of rewording the docs. Delete the row once the rule can no longer be broken. The `_Example:_` row below is a placeholder, not a rule — replace it with your first real rule.
10
+
11
+ | Rule | Enforced by | Where | Source | Expires |
12
+ |------|-------------|-------|--------|---------|
13
+ | _Example: no `console.log` left in committed code_ | lint | `eslint no-console` | _task or bug id_ | `—` |
14
+
15
+ ---
16
+
7
17
  ## Overview
8
18
 
9
19
  <!--
@@ -0,0 +1,15 @@
1
+ # ATW: omp otherwise leaves delegating to sub-agents to the model's own policy,
2
+ # and under some models it then refuses /skill:atw-implement-all's one
3
+ # implementer sub-agent per ticket. With this, every omp session in this
4
+ # project leans toward handing work to sub-agents; delete these lines to go
5
+ # back to omp's default.
6
+ task:
7
+ eager: preferred # set by ATW
8
+
9
+ # ATW: omp otherwise cuts every line of a command's output and of a file it
10
+ # reads at 768 bytes and drops the rest; ATW's workflow and skills have longer
11
+ # lines, and the model then misses the rules at their ends. With this, omp
12
+ # shows every line whole in this project; delete these lines to go back to
13
+ # omp's default.
14
+ tools:
15
+ outputMaxColumns: 0 # set by ATW
@@ -40,7 +40,46 @@ function buildContextKey(platformName: string, kind: string, value: string): str
40
40
  return safeValue ? `${platformName}_${safeValue}` : `${platformName}_${hashValue(value)}`;
41
41
  }
42
42
 
43
- function deriveContextKey(ctx?: { sessionManager?: { getSessionId?: () => string | undefined; getSessionFile?: () => string | undefined } }): string | null {
43
+ type SessionCtx = { sessionManager?: { getSessionId?: () => string | undefined; getSessionFile?: () => string | undefined } };
44
+
45
+ // omp 子代理的会话文件放在父会话的附件目录里(<父>.jsonl → <父>/<名字>.jsonl),
46
+ // omp 自己找根会话也按这个规矩往上走(最多 8 层)。同进程的子代理不设
47
+ // PI_BLOCKED_AGENT,只能这样认。另起的分支会话与父会话同级,不算子代理。
48
+ function outermostSessionFile(ctx?: SessionCtx): string | null {
49
+ const sessionFile = ctx?.sessionManager?.getSessionFile?.();
50
+ if (!sessionFile) return null;
51
+ let current = resolve(sessionFile);
52
+ let root: string | null = null;
53
+ for (let depth = 0; depth < 8; depth++) {
54
+ const parentFile = `${dirname(current)}.jsonl`;
55
+ if (!existsSync(parentFile)) break;
56
+ current = parentFile;
57
+ root = parentFile;
58
+ }
59
+ return root;
60
+ }
61
+
62
+ function sessionHeaderId(sessionFile: string): string | null {
63
+ const prefix = readFilePrefix(sessionFile, 16 * 1024);
64
+ if (!prefix) return null;
65
+ for (const line of prefix.data.toString("utf-8").split("\n")) {
66
+ try {
67
+ const entry = JSON.parse(line) as { type?: unknown; id?: unknown };
68
+ if (entry.type === "session" && typeof entry.id === "string" && entry.id) return entry.id;
69
+ } catch {
70
+ // 不是完整的一行 JSON(读到前缀末尾被截断),接着看下一行
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+
76
+ // 子代理自己的编号没绑任务,沿用最外层会话的编号
77
+ function deriveContextKey(ctx?: SessionCtx): string | null {
78
+ const outermostFile = outermostSessionFile(ctx);
79
+ const outermostSessionId = outermostFile ? sessionHeaderId(outermostFile) : null;
80
+ if (outermostSessionId) {
81
+ return buildContextKey("omp", "session", outermostSessionId);
82
+ }
44
83
  const sessionId = ctx?.sessionManager?.getSessionId?.();
45
84
  if (sessionId) {
46
85
  return buildContextKey("omp", "session", sessionId);
@@ -779,6 +818,37 @@ function shouldSkipWorkflowState(
779
818
  // single event cascade (input, before_agent_start, and context fire closely)
780
819
  // ---------------------------------------------------------------------------
781
820
 
821
+ // Mirrors DECISION_LOG_REMINDER / has_decision_log() in the shared per-turn
822
+ // Python hook: same sentence, implement or accept only.
823
+ const DECISION_LOG_REMINDER =
824
+ "This task has a decision log: keep recording it at key points with `python3 ./.atw/scripts/decision_log.py`; in this conversation, the start row (`decision_log.py start`) goes in just before the first row you log — `add` and the other writing commands write it first when it is missing, so a conversation with nothing to log writes none; read the last rows they print, and when another conversation wrote in between they write only the start row and stop: read it, then run the same command again.";
825
+ // Mirrors DECISION_LOG_ARCHIVE_REMINDER in the shared per-turn Python hook:
826
+ // same sentence, accept only (with a log), placed before DECISION_LOG_REMINDER.
827
+ const DECISION_LOG_ARCHIVE_REMINDER =
828
+ "This task has a decision log: once accepted, after the acceptance row and before `task.py archive`, log one row for the archive (`decision_log.py add`); it goes into the archive commit with the task.";
829
+ // Mirrors DECISION_LOG_REPORT_REMINDER in the shared per-turn Python hook:
830
+ // same sentence, implement or accept (with a log), just before DECISION_LOG_REMINDER.
831
+ const DECISION_LOG_REPORT_REMINDER =
832
+ "This task has a decision log: when the user asks how things stand or for a report (汇报一下, 现在什么情况, what's the status, report), rebuild it from the task directory in four blocks — `python3 ./.atw/scripts/decision_log.py pending --report` prints the draft; post it in plain words, keep the plain-words lines it carries with noob mode on, and fill in what it marks. This is the task's report, not `atw-what-happened`: that skill only the user starts, and it tells what changed in this chat since their last message.";
833
+
834
+ // Mirrors DECISION_LOG_NO_TASK_REPORT_REMINDER / any_task_has_decision_log() in
835
+ // the shared per-turn Python hook: same sentence, no current task only.
836
+ const DECISION_LOG_NO_TASK_REPORT_REMINDER =
837
+ "No task is current, but some task under `.atw/tasks/` has a decision log: when the user asks how things stand or for a report (汇报一下, 现在什么情况, what's the status, report), rebuild it from that task's directory in four blocks — list the active tasks with `python3 ./.atw/scripts/task.py list` and see which of their directories hold a `decision-log.md` (if the user named the task or said enough to tell which one, take that one; if not, only one, take it; several, ask the user which), then `python3 ./.atw/scripts/decision_log.py pending --report --task-dir <dir>` prints the draft; post it in plain words, keep the plain-words lines it carries with noob mode on, and fill in what it marks. This is the task's report, not `atw-what-happened`: that skill only the user starts, and it tells what changed in this chat since their last message.";
838
+
839
+ // 只看 .atw/tasks/ 下一层、只认文件,归档里的不算;读不了当作没有,不打断这一轮
840
+ function anyTaskHasDecisionLog(projectRoot: string): boolean {
841
+ const tasksDir = join(projectRoot, ".atw", "tasks");
842
+ try {
843
+ return readdirSync(tasksDir).some((name) => {
844
+ const p = join(tasksDir, name, "decision-log.md");
845
+ return existsSync(p) && statSync(p).isFile();
846
+ });
847
+ } catch {
848
+ return false;
849
+ }
850
+ }
851
+
782
852
  const SESSION_OVERVIEW_TEXT =
783
853
  "ATW workflow system active. Use skills and agents as directed by the workflow state.";
784
854
 
@@ -797,9 +867,10 @@ class TurnContextCache {
797
867
  this.key = null;
798
868
  }
799
869
 
800
- get(projectRoot: string, contextKey: string | null): { workflowMsg: string } {
870
+ // 决定日志只由主对话写:子代理的每轮提示不带日志提醒
871
+ get(projectRoot: string, contextKey: string | null, subAgent: boolean): { workflowMsg: string } {
801
872
  const now = Date.now();
802
- const cacheKey = `${projectRoot}:${contextKey ?? ""}`;
873
+ const cacheKey = `${projectRoot}:${contextKey ?? ""}:${subAgent}`;
803
874
  if (
804
875
  this.key === cacheKey &&
805
876
  now - this.timestamp < TurnContextCache.TTL_MS
@@ -807,7 +878,20 @@ class TurnContextCache {
807
878
  return { workflowMsg: this.workflowMsg };
808
879
  }
809
880
 
810
- const { status } = resolveActiveTaskStatus(projectRoot, contextKey);
881
+ const { status, taskDir } = resolveActiveTaskStatus(projectRoot, contextKey);
882
+ // 只认文件,与共享钩子的 is_file() 一致
883
+ const logPath = taskDir !== null ? join(taskDir, "decision-log.md") : null;
884
+ const decisionLog =
885
+ !subAgent &&
886
+ (status === "implement" || status === "accept") &&
887
+ logPath !== null &&
888
+ existsSync(logPath) &&
889
+ statSync(logPath).isFile();
890
+ const tail = decisionLog
891
+ ? `${status === "accept" ? `\n${DECISION_LOG_ARCHIVE_REMINDER}` : ""}\n${DECISION_LOG_REPORT_REMINDER}\n${DECISION_LOG_REMINDER}`
892
+ : !subAgent && status === "no_task" && anyTaskHasDecisionLog(projectRoot)
893
+ ? `\n${DECISION_LOG_NO_TASK_REPORT_REMINDER}`
894
+ : "";
811
895
 
812
896
  const workflowPath = join(projectRoot, ".atw", "workflow.md");
813
897
  let workflowMd = "";
@@ -818,11 +902,11 @@ class TurnContextCache {
818
902
  const blocks = parseWorkflowStateBlocks(workflowMd);
819
903
  const activeBlock = blocks.find((b) => b.status === status);
820
904
  if (activeBlock) {
821
- workflowBody = `[workflow-state:${activeBlock.status}]\n${activeBlock.content}\n[/workflow-state:${activeBlock.status}]`;
905
+ workflowBody = `[workflow-state:${activeBlock.status}]\n${selectPlatformBlocks(activeBlock.content, "Oh My Pi")}${tail}\n[/workflow-state:${activeBlock.status}]`;
822
906
  }
823
907
  }
824
908
  if (!workflowBody) {
825
- workflowBody = "Refer to workflow.md for current step.";
909
+ workflowBody = `Refer to workflow.md for current step.${tail}`;
826
910
  }
827
911
 
828
912
  // When skip keyword is present, skip workflow state injection this turn
@@ -859,6 +943,31 @@ function parseWorkflowStateBlocks(markdown: string): WorkflowStateBlock[] {
859
943
  return blocks;
860
944
  }
861
945
 
946
+ // Mirrors select_platform_blocks() in .atw/scripts/common/workflow_phase.py:
947
+ // keep only the `[Platform, ...]` blocks naming this platform, or every block
948
+ // when none does; marker lines are always dropped.
949
+ const PLATFORM_MARKER_RE = /^\[(\/?)([A-Za-z][^[\]]*)\]\s*$/;
950
+ function selectPlatformBlocks(body: string, platform: string): string {
951
+ const norm = (s: string) => s.toLowerCase().replace(/[-_ ]/g, "");
952
+ const names = (m: RegExpMatchArray) => (m[2] ?? "").split(",").map((n) => norm(n.trim()));
953
+ const lines = body.split("\n");
954
+ const anyMatch = lines.some((l) => {
955
+ const m = l.match(PLATFORM_MARKER_RE);
956
+ return !!m && m[1] !== "/" && names(m).includes(norm(platform));
957
+ });
958
+ const out: string[] = [];
959
+ let keep = true;
960
+ for (const line of lines) {
961
+ const m = line.match(PLATFORM_MARKER_RE);
962
+ if (m) {
963
+ keep = m[1] === "/" || !anyMatch || names(m).includes(norm(platform));
964
+ continue;
965
+ }
966
+ if (keep) out.push(line);
967
+ }
968
+ return out.join("\n");
969
+ }
970
+
862
971
  // ---------------------------------------------------------------------------
863
972
  // Sub-agent detection
864
973
  // ---------------------------------------------------------------------------
@@ -890,6 +999,11 @@ export default function(pi: ExtensionAPI): void {
890
999
  const turnCache = new TurnContextCache();
891
1000
  const agentType = detectAgentType();
892
1001
  const isSubAgent = agentType !== null;
1002
+ // 同进程子代理(omp 18 的 task 工具)不设 PI_BLOCKED_AGENT,按会话文件认
1003
+ const isSubAgentSession = (ctx?: SessionCtx): boolean => isSubAgent || outermostSessionFile(ctx) !== null;
1004
+ // Same switch as the other platforms' hooks: channel sets ATW_HOOKS=0 on
1005
+ // its helpers, which must not receive prompts written for the main AI.
1006
+ const hooksDisabled = process.env.ATW_HOOKS === "0" || process.env.ATW_DISABLE_HOOKS === "1";
893
1007
  let taskContextCache: TaskContextCache | null = null;
894
1008
 
895
1009
  // Tracks compaction boundaries — context handler skips scanning when no
@@ -914,12 +1028,13 @@ export default function(pi: ExtensionAPI): void {
914
1028
  };
915
1029
 
916
1030
  pi.on("session_start", async (_event, ctx) => {
1031
+ if (hooksDisabled) return;
917
1032
  projectRoot = findProjectRoot(ctx.cwd);
918
1033
  const contextKey = rememberContextKey(ctx);
919
1034
 
920
1035
  if (!projectRoot) return;
921
1036
 
922
- if (isSubAgent) {
1037
+ if (isSubAgentSession(ctx)) {
923
1038
  // Sub-agent: inject precise task context once
924
1039
  const { taskDir } = resolveActiveTaskStatus(projectRoot, contextKey);
925
1040
  if (taskDir) {
@@ -964,6 +1079,7 @@ export default function(pi: ExtensionAPI): void {
964
1079
  });
965
1080
 
966
1081
  pi.on("before_agent_start", async (_event, ctx) => {
1082
+ if (hooksDisabled) return;
967
1083
  if (!projectRoot) {
968
1084
  projectRoot = findProjectRoot(ctx.cwd);
969
1085
  }
@@ -971,7 +1087,7 @@ export default function(pi: ExtensionAPI): void {
971
1087
  const contextKey = rememberContextKey(ctx);
972
1088
 
973
1089
  // Persistent injection: workflow state for this turn
974
- const cached = turnCache.get(projectRoot, contextKey);
1090
+ const cached = turnCache.get(projectRoot, contextKey, isSubAgentSession(ctx));
975
1091
  lastInjectionTs = Date.now();
976
1092
 
977
1093
  // Skip turn: inject nothing (escape hatch)
@@ -990,6 +1106,7 @@ export default function(pi: ExtensionAPI): void {
990
1106
  // and post-compaction agent.continue() paths). Acts as a safety net when
991
1107
  // before_agent_start's persisted message was removed by compaction.
992
1108
  pi.on("context", async (event, ctx) => {
1109
+ if (hooksDisabled) return;
993
1110
  if (!projectRoot) return;
994
1111
  const contextKey = rememberContextKey(ctx);
995
1112
 
@@ -1020,7 +1137,7 @@ export default function(pi: ExtensionAPI): void {
1020
1137
 
1021
1138
  // Resolve the turn state before the fast path: a skip turn must still
1022
1139
  // run breadcrumb cleanup even when nothing else changed.
1023
- const cached = turnCache.get(projectRoot, contextKey);
1140
+ const cached = turnCache.get(projectRoot, contextKey, isSubAgentSession(ctx));
1024
1141
  const skipping = !cached.workflowMsg;
1025
1142
 
1026
1143
  // Fast path: no task change, no compaction, not skipping — all persisted context is current.
@@ -1060,18 +1177,18 @@ export default function(pi: ExtensionAPI): void {
1060
1177
  };
1061
1178
  });
1062
1179
 
1063
- // OMP passes Bash event.input through to the tool execution parameters, so
1064
- // inject the session key through the shell-agnostic env field. An explicit
1065
- // per-call value wins over the derived key.
1180
+ // omp 18 的 bash 工具参数没有 env,往 event.input.env 里塞的编号到不了 shell
1181
+ // (工单 19 核实)。改成在命令前 export:编号只含 [A-Za-z0-9._-],不用加引号;
1182
+ // 命令里自己赋值的写在后面,照旧以它为准。调用自带 env 编号时(老版本 omp
1183
+ // 认 env)不动。按文档返回 input,也改原对象,后面的扩展看到的是同一条命令。
1066
1184
  pi.on("tool_call", (event, ctx) => {
1067
1185
  if (event.toolName !== "bash") return;
1068
1186
  const contextKey = rememberContextKey(ctx);
1069
1187
  if (!contextKey) return;
1070
- const input = event.input as { env?: Record<string, string> };
1071
- input.env = {
1072
- ATW_CONTEXT_ID: contextKey,
1073
- ...input.env,
1074
- };
1188
+ const input = event.input as { command: string; env?: Record<string, string> };
1189
+ if (input.env?.ATW_CONTEXT_ID) return;
1190
+ input.command = `export ATW_CONTEXT_ID=${contextKey}\n${input.command}`;
1191
+ return { input };
1075
1192
  });
1076
1193
 
1077
1194
  pi.on("input", async (event, ctx) => {
@@ -1089,6 +1206,6 @@ export default function(pi: ExtensionAPI): void {
1089
1206
  // Record the turn's skip decision and pre-warm the cache so
1090
1207
  // before_agent_start and context can use it
1091
1208
  turnCache.beginTurn(skipThisTurn);
1092
- turnCache.get(projectRoot, contextKey);
1209
+ turnCache.get(projectRoot, contextKey, isSubAgentSession(ctx));
1093
1210
  });
1094
1211
  }
@@ -1,4 +1,5 @@
1
1
  import type { AgentTemplate } from "../template-utils.js";
2
2
  export declare function getAllAgents(): AgentTemplate[];
3
3
  export declare function getExtensionTemplate(): string;
4
+ export declare function getConfigTemplate(): string;
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/omp/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAE9C;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/omp/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAE9C;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -6,4 +6,7 @@ export function getAllAgents() {
6
6
  export function getExtensionTemplate() {
7
7
  return readTemplate("extensions/atw/index.ts.txt");
8
8
  }
9
+ export function getConfigTemplate() {
10
+ return readTemplate("config.yml");
11
+ }
9
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/omp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE7E,MAAM,UAAU,YAAY;IAC1B,OAAO,YAAY,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,YAAY,CAAC,6BAA6B,CAAC,CAAC;AACrD,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/omp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG5D,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE7E,MAAM,UAAU,YAAY;IAC1B,OAAO,YAAY,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,YAAY,CAAC,6BAA6B,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,YAAY,CAAC,YAAY,CAAC,CAAC;AACpC,CAAC"}
@@ -36,8 +36,10 @@ function getTaskStatus(ctx, platformInput = null, general = false) {
36
36
  }
37
37
  return (
38
38
  "Status: NO ACTIVE TASK\n" +
39
- "Next-Action: Classify the current turn before creating any ATW task. " +
40
- "Simple conversation / small task asks only whether this turn should create an ATW task. " +
39
+ "Next-Action: If the request is about a task that already exists — the user names it, or asks to continue or accept and only one open task fits — make it this session's task first, as the no-task breadcrumb says; do not ask whether to create a new one. " +
40
+ "Otherwise classify the current turn before creating any ATW task. " +
41
+ "Simple conversation / small task asks whether this turn should create an ATW task. " +
42
+ "In that ask, say what each answer means: without a task there is no requirements document (`prd.md`) and no formal acceptance (each requirement checked with evidence, the user signs off); a task adds writing the requirements, the user confirming the spec, implementing against it, and that acceptance before archiving. " +
41
43
  "Complex task asks whether task creation and planning are allowed."
42
44
  )
43
45
  }
@@ -131,6 +131,7 @@ function promptHasSkipKeyword(text, keyword) {
131
131
  * buildBreadcrumb so users see the broken state and fix workflow.md
132
132
  * rather than the plugin silently masking it.
133
133
  */
134
+ const PLATFORM_MARKER_LINE_RE = /^\[\/?[A-Za-z][^[\]]*\]\s*(?:\n|$)/gm
134
135
  function loadBreadcrumbs(directory) {
135
136
  const workflowPath = join(directory, ".atw", "workflow.md")
136
137
  if (!existsSync(workflowPath)) return {}
@@ -143,7 +144,10 @@ function loadBreadcrumbs(directory) {
143
144
  const result = {}
144
145
  for (const match of content.matchAll(TAG_RE)) {
145
146
  const status = match[1]
146
- const body = match[2].trim()
147
+ // OpenCode has no `[Platform, ...]` block of its own in any breadcrumb, so
148
+ // it gets every block's lines (each names its tool) with the marker lines
149
+ // dropped, like select_platform_blocks() for such platforms.
150
+ const body = match[2].replace(PLATFORM_MARKER_LINE_RE, "").trim()
147
151
  if (body) result[status] = body
148
152
  }
149
153
  return result