@cluesmith/codev 3.2.4 → 3.3.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 (358) hide show
  1. package/dashboard-dist/assets/index-BZRTEMtH.css +32 -0
  2. package/dashboard-dist/assets/{index-BZ1x7x1X.js → index-JCbkpAcV.js} +33 -33
  3. package/dashboard-dist/assets/index-JCbkpAcV.js.map +1 -0
  4. package/dashboard-dist/index.html +2 -2
  5. package/dist/agent-farm/cli.d.ts.map +1 -1
  6. package/dist/agent-farm/cli.js +142 -0
  7. package/dist/agent-farm/cli.js.map +1 -1
  8. package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
  9. package/dist/agent-farm/commands/cleanup.js +16 -0
  10. package/dist/agent-farm/commands/cleanup.js.map +1 -1
  11. package/dist/agent-farm/commands/inbox.d.ts +42 -0
  12. package/dist/agent-farm/commands/inbox.d.ts.map +1 -0
  13. package/dist/agent-farm/commands/inbox.js +129 -0
  14. package/dist/agent-farm/commands/inbox.js.map +1 -0
  15. package/dist/agent-farm/commands/interrupt.d.ts +20 -0
  16. package/dist/agent-farm/commands/interrupt.d.ts.map +1 -0
  17. package/dist/agent-farm/commands/interrupt.js +65 -0
  18. package/dist/agent-farm/commands/interrupt.js.map +1 -0
  19. package/dist/agent-farm/commands/reset/constants.d.ts +52 -0
  20. package/dist/agent-farm/commands/reset/constants.d.ts.map +1 -0
  21. package/dist/agent-farm/commands/reset/constants.js +52 -0
  22. package/dist/agent-farm/commands/reset/constants.js.map +1 -0
  23. package/dist/agent-farm/commands/reset/context.d.ts +230 -0
  24. package/dist/agent-farm/commands/reset/context.d.ts.map +1 -0
  25. package/dist/agent-farm/commands/reset/context.js +428 -0
  26. package/dist/agent-farm/commands/reset/context.js.map +1 -0
  27. package/dist/agent-farm/commands/reset/index.d.ts +192 -0
  28. package/dist/agent-farm/commands/reset/index.d.ts.map +1 -0
  29. package/dist/agent-farm/commands/reset/index.js +488 -0
  30. package/dist/agent-farm/commands/reset/index.js.map +1 -0
  31. package/dist/agent-farm/commands/reset/receipt.d.ts +97 -0
  32. package/dist/agent-farm/commands/reset/receipt.d.ts.map +1 -0
  33. package/dist/agent-farm/commands/reset/receipt.js +149 -0
  34. package/dist/agent-farm/commands/reset/receipt.js.map +1 -0
  35. package/dist/agent-farm/commands/reset/reorient.d.ts +117 -0
  36. package/dist/agent-farm/commands/reset/reorient.d.ts.map +1 -0
  37. package/dist/agent-farm/commands/reset/reorient.js +313 -0
  38. package/dist/agent-farm/commands/reset/reorient.js.map +1 -0
  39. package/dist/agent-farm/commands/reset.d.ts +19 -0
  40. package/dist/agent-farm/commands/reset.d.ts.map +1 -0
  41. package/dist/agent-farm/commands/reset.js +292 -0
  42. package/dist/agent-farm/commands/reset.js.map +1 -0
  43. package/dist/agent-farm/commands/send.d.ts.map +1 -1
  44. package/dist/agent-farm/commands/send.js +49 -8
  45. package/dist/agent-farm/commands/send.js.map +1 -1
  46. package/dist/agent-farm/commands/spawn-worktree.d.ts +105 -6
  47. package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
  48. package/dist/agent-farm/commands/spawn-worktree.js +289 -66
  49. package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
  50. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  51. package/dist/agent-farm/commands/spawn.js +13 -1
  52. package/dist/agent-farm/commands/spawn.js.map +1 -1
  53. package/dist/agent-farm/commands/status.d.ts.map +1 -1
  54. package/dist/agent-farm/commands/status.js +80 -8
  55. package/dist/agent-farm/commands/status.js.map +1 -1
  56. package/dist/agent-farm/db/index.d.ts +1 -1
  57. package/dist/agent-farm/db/index.d.ts.map +1 -1
  58. package/dist/agent-farm/db/index.js +80 -1
  59. package/dist/agent-farm/db/index.js.map +1 -1
  60. package/dist/agent-farm/db/mailbox.d.ts +222 -0
  61. package/dist/agent-farm/db/mailbox.d.ts.map +1 -0
  62. package/dist/agent-farm/db/mailbox.js +304 -0
  63. package/dist/agent-farm/db/mailbox.js.map +1 -0
  64. package/dist/agent-farm/db/schema.d.ts +1 -1
  65. package/dist/agent-farm/db/schema.d.ts.map +1 -1
  66. package/dist/agent-farm/db/schema.js +35 -0
  67. package/dist/agent-farm/db/schema.js.map +1 -1
  68. package/dist/agent-farm/db/types.d.ts +45 -0
  69. package/dist/agent-farm/db/types.d.ts.map +1 -1
  70. package/dist/agent-farm/db/types.js.map +1 -1
  71. package/dist/agent-farm/lib/builder-lookup.d.ts +1 -1
  72. package/dist/agent-farm/lib/builder-lookup.js +2 -2
  73. package/dist/agent-farm/lib/builder-lookup.js.map +1 -1
  74. package/dist/agent-farm/lib/reconnect-backoff.d.ts +54 -0
  75. package/dist/agent-farm/lib/reconnect-backoff.d.ts.map +1 -0
  76. package/dist/agent-farm/lib/reconnect-backoff.js +47 -0
  77. package/dist/agent-farm/lib/reconnect-backoff.js.map +1 -0
  78. package/dist/agent-farm/lib/tower-client.d.ts +16 -6
  79. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  80. package/dist/agent-farm/lib/tower-client.js +37 -6
  81. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  82. package/dist/agent-farm/lib/tunnel-client.d.ts +69 -1
  83. package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
  84. package/dist/agent-farm/lib/tunnel-client.js +218 -27
  85. package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
  86. package/dist/agent-farm/servers/cron-delivery.d.ts +72 -0
  87. package/dist/agent-farm/servers/cron-delivery.d.ts.map +1 -0
  88. package/dist/agent-farm/servers/cron-delivery.js +80 -0
  89. package/dist/agent-farm/servers/cron-delivery.js.map +1 -0
  90. package/dist/agent-farm/servers/delayed-send.d.ts +85 -0
  91. package/dist/agent-farm/servers/delayed-send.d.ts.map +1 -0
  92. package/dist/agent-farm/servers/delayed-send.js +165 -0
  93. package/dist/agent-farm/servers/delayed-send.js.map +1 -0
  94. package/dist/agent-farm/servers/gate-profiles.d.ts +67 -0
  95. package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -0
  96. package/dist/agent-farm/servers/gate-profiles.js +113 -0
  97. package/dist/agent-farm/servers/gate-profiles.js.map +1 -0
  98. package/dist/agent-farm/servers/mailbox-delivery.d.ts +370 -0
  99. package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -0
  100. package/dist/agent-farm/servers/mailbox-delivery.js +617 -0
  101. package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -0
  102. package/dist/agent-farm/servers/mailbox-wiring.d.ts +125 -0
  103. package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -0
  104. package/dist/agent-farm/servers/mailbox-wiring.js +425 -0
  105. package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -0
  106. package/dist/agent-farm/servers/message-write.d.ts +53 -1
  107. package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
  108. package/dist/agent-farm/servers/message-write.js +63 -0
  109. package/dist/agent-farm/servers/message-write.js.map +1 -1
  110. package/dist/agent-farm/servers/overview.d.ts.map +1 -1
  111. package/dist/agent-farm/servers/overview.js +23 -4
  112. package/dist/agent-farm/servers/overview.js.map +1 -1
  113. package/dist/agent-farm/servers/render-gate.d.ts +141 -0
  114. package/dist/agent-farm/servers/render-gate.d.ts.map +1 -0
  115. package/dist/agent-farm/servers/render-gate.js +251 -0
  116. package/dist/agent-farm/servers/render-gate.js.map +1 -0
  117. package/dist/agent-farm/servers/session-submit.d.ts +90 -0
  118. package/dist/agent-farm/servers/session-submit.d.ts.map +1 -0
  119. package/dist/agent-farm/servers/session-submit.js +127 -0
  120. package/dist/agent-farm/servers/session-submit.js.map +1 -0
  121. package/dist/agent-farm/servers/tower-cron.d.ts +10 -7
  122. package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
  123. package/dist/agent-farm/servers/tower-cron.js +58 -53
  124. package/dist/agent-farm/servers/tower-cron.js.map +1 -1
  125. package/dist/agent-farm/servers/tower-instances.d.ts +14 -2
  126. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  127. package/dist/agent-farm/servers/tower-instances.js +78 -16
  128. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  129. package/dist/agent-farm/servers/tower-messages.d.ts +38 -1
  130. package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -1
  131. package/dist/agent-farm/servers/tower-messages.js +106 -1
  132. package/dist/agent-farm/servers/tower-messages.js.map +1 -1
  133. package/dist/agent-farm/servers/tower-routes.d.ts +16 -4
  134. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  135. package/dist/agent-farm/servers/tower-routes.js +670 -105
  136. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  137. package/dist/agent-farm/servers/tower-server.js +163 -31
  138. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  139. package/dist/agent-farm/servers/tower-terminals.d.ts +17 -2
  140. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  141. package/dist/agent-farm/servers/tower-terminals.js +104 -122
  142. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  143. package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -1
  144. package/dist/agent-farm/servers/tower-tunnel.js +63 -4
  145. package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
  146. package/dist/agent-farm/servers/tower-types.d.ts +2 -1
  147. package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
  148. package/dist/agent-farm/servers/tower-utils.d.ts +64 -1
  149. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
  150. package/dist/agent-farm/servers/tower-utils.js +168 -1
  151. package/dist/agent-farm/servers/tower-utils.js.map +1 -1
  152. package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
  153. package/dist/agent-farm/servers/tower-websocket.js +6 -21
  154. package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
  155. package/dist/agent-farm/servers/write-queue.d.ts +35 -0
  156. package/dist/agent-farm/servers/write-queue.d.ts.map +1 -0
  157. package/dist/agent-farm/servers/write-queue.js +56 -0
  158. package/dist/agent-farm/servers/write-queue.js.map +1 -0
  159. package/dist/agent-farm/types.d.ts +39 -0
  160. package/dist/agent-farm/types.d.ts.map +1 -1
  161. package/dist/agent-farm/utils/agent-names.d.ts +2 -2
  162. package/dist/agent-farm/utils/agent-names.d.ts.map +1 -1
  163. package/dist/agent-farm/utils/agent-names.js +3 -3
  164. package/dist/agent-farm/utils/agent-names.js.map +1 -1
  165. package/dist/agent-farm/utils/architect-name.d.ts +2 -2
  166. package/dist/agent-farm/utils/architect-name.d.ts.map +1 -1
  167. package/dist/agent-farm/utils/architect-name.js +3 -3
  168. package/dist/agent-farm/utils/architect-name.js.map +1 -1
  169. package/dist/agent-farm/utils/config.d.ts +13 -0
  170. package/dist/agent-farm/utils/config.d.ts.map +1 -1
  171. package/dist/agent-farm/utils/config.js +33 -1
  172. package/dist/agent-farm/utils/config.js.map +1 -1
  173. package/dist/agent-farm/utils/harness.d.ts +103 -7
  174. package/dist/agent-farm/utils/harness.d.ts.map +1 -1
  175. package/dist/agent-farm/utils/harness.js +126 -19
  176. package/dist/agent-farm/utils/harness.js.map +1 -1
  177. package/dist/cli.d.ts.map +1 -1
  178. package/dist/cli.js +6 -32
  179. package/dist/cli.js.map +1 -1
  180. package/dist/commands/consult/cli-options.d.ts +34 -0
  181. package/dist/commands/consult/cli-options.d.ts.map +1 -0
  182. package/dist/commands/consult/cli-options.js +67 -0
  183. package/dist/commands/consult/cli-options.js.map +1 -0
  184. package/dist/commands/consult/index.d.ts +56 -2
  185. package/dist/commands/consult/index.d.ts.map +1 -1
  186. package/dist/commands/consult/index.js +272 -28
  187. package/dist/commands/consult/index.js.map +1 -1
  188. package/dist/commands/consult/metrics.d.ts +42 -0
  189. package/dist/commands/consult/metrics.d.ts.map +1 -1
  190. package/dist/commands/consult/metrics.js +129 -9
  191. package/dist/commands/consult/metrics.js.map +1 -1
  192. package/dist/commands/doctor.d.ts.map +1 -1
  193. package/dist/commands/doctor.js +71 -19
  194. package/dist/commands/doctor.js.map +1 -1
  195. package/dist/commands/porch/checks.d.ts +23 -0
  196. package/dist/commands/porch/checks.d.ts.map +1 -1
  197. package/dist/commands/porch/checks.js +60 -0
  198. package/dist/commands/porch/checks.js.map +1 -1
  199. package/dist/commands/porch/config.d.ts +20 -0
  200. package/dist/commands/porch/config.d.ts.map +1 -1
  201. package/dist/commands/porch/config.js +20 -0
  202. package/dist/commands/porch/config.js.map +1 -1
  203. package/dist/commands/porch/index.js +21 -28
  204. package/dist/commands/porch/index.js.map +1 -1
  205. package/dist/commands/porch/next.d.ts.map +1 -1
  206. package/dist/commands/porch/next.js +2 -41
  207. package/dist/commands/porch/next.js.map +1 -1
  208. package/dist/lib/config.d.ts +69 -3
  209. package/dist/lib/config.d.ts.map +1 -1
  210. package/dist/lib/config.js +67 -3
  211. package/dist/lib/config.js.map +1 -1
  212. package/dist/lib/consult-lanes.d.ts +149 -0
  213. package/dist/lib/consult-lanes.d.ts.map +1 -0
  214. package/dist/lib/consult-lanes.js +360 -0
  215. package/dist/lib/consult-lanes.js.map +1 -0
  216. package/dist/lib/github.js +1 -1
  217. package/dist/lib/github.js.map +1 -1
  218. package/dist/lib/prompt-behavior-metrics.d.ts +67 -0
  219. package/dist/lib/prompt-behavior-metrics.d.ts.map +1 -0
  220. package/dist/lib/prompt-behavior-metrics.js +290 -0
  221. package/dist/lib/prompt-behavior-metrics.js.map +1 -0
  222. package/dist/lib/skeleton.d.ts +22 -1
  223. package/dist/lib/skeleton.d.ts.map +1 -1
  224. package/dist/lib/skeleton.js +120 -0
  225. package/dist/lib/skeleton.js.map +1 -1
  226. package/dist/lib/test-env.d.ts +74 -0
  227. package/dist/lib/test-env.d.ts.map +1 -0
  228. package/dist/lib/test-env.js +92 -0
  229. package/dist/lib/test-env.js.map +1 -0
  230. package/dist/terminal/pty-manager.d.ts +2 -0
  231. package/dist/terminal/pty-manager.d.ts.map +1 -1
  232. package/dist/terminal/pty-manager.js +16 -6
  233. package/dist/terminal/pty-manager.js.map +1 -1
  234. package/dist/terminal/pty-session.d.ts +131 -0
  235. package/dist/terminal/pty-session.d.ts.map +1 -1
  236. package/dist/terminal/pty-session.js +232 -39
  237. package/dist/terminal/pty-session.js.map +1 -1
  238. package/dist/terminal/ring-buffer.d.ts +39 -6
  239. package/dist/terminal/ring-buffer.d.ts.map +1 -1
  240. package/dist/terminal/ring-buffer.js +74 -6
  241. package/dist/terminal/ring-buffer.js.map +1 -1
  242. package/dist/terminal/session-manager.d.ts +53 -0
  243. package/dist/terminal/session-manager.d.ts.map +1 -1
  244. package/dist/terminal/session-manager.js +94 -9
  245. package/dist/terminal/session-manager.js.map +1 -1
  246. package/dist/terminal/session-screen.d.ts +91 -0
  247. package/dist/terminal/session-screen.d.ts.map +1 -0
  248. package/dist/terminal/session-screen.js +135 -0
  249. package/dist/terminal/session-screen.js.map +1 -0
  250. package/dist/terminal/shellper-main.js +2 -1
  251. package/dist/terminal/shellper-main.js.map +1 -1
  252. package/dist/terminal/shellper-process.d.ts +1 -1
  253. package/dist/terminal/shellper-process.d.ts.map +1 -1
  254. package/dist/terminal/shellper-process.js +17 -8
  255. package/dist/terminal/shellper-process.js.map +1 -1
  256. package/dist/terminal/shellper-replay-buffer.d.ts +69 -7
  257. package/dist/terminal/shellper-replay-buffer.d.ts.map +1 -1
  258. package/dist/terminal/shellper-replay-buffer.js +167 -31
  259. package/dist/terminal/shellper-replay-buffer.js.map +1 -1
  260. package/package.json +8 -6
  261. package/skeleton/.claude/skills/afx/SKILL.md +14 -1
  262. package/skeleton/.claude/skills/arch-init/SKILL.md +22 -9
  263. package/skeleton/.claude/skills/arch-save/SKILL.md +183 -0
  264. package/skeleton/.claude/skills/codev/SKILL.md +31 -0
  265. package/skeleton/.claude/skills/runnable-worktrees/SKILL.md +119 -0
  266. package/skeleton/.codex/skills/afx/SKILL.md +14 -1
  267. package/skeleton/.codex/skills/arch-init/SKILL.md +22 -9
  268. package/skeleton/.codex/skills/arch-save/SKILL.md +183 -0
  269. package/skeleton/.codex/skills/codev/SKILL.md +31 -0
  270. package/skeleton/.codex/skills/runnable-worktrees/SKILL.md +119 -0
  271. package/skeleton/protocols/air/builder-prompt.md +28 -47
  272. package/skeleton/protocols/air/consult-types/impl-review.md +17 -34
  273. package/skeleton/protocols/air/consult-types/pr-review.md +14 -37
  274. package/skeleton/protocols/air/prompts/implement.md +20 -73
  275. package/skeleton/protocols/air/prompts/pr.md +22 -54
  276. package/skeleton/protocols/air/protocol.md +40 -71
  277. package/skeleton/protocols/aspir/builder-prompt.md +29 -66
  278. package/skeleton/protocols/aspir/consult-types/impl-review.md +17 -44
  279. package/skeleton/protocols/aspir/consult-types/phase-review.md +17 -44
  280. package/skeleton/protocols/aspir/consult-types/plan-review.md +14 -38
  281. package/skeleton/protocols/aspir/consult-types/pr-review.md +13 -39
  282. package/skeleton/protocols/aspir/consult-types/spec-review.md +13 -33
  283. package/skeleton/protocols/aspir/prompts/implement.md +27 -196
  284. package/skeleton/protocols/aspir/prompts/plan.md +21 -85
  285. package/skeleton/protocols/aspir/prompts/review.md +29 -228
  286. package/skeleton/protocols/aspir/prompts/specify.md +25 -111
  287. package/skeleton/protocols/aspir/protocol.json +10 -0
  288. package/skeleton/protocols/aspir/protocol.md +36 -82
  289. package/skeleton/protocols/bugfix/builder-prompt.md +23 -45
  290. package/skeleton/protocols/bugfix/consult-types/impl-review.md +21 -45
  291. package/skeleton/protocols/bugfix/consult-types/pr-review.md +18 -52
  292. package/skeleton/protocols/bugfix/prompts/fix.md +16 -61
  293. package/skeleton/protocols/bugfix/prompts/investigate.md +18 -62
  294. package/skeleton/protocols/bugfix/prompts/pr.md +22 -57
  295. package/skeleton/protocols/bugfix/protocol.md +44 -50
  296. package/skeleton/protocols/experiment/builder-prompt.md +25 -58
  297. package/skeleton/protocols/experiment/protocol.md +22 -188
  298. package/skeleton/protocols/experiment/templates/notes.md +11 -71
  299. package/skeleton/protocols/maintain/builder-prompt.md +24 -45
  300. package/skeleton/protocols/maintain/consult-types/impl-review.md +17 -44
  301. package/skeleton/protocols/maintain/consult-types/pr-review.md +13 -39
  302. package/skeleton/protocols/maintain/prompts/maintain.md +1 -1
  303. package/skeleton/protocols/maintain/protocol.md +32 -266
  304. package/skeleton/protocols/maintain/templates/maintenance-run.md +11 -0
  305. package/skeleton/protocols/pir/builder-prompt.md +30 -64
  306. package/skeleton/protocols/pir/consult-types/impl-review.md +17 -50
  307. package/skeleton/protocols/pir/consult-types/pr-review.md +11 -40
  308. package/skeleton/protocols/pir/prompts/implement.md +1 -2
  309. package/skeleton/protocols/pir/prompts/plan.md +0 -3
  310. package/skeleton/protocols/pir/prompts/review.md +1 -1
  311. package/skeleton/protocols/pir/protocol.md +54 -177
  312. package/skeleton/protocols/research/builder-prompt.md +27 -58
  313. package/skeleton/protocols/research/protocol.md +28 -153
  314. package/skeleton/protocols/spike/builder-prompt.md +30 -48
  315. package/skeleton/protocols/spike/protocol.md +24 -107
  316. package/skeleton/protocols/spike/templates/findings.md +9 -39
  317. package/skeleton/protocols/spir/builder-prompt.md +33 -62
  318. package/skeleton/protocols/spir/consult-types/impl-review.md +17 -44
  319. package/skeleton/protocols/spir/consult-types/phase-review.md +17 -44
  320. package/skeleton/protocols/spir/consult-types/plan-review.md +14 -38
  321. package/skeleton/protocols/spir/consult-types/pr-review.md +13 -39
  322. package/skeleton/protocols/spir/consult-types/spec-review.md +13 -33
  323. package/skeleton/protocols/spir/prompts/implement.md +26 -195
  324. package/skeleton/protocols/spir/prompts/plan.md +20 -84
  325. package/skeleton/protocols/spir/prompts/review.md +28 -227
  326. package/skeleton/protocols/spir/prompts/specify.md +24 -110
  327. package/skeleton/protocols/spir/protocol.json +10 -0
  328. package/skeleton/protocols/spir/protocol.md +84 -633
  329. package/skeleton/protocols/spir/templates/plan.md +28 -147
  330. package/skeleton/protocols/spir/templates/review.md +21 -80
  331. package/skeleton/protocols/spir/templates/spec.md +24 -118
  332. package/skeleton/resources/commands/agent-farm.md +259 -0
  333. package/skeleton/resources/commands/consult.md +236 -8
  334. package/skeleton/resources/commands/overview.md +1 -0
  335. package/skeleton/roles/architect.md +67 -317
  336. package/skeleton/roles/builder.md +77 -191
  337. package/skeleton/templates/AGENTS.md +2 -0
  338. package/skeleton/templates/CLAUDE.md +2 -0
  339. package/templates/tower.html +39 -2
  340. package/dashboard-dist/assets/index-BZ1x7x1X.js.map +0 -1
  341. package/dashboard-dist/assets/index-DB1KBSNE.css +0 -32
  342. package/dist/agent-farm/servers/send-buffer.d.ts +0 -59
  343. package/dist/agent-farm/servers/send-buffer.d.ts.map +0 -1
  344. package/dist/agent-farm/servers/send-buffer.js +0 -116
  345. package/dist/agent-farm/servers/send-buffer.js.map +0 -1
  346. package/skeleton/porch/prompts/defend.md +0 -108
  347. package/skeleton/porch/prompts/diagnose.md +0 -70
  348. package/skeleton/porch/prompts/evaluate.md +0 -132
  349. package/skeleton/porch/prompts/fix.md +0 -59
  350. package/skeleton/porch/prompts/implement.md +0 -88
  351. package/skeleton/porch/prompts/plan.md +0 -74
  352. package/skeleton/porch/prompts/pr.md +0 -84
  353. package/skeleton/porch/prompts/review.md +0 -249
  354. package/skeleton/porch/prompts/specify.md +0 -53
  355. package/skeleton/porch/prompts/test.md +0 -63
  356. package/skeleton/protocols/aspir/templates/plan.md +0 -184
  357. package/skeleton/protocols/aspir/templates/review.md +0 -120
  358. package/skeleton/protocols/aspir/templates/spec.md +0 -154
