@chinhae/atw-cli 0.1.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 (710) hide show
  1. package/COPYRIGHT +14 -0
  2. package/LICENSE +77 -0
  3. package/README.md +122 -0
  4. package/bin/atw.js +3 -0
  5. package/dist/cli/index.d.ts +3 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +299 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/commands/ablate.d.ts +14 -0
  10. package/dist/commands/ablate.d.ts.map +1 -0
  11. package/dist/commands/ablate.js +307 -0
  12. package/dist/commands/ablate.js.map +1 -0
  13. package/dist/commands/channel/adapters/claude.d.ts +53 -0
  14. package/dist/commands/channel/adapters/claude.d.ts.map +1 -0
  15. package/dist/commands/channel/adapters/claude.js +225 -0
  16. package/dist/commands/channel/adapters/claude.js.map +1 -0
  17. package/dist/commands/channel/adapters/codex.d.ts +93 -0
  18. package/dist/commands/channel/adapters/codex.d.ts.map +1 -0
  19. package/dist/commands/channel/adapters/codex.js +573 -0
  20. package/dist/commands/channel/adapters/codex.js.map +1 -0
  21. package/dist/commands/channel/adapters/index.d.ts +94 -0
  22. package/dist/commands/channel/adapters/index.d.ts.map +1 -0
  23. package/dist/commands/channel/adapters/index.js +116 -0
  24. package/dist/commands/channel/adapters/index.js.map +1 -0
  25. package/dist/commands/channel/adapters/types.d.ts +33 -0
  26. package/dist/commands/channel/adapters/types.d.ts.map +1 -0
  27. package/dist/commands/channel/adapters/types.js +2 -0
  28. package/dist/commands/channel/adapters/types.js.map +1 -0
  29. package/dist/commands/channel/agent-loader.d.ts +32 -0
  30. package/dist/commands/channel/agent-loader.d.ts.map +1 -0
  31. package/dist/commands/channel/agent-loader.js +158 -0
  32. package/dist/commands/channel/agent-loader.js.map +1 -0
  33. package/dist/commands/channel/context-loader.d.ts +26 -0
  34. package/dist/commands/channel/context-loader.d.ts.map +1 -0
  35. package/dist/commands/channel/context-loader.js +311 -0
  36. package/dist/commands/channel/context-loader.js.map +1 -0
  37. package/dist/commands/channel/context-trust.d.ts +31 -0
  38. package/dist/commands/channel/context-trust.d.ts.map +1 -0
  39. package/dist/commands/channel/context-trust.js +139 -0
  40. package/dist/commands/channel/context-trust.js.map +1 -0
  41. package/dist/commands/channel/context.d.ts +16 -0
  42. package/dist/commands/channel/context.d.ts.map +1 -0
  43. package/dist/commands/channel/context.js +83 -0
  44. package/dist/commands/channel/context.js.map +1 -0
  45. package/dist/commands/channel/create.d.ts +27 -0
  46. package/dist/commands/channel/create.d.ts.map +1 -0
  47. package/dist/commands/channel/create.js +39 -0
  48. package/dist/commands/channel/create.js.map +1 -0
  49. package/dist/commands/channel/dev-parse-trace.d.ts +14 -0
  50. package/dist/commands/channel/dev-parse-trace.d.ts.map +1 -0
  51. package/dist/commands/channel/dev-parse-trace.js +70 -0
  52. package/dist/commands/channel/dev-parse-trace.js.map +1 -0
  53. package/dist/commands/channel/guard.d.ts +150 -0
  54. package/dist/commands/channel/guard.d.ts.map +1 -0
  55. package/dist/commands/channel/guard.js +479 -0
  56. package/dist/commands/channel/guard.js.map +1 -0
  57. package/dist/commands/channel/index.d.ts +3 -0
  58. package/dist/commands/channel/index.d.ts.map +1 -0
  59. package/dist/commands/channel/index.js +535 -0
  60. package/dist/commands/channel/index.js.map +1 -0
  61. package/dist/commands/channel/interrupt.d.ts +10 -0
  62. package/dist/commands/channel/interrupt.d.ts.map +1 -0
  63. package/dist/commands/channel/interrupt.js +22 -0
  64. package/dist/commands/channel/interrupt.js.map +1 -0
  65. package/dist/commands/channel/kill.d.ts +7 -0
  66. package/dist/commands/channel/kill.d.ts.map +1 -0
  67. package/dist/commands/channel/kill.js +130 -0
  68. package/dist/commands/channel/kill.js.map +1 -0
  69. package/dist/commands/channel/list.d.ts +17 -0
  70. package/dist/commands/channel/list.d.ts.map +1 -0
  71. package/dist/commands/channel/list.js +233 -0
  72. package/dist/commands/channel/list.js.map +1 -0
  73. package/dist/commands/channel/messages.d.ts +15 -0
  74. package/dist/commands/channel/messages.d.ts.map +1 -0
  75. package/dist/commands/channel/messages.js +245 -0
  76. package/dist/commands/channel/messages.js.map +1 -0
  77. package/dist/commands/channel/rm.d.ts +27 -0
  78. package/dist/commands/channel/rm.d.ts.map +1 -0
  79. package/dist/commands/channel/rm.js +216 -0
  80. package/dist/commands/channel/rm.js.map +1 -0
  81. package/dist/commands/channel/run.d.ts +30 -0
  82. package/dist/commands/channel/run.d.ts.map +1 -0
  83. package/dist/commands/channel/run.js +130 -0
  84. package/dist/commands/channel/run.js.map +1 -0
  85. package/dist/commands/channel/send.d.ts +11 -0
  86. package/dist/commands/channel/send.d.ts.map +1 -0
  87. package/dist/commands/channel/send.js +24 -0
  88. package/dist/commands/channel/send.js.map +1 -0
  89. package/dist/commands/channel/spawn.d.ts +43 -0
  90. package/dist/commands/channel/spawn.d.ts.map +1 -0
  91. package/dist/commands/channel/spawn.js +247 -0
  92. package/dist/commands/channel/spawn.js.map +1 -0
  93. package/dist/commands/channel/store/events.d.ts +22 -0
  94. package/dist/commands/channel/store/events.d.ts.map +1 -0
  95. package/dist/commands/channel/store/events.js +43 -0
  96. package/dist/commands/channel/store/events.js.map +1 -0
  97. package/dist/commands/channel/store/filter.d.ts +3 -0
  98. package/dist/commands/channel/store/filter.d.ts.map +1 -0
  99. package/dist/commands/channel/store/filter.js +2 -0
  100. package/dist/commands/channel/store/filter.js.map +1 -0
  101. package/dist/commands/channel/store/lock.d.ts +23 -0
  102. package/dist/commands/channel/store/lock.d.ts.map +1 -0
  103. package/dist/commands/channel/store/lock.js +99 -0
  104. package/dist/commands/channel/store/lock.js.map +1 -0
  105. package/dist/commands/channel/store/paths.d.ts +77 -0
  106. package/dist/commands/channel/store/paths.d.ts.map +1 -0
  107. package/dist/commands/channel/store/paths.js +272 -0
  108. package/dist/commands/channel/store/paths.js.map +1 -0
  109. package/dist/commands/channel/store/schema.d.ts +27 -0
  110. package/dist/commands/channel/store/schema.d.ts.map +1 -0
  111. package/dist/commands/channel/store/schema.js +34 -0
  112. package/dist/commands/channel/store/schema.js.map +1 -0
  113. package/dist/commands/channel/store/thread-state.d.ts +5 -0
  114. package/dist/commands/channel/store/thread-state.d.ts.map +1 -0
  115. package/dist/commands/channel/store/thread-state.js +16 -0
  116. package/dist/commands/channel/store/thread-state.js.map +1 -0
  117. package/dist/commands/channel/store/watch.d.ts +19 -0
  118. package/dist/commands/channel/store/watch.d.ts.map +1 -0
  119. package/dist/commands/channel/store/watch.js +153 -0
  120. package/dist/commands/channel/store/watch.js.map +1 -0
  121. package/dist/commands/channel/supervisor/idle.d.ts +45 -0
  122. package/dist/commands/channel/supervisor/idle.d.ts.map +1 -0
  123. package/dist/commands/channel/supervisor/idle.js +70 -0
  124. package/dist/commands/channel/supervisor/idle.js.map +1 -0
  125. package/dist/commands/channel/supervisor/inbox.d.ts +30 -0
  126. package/dist/commands/channel/supervisor/inbox.d.ts.map +1 -0
  127. package/dist/commands/channel/supervisor/inbox.js +160 -0
  128. package/dist/commands/channel/supervisor/inbox.js.map +1 -0
  129. package/dist/commands/channel/supervisor/shutdown.d.ts +68 -0
  130. package/dist/commands/channel/supervisor/shutdown.d.ts.map +1 -0
  131. package/dist/commands/channel/supervisor/shutdown.js +146 -0
  132. package/dist/commands/channel/supervisor/shutdown.js.map +1 -0
  133. package/dist/commands/channel/supervisor/stdout.d.ts +71 -0
  134. package/dist/commands/channel/supervisor/stdout.d.ts.map +1 -0
  135. package/dist/commands/channel/supervisor/stdout.js +229 -0
  136. package/dist/commands/channel/supervisor/stdout.js.map +1 -0
  137. package/dist/commands/channel/supervisor/turns.d.ts +31 -0
  138. package/dist/commands/channel/supervisor/turns.d.ts.map +1 -0
  139. package/dist/commands/channel/supervisor/turns.js +45 -0
  140. package/dist/commands/channel/supervisor/turns.js.map +1 -0
  141. package/dist/commands/channel/supervisor/warning.d.ts +48 -0
  142. package/dist/commands/channel/supervisor/warning.d.ts.map +1 -0
  143. package/dist/commands/channel/supervisor/warning.js +77 -0
  144. package/dist/commands/channel/supervisor/warning.js.map +1 -0
  145. package/dist/commands/channel/supervisor.d.ts +91 -0
  146. package/dist/commands/channel/supervisor.d.ts.map +1 -0
  147. package/dist/commands/channel/supervisor.js +463 -0
  148. package/dist/commands/channel/supervisor.js.map +1 -0
  149. package/dist/commands/channel/text-body.d.ts +13 -0
  150. package/dist/commands/channel/text-body.d.ts.map +1 -0
  151. package/dist/commands/channel/text-body.js +47 -0
  152. package/dist/commands/channel/text-body.js.map +1 -0
  153. package/dist/commands/channel/threads.d.ts +39 -0
  154. package/dist/commands/channel/threads.d.ts.map +1 -0
  155. package/dist/commands/channel/threads.js +106 -0
  156. package/dist/commands/channel/threads.js.map +1 -0
  157. package/dist/commands/channel/title.d.ts +12 -0
  158. package/dist/commands/channel/title.d.ts.map +1 -0
  159. package/dist/commands/channel/title.js +24 -0
  160. package/dist/commands/channel/title.js.map +1 -0
  161. package/dist/commands/channel/wait.d.ts +17 -0
  162. package/dist/commands/channel/wait.d.ts.map +1 -0
  163. package/dist/commands/channel/wait.js +75 -0
  164. package/dist/commands/channel/wait.js.map +1 -0
  165. package/dist/commands/init.d.ts +71 -0
  166. package/dist/commands/init.d.ts.map +1 -0
  167. package/dist/commands/init.js +1612 -0
  168. package/dist/commands/init.js.map +1 -0
  169. package/dist/commands/mem.d.ts +30 -0
  170. package/dist/commands/mem.d.ts.map +1 -0
  171. package/dist/commands/mem.js +423 -0
  172. package/dist/commands/mem.js.map +1 -0
  173. package/dist/commands/uninstall.d.ts +36 -0
  174. package/dist/commands/uninstall.d.ts.map +1 -0
  175. package/dist/commands/uninstall.js +205 -0
  176. package/dist/commands/uninstall.js.map +1 -0
  177. package/dist/commands/update.d.ts +133 -0
  178. package/dist/commands/update.d.ts.map +1 -0
  179. package/dist/commands/update.js +2255 -0
  180. package/dist/commands/update.js.map +1 -0
  181. package/dist/commands/upgrade.d.ts +28 -0
  182. package/dist/commands/upgrade.d.ts.map +1 -0
  183. package/dist/commands/upgrade.js +84 -0
  184. package/dist/commands/upgrade.js.map +1 -0
  185. package/dist/commands/workflow.d.ts +35 -0
  186. package/dist/commands/workflow.d.ts.map +1 -0
  187. package/dist/commands/workflow.js +232 -0
  188. package/dist/commands/workflow.js.map +1 -0
  189. package/dist/configurators/antigravity.d.ts +7 -0
  190. package/dist/configurators/antigravity.d.ts.map +1 -0
  191. package/dist/configurators/antigravity.js +11 -0
  192. package/dist/configurators/antigravity.js.map +1 -0
  193. package/dist/configurators/claude.d.ts +23 -0
  194. package/dist/configurators/claude.d.ts.map +1 -0
  195. package/dist/configurators/claude.js +123 -0
  196. package/dist/configurators/claude.js.map +1 -0
  197. package/dist/configurators/codebuddy.d.ts +10 -0
  198. package/dist/configurators/codebuddy.d.ts.map +1 -0
  199. package/dist/configurators/codebuddy.js +24 -0
  200. package/dist/configurators/codebuddy.js.map +1 -0
  201. package/dist/configurators/codex.d.ts +57 -0
  202. package/dist/configurators/codex.d.ts.map +1 -0
  203. package/dist/configurators/codex.js +170 -0
  204. package/dist/configurators/codex.js.map +1 -0
  205. package/dist/configurators/copilot.d.ts +18 -0
  206. package/dist/configurators/copilot.d.ts.map +1 -0
  207. package/dist/configurators/copilot.js +50 -0
  208. package/dist/configurators/copilot.js.map +1 -0
  209. package/dist/configurators/cursor.d.ts +10 -0
  210. package/dist/configurators/cursor.d.ts.map +1 -0
  211. package/dist/configurators/cursor.js +23 -0
  212. package/dist/configurators/cursor.js.map +1 -0
  213. package/dist/configurators/devin.d.ts +8 -0
  214. package/dist/configurators/devin.d.ts.map +1 -0
  215. package/dist/configurators/devin.js +12 -0
  216. package/dist/configurators/devin.js.map +1 -0
  217. package/dist/configurators/droid.d.ts +10 -0
  218. package/dist/configurators/droid.d.ts.map +1 -0
  219. package/dist/configurators/droid.js +24 -0
  220. package/dist/configurators/droid.js.map +1 -0
  221. package/dist/configurators/dsh.d.ts +29 -0
  222. package/dist/configurators/dsh.d.ts.map +1 -0
  223. package/dist/configurators/dsh.js +64 -0
  224. package/dist/configurators/dsh.js.map +1 -0
  225. package/dist/configurators/gemini.d.ts +19 -0
  226. package/dist/configurators/gemini.d.ts.map +1 -0
  227. package/dist/configurators/gemini.js +40 -0
  228. package/dist/configurators/gemini.js.map +1 -0
  229. package/dist/configurators/grok.d.ts +17 -0
  230. package/dist/configurators/grok.d.ts.map +1 -0
  231. package/dist/configurators/grok.js +38 -0
  232. package/dist/configurators/grok.js.map +1 -0
  233. package/dist/configurators/index.d.ts +68 -0
  234. package/dist/configurators/index.d.ts.map +1 -0
  235. package/dist/configurators/index.js +191 -0
  236. package/dist/configurators/index.js.map +1 -0
  237. package/dist/configurators/kilo.d.ts +7 -0
  238. package/dist/configurators/kilo.d.ts.map +1 -0
  239. package/dist/configurators/kilo.js +11 -0
  240. package/dist/configurators/kilo.js.map +1 -0
  241. package/dist/configurators/kimi.d.ts +26 -0
  242. package/dist/configurators/kimi.d.ts.map +1 -0
  243. package/dist/configurators/kimi.js +74 -0
  244. package/dist/configurators/kimi.js.map +1 -0
  245. package/dist/configurators/kiro.d.ts +11 -0
  246. package/dist/configurators/kiro.d.ts.map +1 -0
  247. package/dist/configurators/kiro.js +30 -0
  248. package/dist/configurators/kiro.js.map +1 -0
  249. package/dist/configurators/omp.d.ts +6 -0
  250. package/dist/configurators/omp.d.ts.map +1 -0
  251. package/dist/configurators/omp.js +28 -0
  252. package/dist/configurators/omp.js.map +1 -0
  253. package/dist/configurators/opencode.d.ts +5 -0
  254. package/dist/configurators/opencode.d.ts.map +1 -0
  255. package/dist/configurators/opencode.js +80 -0
  256. package/dist/configurators/opencode.js.map +1 -0
  257. package/dist/configurators/pi.d.ts +5 -0
  258. package/dist/configurators/pi.d.ts.map +1 -0
  259. package/dist/configurators/pi.js +39 -0
  260. package/dist/configurators/pi.js.map +1 -0
  261. package/dist/configurators/qoder.d.ts +12 -0
  262. package/dist/configurators/qoder.d.ts.map +1 -0
  263. package/dist/configurators/qoder.js +30 -0
  264. package/dist/configurators/qoder.js.map +1 -0
  265. package/dist/configurators/reasonix.d.ts +17 -0
  266. package/dist/configurators/reasonix.d.ts.map +1 -0
  267. package/dist/configurators/reasonix.js +37 -0
  268. package/dist/configurators/reasonix.js.map +1 -0
  269. package/dist/configurators/shared.d.ts +196 -0
  270. package/dist/configurators/shared.d.ts.map +1 -0
  271. package/dist/configurators/shared.js +600 -0
  272. package/dist/configurators/shared.js.map +1 -0
  273. package/dist/configurators/snow.d.ts +25 -0
  274. package/dist/configurators/snow.d.ts.map +1 -0
  275. package/dist/configurators/snow.js +69 -0
  276. package/dist/configurators/snow.js.map +1 -0
  277. package/dist/configurators/trae.d.ts +16 -0
  278. package/dist/configurators/trae.d.ts.map +1 -0
  279. package/dist/configurators/trae.js +34 -0
  280. package/dist/configurators/trae.js.map +1 -0
  281. package/dist/configurators/workflow.d.ts +51 -0
  282. package/dist/configurators/workflow.d.ts.map +1 -0
  283. package/dist/configurators/workflow.js +210 -0
  284. package/dist/configurators/workflow.js.map +1 -0
  285. package/dist/configurators/zcode.d.ts +19 -0
  286. package/dist/configurators/zcode.d.ts.map +1 -0
  287. package/dist/configurators/zcode.js +51 -0
  288. package/dist/configurators/zcode.js.map +1 -0
  289. package/dist/constants/paths.d.ts +74 -0
  290. package/dist/constants/paths.d.ts.map +1 -0
  291. package/dist/constants/paths.js +83 -0
  292. package/dist/constants/paths.js.map +1 -0
  293. package/dist/constants/version.d.ts +9 -0
  294. package/dist/constants/version.d.ts.map +1 -0
  295. package/dist/constants/version.js +15 -0
  296. package/dist/constants/version.js.map +1 -0
  297. package/dist/index.d.ts +9 -0
  298. package/dist/index.d.ts.map +1 -0
  299. package/dist/index.js +9 -0
  300. package/dist/index.js.map +1 -0
  301. package/dist/migrations/index.d.ts +65 -0
  302. package/dist/migrations/index.d.ts.map +1 -0
  303. package/dist/migrations/index.js +202 -0
  304. package/dist/migrations/index.js.map +1 -0
  305. package/dist/templates/atw/agents/implement-agent.md +69 -0
  306. package/dist/templates/atw/agents/review.md +68 -0
  307. package/dist/templates/atw/config.yaml +158 -0
  308. package/dist/templates/atw/gitattributes.txt +9 -0
  309. package/dist/templates/atw/gitignore.txt +32 -0
  310. package/dist/templates/atw/index.d.ts +70 -0
  311. package/dist/templates/atw/index.d.ts.map +1 -0
  312. package/dist/templates/atw/index.js +137 -0
  313. package/dist/templates/atw/index.js.map +1 -0
  314. package/dist/templates/atw/scripts/__init__.py +5 -0
  315. package/dist/templates/atw/scripts/add_session.py +1545 -0
  316. package/dist/templates/atw/scripts/common/__init__.py +94 -0
  317. package/dist/templates/atw/scripts/common/active_task.py +857 -0
  318. package/dist/templates/atw/scripts/common/atw_config.py +239 -0
  319. package/dist/templates/atw/scripts/common/cli_adapter.py +949 -0
  320. package/dist/templates/atw/scripts/common/config.py +482 -0
  321. package/dist/templates/atw/scripts/common/developer.py +192 -0
  322. package/dist/templates/atw/scripts/common/git.py +203 -0
  323. package/dist/templates/atw/scripts/common/git_context.py +106 -0
  324. package/dist/templates/atw/scripts/common/io.py +160 -0
  325. package/dist/templates/atw/scripts/common/log.py +45 -0
  326. package/dist/templates/atw/scripts/common/packages_context.py +238 -0
  327. package/dist/templates/atw/scripts/common/paths.py +543 -0
  328. package/dist/templates/atw/scripts/common/safe_commit.py +322 -0
  329. package/dist/templates/atw/scripts/common/session_context.py +892 -0
  330. package/dist/templates/atw/scripts/common/task_context.py +470 -0
  331. package/dist/templates/atw/scripts/common/task_queue.py +188 -0
  332. package/dist/templates/atw/scripts/common/task_store.py +1940 -0
  333. package/dist/templates/atw/scripts/common/task_utils.py +498 -0
  334. package/dist/templates/atw/scripts/common/tasks.py +122 -0
  335. package/dist/templates/atw/scripts/common/types.py +110 -0
  336. package/dist/templates/atw/scripts/common/workflow_phase.py +242 -0
  337. package/dist/templates/atw/scripts/get_context.py +16 -0
  338. package/dist/templates/atw/scripts/get_developer.py +26 -0
  339. package/dist/templates/atw/scripts/github_sync.py +391 -0
  340. package/dist/templates/atw/scripts/hooks/linear_sync.py +243 -0
  341. package/dist/templates/atw/scripts/init_developer.py +51 -0
  342. package/dist/templates/atw/scripts/task.py +833 -0
  343. package/dist/templates/atw/scripts/tickets.py +495 -0
  344. package/dist/templates/atw/tasks/.gitkeep +0 -0
  345. package/dist/templates/atw/workflow.md +754 -0
  346. package/dist/templates/claude/agents/atw-implement-agent.md +107 -0
  347. package/dist/templates/claude/agents/atw-review.md +113 -0
  348. package/dist/templates/claude/hooks/statusline.py +332 -0
  349. package/dist/templates/claude/index.d.ts +31 -0
  350. package/dist/templates/claude/index.d.ts.map +1 -0
  351. package/dist/templates/claude/index.js +57 -0
  352. package/dist/templates/claude/index.js.map +1 -0
  353. package/dist/templates/claude/settings.json +73 -0
  354. package/dist/templates/codebuddy/agents/atw-implement-agent.md +107 -0
  355. package/dist/templates/codebuddy/agents/atw-review.md +113 -0
  356. package/dist/templates/codebuddy/index.d.ts +15 -0
  357. package/dist/templates/codebuddy/index.d.ts.map +1 -0
  358. package/dist/templates/codebuddy/index.js +15 -0
  359. package/dist/templates/codebuddy/index.js.map +1 -0
  360. package/dist/templates/codebuddy/settings.json +69 -0
  361. package/dist/templates/codex/agents/atw-implement-agent.toml +37 -0
  362. package/dist/templates/codex/agents/atw-review.toml +56 -0
  363. package/dist/templates/codex/config.toml +39 -0
  364. package/dist/templates/codex/hooks/session-start.py +514 -0
  365. package/dist/templates/codex/hooks.json +27 -0
  366. package/dist/templates/codex/index.d.ts +35 -0
  367. package/dist/templates/codex/index.d.ts.map +1 -0
  368. package/dist/templates/codex/index.js +67 -0
  369. package/dist/templates/codex/index.js.map +1 -0
  370. package/dist/templates/common/bundled-skills/atw-askme/SKILL.md +7 -0
  371. package/dist/templates/common/bundled-skills/atw-askme/agents/openai.yaml +5 -0
  372. package/dist/templates/common/bundled-skills/atw-askme-with-docs/SKILL.md +7 -0
  373. package/dist/templates/common/bundled-skills/atw-askme-with-docs/agents/openai.yaml +5 -0
  374. package/dist/templates/common/bundled-skills/atw-channel/SKILL.md +67 -0
  375. package/dist/templates/common/bundled-skills/atw-channel/references/command-reference.md +480 -0
  376. package/dist/templates/common/bundled-skills/atw-channel/references/forum.md +233 -0
  377. package/dist/templates/common/bundled-skills/atw-channel/references/progress-debugging.md +226 -0
  378. package/dist/templates/common/bundled-skills/atw-channel/references/workers.md +274 -0
  379. package/dist/templates/common/bundled-skills/atw-channel/references/workflows.md +125 -0
  380. package/dist/templates/common/bundled-skills/atw-code-review/SKILL.md +113 -0
  381. package/dist/templates/common/bundled-skills/atw-code-review/agents/openai.yaml +3 -0
  382. package/dist/templates/common/bundled-skills/atw-codebase-design/DEEPENING.md +37 -0
  383. package/dist/templates/common/bundled-skills/atw-codebase-design/DESIGN-IT-TWICE.md +44 -0
  384. package/dist/templates/common/bundled-skills/atw-codebase-design/SKILL.md +114 -0
  385. package/dist/templates/common/bundled-skills/atw-codebase-design/agents/openai.yaml +3 -0
  386. package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/SKILL.md +138 -0
  387. package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/agents/openai.yaml +3 -0
  388. package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  389. package/dist/templates/common/bundled-skills/atw-domain-modeling/ADR-FORMAT.md +47 -0
  390. package/dist/templates/common/bundled-skills/atw-domain-modeling/CONTEXT-FORMAT.md +60 -0
  391. package/dist/templates/common/bundled-skills/atw-domain-modeling/SKILL.md +74 -0
  392. package/dist/templates/common/bundled-skills/atw-domain-modeling/agents/openai.yaml +3 -0
  393. package/dist/templates/common/bundled-skills/atw-handoff/SKILL.md +16 -0
  394. package/dist/templates/common/bundled-skills/atw-handoff/agents/openai.yaml +5 -0
  395. package/dist/templates/common/bundled-skills/atw-implement/SKILL.md +21 -0
  396. package/dist/templates/common/bundled-skills/atw-implement/agents/openai.yaml +5 -0
  397. package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/HTML-REPORT.md +123 -0
  398. package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/SKILL.md +71 -0
  399. package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/agents/openai.yaml +5 -0
  400. package/dist/templates/common/bundled-skills/atw-init-repo/SKILL.md +130 -0
  401. package/dist/templates/common/bundled-skills/atw-init-repo/references/domain.md +51 -0
  402. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw-local.md +133 -0
  403. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw.md +109 -0
  404. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-github.md +45 -0
  405. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-gitlab.md +46 -0
  406. package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-local.md +30 -0
  407. package/dist/templates/common/bundled-skills/atw-init-repo/references/triage-labels.md +15 -0
  408. package/dist/templates/common/bundled-skills/atw-interview/SKILL.md +22 -0
  409. package/dist/templates/common/bundled-skills/atw-interview/agents/openai.yaml +3 -0
  410. package/dist/templates/common/bundled-skills/atw-map/SKILL.md +128 -0
  411. package/dist/templates/common/bundled-skills/atw-map/agents/openai.yaml +5 -0
  412. package/dist/templates/common/bundled-skills/atw-merge/SKILL.md +14 -0
  413. package/dist/templates/common/bundled-skills/atw-merge/agents/openai.yaml +3 -0
  414. package/dist/templates/common/bundled-skills/atw-meta/SKILL.md +85 -0
  415. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/add-project-local-conventions.md +83 -0
  416. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-agents.md +55 -0
  417. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-context-loading.md +80 -0
  418. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-hooks.md +57 -0
  419. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-skills-or-commands.md +123 -0
  420. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-spec-structure.md +83 -0
  421. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-task-lifecycle.md +91 -0
  422. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-workflow.md +59 -0
  423. package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/overview.md +55 -0
  424. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/bundled-skills.md +159 -0
  425. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/context-injection.md +68 -0
  426. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/generated-files.md +80 -0
  427. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/multi-agent-channel.md +69 -0
  428. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/overview.md +51 -0
  429. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/spec-system.md +102 -0
  430. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/task-system.md +126 -0
  431. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/workflow.md +79 -0
  432. package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/workspace-memory.md +71 -0
  433. package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/agents.md +80 -0
  434. package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/hooks-and-settings.md +72 -0
  435. package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/overview.md +59 -0
  436. package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/platform-map.md +112 -0
  437. package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/skills-and-commands.md +86 -0
  438. package/dist/templates/common/bundled-skills/atw-prototype/LOGIC.md +67 -0
  439. package/dist/templates/common/bundled-skills/atw-prototype/SKILL.md +26 -0
  440. package/dist/templates/common/bundled-skills/atw-prototype/UI.md +112 -0
  441. package/dist/templates/common/bundled-skills/atw-prototype/agents/openai.yaml +3 -0
  442. package/dist/templates/common/bundled-skills/atw-research/SKILL.md +14 -0
  443. package/dist/templates/common/bundled-skills/atw-research/agents/openai.yaml +3 -0
  444. package/dist/templates/common/bundled-skills/atw-session-insight/SKILL.md +81 -0
  445. package/dist/templates/common/bundled-skills/atw-session-insight/references/cli-quick-reference.md +65 -0
  446. package/dist/templates/common/bundled-skills/atw-session-insight/references/triggering-patterns.md +93 -0
  447. package/dist/templates/common/bundled-skills/atw-spec/SKILL.md +75 -0
  448. package/dist/templates/common/bundled-skills/atw-spec/agents/openai.yaml +5 -0
  449. package/dist/templates/common/bundled-skills/atw-spec-bootstrap/SKILL.md +41 -0
  450. package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/mcp-setup.md +90 -0
  451. package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/repository-analysis.md +59 -0
  452. package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/spec-task-planning.md +61 -0
  453. package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/spec-writing.md +70 -0
  454. package/dist/templates/common/bundled-skills/atw-tdd/SKILL.md +38 -0
  455. package/dist/templates/common/bundled-skills/atw-tdd/agents/openai.yaml +3 -0
  456. package/dist/templates/common/bundled-skills/atw-tdd/mocking.md +59 -0
  457. package/dist/templates/common/bundled-skills/atw-tdd/tests.md +77 -0
  458. package/dist/templates/common/bundled-skills/atw-tickets/SKILL.md +105 -0
  459. package/dist/templates/common/bundled-skills/atw-tickets/agents/openai.yaml +5 -0
  460. package/dist/templates/common/bundled-skills/atw-triage/AGENT-BRIEF.md +207 -0
  461. package/dist/templates/common/bundled-skills/atw-triage/OUT-OF-SCOPE.md +105 -0
  462. package/dist/templates/common/bundled-skills/atw-triage/SKILL.md +112 -0
  463. package/dist/templates/common/bundled-skills/atw-triage/agents/openai.yaml +5 -0
  464. package/dist/templates/common/commands/continue.md +55 -0
  465. package/dist/templates/common/commands/finish-work.md +69 -0
  466. package/dist/templates/common/commands/start.md +68 -0
  467. package/dist/templates/common/index.d.ts +48 -0
  468. package/dist/templates/common/index.d.ts.map +1 -0
  469. package/dist/templates/common/index.js +104 -0
  470. package/dist/templates/common/index.js.map +1 -0
  471. package/dist/templates/common/skills/before-dev.md +44 -0
  472. package/dist/templates/common/skills/brainstorm.md +194 -0
  473. package/dist/templates/common/skills/update-spec.md +351 -0
  474. package/dist/templates/copilot/copilot-instructions.md +11 -0
  475. package/dist/templates/copilot/hooks/session-start.py +510 -0
  476. package/dist/templates/copilot/hooks.json +19 -0
  477. package/dist/templates/copilot/index.d.ts +23 -0
  478. package/dist/templates/copilot/index.d.ts.map +1 -0
  479. package/dist/templates/copilot/index.js +48 -0
  480. package/dist/templates/copilot/index.js.map +1 -0
  481. package/dist/templates/cursor/agents/atw-implement-agent.md +106 -0
  482. package/dist/templates/cursor/agents/atw-review.md +112 -0
  483. package/dist/templates/cursor/hooks.json +24 -0
  484. package/dist/templates/cursor/index.d.ts +13 -0
  485. package/dist/templates/cursor/index.d.ts.map +1 -0
  486. package/dist/templates/cursor/index.js +13 -0
  487. package/dist/templates/cursor/index.js.map +1 -0
  488. package/dist/templates/droid/droids/atw-implement-agent.md +99 -0
  489. package/dist/templates/droid/droids/atw-review.md +105 -0
  490. package/dist/templates/droid/index.d.ts +15 -0
  491. package/dist/templates/droid/index.d.ts.map +1 -0
  492. package/dist/templates/droid/index.js +15 -0
  493. package/dist/templates/droid/index.js.map +1 -0
  494. package/dist/templates/droid/settings.json +69 -0
  495. package/dist/templates/dsh/DSH.md +56 -0
  496. package/dist/templates/dsh/index.d.ts +21 -0
  497. package/dist/templates/dsh/index.d.ts.map +1 -0
  498. package/dist/templates/dsh/index.js +25 -0
  499. package/dist/templates/dsh/index.js.map +1 -0
  500. package/dist/templates/extract.d.ts +40 -0
  501. package/dist/templates/extract.d.ts.map +1 -0
  502. package/dist/templates/extract.js +106 -0
  503. package/dist/templates/extract.js.map +1 -0
  504. package/dist/templates/gemini/agents/atw-implement-agent.md +99 -0
  505. package/dist/templates/gemini/agents/atw-review.md +105 -0
  506. package/dist/templates/gemini/index.d.ts +13 -0
  507. package/dist/templates/gemini/index.d.ts.map +1 -0
  508. package/dist/templates/gemini/index.js +13 -0
  509. package/dist/templates/gemini/index.js.map +1 -0
  510. package/dist/templates/gemini/settings.json +40 -0
  511. package/dist/templates/grok/agents/atw-implement-agent.md +115 -0
  512. package/dist/templates/grok/agents/atw-review.md +105 -0
  513. package/dist/templates/grok/index.d.ts +15 -0
  514. package/dist/templates/grok/index.d.ts.map +1 -0
  515. package/dist/templates/grok/index.js +18 -0
  516. package/dist/templates/grok/index.js.map +1 -0
  517. package/dist/templates/kimi/agents/atw-implement-agent.md +114 -0
  518. package/dist/templates/kimi/agents/atw-review.md +103 -0
  519. package/dist/templates/kimi/index.d.ts +20 -0
  520. package/dist/templates/kimi/index.d.ts.map +1 -0
  521. package/dist/templates/kimi/index.js +23 -0
  522. package/dist/templates/kimi/index.js.map +1 -0
  523. package/dist/templates/kiro/agents/atw-implement-agent.json +26 -0
  524. package/dist/templates/kiro/agents/atw-review.json +26 -0
  525. package/dist/templates/kiro/agents/atw.json +34 -0
  526. package/dist/templates/kiro/hooks/atw-workflow-state.kiro.hook +14 -0
  527. package/dist/templates/kiro/index.d.ts +32 -0
  528. package/dist/templates/kiro/index.d.ts.map +1 -0
  529. package/dist/templates/kiro/index.js +28 -0
  530. package/dist/templates/kiro/index.js.map +1 -0
  531. package/dist/templates/markdown/agents.md +21 -0
  532. package/dist/templates/markdown/gitignore.txt +15 -0
  533. package/dist/templates/markdown/index.d.ts +27 -0
  534. package/dist/templates/markdown/index.d.ts.map +1 -0
  535. package/dist/templates/markdown/index.js +52 -0
  536. package/dist/templates/markdown/index.js.map +1 -0
  537. package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
  538. package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
  539. package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
  540. package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
  541. package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
  542. package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
  543. package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
  544. package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
  545. package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
  546. package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
  547. package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
  548. package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
  549. package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
  550. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +223 -0
  551. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +290 -0
  552. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +634 -0
  553. package/dist/templates/markdown/spec/guides/index.md.txt +97 -0
  554. package/dist/templates/markdown/workspace-index.md +125 -0
  555. package/dist/templates/markdown/worktree.yaml.txt +58 -0
  556. package/dist/templates/omp/agents/atw-implement-agent.md +45 -0
  557. package/dist/templates/omp/agents/atw-review.md +41 -0
  558. package/dist/templates/omp/extensions/atw/index.ts.txt +1109 -0
  559. package/dist/templates/omp/index.d.ts +4 -0
  560. package/dist/templates/omp/index.d.ts.map +1 -0
  561. package/dist/templates/omp/index.js +9 -0
  562. package/dist/templates/omp/index.js.map +1 -0
  563. package/dist/templates/opencode/agents/atw-implement-agent.md +115 -0
  564. package/dist/templates/opencode/agents/atw-review.md +120 -0
  565. package/dist/templates/opencode/lib/atw-context.js +637 -0
  566. package/dist/templates/opencode/lib/context-visibility.js +148 -0
  567. package/dist/templates/opencode/lib/session-utils.js +474 -0
  568. package/dist/templates/opencode/package.json +6 -0
  569. package/dist/templates/opencode/plugins/inject-subagent-context.js +390 -0
  570. package/dist/templates/opencode/plugins/inject-workflow-state.js +240 -0
  571. package/dist/templates/opencode/plugins/session-start.js +65 -0
  572. package/dist/templates/pi/agents/atw-implement-agent.md +42 -0
  573. package/dist/templates/pi/agents/atw-review.md +37 -0
  574. package/dist/templates/pi/extensions/atw/index.ts.txt +2014 -0
  575. package/dist/templates/pi/index.d.ts +5 -0
  576. package/dist/templates/pi/index.d.ts.map +1 -0
  577. package/dist/templates/pi/index.js +12 -0
  578. package/dist/templates/pi/index.js.map +1 -0
  579. package/dist/templates/pi/settings.json +9 -0
  580. package/dist/templates/qoder/agents/atw-implement-agent.md +100 -0
  581. package/dist/templates/qoder/agents/atw-review.md +106 -0
  582. package/dist/templates/qoder/index.d.ts +15 -0
  583. package/dist/templates/qoder/index.d.ts.map +1 -0
  584. package/dist/templates/qoder/index.js +15 -0
  585. package/dist/templates/qoder/index.js.map +1 -0
  586. package/dist/templates/qoder/settings.json +59 -0
  587. package/dist/templates/reasonix/agents/atw-implement-agent.md +41 -0
  588. package/dist/templates/reasonix/agents/atw-review.md +36 -0
  589. package/dist/templates/reasonix/index.d.ts +13 -0
  590. package/dist/templates/reasonix/index.d.ts.map +1 -0
  591. package/dist/templates/reasonix/index.js +16 -0
  592. package/dist/templates/reasonix/index.js.map +1 -0
  593. package/dist/templates/shared-hooks/index.d.ts +77 -0
  594. package/dist/templates/shared-hooks/index.d.ts.map +1 -0
  595. package/dist/templates/shared-hooks/index.js +140 -0
  596. package/dist/templates/shared-hooks/index.js.map +1 -0
  597. package/dist/templates/shared-hooks/inject-shell-session-context.py +292 -0
  598. package/dist/templates/shared-hooks/inject-subagent-context.py +1178 -0
  599. package/dist/templates/shared-hooks/inject-workflow-state.py +488 -0
  600. package/dist/templates/shared-hooks/session-start.py +889 -0
  601. package/dist/templates/snow/SNOW.md +86 -0
  602. package/dist/templates/snow/agents/atw-implement-agent.md +152 -0
  603. package/dist/templates/snow/agents/atw-review.md +135 -0
  604. package/dist/templates/snow/hooks/beforeSubAgentStart.json +15 -0
  605. package/dist/templates/snow/hooks/onSessionStart.json +15 -0
  606. package/dist/templates/snow/hooks/onUserMessage.json +15 -0
  607. package/dist/templates/snow/hooks/write-atw-context.py +637 -0
  608. package/dist/templates/snow/index.d.ts +25 -0
  609. package/dist/templates/snow/index.d.ts.map +1 -0
  610. package/dist/templates/snow/index.js +35 -0
  611. package/dist/templates/snow/index.js.map +1 -0
  612. package/dist/templates/template-utils.d.ts +26 -0
  613. package/dist/templates/template-utils.d.ts.map +1 -0
  614. package/dist/templates/template-utils.js +64 -0
  615. package/dist/templates/template-utils.js.map +1 -0
  616. package/dist/templates/trae/agents/atw-implement-agent.md +100 -0
  617. package/dist/templates/trae/agents/atw-review.md +106 -0
  618. package/dist/templates/trae/hooks.json +39 -0
  619. package/dist/templates/trae/index.d.ts +15 -0
  620. package/dist/templates/trae/index.d.ts.map +1 -0
  621. package/dist/templates/trae/index.js +15 -0
  622. package/dist/templates/trae/index.js.map +1 -0
  623. package/dist/templates/zcode/agents/atw-implement-agent.md +108 -0
  624. package/dist/templates/zcode/agents/atw-review.md +109 -0
  625. package/dist/templates/zcode/config.json +52 -0
  626. package/dist/templates/zcode/index.d.ts +22 -0
  627. package/dist/templates/zcode/index.d.ts.map +1 -0
  628. package/dist/templates/zcode/index.js +26 -0
  629. package/dist/templates/zcode/index.js.map +1 -0
  630. package/dist/types/ai-tools.d.ts +95 -0
  631. package/dist/types/ai-tools.d.ts.map +1 -0
  632. package/dist/types/ai-tools.js +494 -0
  633. package/dist/types/ai-tools.js.map +1 -0
  634. package/dist/types/migration.d.ts +125 -0
  635. package/dist/types/migration.d.ts.map +1 -0
  636. package/dist/types/migration.js +8 -0
  637. package/dist/types/migration.js.map +1 -0
  638. package/dist/utils/ablation-store.d.ts +123 -0
  639. package/dist/utils/ablation-store.d.ts.map +1 -0
  640. package/dist/utils/ablation-store.js +749 -0
  641. package/dist/utils/ablation-store.js.map +1 -0
  642. package/dist/utils/agent-refs.d.ts +31 -0
  643. package/dist/utils/agent-refs.d.ts.map +1 -0
  644. package/dist/utils/agent-refs.js +63 -0
  645. package/dist/utils/agent-refs.js.map +1 -0
  646. package/dist/utils/atomic-write.d.ts +12 -0
  647. package/dist/utils/atomic-write.d.ts.map +1 -0
  648. package/dist/utils/atomic-write.js +30 -0
  649. package/dist/utils/atomic-write.js.map +1 -0
  650. package/dist/utils/compare-versions.d.ts +12 -0
  651. package/dist/utils/compare-versions.d.ts.map +1 -0
  652. package/dist/utils/compare-versions.js +86 -0
  653. package/dist/utils/compare-versions.js.map +1 -0
  654. package/dist/utils/cwd-guard.d.ts +38 -0
  655. package/dist/utils/cwd-guard.d.ts.map +1 -0
  656. package/dist/utils/cwd-guard.js +62 -0
  657. package/dist/utils/cwd-guard.js.map +1 -0
  658. package/dist/utils/file-writer.d.ts +36 -0
  659. package/dist/utils/file-writer.d.ts.map +1 -0
  660. package/dist/utils/file-writer.js +204 -0
  661. package/dist/utils/file-writer.js.map +1 -0
  662. package/dist/utils/managed-paths.d.ts +5 -0
  663. package/dist/utils/managed-paths.d.ts.map +1 -0
  664. package/dist/utils/managed-paths.js +51 -0
  665. package/dist/utils/managed-paths.js.map +1 -0
  666. package/dist/utils/managed-removal.d.ts +74 -0
  667. package/dist/utils/managed-removal.d.ts.map +1 -0
  668. package/dist/utils/managed-removal.js +270 -0
  669. package/dist/utils/managed-removal.js.map +1 -0
  670. package/dist/utils/manifest-prune.d.ts +61 -0
  671. package/dist/utils/manifest-prune.d.ts.map +1 -0
  672. package/dist/utils/manifest-prune.js +135 -0
  673. package/dist/utils/manifest-prune.js.map +1 -0
  674. package/dist/utils/posix.d.ts +13 -0
  675. package/dist/utils/posix.d.ts.map +1 -0
  676. package/dist/utils/posix.js +15 -0
  677. package/dist/utils/posix.js.map +1 -0
  678. package/dist/utils/project-detector.d.ts +46 -0
  679. package/dist/utils/project-detector.d.ts.map +1 -0
  680. package/dist/utils/project-detector.js +666 -0
  681. package/dist/utils/project-detector.js.map +1 -0
  682. package/dist/utils/proxy.d.ts +25 -0
  683. package/dist/utils/proxy.d.ts.map +1 -0
  684. package/dist/utils/proxy.js +60 -0
  685. package/dist/utils/proxy.js.map +1 -0
  686. package/dist/utils/registry-config.d.ts +7 -0
  687. package/dist/utils/registry-config.d.ts.map +1 -0
  688. package/dist/utils/registry-config.js +172 -0
  689. package/dist/utils/registry-config.js.map +1 -0
  690. package/dist/utils/task-json.d.ts +13 -0
  691. package/dist/utils/task-json.d.ts.map +1 -0
  692. package/dist/utils/task-json.js +12 -0
  693. package/dist/utils/task-json.js.map +1 -0
  694. package/dist/utils/template-fetcher.d.ts +161 -0
  695. package/dist/utils/template-fetcher.d.ts.map +1 -0
  696. package/dist/utils/template-fetcher.js +994 -0
  697. package/dist/utils/template-fetcher.js.map +1 -0
  698. package/dist/utils/template-hash.d.ts +127 -0
  699. package/dist/utils/template-hash.d.ts.map +1 -0
  700. package/dist/utils/template-hash.js +335 -0
  701. package/dist/utils/template-hash.js.map +1 -0
  702. package/dist/utils/uninstall-scrubbers.d.ts +66 -0
  703. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -0
  704. package/dist/utils/uninstall-scrubbers.js +417 -0
  705. package/dist/utils/uninstall-scrubbers.js.map +1 -0
  706. package/dist/utils/workflow-resolver.d.ts +86 -0
  707. package/dist/utils/workflow-resolver.d.ts.map +1 -0
  708. package/dist/utils/workflow-resolver.js +265 -0
  709. package/dist/utils/workflow-resolver.js.map +1 -0
  710. package/package.json +93 -0