@@ -2,56 +2,126 @@
2
2
  * Standalone replay buffer for the shellper process.
3
3
  *
4
4
  * Unlike RingBuffer (which stores lines), this stores raw byte chunks
5
- * to preserve exact terminal output including escape sequences. It tracks
6
- * the total bytes stored and evicts oldest chunks when the limit is exceeded.
5
+ * to preserve exact terminal output including escape sequences. It evicts
6
+ * the oldest chunks when either the line or the byte ceiling is exceeded;
7
+ * both ceilings are needed, because a full-screen TUI emits almost no
8
+ * newlines and so is bounded only by the byte one (#1205).
7
9
  *
8
10
  * This module has NO dependencies beyond Node.js built-ins so the shellper
9
11
  * process doesn't need to pull in the full package dependency tree.
12
+ * (shellper-protocol.ts is a sibling module under the same constraint.)
10
13
  */
14
+ import { REPLAY_PAYLOAD_MAX } from './shellper-protocol.js';
15
+ /**
16
+ * Byte ceiling on what this buffer retains (#1205). Until it existed the buffer
17
+ * was bounded only by line count, and a full-screen TUI (which redraws in place
18
+ * and emits almost no newlines) grew it without limit for the life of the
19
+ * session — multi-GB in the field.
20
+ *
21
+ * Derived from REPLAY_PAYLOAD_MAX rather than written as its own literal, and
22
+ * that derivation is the point: every send is capped at REPLAY_PAYLOAD_MAX and
23
+ * ShellperProcess.getReplayData() has no production callers, so it is provably
24
+ * the most that can ever leave the process. Bytes retained above it are
25
+ * unreadable by any consumer and are pure resident cost. Tying the two together
26
+ * keeps that true if the send cap ever moves — retaining more than can be sent
27
+ * would be waste, retaining less would make the send cap unreachable.
28
+ *
29
+ * This is a retention policy, not a wire constraint, which is why it lives here
30
+ * next to the buffer rather than in shellper-protocol.ts.
31
+ */
32
+ export const REPLAY_BUFFER_MAX_BYTES = REPLAY_PAYLOAD_MAX;
33
+ const ESC = 0x1b;
34
+ /**
35
+ * How far past a byte-driven trim point we scan looking for an ESC to align to.
36
+ * Bounded so alignment can never turn into a long scan over ESC-free data.
37
+ */
38
+ const ESC_ALIGN_SCAN_LIMIT = 4096;
39
+ /**
40
+ * Nudge a trim offset forward to the next ESC byte, so a cut doesn't land in
41
+ * the middle of an escape sequence and leave the client rendering its tail as
42
+ * literal garbage. Returns `offset` unchanged when no ESC is within the scan
43
+ * window, which is the correct fallback: a raw cut is what we'd have done
44
+ * anyway, and the post-connect repaint nudge covers the rest.
45
+ *
46
+ * Only byte-driven cuts need this. A newline-driven cut lands just past a
47
+ * `\n`, which can never appear inside an escape sequence, so it is already
48
+ * safe and aligning it would discard content for nothing.
49
+ */
50
+ function alignToEscape(buf, offset) {
51
+ const limit = Math.min(buf.length, offset + ESC_ALIGN_SCAN_LIMIT);
52
+ for (let i = offset; i < limit; i++) {
53
+ if (buf[i] === ESC)
54
+ return i;
55
+ }
56
+ return offset;
57
+ }
58
+ function countNewlines(buf) {
59
+ let count = 0;
60
+ for (let i = 0; i < buf.length; i++) {
61
+ if (buf[i] === 0x0a)
62
+ count++;
63
+ }
64
+ return count;
65
+ }
11
66
  export class ShellperReplayBuffer {
12
67
  chunks = [];
13
68
  totalBytes = 0;
14
69
  maxLines;
70
+ maxBytes;
15
71
  lineCount = 0;
16
72
  /**
17
73
  * @param maxLines Maximum number of lines to retain. Lines are delimited
18
74
  * by newline characters in the raw data stream.
75
+ * @param maxBytes Maximum bytes to retain. Required because `maxLines` alone
76
+ * does not bound anything for a full-screen TUI: such an app redraws in
77
+ * place via cursor addressing and emits almost no newlines, so the line
78
+ * ceiling never fires and the buffer grows for the life of the session
79
+ * (#1205). Defaults to REPLAY_BUFFER_MAX_BYTES.
19
80
  */
20
- constructor(maxLines = 10_000) {
81
+ constructor(maxLines = 10_000, maxBytes = REPLAY_BUFFER_MAX_BYTES) {
21
82
  this.maxLines = maxLines;
83
+ this.maxBytes = maxBytes;
22
84
  }
23
85
  /**
24
86
  * Append raw PTY output data to the buffer.
25
- * Evicts oldest chunks if the line count exceeds maxLines.
87
+ * Evicts oldest chunks if either the line or the byte ceiling is exceeded.
26
88
  */
27
89
  append(data) {
28
90
  const buf = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data;
29
91
  if (buf.length === 0)
30
92
  return;
31
- // Count newlines in this chunk
32
- let newLines = 0;
33
- for (let i = 0; i < buf.length; i++) {
34
- if (buf[i] === 0x0a)
35
- newLines++;
36
- }
37
93
  this.chunks.push(buf);
38
94
  this.totalBytes += buf.length;
39
- this.lineCount += newLines;
40
- // Evict oldest chunks if we've exceeded the line limit
41
- while (this.lineCount > this.maxLines && this.chunks.length > 1) {
95
+ this.lineCount += countNewlines(buf);
96
+ this.evict();
97
+ }
98
+ /**
99
+ * Drop the oldest data until both ceilings are satisfied.
100
+ *
101
+ * Trimming from the front can cut mid-escape-sequence or discard an
102
+ * alt-screen-enter, which is why it was rejected in #1047. It is accepted
103
+ * here because every layer above already does exactly this (the send cap,
104
+ * the ring seed, the frame-skip path) and relies on the client's
105
+ * post-connect repaint nudge; an unbounded buffer, by contrast, killed
106
+ * sessions. Byte-driven cuts are ESC-aligned to narrow the window in which
107
+ * a client renders a truncated sequence as literal text.
108
+ */
109
+ evict() {
110
+ while ((this.lineCount > this.maxLines || this.totalBytes > this.maxBytes) &&
111
+ this.chunks.length > 1) {
42
112
  const oldest = this.chunks[0];
43
- let removedLines = 0;
44
- for (let i = 0; i < oldest.length; i++) {
45
- if (oldest[i] === 0x0a)
46
- removedLines++;
47
- }
48
113
  this.chunks.shift();
49
114
  this.totalBytes -= oldest.length;
50
- this.lineCount -= removedLines;
115
+ this.lineCount -= countNewlines(oldest);
51
116
  }
52
- // Handle edge case: single chunk exceeds line limit.
53
- // Trim from the front to keep only the last maxLines lines.
54
- if (this.lineCount > this.maxLines && this.chunks.length === 1) {
117
+ // A single remaining chunk can still exceed either ceiling on its own.
118
+ if (this.chunks.length !== 1)
119
+ return;
120
+ // Line ceiling: cut just past the newline that leaves maxLines behind.
121
+ // A newline never appears inside an escape sequence, so this cut is
122
+ // inherently safe and must not be ESC-aligned (that would discard content
123
+ // for no benefit).
124
+ if (this.lineCount > this.maxLines) {
55
125
  const chunk = this.chunks[0];
56
126
  let linesToSkip = this.lineCount - this.maxLines;
57
127
  let offset = 0;
@@ -60,21 +130,87 @@ export class ShellperReplayBuffer {
60
130
  linesToSkip--;
61
131
  offset++;
62
132
  }
63
- this.chunks[0] = chunk.subarray(offset);
64
- this.totalBytes = this.chunks[0].length;
65
- this.lineCount = this.maxLines;
133
+ this.replaceSoleChunk(chunk.subarray(offset));
134
+ }
135
+ // Byte ceiling: keep the tail. This cut can land anywhere, so align it.
136
+ const chunk = this.chunks[0];
137
+ if (chunk.length > this.maxBytes) {
138
+ this.replaceSoleChunk(chunk.subarray(alignToEscape(chunk, chunk.length - this.maxBytes)));
66
139
  }
67
140
  }
68
141
  /**
69
- * Get all buffered data as a single concatenated Buffer.
70
- * Used for the REPLAY frame on reconnection.
142
+ * Replace the only chunk with a trimmed version of itself.
143
+ *
144
+ * Copies rather than retaining the `subarray` view: a view keeps the entire
145
+ * original allocation alive, so trimming an oversized chunk down to the
146
+ * ceiling would free none of the memory this class exists to bound. The copy
147
+ * is at most `maxBytes` and only happens on the rare path where a single
148
+ * append exceeded a ceiling by itself.
71
149
  */
72
- getReplayData() {
150
+ replaceSoleChunk(next) {
151
+ const owned = Buffer.from(next);
152
+ this.chunks[0] = owned;
153
+ this.totalBytes = owned.length;
154
+ this.lineCount = countNewlines(owned);
155
+ }
156
+ /**
157
+ * Get buffered data as a single Buffer, for the REPLAY frame on reconnection.
158
+ *
159
+ * @param maxBytes When given, return at most this many bytes (the most recent
160
+ * ones). The tail is collected by walking `chunks` backwards and slicing
161
+ * only the boundary chunk, so the allocation is O(maxBytes) rather than
162
+ * O(history).
163
+ *
164
+ * That distinction is the whole point (#1205). This runs on *every* client
165
+ * connect, and the caller's cap used to be applied to the result — meaning a
166
+ * multi-GB buffer allocated a multi-GB copy on top of itself at exactly the
167
+ * moment a user opened the terminal, then threw almost all of it away. Peak
168
+ * footprint doubled, and sessions were killed for it. Capping here bounds the
169
+ * spike regardless of how large the buffer has already grown, which also
170
+ * makes this correct for a buffer that accumulated before any byte ceiling
171
+ * existed.
172
+ */
173
+ getReplayData(maxBytes) {
73
174
  if (this.chunks.length === 0)
74
175
  return Buffer.alloc(0);
75
- if (this.chunks.length === 1)
76
- return this.chunks[0];
77
- return Buffer.concat(this.chunks);
176
+ if (maxBytes === undefined || this.totalBytes <= maxBytes) {
177
+ // Single-chunk fast path returns the internal Buffer *by reference*
178
+ // rather than copying. Safe because nothing mutates chunks in place and
179
+ // callers only read, but it is an aliasing property the old
180
+ // always-concat version did not have: a caller that mutated the result
181
+ // would corrupt the buffer. Copy here if that ever stops being true.
182
+ if (this.chunks.length === 1)
183
+ return this.chunks[0];
184
+ return Buffer.concat(this.chunks, this.totalBytes);
185
+ }
186
+ if (maxBytes <= 0)
187
+ return Buffer.alloc(0);
188
+ const tail = [];
189
+ let collected = 0;
190
+ for (let i = this.chunks.length - 1; i >= 0 && collected < maxBytes; i--) {
191
+ const chunk = this.chunks[i];
192
+ const remaining = maxBytes - collected;
193
+ if (chunk.length <= remaining) {
194
+ tail.push(chunk);
195
+ collected += chunk.length;
196
+ continue;
197
+ }
198
+ // Boundary chunk: take only its tail, aligned off a mid-sequence cut.
199
+ //
200
+ // `break` is load-bearing. ESC alignment moves the cut *forward*, so the
201
+ // piece is usually shorter than `remaining` — without breaking, the loop
202
+ // would see spare capacity and keep taking bytes from still-older chunks,
203
+ // stitching fragments across a gap into what must be one contiguous
204
+ // suffix. That also re-admits the unaligned mid-sequence prefix this
205
+ // alignment exists to prevent. Returning fewer than `maxBytes` is the
206
+ // accepted contract; returning a spliced stream is not.
207
+ const piece = chunk.subarray(alignToEscape(chunk, chunk.length - remaining));
208
+ tail.push(piece);
209
+ collected += piece.length;
210
+ break;
211
+ }
212
+ tail.reverse();
213
+ return Buffer.concat(tail, collected);
78
214
  }
79
215
  /** Current number of bytes stored. */
80
216
  get size() {
@@ -1 +1 @@
1
- {"version":3,"file":"shellper-replay-buffer.js","sourceRoot":"","sources":["../../src/terminal/shellper-replay-buffer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shellper-replay-buffer.js","sourceRoot":"","sources":["../../src/terminal/shellper-replay-buffer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cluesmith/codev",
3
- "version": "3.2.4",
3
+ "version": "3.3.0",
4
4
  "description": "Codev CLI - AI-assisted software development framework",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,8 @@
23
23
  "dependencies": {
24
24
  "@anthropic-ai/claude-agent-sdk": "^0.2.41",
25
25
  "@google/genai": "^1.0.0",
26
- "@openai/codex-sdk": "^0.142.5",
26
+ "@openai/codex-sdk": "^0.146.0",
27
+ "@xterm/headless": "^6.0.0",
27
28
  "better-sqlite3": "^12.10.0",
28
29
  "chalk": "^5.3.0",
29
30
  "commander": "^12.1.0",
@@ -33,7 +34,8 @@
33
34
  "open": "^10.1.0",
34
35
  "tree-kill": "^1.2.2",
35
36
  "ws": "^8.18.0",
36
- "@cluesmith/codev-core": "3.2.4"
37
+ "@cluesmith/codev-core": "3.3.0",
38
+ "@cluesmith/codev-sdk": "3.3.0"
37
39
  },
38
40
  "devDependencies": {
39
41
  "@playwright/test": "^1.58.0",
@@ -49,7 +51,7 @@
49
51
  "typescript": "^6.0.3",
50
52
  "vitest": "^4.0.15",
51
53
  "@cluesmith/codev-web": "0.0.0",
52
- "@cluesmith/codev-types": "3.2.4"
54
+ "@cluesmith/codev-types": "3.3.0"
53
55
  },
54
56
  "engines": {
55
57
  "node": ">=20.0.0"
@@ -71,8 +73,8 @@
71
73
  },
72
74
  "scripts": {
73
75
  "clean": "rm -rf dist",
74
- "build": "pnpm clean && tsc && pnpm build:dashboard && pnpm copy-skeleton",
75
- "build:dashboard": "cd ../../apps/web && pnpm build && rm -rf ../../packages/codev/dashboard-dist && cp -r dist ../../packages/codev/dashboard-dist",
76
+ "build": "pnpm --filter \"@cluesmith/codev^...\" build && pnpm clean && tsc && pnpm copy-dashboard && pnpm copy-skeleton",
77
+ "copy-dashboard": "rm -rf dashboard-dist && cp -r ../../apps/web/dist dashboard-dist",
76
78
  "dev:dashboard": "cd ../../apps/web && pnpm dev",
77
79
  "copy-skeleton": "rm -rf skeleton && cp -r ../../codev-skeleton skeleton",
78
80
  "dev": "tsx src/cli.ts",
@@ -144,7 +144,20 @@ afx cron enable <name> # Enable
144
144
  afx cron disable <name> # Disable
145
145
  ```
146
146
 
147
- There is NO `afx cron add` — create YAML files in `.af-cron/` directly.
147
+ There is NO `afx cron add` — create YAML files in `.af-cron/` directly:
148
+
149
+ ```yaml
150
+ name: Service Health Check # required, unique per workspace
151
+ schedule: "*/15 * * * *" # required, cron expression (or @hourly/@daily/@startup)
152
+ command: ./health-check.sh # required, run via shell
153
+ message: "Health alert: ${output}" # required, ${output} = trimmed command output
154
+ condition: "exitCode != 0" # optional JS expression, see below
155
+ target: architect # optional, default architect
156
+ timeout: 30 # optional, seconds, default 30
157
+ enabled: true # optional, default true
158
+ ```
159
+
160
+ `condition` is a JavaScript expression with two variables in scope: `output` (string — the command's trimmed output) and `exitCode` (number — 0 on success, the command's exit code on non-zero exit, 124 on timeout, -1 on spawn failure). With a `condition`, the message is delivered exactly when it evaluates truthy — including on failed runs (e.g. `exitCode != 0` alerts when the command fails). Without a `condition`, the message is delivered only when the command exits 0.
148
161
 
149
162
  ## Other commands
150
163
 
@@ -63,7 +63,11 @@ not choose; a state save happens at a boundary **you** pick, with a summary
63
63
  **you** curate. That is strictly better, so use it:
64
64
 
65
65
  ```
66
- /arch-init (recover) → work → save at a checkpoint → suggest /clear → human /clears → /arch-init → …
66
+ /arch-init (recover) → work → save at a checkpoint → refresh → /arch-init (recover) → …
67
+ │
68
+ packaged: /arch-save ─────────────────┤ stops monitors, saves, clears,
69
+ │ schedules /arch-init
70
+ manual: suggest /clear → human clears ┘ then human runs /arch-init
67
71
  ```
68
72
 
69
73
  **When to save.** Save at a *resumable boundary* — a point a fresh session
@@ -99,17 +103,26 @@ plus the most recent dated section*, so a save must leave exactly that behind:
99
103
  dumps or raw tool output. Include only: current focus, open loops, and the
100
104
  instructions a fresh session needs to resume.
101
105
 
102
- **Then — and only then — suggest `/clear`.** Save first, *then* tell the human
103
- it is a good time to clear. You cannot clear your own context and must never
104
- decide unilaterally to lose it; keeping the irreversible step behind a human
105
- keystroke means accepting the suggestion can never lose anything, because the
106
- save already happened. Make the suggestion **advisory, never nagging**, and
107
- only right after a save — e.g.:
106
+ **Then — and only then — suggest the refresh.** Save first, *then* tell the
107
+ human it is a good time to clear. You must never decide unilaterally to lose
108
+ your context; keeping the irreversible step behind a human decision means
109
+ accepting the suggestion can never lose anything, because the save already
110
+ happened. Make the suggestion **advisory, never nagging**, and only right
111
+ after a save — e.g.:
108
112
 
109
- > State saved to `codev/state/<name>.md` — good time to `/clear` if this
113
+ > State saved to `codev/state/<name>.md` — good time to refresh if this
110
114
  > session is feeling heavy.
111
115
 
112
- Do not repeat it, and do not prompt to `/clear` at any other time.
116
+ Do not repeat it, and do not prompt for it at any other time.
117
+
118
+ **`/arch-save` packages this whole loop**, and is the preferred path when the
119
+ owner directs a refresh: it stops your monitors, writes the pruned state file,
120
+ clears, and schedules `/arch-init` to bring you back — in that order, which is
121
+ the part that matters. The save discipline above is what it performs at its
122
+ step 3, so this section remains the source of truth for *how to write the
123
+ file*; `/arch-save` is the source of truth for *the sequence*. The manual path
124
+ (save → human clears → `/arch-init`) stays valid and is the fallback when
125
+ Tower is unavailable.
113
126
 
114
127
  ## Guardrails (architect-wide; the state file may add more)
115
128
 
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: arch-save
3
+ description: Save an architect's state, clear its context, and re-init automatically — the packaged save→clear→re-init refresh cycle. Use when the owner directs a context refresh, or says "/arch-save", "save and clear", "refresh your context". Runs on the owner's direction; an architect does not invoke it autonomously mid-task. Counterpart to /arch-init, which recovers the state this writes.
4
+ argument-hint: "[name] (e.g. main; omit to auto-detect via afx whoami)"
5
+ ---
6
+
7
+ # /arch-save — save state, clear, and come back as yourself
8
+
9
+ Long sessions accumulate stale context. This is the deliberate cure: you choose the
10
+ moment, you choose what survives, and a fresh session resumes from what you wrote.
11
+
12
+ `$ARGUMENTS` is the architect name (e.g. `main`). Omit it to auto-detect.
13
+
14
+ ## When NOT to run this
15
+
16
+ **On the owner's direction, or when the owner runs it themselves.** Do not invoke this
17
+ autonomously mid-task on your own judgement — the irreversible step is a human decision,
18
+ relocated from "press `/clear`" to "invoke `/arch-save`", not removed. If the owner tells
19
+ you to run it, run it; if you think it is time, *suggest* it and wait.
20
+
21
+ **Only at a resumable boundary** — a gate approval, a PR merge, a completed investigation,
22
+ the end of a long tool-heavy stretch. **Never mid-task.** Nothing here can check that; the
23
+ state file must describe a point a fresh session can resume *from*, not a half-finished
24
+ action. A mid-task snapshot resumes into confusion.
25
+
26
+ ## The procedure
27
+
28
+ Do these in order. **The order is the feature** — step 3 must precede step 4, because the
29
+ context that knows what to write is the one about to be destroyed.
30
+
31
+ ### 1. Resolve your name
32
+
33
+ If `$ARGUMENTS` is non-empty, that is your name. Otherwise run `afx whoami` and use the
34
+ reported `name` when `type: architect`.
35
+
36
+ - `type: builder` → **STOP.** This terminal is a builder. Report the mismatch.
37
+ - Non-zero exit → **STOP** and ask which architect you are. Do **not** guess, and do not
38
+ default to `main` — writing another architect's state file is the exact failure
39
+ `/arch-init` exists to prevent (#1094).
40
+
41
+ **Validate the name before building any path**: `[a-z][a-z0-9-]*`, at most 64 characters.
42
+ Reject slashes, `..`, uppercase, spaces. Never interpolate an unvalidated name into
43
+ `codev/state/<name>.md`.
44
+
45
+ ### 2. Stop your own monitors
46
+
47
+ Enumerate every monitor, watcher or background task you armed, and stop it.
48
+
49
+ This is the half that only *you* can do. Monitors are **session-bound, not
50
+ context-bound**: they survive `/clear` and keep firing into a context that cannot evaluate
51
+ their alerts. `pgrep` cannot see them — they are harness background tasks, not shell
52
+ processes — so the instance after the clear has no handle on them. You do. Use it.
53
+
54
+ ### 3. Write the pruned state file
55
+
56
+ Rewrite `codev/state/<name>.md`. **Pruning is part of the save, not polish afterwards — a
57
+ save that only appends has not done its job.**
58
+
59
+ - **Rewrite the current-state / open-loops section in place.** Do not accumulate stale
60
+ "current state" blocks. Never leave two sections with the same heading — a duplicated
61
+ "How to resume" means you appended where you should have overwritten.
62
+ - **Delete resolved loops outright.** A closed item's record is the log entry, not a
63
+ lingering line in current state.
64
+ - **Append one short dated entry** for what changed this stretch.
65
+ - **Collapse older entries into one-line summaries that point at durable artifacts** — the
66
+ merged PRs, closed issues and reviews where the detail actually lives.
67
+ - **Aim for one screen.** If the file has grown past easy reading, prune as part of *this*
68
+ save rather than leaving it for next time.
69
+
70
+ **Prune by pointer, never by deletion.** These files are gitignored (`.gitignore:15`), so
71
+ there is no history to recover from — pruned prose is gone for good. Replace detail with a
72
+ pointer to something durable; never delete the only record of something. Copying the file
73
+ first (`cp codev/state/<name>.md codev/state/.<name>.bak.md`) is cheap insurance.
74
+
75
+ **Content guardrails.** No secrets — tokens, keys, credentials. No transcript dumps, no
76
+ raw tool output. Only: current focus, open loops, and what a fresh session needs to resume.
77
+
78
+ Use the template at the end of this document.
79
+
80
+ ### 4. Clear
81
+
82
+ ```bash
83
+ afx send architect:<name> --raw '/clear'
84
+ ```
85
+
86
+ **`architect:<name>`, never bare `architect`.** For a non-builder sender the bare form
87
+ resolves to `main`, or to the first registered architect — so a *sibling* architect
88
+ running this would clear **main's** terminal instead of its own. That destroys the context
89
+ of someone who never asked for anything, and it is one word away from correct.
90
+
91
+ **`--raw`, never the escape channel.** The escape route writes a bare ESC and discards the
92
+ message body, so `/clear` sent that way delivers an interrupt: the command appears to
93
+ succeed and nothing is cleared.
94
+
95
+ ### 5. Schedule the re-init
96
+
97
+ ```bash
98
+ afx send architect:<name> --delay 15 --raw '/arch-init <name>'
99
+ ```
100
+
101
+ Tower holds this for 15 seconds and then delivers it. It has to come from outside the
102
+ session, because the clear destroys the context that would otherwise send it.
103
+
104
+ **Tower does not know whether the clear landed** — it waits out a delay, it does not
105
+ observe the result. 15 seconds is a value chosen because it works in practice, not a
106
+ guarantee about the clear's completion. If the timing is wrong the re-init arrives at the
107
+ wrong moment, which costs one manual message (see below) and nothing else. That is the
108
+ whole reason this cycle can be built on a delay rather than on machinery.
109
+
110
+ Delayed sends are **not persisted** — if Tower restarts inside the window, the message is
111
+ dropped. That is recoverable; see below.
112
+
113
+ **If this send fails, do not end your turn.** Step 4 queued the `/clear`, but it does not
114
+ take effect until your turn ends — so at this moment you still have your full context and
115
+ the failure is recoverable. Retry the send; if it keeps failing (Tower down, for example),
116
+ tell the owner that the clear is queued with no re-init scheduled, and give them the
117
+ command to send by hand once Tower is back. Ending the turn here is the one way to turn a
118
+ recoverable failure into a cleared session nobody is coming back for.
119
+
120
+ ### 6. Stop
121
+
122
+ Do not start new work. End your turn so the clear can take effect.
123
+
124
+ ## After the clear
125
+
126
+ `/arch-init` will read your state file and resume. Two things it should do first, in this
127
+ order:
128
+
129
+ 1. **Reconcile monitors.** You stopped yours in step 2, but treat any alert you cannot
130
+ account for from the state block's monitor list as **stale** — disregard it, and stop
131
+ it if you can. An alert from a decommissioned target is indistinguishable from a live
132
+ one.
133
+ 2. **Then re-arm** the monitors the block lists, and let each one **self-test once** before
134
+ trusting its alerts. A freshly-armed monitor's first alert has been a false positive in
135
+ practice.
136
+
137
+ ## If `/arch-init` never arrives
138
+
139
+ Nothing is lost. The state file is on disk, the terminal is alive. Send it by hand:
140
+
141
+ ```bash
142
+ afx send architect:<name> --raw '/arch-init <name>'
143
+ ```
144
+
145
+ This is the recovery the whole design leans on, which is why the cycle can accept imprecise
146
+ timing rather than needing machinery to guarantee it.
147
+
148
+ **If the clear did not take effect** — you still have your full context and a stray
149
+ `/arch-init` arrived — nothing was destroyed. Check whether `/clear` was submitted as its
150
+ own message rather than merged into another one, and report it; a `/clear` that arrives as
151
+ literal text on the front of the next message never executes.
152
+
153
+ ## State block template
154
+
155
+ The structure below comes from a live run of this cycle. Every element earns its place;
156
+ keep them all, including a `MONITORS:` line even when the answer is "none armed" — an
157
+ omitted monitor list is indistinguishable from a forgotten one.
158
+
159
+ ```
160
+ # <lane> architect — state (vNN, <date> ~HH:MM UTC — <milestone>, DELIBERATE /clear cycle)
161
+ # ⭐ THIS /clear IS INTENTIONAL (owner-directed context refresh). On re-init: normal
162
+ # /arch-init flow, then:
163
+ # 1. MONITORS: <what to stop if it is still firing, then what to re-arm> — watch target,
164
+ # cadence, alert pattern. Self-test once before trusting alerts. ("none armed" is a
165
+ # valid and complete answer.)
166
+ # 2. DONE pre-clear, with receipts: <PR> MERGED (<sha>, verified on origin/<branch>);
167
+ # <branch> PUSH-VERIFIED (<sha> local==origin). Distinguish "written" from "verified" —
168
+ # a cold reader cannot tell.
169
+ # 3. ACTIVE LANES: <builder-id> = <workstream> (<brief file on disk>; <standing rule>).
170
+ # Name the file, so no instruction lives only in the context being destroyed.
171
+ # 4. LATEST RESULTS: <the decision-relevant numbers>, so the first post-resume decision
172
+ # needs no archaeology.
173
+ # 5. QUEUED, with ordering: <item> — WAITS for <verdict>; <item> — <when>.
174
+ # 6. ENVELOPE: <standing authorization that survives>; <what expired with the completed
175
+ # work>.
176
+ ```
177
+
178
+ ## Guardrails (architect-wide)
179
+
180
+ - **Never auto-approve porch gates.** A gate notification is for the human, not you.
181
+ - **Touch only your own builders / spawns / filings.**
182
+ - **Never `cd` into a builder worktree**; use `git -C` and absolute paths.
183
+ - **Stay on the default branch at the workspace root.**
@@ -57,3 +57,34 @@ codev doctor
57
57
  - `codev init` creates a new directory — use `codev adopt` for existing projects
58
58
  - Always run `codev adopt` and `codev update` from the project root
59
59
  - `codev update` only updates framework files — it never touches specs/plans/reviews
60
+
61
+ ## Local build and install (this repository)
62
+
63
+ Test changes locally before publishing. Run from the repository root:
64
+
65
+ ```bash
66
+ pnpm build # builds core first, then codev (including dashboard)
67
+ pnpm -w run local-install # packs both packages, installs globally, restarts Tower
68
+ ```
69
+
70
+ `local-install` (`scripts/local-install.sh`) packs `@cluesmith/codev-core` and
71
+ `@cluesmith/codev`, installs both in a single `npm install -g` (separate installs fail —
72
+ `codev-core` is not on the public registry), restores the executable bit on
73
+ `scripts/forge/**/*.sh` that `pnpm pack` strips, and restarts Tower last. Install runs while
74
+ Tower is up; only the final restart causes downtime. **Do not stop Tower first**, and do not use
75
+ `npm link` / `pnpm link` — it breaks global installs.
76
+
77
+ `pnpm build` also runs `copy-skeleton`, which copies `codev-skeleton/` into
78
+ `packages/codev/skeleton`. **Tests read that copy**, so after editing anything under
79
+ `codev-skeleton/` you must rebuild before the suite reflects your change.
80
+
81
+ ### Where to run things
82
+
83
+ - `pnpm install` — repository root (installs all workspace packages)
84
+ - `pnpm build` / `pnpm test` — `packages/codev/`, or `pnpm --filter @cluesmith/codev build`
85
+ - Unit tests `packages/codev/tests/unit/` · E2E `packages/codev/tests/e2e/`
86
+ - Never run npm commands from the repository root unless told to
87
+
88
+ ### Measuring code size
89
+
90
+ `tokei -e "tests/lib" -e "node_modules" -e ".git" -e ".builders" -e "dist" .`