@@ -0,0 +1,1178 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Multi-Platform Sub-Agent Context Injection Hook
5
+
6
+ Injects task-specific context when sub-agents (implement-agent, review) are spawned.
7
+
8
+ Core Design Philosophy:
9
+ - Hook is responsible for injecting all context, subagent works autonomously with complete info
10
+ - Each agent has a dedicated jsonl file defining its context
11
+ - No resume needed, no segmentation, behavior controlled by code not prompt
12
+
13
+ Trigger: PreToolUse (before Task tool call)
14
+
15
+ Context Source: ATW active task resolver points to task directory
16
+ - implement.jsonl - Implement agent dedicated context
17
+ - check.jsonl - Check agent dedicated context
18
+ - prd.md - Requirements document
19
+ - codex-review-output.txt - Code Review results
20
+ """
21
+ from __future__ import annotations
22
+
23
+ # IMPORTANT: Suppress all warnings FIRST
24
+ import warnings
25
+ warnings.filterwarnings("ignore")
26
+
27
+ import json
28
+ import os
29
+ import sys
30
+ from pathlib import Path
31
+ from typing import Any
32
+
33
+ # Hook hosts send UTF-8 JSON regardless of the process locale.
34
+ _stdin_reconfigure = getattr(sys.stdin, "reconfigure", None)
35
+ if callable(_stdin_reconfigure):
36
+ try:
37
+ _stdin_reconfigure(encoding="utf-8", errors="replace")
38
+ except (OSError, ValueError):
39
+ pass
40
+
41
+ # IMPORTANT: Force stdout to use UTF-8 on Windows
42
+ # This fixes UnicodeEncodeError when outputting non-ASCII characters
43
+ if sys.platform.startswith("win"):
44
+ import io as _io
45
+ if hasattr(sys.stdout, "reconfigure"):
46
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
47
+ elif hasattr(sys.stdout, "detach"):
48
+ sys.stdout = _io.TextIOWrapper(sys.stdout.detach(), encoding="utf-8", errors="replace") # type: ignore[union-attr]
49
+
50
+
51
+ # =============================================================================
52
+ # Path Constants (change here to rename directories)
53
+ # =============================================================================
54
+
55
+ DIR_WORKFLOW = ".atw"
56
+ DIR_SPEC = "spec"
57
+ FILE_TASK_JSON = "task.json"
58
+
59
+ # Implementation tickets. Ticket state lives in the ticket file itself, so the
60
+ # hook reads it directly rather than shelling out to tickets.py.
61
+ DIR_TICKETS = "issues"
62
+ TICKET_DOING = "**Impl:** doing"
63
+ TICKET_READY = "**Impl:** ready"
64
+ TICKET_BLOCKED_PREFIX = "**Blocked by:**"
65
+
66
+ # Contract literals, not prose — these two strings are what tells "said there
67
+ # is no current ticket" apart from "silently skipped the section", and what
68
+ # the host shows as the blocking reason. Reword only via PLAN.md.
69
+ NO_CURRENT_TICKET = "No ticket in progress"
70
+ MULTI_DOING_HEADLINE = "Multiple tickets marked doing"
71
+
72
+ # =============================================================================
73
+ # Subagent Constants (change here to rename subagent types)
74
+ # =============================================================================
75
+
76
+ AGENT_IMPLEMENT = "atw-implement-agent"
77
+ AGENT_REVIEW = "atw-review"
78
+
79
+ # Agents that require a task directory
80
+ AGENTS_REQUIRE_TASK = (AGENT_IMPLEMENT, AGENT_REVIEW)
81
+ # All supported agents. Platform sub-agent **type** names only — always
82
+ # prefixed. The unprefixed channel names (`review` / `implement-agent`, loaded
83
+ # by filename from `.atw/agents/<name>.md`) are a separate namespace on
84
+ # purpose; letting them in here would make "unifying" the two look harmless.
85
+ #
86
+ # `atw-research` was retired as a sub-agent. Its context path used to stay in
87
+ # place behind this whitelist — two call sites that could never be reached,
88
+ # because every caller filters on AGENTS_ALL first. Having callers is not the
89
+ # same as being reachable, and the caller count is what made it look live for a
90
+ # whole milestone. The path is gone now; the JS port in
91
+ # templates/opencode/plugins/ lost the same one.
92
+ AGENTS_ALL = (AGENT_IMPLEMENT, AGENT_REVIEW)
93
+
94
+
95
+ def find_repo_root(start_path: str) -> str | None:
96
+ """
97
+ Find git repo root from start_path upwards
98
+
99
+ Returns:
100
+ Repo root path, or None if not found
101
+ """
102
+ current = Path(start_path).resolve()
103
+ while current != current.parent:
104
+ if (current / ".git").exists():
105
+ return str(current)
106
+ current = current.parent
107
+ return None
108
+
109
+
110
+ def _detect_platform(input_data: dict) -> str | None:
111
+ if _hook_event_name(input_data) == "SubagentStart":
112
+ return "codex"
113
+ if isinstance(input_data.get("cursor_version"), str):
114
+ return "cursor"
115
+ # CLAUDE_PROJECT_DIR is a compatibility alias that several hosts set
116
+ # alongside their own variable — CodeBuddy, ZCode and Trae all do. It must
117
+ # therefore be checked LAST, or every one of them is detected as claude and
118
+ # the context key becomes `claude_<their-session-id>`. That key does not
119
+ # match the session file `task.py start` wrote under the host's real name,
120
+ # so the sub-agent starts with no task context while the pointer exists on
121
+ # disk. Same fix as inject-workflow-state.py and session-start.py; this
122
+ # third copy was missed when those two were corrected.
123
+ env_map = {
124
+ "ZCODE_PROJECT_DIR": "zcode",
125
+ "CURSOR_PROJECT_DIR": "cursor",
126
+ "CODEBUDDY_PROJECT_DIR": "codebuddy",
127
+ "FACTORY_PROJECT_DIR": "droid",
128
+ "GEMINI_PROJECT_DIR": "gemini",
129
+ "QODER_PROJECT_DIR": "qoder",
130
+ "KIRO_PROJECT_DIR": "kiro",
131
+ "COPILOT_PROJECT_DIR": "copilot",
132
+ "TRAE_PROJECT_DIR": "trae",
133
+ # Last: the shared alias, only meaningful once no vendor key matched.
134
+ "CLAUDE_PROJECT_DIR": "claude",
135
+ }
136
+ for env_name, platform in env_map.items():
137
+ if os.environ.get(env_name):
138
+ return platform
139
+ script_parts = set(Path(sys.argv[0]).parts)
140
+ if ".claude" in script_parts:
141
+ return "claude"
142
+ if ".cursor" in script_parts:
143
+ return "cursor"
144
+ if ".gemini" in script_parts:
145
+ return "gemini"
146
+ if ".qoder" in script_parts:
147
+ return "qoder"
148
+ if ".codebuddy" in script_parts:
149
+ return "codebuddy"
150
+ if ".factory" in script_parts:
151
+ return "droid"
152
+ if ".kiro" in script_parts:
153
+ return "kiro"
154
+ if ".zcode" in script_parts:
155
+ return "zcode"
156
+ return None
157
+
158
+
159
+ def get_current_task(
160
+ repo_root: str,
161
+ input_data: dict,
162
+ *,
163
+ platform: str | None = None,
164
+ allow_single_session_fallback: bool = True,
165
+ allow_environment_context: bool = True,
166
+ require_existing: bool = False,
167
+ ) -> str | None:
168
+ """Resolve current task directory through the unified active task resolver."""
169
+ scripts_dir = Path(repo_root) / DIR_WORKFLOW / "scripts"
170
+ if str(scripts_dir) not in sys.path:
171
+ sys.path.insert(0, str(scripts_dir))
172
+ try:
173
+ from common.active_task import resolve_active_task # type: ignore[import-not-found]
174
+ except Exception:
175
+ return None
176
+
177
+ active = resolve_active_task(
178
+ Path(repo_root),
179
+ input_data,
180
+ platform=platform or _detect_platform(input_data),
181
+ allow_single_session_fallback=allow_single_session_fallback,
182
+ allow_environment_context=allow_environment_context,
183
+ )
184
+ if require_existing and active.stale:
185
+ return None
186
+ return active.task_path
187
+
188
+
189
+ # =============================================================================
190
+ # Context Injection Limits
191
+ #
192
+ # Notice text and behavior mirrored byte-for-byte in the Pi TS extension
193
+ # (templates/pi/extensions/atw/index.ts.txt). Changing wording here
194
+ # requires changing it there too.
195
+ # =============================================================================
196
+
197
+ DEFAULT_MAX_FILE_BYTES = 32768
198
+ DEFAULT_MAX_ARTIFACT_BYTES = 65536
199
+ DEFAULT_MAX_TOTAL_BYTES = 131072
200
+
201
+ DEFAULT_LIMITS: dict[str, int] = {
202
+ "max_file_bytes": DEFAULT_MAX_FILE_BYTES,
203
+ "max_artifact_bytes": DEFAULT_MAX_ARTIFACT_BYTES,
204
+ "max_total_bytes": DEFAULT_MAX_TOTAL_BYTES,
205
+ }
206
+
207
+
208
+ def _get_limits(repo_root: str) -> dict[str, int]:
209
+ """Load context-injection byte limits from config.yaml, with safe fallback."""
210
+ scripts_dir = Path(repo_root) / DIR_WORKFLOW / "scripts"
211
+ if str(scripts_dir) not in sys.path:
212
+ sys.path.insert(0, str(scripts_dir))
213
+ try:
214
+ from common.config import get_context_injection_limits # type: ignore[import-not-found]
215
+
216
+ return get_context_injection_limits(Path(repo_root))
217
+ except Exception:
218
+ return dict(DEFAULT_LIMITS)
219
+
220
+
221
+ def truncate_utf8(data: bytes, cap: int) -> bytes:
222
+ """Truncate ``data`` to at most ``cap`` bytes without splitting a UTF-8
223
+ multi-byte sequence.
224
+
225
+ ``cap <= 0`` means "no limit" — returns ``data`` unchanged.
226
+ """
227
+ if cap <= 0 or len(data) <= cap:
228
+ return data
229
+
230
+ truncated = data[:cap]
231
+ i = len(truncated)
232
+ # Back off over continuation bytes (10xxxxxx) to find the lead byte.
233
+ while i > 0 and (truncated[i - 1] & 0xC0) == 0x80:
234
+ i -= 1
235
+ if i == 0:
236
+ return b""
237
+
238
+ lead = truncated[i - 1]
239
+ if lead & 0x80:
240
+ if (lead & 0xE0) == 0xC0:
241
+ seq_len = 2
242
+ elif (lead & 0xF0) == 0xE0:
243
+ seq_len = 3
244
+ elif (lead & 0xF8) == 0xF0:
245
+ seq_len = 4
246
+ else:
247
+ seq_len = 1
248
+ # Drop the lead byte too if its full sequence didn't fit.
249
+ if (i - 1) + seq_len > len(truncated):
250
+ i -= 1
251
+
252
+ return truncated[:i]
253
+
254
+
255
+ class _Budget:
256
+ """Tracks the running total of bytes emitted into the sub-agent context."""
257
+
258
+ def __init__(self, max_total_bytes: int) -> None:
259
+ self.max_total_bytes = max_total_bytes
260
+ self.used = 0
261
+
262
+ def has_room(self, size: int) -> bool:
263
+ if self.max_total_bytes <= 0:
264
+ return True
265
+ return self.used + size <= self.max_total_bytes
266
+
267
+ def add(self, size: int) -> None:
268
+ self.used += size
269
+
270
+
271
+ def _real_path_contained(base_real: str, target_real: str) -> bool:
272
+ """Whether an already-realpath'd target sits under an already-realpath'd base.
273
+
274
+ ValueError on Windows when the two sit on different drives; that is
275
+ outside the base by definition, so it fails closed.
276
+ """
277
+ try:
278
+ return os.path.commonpath([base_real, target_real]) == base_real
279
+ except ValueError:
280
+ return False
281
+
282
+
283
+ def _read_file_bytes(base_path: str, file_path: str) -> bytes | None:
284
+ """Read raw file bytes, return None if file doesn't exist."""
285
+ full_path = os.path.join(base_path, file_path)
286
+ try:
287
+ root_real = os.path.realpath(base_path)
288
+ # `.atw` may itself be a symlink into a store outside the repo
289
+ #; its real location is a second legitimate containment base.
290
+ workflow_real = os.path.realpath(os.path.join(base_path, ".atw"))
291
+ full_real = os.path.realpath(full_path)
292
+ if not _real_path_contained(root_real, full_real) and not (
293
+ _real_path_contained(workflow_real, full_real)
294
+ ):
295
+ return None
296
+ except OSError:
297
+ return None
298
+ if os.path.exists(full_path) and os.path.isfile(full_path):
299
+ try:
300
+ with open(full_path, "rb") as f:
301
+ return f.read()
302
+ except Exception:
303
+ return None
304
+ return None
305
+
306
+
307
+ def _truncate_notice(path: str, cap: int) -> str:
308
+ return f"\n[ATW: truncated at {cap} bytes — read {path} for the full content]"
309
+
310
+
311
+ def _is_binary_content(data: bytes) -> bool:
312
+ """Return True when raw bytes should not be decoded into model context."""
313
+ if b"\x00" in data:
314
+ return True
315
+ try:
316
+ data.decode("utf-8", errors="strict")
317
+ except UnicodeDecodeError:
318
+ return True
319
+ return False
320
+
321
+
322
+ def _binary_notice(path: str, size: int, reason: str) -> str:
323
+ return (
324
+ f"[ATW: not inlined (binary file) — "
325
+ f"{path} ({size} bytes): {reason}]"
326
+ )
327
+
328
+
329
+ def _index_notice(path: str, size: int, reason: str) -> str:
330
+ return (
331
+ f"[ATW: not inlined (total context limit reached) — "
332
+ f"{path} ({size} bytes): {reason}]"
333
+ )
334
+
335
+
336
+ def _budgeted_block(
337
+ budget: _Budget,
338
+ header: str,
339
+ plain_path: str,
340
+ content: str,
341
+ reason: str,
342
+ size_for_index: int,
343
+ ) -> str:
344
+ """Return an inlined ``=== header ===`` block, or degrade to an index
345
+ notice once the total context budget is exhausted."""
346
+ block = f"=== {header} ===\n{content}"
347
+ block_bytes = len(block.encode("utf-8"))
348
+ if not budget.has_room(block_bytes):
349
+ notice = _index_notice(plain_path, size_for_index, reason)
350
+ budget.add(len(notice.encode("utf-8")))
351
+ return notice
352
+ budget.add(block_bytes)
353
+ return block
354
+
355
+
356
+ def _materialize_file(
357
+ base_path: str,
358
+ file_path: str,
359
+ reason: str,
360
+ limits: dict[str, int],
361
+ budget: _Budget,
362
+ ) -> str | None:
363
+ """Read a JSONL-referenced file, apply the per-file cap, then budget it."""
364
+ data = _read_file_bytes(base_path, file_path)
365
+ if data is None:
366
+ return None
367
+
368
+ size = len(data)
369
+ if _is_binary_content(data):
370
+ notice = _binary_notice(file_path, size, reason)
371
+ budget.add(len(notice.encode("utf-8")))
372
+ return notice
373
+
374
+ cap = limits["max_file_bytes"]
375
+ truncated_bytes = truncate_utf8(data, cap)
376
+ content = truncated_bytes.decode("utf-8", errors="replace")
377
+ if len(truncated_bytes) < size:
378
+ content += _truncate_notice(file_path, cap)
379
+
380
+ return _budgeted_block(budget, file_path, file_path, content, reason, size)
381
+
382
+
383
+ def _materialize_directory(
384
+ base_path: str,
385
+ dir_path: str,
386
+ reason: str,
387
+ limits: dict[str, int],
388
+ budget: _Budget,
389
+ max_files: int = 20,
390
+ ) -> list[str]:
391
+ """Read all .md files in a directory, applying the same per-file and
392
+ total caps as a single-file JSONL entry."""
393
+ full_path = os.path.join(base_path, dir_path)
394
+ if not os.path.exists(full_path) or not os.path.isdir(full_path):
395
+ return []
396
+
397
+ blocks: list[str] = []
398
+ try:
399
+ md_files = sorted(
400
+ f
401
+ for f in os.listdir(full_path)
402
+ if f.endswith(".md") and os.path.isfile(os.path.join(full_path, f))
403
+ )
404
+ for filename in md_files[:max_files]:
405
+ relative_path = os.path.join(dir_path, filename)
406
+ block = _materialize_file(base_path, relative_path, reason, limits, budget)
407
+ if block:
408
+ blocks.append(block)
409
+ except Exception:
410
+ pass
411
+
412
+ return blocks
413
+
414
+
415
+ def read_jsonl_entries(base_path: str, jsonl_path: str) -> list[dict]:
416
+ """
417
+ Parse all file/directory entries referenced in a jsonl context file.
418
+
419
+ Schema:
420
+ {"file": "path/to/file.md", "reason": "..."}
421
+ {"file": "path/to/dir/", "type": "directory", "reason": "..."}
422
+ {"_example": "..."} # legacy placeholder — skipped (no `file` field)
423
+
424
+ Rows without a ``file`` field (e.g. the placeholder line older ATW
425
+ versions wrote at ``task.py create`` time) are skipped silently. If the
426
+ resulting entry list is empty, a stderr warning is emitted so the operator
427
+ can debug missing context.
428
+
429
+ Returns:
430
+ [{"file": path, "type": "file" | "directory", "reason": reason}, ...]
431
+ """
432
+ full_path = os.path.join(base_path, jsonl_path)
433
+ if not os.path.exists(full_path):
434
+ print(
435
+ f"[inject-subagent-context] WARN: {jsonl_path} not found — "
436
+ f"sub-agent will receive only task artifacts",
437
+ file=sys.stderr,
438
+ )
439
+ return []
440
+
441
+ entries: list[dict] = []
442
+ saw_real_entry = False
443
+ try:
444
+ with open(full_path, "r", encoding="utf-8") as f:
445
+ for line in f:
446
+ line = line.strip()
447
+ if not line:
448
+ continue
449
+ try:
450
+ item = json.loads(line)
451
+ file_path = item.get("file") or item.get("path")
452
+
453
+ if not file_path:
454
+ # Seed / comment row — skip silently
455
+ continue
456
+
457
+ saw_real_entry = True
458
+ entries.append(
459
+ {
460
+ "file": file_path,
461
+ "type": item.get("type", "file"),
462
+ "reason": item.get("reason") or "-",
463
+ }
464
+ )
465
+ except json.JSONDecodeError:
466
+ continue
467
+ except Exception:
468
+ pass
469
+
470
+ if not saw_real_entry:
471
+ print(
472
+ f"[inject-subagent-context] WARN: {jsonl_path} has no curated "
473
+ f"entries (only seed / empty) — sub-agent will receive only "
474
+ f"task artifacts. See workflow.md planning artifact guidance.",
475
+ file=sys.stderr,
476
+ )
477
+
478
+ return entries
479
+
480
+
481
+ def _materialize_jsonl_entries(
482
+ base_path: str, jsonl_path: str, limits: dict[str, int], budget: _Budget
483
+ ) -> list[str]:
484
+ """Materialize every entry in a jsonl context file into context blocks,
485
+ applying per-file and total budget caps."""
486
+ blocks: list[str] = []
487
+ for entry in read_jsonl_entries(base_path, jsonl_path):
488
+ if entry["type"] == "directory":
489
+ blocks.extend(
490
+ _materialize_directory(
491
+ base_path, entry["file"], entry["reason"], limits, budget
492
+ )
493
+ )
494
+ else:
495
+ block = _materialize_file(
496
+ base_path, entry["file"], entry["reason"], limits, budget
497
+ )
498
+ if block:
499
+ blocks.append(block)
500
+ return blocks
501
+
502
+
503
+ def get_agent_context(
504
+ repo_root: str,
505
+ task_dir: str,
506
+ agent_type: str,
507
+ limits: dict[str, int],
508
+ budget: _Budget,
509
+ ) -> str:
510
+ """
511
+ Get context from {agent_type}.jsonl for the specified agent.
512
+ Only reads implement.jsonl or check.jsonl (the two JSONL files the task system creates).
513
+ """
514
+ agent_jsonl = f"{task_dir}/{agent_type}.jsonl"
515
+ blocks = _materialize_jsonl_entries(repo_root, agent_jsonl, limits, budget)
516
+ if not blocks:
517
+ # Zero curated context reaches the model silently otherwise — the
518
+ # stderr WARN above never enters any session. Put the fact in
519
+ # the prompt itself so the sub-agent compensates instead of assuming
520
+ # the spec context was complete.
521
+ return (
522
+ f"[ATW] {agent_jsonl} has no curated entries, so no spec/research "
523
+ "context was injected. Before working, read the guidelines relevant "
524
+ "to the code you will touch under .atw/spec/, and treat the task "
525
+ "artifacts below as the only prepared context."
526
+ )
527
+ return "\n\n".join(blocks)
528
+
529
+
530
+ def _materialize_artifact(
531
+ base_path: str,
532
+ file_path: str,
533
+ header_label: str,
534
+ reason: str,
535
+ limits: dict[str, int],
536
+ budget: _Budget,
537
+ ) -> str | None:
538
+ """Read a task artifact (`prd.md`), apply the per-artifact cap, then
539
+ budget it."""
540
+ data = _read_file_bytes(base_path, file_path)
541
+ if data is None:
542
+ return None
543
+
544
+ size = len(data)
545
+ cap = limits["max_artifact_bytes"]
546
+ truncated_bytes = truncate_utf8(data, cap)
547
+ content = truncated_bytes.decode("utf-8", errors="replace")
548
+ if len(truncated_bytes) < size:
549
+ content += _truncate_notice(file_path, cap)
550
+
551
+ return _budgeted_block(budget, header_label, file_path, content, reason, size)
552
+
553
+
554
+ class MultipleTicketsDoing(Exception):
555
+ """More than one ticket claims ``**Impl:** doing``.
556
+
557
+ Picking the first one would silently inject the wrong ticket, so the hook
558
+ refuses to choose. The two callers surface this differently because the
559
+ host treats exit codes differently per event — see main() and
560
+ _handle_codex_subagent_start().
561
+ """
562
+
563
+ def __init__(self, tickets: list[str]) -> None:
564
+ self.tickets = tickets
565
+ listed = "\n".join(f" - {t}" for t in tickets)
566
+ super().__init__(
567
+ f"{MULTI_DOING_HEADLINE} — the hook cannot pick a current ticket:\n"
568
+ f"{listed}\n"
569
+ f"Set all but one back to `{TICKET_READY}`, then retry."
570
+ )
571
+
572
+
573
+ def _blocked_by_clear(text: str) -> bool:
574
+ """Whether a ticket's ``**Blocked by:**`` field is cleared (or absent)."""
575
+ for line in text.splitlines():
576
+ stripped = line.strip()
577
+ if stripped.startswith(TICKET_BLOCKED_PREFIX):
578
+ return stripped[len(TICKET_BLOCKED_PREFIX):].strip().lower() in ("", "none")
579
+ return True
580
+
581
+
582
+ def _ticket_title(text: str, fallback: str) -> str:
583
+ for line in text.splitlines():
584
+ if line.startswith("#"):
585
+ return line.lstrip("#").strip()
586
+ return fallback
587
+
588
+
589
+ def scan_tickets(repo_root: str, task_dir: str) -> tuple[list[str], list[tuple[str, str]]]:
590
+ """Split ``<task_dir>/issues/*.md`` into (doing paths, frontier summaries).
591
+
592
+ Frontier = the remaining ``ready`` tickets whose blockers are cleared.
593
+ """
594
+ issues_dir = Path(repo_root) / task_dir / DIR_TICKETS
595
+ doing: list[str] = []
596
+ frontier: list[tuple[str, str]] = []
597
+ if not issues_dir.is_dir():
598
+ return doing, frontier
599
+ for ticket in sorted(issues_dir.glob("*.md")):
600
+ rel = f"{task_dir}/{DIR_TICKETS}/{ticket.name}"
601
+ try:
602
+ text = ticket.read_text(encoding="utf-8", errors="replace")
603
+ except OSError:
604
+ continue
605
+ if TICKET_DOING in text:
606
+ doing.append(rel)
607
+ elif TICKET_READY in text and _blocked_by_clear(text):
608
+ frontier.append((rel, _ticket_title(text, ticket.name)))
609
+ return doing, frontier
610
+
611
+
612
+ def ticket_conflict_notice(repo_root: str, task_dir: str) -> str:
613
+ """One-line warning for agents that do not consume the ticket axis.
614
+
615
+ The implement agent neither reads nor writes ``**Impl:**`` — the only writer
616
+ is ``tickets.py set_impl``, driven by the main session. A contradiction it
617
+ cannot deepen is not worth blocking a spawn over, and the misjudgement is
618
+ asymmetric: one false multi-doing reading would stall implementation for a
619
+ reason unrelated to implementation. So it starts, and it is told. Count
620
+ only; no ticket content crosses this path while the state is broken.
621
+ """
622
+ doing, _ = scan_tickets(repo_root, task_dir)
623
+ if len(doing) < 2:
624
+ return ""
625
+ return (
626
+ f"=== Ticket State ===\n"
627
+ f"{MULTI_DOING_HEADLINE}: {len(doing)} tickets are marked "
628
+ f"`{TICKET_DOING}`. The ticket state contradicts itself, so no ticket "
629
+ f"content is injected this turn. Resolve it before relying on any "
630
+ f"ticket-derived state."
631
+ )
632
+
633
+
634
+ def get_ticket_context(
635
+ repo_root: str,
636
+ task_dir: str,
637
+ limits: dict[str, int],
638
+ budget: _Budget,
639
+ ) -> str:
640
+ """Current ticket in full + frontier summary, injected every round.
641
+
642
+ Raises MultipleTicketsDoing when the ticket state contradicts itself.
643
+ """
644
+ doing, frontier = scan_tickets(repo_root, task_dir)
645
+ if len(doing) > 1:
646
+ raise MultipleTicketsDoing(doing)
647
+
648
+ if doing:
649
+ current = _materialize_artifact(
650
+ repo_root,
651
+ doing[0],
652
+ f"{doing[0]} (Current Ticket)",
653
+ "Current ticket",
654
+ limits,
655
+ budget,
656
+ ) or f"=== {doing[0]} (Current Ticket) ===\n[ATW: ticket unreadable]"
657
+ else:
658
+ # Not budgeted on purpose: saying so is the whole point of this branch,
659
+ # and a byte cap must never be what makes it disappear.
660
+ current = f"=== Current Ticket ===\n{NO_CURRENT_TICKET}"
661
+
662
+ listed = "\n".join(f"- {rel} — {title}" for rel, title in frontier) or "(none)"
663
+ summary = _budgeted_block(
664
+ budget,
665
+ "Frontier (ready tickets)",
666
+ f"{task_dir}/{DIR_TICKETS}/",
667
+ listed,
668
+ "Ready tickets with blockers cleared",
669
+ len(listed.encode("utf-8")),
670
+ )
671
+ return f"{current}\n\n{summary}"
672
+
673
+
674
+ def get_implement_context(repo_root: str, task_dir: str) -> str:
675
+ """
676
+ Complete context for Implement Agent
677
+
678
+ Read order:
679
+ 1. All files in implement.jsonl (spec/research manifests)
680
+ 2. prd.md (requirements)
681
+
682
+ `design.md` and `implement.md` are gone (D32/C23): the spec skills produce
683
+ the design and tickets replaced the execution plan, so nothing writes them
684
+ any more. Materializing them anyway is not harmless tolerance — it is the
685
+ reason the retirement never actually landed: as long as a reader still
686
+ reaches for them, "cut" is only a claim about the writer.
687
+
688
+ The ticket sections live on the review path only: the current ticket is what
689
+ the Spec axis reviews against, and it is `check.jsonl` that carries its path.
690
+ A self-contradicting ticket state still gets announced here — see
691
+ `ticket_conflict_notice`.
692
+ """
693
+ limits = _get_limits(repo_root)
694
+ budget = _Budget(limits["max_total_bytes"])
695
+ context_parts = []
696
+
697
+ # 0. Broken ticket state is stated up front, never silently skipped
698
+ notice = ticket_conflict_notice(repo_root, task_dir)
699
+ if notice:
700
+ context_parts.append(notice)
701
+
702
+ # 1. Read implement.jsonl
703
+ base_context = get_agent_context(repo_root, task_dir, "implement", limits, budget)
704
+ if base_context:
705
+ context_parts.append(base_context)
706
+
707
+ # 2. Requirements document
708
+ prd_block = _materialize_artifact(
709
+ repo_root,
710
+ f"{task_dir}/prd.md",
711
+ f"{task_dir}/prd.md (Requirements)",
712
+ "Requirements document",
713
+ limits,
714
+ budget,
715
+ )
716
+ if prd_block:
717
+ context_parts.append(prd_block)
718
+
719
+ return "\n\n".join(context_parts)
720
+
721
+
722
+ def get_check_context(repo_root: str, task_dir: str) -> str:
723
+ """
724
+ Context for the review agent: check.jsonl + task artifacts + current ticket.
725
+
726
+ Name kept as ``check`` to match ``check.jsonl`` (C6: the jsonl is named
727
+ after the role, not after the sub-agent type).
728
+ """
729
+ limits = _get_limits(repo_root)
730
+ budget = _Budget(limits["max_total_bytes"])
731
+ context_parts = []
732
+
733
+ base_context = get_agent_context(repo_root, task_dir, "check", limits, budget)
734
+ if base_context:
735
+ context_parts.append(base_context)
736
+
737
+ prd_block = _materialize_artifact(
738
+ repo_root,
739
+ f"{task_dir}/prd.md",
740
+ f"{task_dir}/prd.md (Requirements)",
741
+ "Requirements document",
742
+ limits,
743
+ budget,
744
+ )
745
+ if prd_block:
746
+ context_parts.append(prd_block)
747
+
748
+ context_parts.append(get_ticket_context(repo_root, task_dir, limits, budget))
749
+
750
+ # `design.md` / `implement.md` are not read here either — same reason as in
751
+ # get_implement_context: both axes reach the model prompt through this file,
752
+ # so leaving one of them reaching for a retired artifact would keep D32 from
753
+ # landing on that half.
754
+ return "\n\n".join(context_parts)
755
+
756
+
757
+ def build_implement_prompt(original_prompt: str, context: str) -> str:
758
+ """Build complete prompt for Implement"""
759
+ return f"""<!-- atw-hook-injected -->
760
+ # Implement Agent Task
761
+
762
+ You are the Implement Agent in the Multi-Agent Pipeline.
763
+
764
+ ## Your Context
765
+
766
+ All the information you need has been prepared for you:
767
+
768
+ {context}
769
+
770
+ ---
771
+
772
+ ## Your Task
773
+
774
+ {original_prompt}
775
+
776
+ ---
777
+
778
+ ## Workflow
779
+
780
+ 1. **Understand specs** - All dev specs are injected above, understand them
781
+ 2. **Understand task artifacts** - Read requirements, technical design if present, and execution plan if present
782
+ 3. **Implement feature** - Implement following specs and task artifacts
783
+ 4. **Self-check** - Ensure code quality against check specs
784
+
785
+ ## Important Constraints
786
+
787
+ - Do NOT execute git commit, only code modifications
788
+ - Follow all dev specs injected above
789
+ - Report list of modified/created files when done"""
790
+
791
+
792
+ def build_check_prompt(original_prompt: str, context: str) -> str:
793
+ """Build complete prompt for Check"""
794
+ return f"""<!-- atw-hook-injected -->
795
+ # Check Agent Task
796
+
797
+ You are the Check Agent in the Multi-Agent Pipeline (code and cross-layer checker).
798
+
799
+ ## Your Context
800
+
801
+ All check specs and dev specs you need:
802
+
803
+ {context}
804
+
805
+ ---
806
+
807
+ ## Your Task
808
+
809
+ {original_prompt}
810
+
811
+ ---
812
+
813
+ ## Workflow
814
+
815
+ 1. **Get changes** - Run `git diff --name-only` and `git diff` to get code changes
816
+ 2. **Check against specs** - Check item by item against specs above
817
+ 3. **Self-fix** - Fix issues directly, don't just report
818
+ 4. **Run verification** - Run project's lint and typecheck commands
819
+
820
+ ## Important Constraints
821
+
822
+ - Fix issues yourself, don't just report
823
+ - Must execute complete checklist in check specs
824
+ - Pay special attention to impact radius analysis (L1-L5)"""
825
+
826
+
827
+ def _string_value(value: Any) -> str:
828
+ if isinstance(value, str):
829
+ stripped = value.strip()
830
+ return stripped
831
+ return ""
832
+
833
+
834
+ def _hook_event_name(input_data: dict) -> str:
835
+ """Return a hook event name from the documented snake/camel-case fields."""
836
+ return _string_value(
837
+ input_data.get("hook_event_name") or input_data.get("hookEventName")
838
+ )
839
+
840
+
841
+ def _codex_subagent_type(input_data: dict) -> str:
842
+ """Return an ATW Codex agent type only for a native start event."""
843
+ if _hook_event_name(input_data) != "SubagentStart":
844
+ return ""
845
+ agent_type = _string_value(
846
+ input_data.get("agent_type") or input_data.get("agentType")
847
+ )
848
+ return agent_type if agent_type in AGENTS_ALL else ""
849
+
850
+
851
+ def build_codex_subagent_context(
852
+ subagent_type: str,
853
+ task_dir: str,
854
+ context: str,
855
+ ) -> str:
856
+ """Build developer context for a native, already-dispatched Codex role."""
857
+ role = subagent_type.removeprefix("atw-")
858
+ return f"""<!-- atw-hook-injected -->
859
+ # ATW Native {role.title()} Subagent
860
+
861
+ You are the dispatched `{subagent_type}` role for this task. Perform that role
862
+ directly; do not follow main-session dispatch or wait instructions, and do not
863
+ spawn another ATW subagent.
864
+
865
+ Active task: {task_dir}
866
+
867
+ ## Curated Context
868
+
869
+ {context}"""
870
+
871
+
872
+ def _handle_codex_subagent_start(input_data: dict) -> None:
873
+ """Emit Codex developer context for a recognised native ATW subagent.
874
+
875
+ The event supplies the parent session id. Disabling the generic
876
+ single-session fallback is essential here: native starts must never borrow
877
+ a task from another Codex window when that parent id is absent or stale.
878
+ """
879
+ subagent_type = _codex_subagent_type(input_data)
880
+ parent_session_id = _string_value(input_data.get("session_id"))
881
+ if not subagent_type or not parent_session_id:
882
+ return
883
+
884
+ # Payload cwd first, then our own — some hosts (CodeBuddy IDE 4.10.4)
885
+ # report "/" for every hook event. See inject-workflow-state.py.
886
+ repo_root = None
887
+ for candidate in (_string_value(input_data.get("cwd")), os.getcwd()):
888
+ if not candidate:
889
+ continue
890
+ repo_root = find_repo_root(candidate)
891
+ if repo_root:
892
+ break
893
+ if not repo_root:
894
+ return
895
+
896
+ task_dir = get_current_task(
897
+ repo_root,
898
+ {"session_id": parent_session_id},
899
+ platform="codex",
900
+ allow_single_session_fallback=False,
901
+ allow_environment_context=False,
902
+ require_existing=True,
903
+ )
904
+ if not task_dir:
905
+ return
906
+
907
+ if subagent_type in AGENTS_REQUIRE_TASK:
908
+ task_dir_full = Path(repo_root) / task_dir
909
+ if not task_dir_full.is_dir():
910
+ return
911
+
912
+ try:
913
+ if subagent_type == AGENT_IMPLEMENT:
914
+ context = get_implement_context(repo_root, task_dir)
915
+ elif subagent_type == AGENT_REVIEW:
916
+ context = get_check_context(repo_root, task_dir)
917
+ else:
918
+ # `_codex_subagent_type` already filtered on AGENTS_ALL, so no other
919
+ # value can arrive here. Return rather than invent a context.
920
+ return
921
+ except MultipleTicketsDoing as conflict:
922
+ # This event has no blocking channel. A non-zero exit here renders only
923
+ # as a `<hook> hook error` line in the child's own transcript: Claude
924
+ # never sees it and the child starts anyway — worse than silence,
925
+ # because it looks like a normal start. additionalContext is the only
926
+ # channel that reaches the agent, so state the conflict there, ship no
927
+ # ticket content, and exit 0.
928
+ context = str(conflict)
929
+
930
+ if not context:
931
+ return
932
+
933
+ output = {
934
+ "hookSpecificOutput": {
935
+ "hookEventName": "SubagentStart",
936
+ "additionalContext": build_codex_subagent_context(
937
+ subagent_type, task_dir, context
938
+ ),
939
+ }
940
+ }
941
+ print(json.dumps(output, ensure_ascii=False))
942
+
943
+
944
+ def _extract_subagent_name(value: Any) -> str:
945
+ """Extract a sub-agent name from common platform encodings.
946
+
947
+ Cursor's native Task args encode custom sub-agents as a protobuf oneof,
948
+ which can appear in hook JSON as either ``{"custom": {"name": "..."}}``
949
+ or ``{"type": {"case": "custom", "value": {"name": "..."}}}``.
950
+ """
951
+ direct = _string_value(value)
952
+ if direct:
953
+ return direct
954
+
955
+ if not isinstance(value, dict):
956
+ return ""
957
+
958
+ for key in ("name", "subagent_type_name", "subagentTypeName"):
959
+ direct = _string_value(value.get(key))
960
+ if direct:
961
+ return direct
962
+
963
+ custom = value.get("custom")
964
+ if isinstance(custom, dict):
965
+ custom_name = _string_value(custom.get("name"))
966
+ if custom_name:
967
+ return custom_name
968
+
969
+ oneof = value.get("type")
970
+ if isinstance(oneof, dict):
971
+ case_name = _string_value(oneof.get("case"))
972
+ if case_name == "custom":
973
+ nested_value = oneof.get("value")
974
+ if isinstance(nested_value, dict):
975
+ custom_name = _string_value(nested_value.get("name"))
976
+ if custom_name:
977
+ return custom_name
978
+ if case_name:
979
+ return case_name
980
+
981
+ case_name = _string_value(value.get("case"))
982
+ if case_name == "custom":
983
+ nested_value = value.get("value")
984
+ if isinstance(nested_value, dict):
985
+ custom_name = _string_value(nested_value.get("name"))
986
+ if custom_name:
987
+ return custom_name
988
+ if case_name:
989
+ return case_name
990
+
991
+ for agent_name in AGENTS_ALL:
992
+ if agent_name in value:
993
+ return agent_name
994
+
995
+ return ""
996
+
997
+
998
+ def _extract_subagent_type(tool_input: dict) -> str:
999
+ for key in (
1000
+ "subagent_type",
1001
+ "subagentType",
1002
+ "subagent_type_name",
1003
+ "subagentTypeName",
1004
+ "subagent_name",
1005
+ "subagentName",
1006
+ "agent_type",
1007
+ "agentType",
1008
+ "name",
1009
+ ):
1010
+ agent_name = _extract_subagent_name(tool_input.get(key))
1011
+ if agent_name:
1012
+ return agent_name
1013
+ return ""
1014
+
1015
+
1016
+ def _parse_hook_input(input_data: dict) -> tuple[str, str, dict]:
1017
+ """Parse hook input across different platform formats.
1018
+
1019
+ Returns (subagent_type, original_prompt, tool_input).
1020
+ Handles:
1021
+ - Claude Code / Qoder / Droid: tool_name=Task|Agent, tool_input.subagent_type
1022
+ - CodeBuddy: tool_name=task (IDE) or Task (CLI), tool_input.subagent_name
1023
+ - Cursor: tool_name=Task|Subagent, tool_input.subagent_type
1024
+ - Copilot CLI: toolName=task (camelCase key, lowercase value)
1025
+ - ZCode: toolName=Agent, toolInput/tool_input.subagent_type
1026
+ - Gemini CLI: tool_name IS the agent name (BeforeTool matcher already filtered)
1027
+ - Kiro: agentSpawn hook, agent_name field at top level
1028
+ """
1029
+ tool_input = input_data.get("tool_input", {})
1030
+ if not isinstance(tool_input, dict):
1031
+ tool_input = input_data.get("toolInput", {})
1032
+ if not isinstance(tool_input, dict):
1033
+ tool_input = {}
1034
+
1035
+ # Standard format: Task/Agent tool with subagent_type
1036
+ tool_name = input_data.get("tool_name", "") or input_data.get("toolName", "")
1037
+ if tool_name.lower() in ("task", "agent", "subagent"):
1038
+ return (
1039
+ _extract_subagent_type(tool_input),
1040
+ tool_input.get("prompt", ""),
1041
+ tool_input,
1042
+ )
1043
+
1044
+ # Kiro: agentSpawn hook passes agent_name at top level
1045
+ agent_name = input_data.get("agent_name", "")
1046
+ if agent_name:
1047
+ return agent_name, tool_input.get("prompt", input_data.get("prompt", "")), tool_input
1048
+
1049
+ # Gemini CLI: BeforeTool where tool_name IS the agent name
1050
+ # (matcher already ensured it's one of our agents)
1051
+ if tool_name in AGENTS_ALL:
1052
+ return tool_name, tool_input.get("prompt", ""), tool_input
1053
+
1054
+ # Copilot CLI: toolName field (camelCase), value might be the agent name
1055
+ tool_name_camel = input_data.get("toolName", "")
1056
+ if tool_name_camel in AGENTS_ALL:
1057
+ return tool_name_camel, input_data.get("toolArgs", ""), tool_input
1058
+
1059
+ return "", "", tool_input
1060
+
1061
+
1062
+ def main():
1063
+ if os.environ.get("ATW_HOOKS") == "0" or os.environ.get("ATW_DISABLE_HOOKS") == "1":
1064
+ sys.exit(0)
1065
+
1066
+ try:
1067
+ input_data = json.load(sys.stdin)
1068
+ except json.JSONDecodeError:
1069
+ sys.exit(0)
1070
+ if not isinstance(input_data, dict):
1071
+ sys.exit(0)
1072
+
1073
+ if _hook_event_name(input_data) == "SubagentStart":
1074
+ try:
1075
+ _handle_codex_subagent_start(input_data)
1076
+ except Exception:
1077
+ # A native context hook must never prevent Codex from spawning the
1078
+ # requested child when its runtime state is unavailable or stale.
1079
+ pass
1080
+ sys.exit(0)
1081
+
1082
+ subagent_type, original_prompt, tool_input = _parse_hook_input(input_data)
1083
+ cwd = input_data.get("cwd", os.getcwd())
1084
+
1085
+ # Only handle subagent types we care about
1086
+ if subagent_type not in AGENTS_ALL:
1087
+ sys.exit(0)
1088
+
1089
+ # Find repo root
1090
+ repo_root = find_repo_root(cwd)
1091
+ if not repo_root:
1092
+ sys.exit(0)
1093
+
1094
+ # Get current task directory. May be None here — the AGENTS_REQUIRE_TASK
1095
+ # check below is what refuses to continue without one.
1096
+ task_dir = get_current_task(repo_root, input_data)
1097
+
1098
+ # implement/check need task directory
1099
+ if subagent_type in AGENTS_REQUIRE_TASK:
1100
+ if not task_dir:
1101
+ sys.exit(0)
1102
+ # Contain the pointer before reading anything through it. `task.py` now
1103
+ # refuses to store a ref that leaves the repo, but a session file
1104
+ # written before that fix can still hold one, and `atw update`
1105
+ # does not rewrite session files — so a poisoned pointer outlives the
1106
+ # upgrade that closed the writer. This is the last hop before the
1107
+ # task's prd.md reaches the model prompt, so it checks again.
1108
+ try:
1109
+ root_real = os.path.realpath(repo_root)
1110
+ # `.atw` may itself be a symlink into a store outside the
1111
+ # repo; its real location is a second legitimate base.
1112
+ workflow_real = os.path.realpath(os.path.join(repo_root, ".atw"))
1113
+ task_dir_full = os.path.realpath(os.path.join(repo_root, task_dir))
1114
+ if not _real_path_contained(root_real, task_dir_full) and not (
1115
+ _real_path_contained(workflow_real, task_dir_full)
1116
+ ):
1117
+ sys.exit(0)
1118
+ except OSError:
1119
+ sys.exit(0)
1120
+ if not os.path.exists(task_dir_full):
1121
+ sys.exit(0)
1122
+
1123
+ # Get context and build prompt based on subagent type
1124
+ try:
1125
+ if subagent_type == AGENT_IMPLEMENT:
1126
+ assert task_dir is not None # validated above
1127
+ context = get_implement_context(repo_root, task_dir)
1128
+ new_prompt = build_implement_prompt(original_prompt, context)
1129
+ elif subagent_type == AGENT_REVIEW:
1130
+ assert task_dir is not None # validated above
1131
+ context = get_check_context(repo_root, task_dir)
1132
+ new_prompt = build_check_prompt(original_prompt, context)
1133
+ else:
1134
+ sys.exit(0)
1135
+ except MultipleTicketsDoing as conflict:
1136
+ # Exit code 2 is the only code that makes the host block the Task call,
1137
+ # and on this event stderr *is* the blocking reason shown to the user.
1138
+ # 1 or any other non-zero is a non-blocking error: the message is shown
1139
+ # but execution continues, so the sub-agent starts with no injection.
1140
+ print(str(conflict), file=sys.stderr)
1141
+ sys.exit(2)
1142
+
1143
+ if not context:
1144
+ sys.exit(0)
1145
+
1146
+ # Return updated input. Most platforms ignore unrecognized fields, so we
1147
+ # include multiple formats. ZCode is stricter; live probing confirmed the
1148
+ # nested Claude-compatible shape below reaches the sub-agent prompt.
1149
+ updated = {**tool_input, "prompt": new_prompt}
1150
+ if _detect_platform(input_data) == "zcode":
1151
+ output = {
1152
+ "hookSpecificOutput": {
1153
+ "hookEventName": "PreToolUse",
1154
+ "permissionDecision": "allow",
1155
+ "updatedInput": updated,
1156
+ }
1157
+ }
1158
+ else:
1159
+ output = {
1160
+ # Claude Code / Qoder / CodeBuddy / Droid format
1161
+ "hookSpecificOutput": {
1162
+ "hookEventName": "PreToolUse",
1163
+ "permissionDecision": "allow",
1164
+ "updatedInput": updated,
1165
+ },
1166
+ # Cursor format
1167
+ "permission": "allow",
1168
+ "updated_input": updated,
1169
+ # Gemini format
1170
+ "updatedInput": updated,
1171
+ }
1172
+
1173
+ print(json.dumps(output, ensure_ascii=False))
1174
+ sys.exit(0)
1175
+
1176
+
1177
+ if __name__ == "__main__":
1178
+ main()