@cluesmith/codev 3.2.4 → 3.3.1

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 (394) hide show
  1. package/dashboard-dist/assets/index-BZRTEMtH.css +32 -0
  2. package/dashboard-dist/assets/{index-BZ1x7x1X.js → index-D3XaKpZW.js} +46 -44
  3. package/dashboard-dist/assets/index-D3XaKpZW.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 +154 -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 +34 -0
  40. package/dist/agent-farm/commands/reset.d.ts.map +1 -0
  41. package/dist/agent-farm/commands/reset.js +309 -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/commands/tower.d.ts.map +1 -1
  57. package/dist/agent-farm/commands/tower.js +13 -0
  58. package/dist/agent-farm/commands/tower.js.map +1 -1
  59. package/dist/agent-farm/db/index.d.ts +1 -1
  60. package/dist/agent-farm/db/index.d.ts.map +1 -1
  61. package/dist/agent-farm/db/index.js +80 -1
  62. package/dist/agent-farm/db/index.js.map +1 -1
  63. package/dist/agent-farm/db/mailbox.d.ts +222 -0
  64. package/dist/agent-farm/db/mailbox.d.ts.map +1 -0
  65. package/dist/agent-farm/db/mailbox.js +304 -0
  66. package/dist/agent-farm/db/mailbox.js.map +1 -0
  67. package/dist/agent-farm/db/schema.d.ts +1 -1
  68. package/dist/agent-farm/db/schema.d.ts.map +1 -1
  69. package/dist/agent-farm/db/schema.js +35 -0
  70. package/dist/agent-farm/db/schema.js.map +1 -1
  71. package/dist/agent-farm/db/types.d.ts +45 -0
  72. package/dist/agent-farm/db/types.d.ts.map +1 -1
  73. package/dist/agent-farm/db/types.js.map +1 -1
  74. package/dist/agent-farm/lib/builder-lookup.d.ts +1 -1
  75. package/dist/agent-farm/lib/builder-lookup.js +2 -2
  76. package/dist/agent-farm/lib/builder-lookup.js.map +1 -1
  77. package/dist/agent-farm/lib/reconnect-backoff.d.ts +64 -0
  78. package/dist/agent-farm/lib/reconnect-backoff.d.ts.map +1 -0
  79. package/dist/agent-farm/lib/reconnect-backoff.js +57 -0
  80. package/dist/agent-farm/lib/reconnect-backoff.js.map +1 -0
  81. package/dist/agent-farm/lib/tower-client.d.ts +16 -6
  82. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  83. package/dist/agent-farm/lib/tower-client.js +37 -6
  84. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  85. package/dist/agent-farm/lib/tunnel-client.d.ts +69 -1
  86. package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
  87. package/dist/agent-farm/lib/tunnel-client.js +225 -30
  88. package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
  89. package/dist/agent-farm/servers/canvas-relay.d.ts +60 -0
  90. package/dist/agent-farm/servers/canvas-relay.d.ts.map +1 -0
  91. package/dist/agent-farm/servers/canvas-relay.js +376 -0
  92. package/dist/agent-farm/servers/canvas-relay.js.map +1 -0
  93. package/dist/agent-farm/servers/cron-delivery.d.ts +72 -0
  94. package/dist/agent-farm/servers/cron-delivery.d.ts.map +1 -0
  95. package/dist/agent-farm/servers/cron-delivery.js +80 -0
  96. package/dist/agent-farm/servers/cron-delivery.js.map +1 -0
  97. package/dist/agent-farm/servers/delayed-send.d.ts +85 -0
  98. package/dist/agent-farm/servers/delayed-send.d.ts.map +1 -0
  99. package/dist/agent-farm/servers/delayed-send.js +165 -0
  100. package/dist/agent-farm/servers/delayed-send.js.map +1 -0
  101. package/dist/agent-farm/servers/gate-profiles.d.ts +67 -0
  102. package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -0
  103. package/dist/agent-farm/servers/gate-profiles.js +113 -0
  104. package/dist/agent-farm/servers/gate-profiles.js.map +1 -0
  105. package/dist/agent-farm/servers/mailbox-delivery.d.ts +370 -0
  106. package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -0
  107. package/dist/agent-farm/servers/mailbox-delivery.js +617 -0
  108. package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -0
  109. package/dist/agent-farm/servers/mailbox-wiring.d.ts +125 -0
  110. package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -0
  111. package/dist/agent-farm/servers/mailbox-wiring.js +425 -0
  112. package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -0
  113. package/dist/agent-farm/servers/message-write.d.ts +53 -1
  114. package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
  115. package/dist/agent-farm/servers/message-write.js +63 -0
  116. package/dist/agent-farm/servers/message-write.js.map +1 -1
  117. package/dist/agent-farm/servers/overview.d.ts +19 -0
  118. package/dist/agent-farm/servers/overview.d.ts.map +1 -1
  119. package/dist/agent-farm/servers/overview.js +100 -4
  120. package/dist/agent-farm/servers/overview.js.map +1 -1
  121. package/dist/agent-farm/servers/render-gate.d.ts +141 -0
  122. package/dist/agent-farm/servers/render-gate.d.ts.map +1 -0
  123. package/dist/agent-farm/servers/render-gate.js +251 -0
  124. package/dist/agent-farm/servers/render-gate.js.map +1 -0
  125. package/dist/agent-farm/servers/session-submit.d.ts +90 -0
  126. package/dist/agent-farm/servers/session-submit.d.ts.map +1 -0
  127. package/dist/agent-farm/servers/session-submit.js +127 -0
  128. package/dist/agent-farm/servers/session-submit.js.map +1 -0
  129. package/dist/agent-farm/servers/tower-cron.d.ts +10 -7
  130. package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
  131. package/dist/agent-farm/servers/tower-cron.js +58 -53
  132. package/dist/agent-farm/servers/tower-cron.js.map +1 -1
  133. package/dist/agent-farm/servers/tower-instances.d.ts +14 -2
  134. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  135. package/dist/agent-farm/servers/tower-instances.js +78 -16
  136. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  137. package/dist/agent-farm/servers/tower-messages.d.ts +38 -1
  138. package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -1
  139. package/dist/agent-farm/servers/tower-messages.js +106 -1
  140. package/dist/agent-farm/servers/tower-messages.js.map +1 -1
  141. package/dist/agent-farm/servers/tower-routes.d.ts +16 -4
  142. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  143. package/dist/agent-farm/servers/tower-routes.js +826 -145
  144. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  145. package/dist/agent-farm/servers/tower-server.js +188 -34
  146. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  147. package/dist/agent-farm/servers/tower-terminals.d.ts +23 -2
  148. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  149. package/dist/agent-farm/servers/tower-terminals.js +134 -127
  150. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  151. package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -1
  152. package/dist/agent-farm/servers/tower-tunnel.js +63 -4
  153. package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
  154. package/dist/agent-farm/servers/tower-types.d.ts +2 -1
  155. package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
  156. package/dist/agent-farm/servers/tower-utils.d.ts +64 -1
  157. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
  158. package/dist/agent-farm/servers/tower-utils.js +168 -1
  159. package/dist/agent-farm/servers/tower-utils.js.map +1 -1
  160. package/dist/agent-farm/servers/tower-websocket.d.ts +6 -1
  161. package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
  162. package/dist/agent-farm/servers/tower-websocket.js +95 -57
  163. package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
  164. package/dist/agent-farm/servers/write-queue.d.ts +35 -0
  165. package/dist/agent-farm/servers/write-queue.d.ts.map +1 -0
  166. package/dist/agent-farm/servers/write-queue.js +56 -0
  167. package/dist/agent-farm/servers/write-queue.js.map +1 -0
  168. package/dist/agent-farm/types.d.ts +39 -0
  169. package/dist/agent-farm/types.d.ts.map +1 -1
  170. package/dist/agent-farm/utils/agent-names.d.ts +2 -2
  171. package/dist/agent-farm/utils/agent-names.d.ts.map +1 -1
  172. package/dist/agent-farm/utils/agent-names.js +3 -3
  173. package/dist/agent-farm/utils/agent-names.js.map +1 -1
  174. package/dist/agent-farm/utils/architect-name.d.ts +2 -2
  175. package/dist/agent-farm/utils/architect-name.d.ts.map +1 -1
  176. package/dist/agent-farm/utils/architect-name.js +3 -3
  177. package/dist/agent-farm/utils/architect-name.js.map +1 -1
  178. package/dist/agent-farm/utils/config.d.ts +13 -0
  179. package/dist/agent-farm/utils/config.d.ts.map +1 -1
  180. package/dist/agent-farm/utils/config.js +33 -1
  181. package/dist/agent-farm/utils/config.js.map +1 -1
  182. package/dist/agent-farm/utils/harness.d.ts +103 -7
  183. package/dist/agent-farm/utils/harness.d.ts.map +1 -1
  184. package/dist/agent-farm/utils/harness.js +126 -19
  185. package/dist/agent-farm/utils/harness.js.map +1 -1
  186. package/dist/agent-farm/utils/message-format.d.ts +8 -0
  187. package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
  188. package/dist/agent-farm/utils/message-format.js +20 -0
  189. package/dist/agent-farm/utils/message-format.js.map +1 -1
  190. package/dist/agent-farm/utils/server-utils.d.ts +80 -4
  191. package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
  192. package/dist/agent-farm/utils/server-utils.js +286 -5
  193. package/dist/agent-farm/utils/server-utils.js.map +1 -1
  194. package/dist/cli.d.ts.map +1 -1
  195. package/dist/cli.js +6 -32
  196. package/dist/cli.js.map +1 -1
  197. package/dist/commands/consult/cli-options.d.ts +34 -0
  198. package/dist/commands/consult/cli-options.d.ts.map +1 -0
  199. package/dist/commands/consult/cli-options.js +67 -0
  200. package/dist/commands/consult/cli-options.js.map +1 -0
  201. package/dist/commands/consult/index.d.ts +56 -2
  202. package/dist/commands/consult/index.d.ts.map +1 -1
  203. package/dist/commands/consult/index.js +272 -28
  204. package/dist/commands/consult/index.js.map +1 -1
  205. package/dist/commands/consult/metrics.d.ts +42 -0
  206. package/dist/commands/consult/metrics.d.ts.map +1 -1
  207. package/dist/commands/consult/metrics.js +129 -9
  208. package/dist/commands/consult/metrics.js.map +1 -1
  209. package/dist/commands/doctor.d.ts.map +1 -1
  210. package/dist/commands/doctor.js +71 -19
  211. package/dist/commands/doctor.js.map +1 -1
  212. package/dist/commands/porch/checks.d.ts +23 -0
  213. package/dist/commands/porch/checks.d.ts.map +1 -1
  214. package/dist/commands/porch/checks.js +60 -0
  215. package/dist/commands/porch/checks.js.map +1 -1
  216. package/dist/commands/porch/config.d.ts +20 -0
  217. package/dist/commands/porch/config.d.ts.map +1 -1
  218. package/dist/commands/porch/config.js +20 -0
  219. package/dist/commands/porch/config.js.map +1 -1
  220. package/dist/commands/porch/index.js +21 -28
  221. package/dist/commands/porch/index.js.map +1 -1
  222. package/dist/commands/porch/next.d.ts.map +1 -1
  223. package/dist/commands/porch/next.js +2 -41
  224. package/dist/commands/porch/next.js.map +1 -1
  225. package/dist/lib/config.d.ts +69 -3
  226. package/dist/lib/config.d.ts.map +1 -1
  227. package/dist/lib/config.js +67 -3
  228. package/dist/lib/config.js.map +1 -1
  229. package/dist/lib/consult-lanes.d.ts +149 -0
  230. package/dist/lib/consult-lanes.d.ts.map +1 -0
  231. package/dist/lib/consult-lanes.js +360 -0
  232. package/dist/lib/consult-lanes.js.map +1 -0
  233. package/dist/lib/forge-contracts.d.ts +9 -0
  234. package/dist/lib/forge-contracts.d.ts.map +1 -1
  235. package/dist/lib/forge-contracts.js.map +1 -1
  236. package/dist/lib/github.d.ts +15 -1
  237. package/dist/lib/github.d.ts.map +1 -1
  238. package/dist/lib/github.js +18 -1
  239. package/dist/lib/github.js.map +1 -1
  240. package/dist/lib/prompt-behavior-metrics.d.ts +67 -0
  241. package/dist/lib/prompt-behavior-metrics.d.ts.map +1 -0
  242. package/dist/lib/prompt-behavior-metrics.js +290 -0
  243. package/dist/lib/prompt-behavior-metrics.js.map +1 -0
  244. package/dist/lib/skeleton.d.ts +22 -1
  245. package/dist/lib/skeleton.d.ts.map +1 -1
  246. package/dist/lib/skeleton.js +120 -0
  247. package/dist/lib/skeleton.js.map +1 -1
  248. package/dist/lib/test-env.d.ts +74 -0
  249. package/dist/lib/test-env.d.ts.map +1 -0
  250. package/dist/lib/test-env.js +92 -0
  251. package/dist/lib/test-env.js.map +1 -0
  252. package/dist/terminal/attach-replay.d.ts +39 -0
  253. package/dist/terminal/attach-replay.d.ts.map +1 -0
  254. package/dist/terminal/attach-replay.js +76 -0
  255. package/dist/terminal/attach-replay.js.map +1 -0
  256. package/dist/terminal/pty-manager.d.ts +2 -0
  257. package/dist/terminal/pty-manager.d.ts.map +1 -1
  258. package/dist/terminal/pty-manager.js +51 -23
  259. package/dist/terminal/pty-manager.js.map +1 -1
  260. package/dist/terminal/pty-session.d.ts +201 -1
  261. package/dist/terminal/pty-session.d.ts.map +1 -1
  262. package/dist/terminal/pty-session.js +327 -46
  263. package/dist/terminal/pty-session.js.map +1 -1
  264. package/dist/terminal/ring-buffer.d.ts +39 -6
  265. package/dist/terminal/ring-buffer.d.ts.map +1 -1
  266. package/dist/terminal/ring-buffer.js +74 -6
  267. package/dist/terminal/ring-buffer.js.map +1 -1
  268. package/dist/terminal/session-manager.d.ts +53 -0
  269. package/dist/terminal/session-manager.d.ts.map +1 -1
  270. package/dist/terminal/session-manager.js +94 -9
  271. package/dist/terminal/session-manager.js.map +1 -1
  272. package/dist/terminal/session-screen.d.ts +116 -0
  273. package/dist/terminal/session-screen.d.ts.map +1 -0
  274. package/dist/terminal/session-screen.js +180 -0
  275. package/dist/terminal/session-screen.js.map +1 -0
  276. package/dist/terminal/shellper-main.js +2 -1
  277. package/dist/terminal/shellper-main.js.map +1 -1
  278. package/dist/terminal/shellper-process.d.ts +1 -1
  279. package/dist/terminal/shellper-process.d.ts.map +1 -1
  280. package/dist/terminal/shellper-process.js +17 -8
  281. package/dist/terminal/shellper-process.js.map +1 -1
  282. package/dist/terminal/shellper-replay-buffer.d.ts +69 -7
  283. package/dist/terminal/shellper-replay-buffer.d.ts.map +1 -1
  284. package/dist/terminal/shellper-replay-buffer.js +167 -31
  285. package/dist/terminal/shellper-replay-buffer.js.map +1 -1
  286. package/package.json +13 -8
  287. package/scripts/forge/gitea/pr-view.sh +4 -1
  288. package/scripts/forge/github/pr-view.sh +1 -1
  289. package/scripts/forge/gitlab/pr-view.sh +4 -1
  290. package/skeleton/.claude/skills/afx/SKILL.md +68 -1
  291. package/skeleton/.claude/skills/arch-init/SKILL.md +22 -9
  292. package/skeleton/.claude/skills/arch-save/SKILL.md +183 -0
  293. package/skeleton/.claude/skills/codev/SKILL.md +31 -0
  294. package/skeleton/.claude/skills/runnable-worktrees/SKILL.md +119 -0
  295. package/skeleton/.codex/skills/afx/SKILL.md +68 -1
  296. package/skeleton/.codex/skills/arch-init/SKILL.md +22 -9
  297. package/skeleton/.codex/skills/arch-save/SKILL.md +183 -0
  298. package/skeleton/.codex/skills/codev/SKILL.md +31 -0
  299. package/skeleton/.codex/skills/runnable-worktrees/SKILL.md +119 -0
  300. package/skeleton/protocols/air/builder-prompt.md +28 -47
  301. package/skeleton/protocols/air/consult-types/impl-review.md +17 -34
  302. package/skeleton/protocols/air/consult-types/pr-review.md +14 -37
  303. package/skeleton/protocols/air/prompts/implement.md +20 -73
  304. package/skeleton/protocols/air/prompts/pr.md +22 -54
  305. package/skeleton/protocols/air/protocol.md +40 -71
  306. package/skeleton/protocols/aspir/builder-prompt.md +29 -66
  307. package/skeleton/protocols/aspir/consult-types/impl-review.md +17 -44
  308. package/skeleton/protocols/aspir/consult-types/phase-review.md +17 -44
  309. package/skeleton/protocols/aspir/consult-types/plan-review.md +14 -38
  310. package/skeleton/protocols/aspir/consult-types/pr-review.md +13 -39
  311. package/skeleton/protocols/aspir/consult-types/spec-review.md +13 -33
  312. package/skeleton/protocols/aspir/prompts/implement.md +27 -196
  313. package/skeleton/protocols/aspir/prompts/plan.md +21 -85
  314. package/skeleton/protocols/aspir/prompts/review.md +29 -228
  315. package/skeleton/protocols/aspir/prompts/specify.md +25 -111
  316. package/skeleton/protocols/aspir/protocol.json +10 -0
  317. package/skeleton/protocols/aspir/protocol.md +36 -82
  318. package/skeleton/protocols/bugfix/builder-prompt.md +23 -45
  319. package/skeleton/protocols/bugfix/consult-types/impl-review.md +21 -45
  320. package/skeleton/protocols/bugfix/consult-types/pr-review.md +18 -52
  321. package/skeleton/protocols/bugfix/prompts/fix.md +16 -61
  322. package/skeleton/protocols/bugfix/prompts/investigate.md +18 -62
  323. package/skeleton/protocols/bugfix/prompts/pr.md +22 -57
  324. package/skeleton/protocols/bugfix/protocol.md +44 -50
  325. package/skeleton/protocols/experiment/builder-prompt.md +25 -58
  326. package/skeleton/protocols/experiment/protocol.md +22 -188
  327. package/skeleton/protocols/experiment/templates/notes.md +11 -71
  328. package/skeleton/protocols/maintain/builder-prompt.md +24 -45
  329. package/skeleton/protocols/maintain/consult-types/impl-review.md +17 -44
  330. package/skeleton/protocols/maintain/consult-types/pr-review.md +13 -39
  331. package/skeleton/protocols/maintain/prompts/maintain.md +1 -1
  332. package/skeleton/protocols/maintain/protocol.md +32 -266
  333. package/skeleton/protocols/maintain/templates/maintenance-run.md +11 -0
  334. package/skeleton/protocols/pir/builder-prompt.md +31 -64
  335. package/skeleton/protocols/pir/consult-types/impl-review.md +17 -50
  336. package/skeleton/protocols/pir/consult-types/pr-review.md +11 -40
  337. package/skeleton/protocols/pir/prompts/implement.md +2 -3
  338. package/skeleton/protocols/pir/prompts/plan.md +1 -4
  339. package/skeleton/protocols/pir/prompts/review.md +2 -2
  340. package/skeleton/protocols/pir/protocol.md +54 -177
  341. package/skeleton/protocols/research/builder-prompt.md +27 -58
  342. package/skeleton/protocols/research/protocol.md +28 -153
  343. package/skeleton/protocols/spike/builder-prompt.md +30 -48
  344. package/skeleton/protocols/spike/protocol.md +24 -107
  345. package/skeleton/protocols/spike/templates/findings.md +9 -39
  346. package/skeleton/protocols/spir/builder-prompt.md +33 -62
  347. package/skeleton/protocols/spir/consult-types/impl-review.md +17 -44
  348. package/skeleton/protocols/spir/consult-types/phase-review.md +17 -44
  349. package/skeleton/protocols/spir/consult-types/plan-review.md +14 -38
  350. package/skeleton/protocols/spir/consult-types/pr-review.md +13 -39
  351. package/skeleton/protocols/spir/consult-types/spec-review.md +13 -33
  352. package/skeleton/protocols/spir/prompts/implement.md +26 -195
  353. package/skeleton/protocols/spir/prompts/plan.md +20 -84
  354. package/skeleton/protocols/spir/prompts/review.md +28 -227
  355. package/skeleton/protocols/spir/prompts/specify.md +24 -110
  356. package/skeleton/protocols/spir/protocol.json +10 -0
  357. package/skeleton/protocols/spir/protocol.md +84 -633
  358. package/skeleton/protocols/spir/templates/plan.md +28 -147
  359. package/skeleton/protocols/spir/templates/review.md +21 -80
  360. package/skeleton/protocols/spir/templates/spec.md +24 -118
  361. package/skeleton/resources/commands/agent-farm.md +262 -0
  362. package/skeleton/resources/commands/consult.md +236 -8
  363. package/skeleton/resources/commands/overview.md +1 -0
  364. package/skeleton/roles/architect.md +67 -317
  365. package/skeleton/roles/builder.md +76 -191
  366. package/skeleton/templates/AGENTS.md +2 -0
  367. package/skeleton/templates/CLAUDE.md +2 -0
  368. package/templates/3d-viewer.html +32 -4
  369. package/templates/open.html +58 -12
  370. package/templates/tower.html +65 -9
  371. package/templates/vendor/three-3MFLoader.js +1478 -0
  372. package/templates/vendor/three-STLLoader.js +410 -0
  373. package/templates/vendor/three-TrackballControls.js +828 -0
  374. package/templates/vendor/three-fflate.module.js +2474 -0
  375. package/templates/vendor/three.module.js +53044 -0
  376. package/dashboard-dist/assets/index-BZ1x7x1X.js.map +0 -1
  377. package/dashboard-dist/assets/index-DB1KBSNE.css +0 -32
  378. package/dist/agent-farm/servers/send-buffer.d.ts +0 -59
  379. package/dist/agent-farm/servers/send-buffer.d.ts.map +0 -1
  380. package/dist/agent-farm/servers/send-buffer.js +0 -116
  381. package/dist/agent-farm/servers/send-buffer.js.map +0 -1
  382. package/skeleton/porch/prompts/defend.md +0 -108
  383. package/skeleton/porch/prompts/diagnose.md +0 -70
  384. package/skeleton/porch/prompts/evaluate.md +0 -132
  385. package/skeleton/porch/prompts/fix.md +0 -59
  386. package/skeleton/porch/prompts/implement.md +0 -88
  387. package/skeleton/porch/prompts/plan.md +0 -74
  388. package/skeleton/porch/prompts/pr.md +0 -84
  389. package/skeleton/porch/prompts/review.md +0 -249
  390. package/skeleton/porch/prompts/specify.md +0 -53
  391. package/skeleton/porch/prompts/test.md +0 -63
  392. package/skeleton/protocols/aspir/templates/plan.md +0 -184
  393. package/skeleton/protocols/aspir/templates/review.md +0 -120
  394. package/skeleton/protocols/aspir/templates/spec.md +0 -154
@@ -1,232 +1,117 @@
1
1
  # Role: Builder
2
2
 
3
- A Builder is an implementation agent that works on a single project in an isolated git worktree.
3
+ You implement one project in an isolated git worktree, and you own it end to end: artifacts,
4
+ code, tests, PR.
4
5
 
5
- ## Two Operating Modes
6
+ ## Two modes
6
7
 
7
- Builders run in one of two modes, determined by how they were spawned:
8
+ | Mode | How you know | How you work |
9
+ |---|---|---|
10
+ | **Strict** (default) | spawned without `--soft` | Porch orchestrates. `porch next` gives you tasks; `porch done` signals completion. |
11
+ | **Soft** | spawned with `--soft` | You follow the protocol yourself; the architect verifies compliance. |
8
12
 
9
- | Mode | Command | Behavior |
10
- |------|---------|----------|
11
- | **Strict** (default) | `afx spawn XXXX` | Porch orchestrates - runs autonomously to completion |
12
- | **Soft** | `afx spawn XXXX --soft` | AI follows protocol - architect verifies compliance |
13
+ In strict mode porch drives the loop — run it, do the work it hands you, run it again. Do not
14
+ hand-run consultations it would run, advance plan phases yourself, or skip the 3-way review.
13
15
 
14
- ## Strict Mode (Default)
16
+ Never hand-edit `status.yaml` — only porch commands modify project state.
15
17
 
16
- Spawned with: `afx spawn XXXX`
18
+ ## Gates
17
19
 
18
- In strict mode, porch orchestrates your work and drives the protocol to completion autonomously. Your job is simple: **run porch until the project completes**.
20
+ Porch stops at human approval gates (`spec-approval`, `plan-approval`, `pr`). When it does:
21
+ say so, **stop**, and wait.
19
22
 
20
- ### The Core Loop
23
+ Never treat a porch gate as approved without an explicit human decision — a gate message is a notification to the human, not authorization.
21
24
 
22
- ```bash
23
- # 1. Check your current state
24
- porch status
25
-
26
- # 2. Run the protocol loop
27
- porch run
28
-
29
- # 3. If porch hits a gate, STOP and wait for human approval
30
- # 4. After gate approval, run porch again
31
- # 5. Repeat until project is complete
32
- ```
33
-
34
- Porch handles:
35
- - Spawning Claude to create artifacts (spec, plan, code)
36
- - Running 3-way consultations (Gemini, Codex, Claude)
37
- - Iterating based on feedback
38
- - Enforcing phase transitions
39
-
40
- ### Gates: When to STOP
41
-
42
- Porch has two human approval gates:
43
-
44
- | Gate | When | What to do |
45
- |------|------|------------|
46
- | `spec-approval` | After spec is written | **STOP** and wait |
47
- | `plan-approval` | After plan is written | **STOP** and wait |
48
-
49
- When porch outputs:
50
- ```
51
- GATE: spec-approval
52
- Human approval required. STOP and wait.
53
- ```
54
-
55
- You must:
56
- 1. Output a clear message: "Spec ready for approval. Waiting for human."
57
- 2. **STOP working**
58
- 3. Wait for the human to run `porch approve XXXX spec-approval`
59
- 4. After approval, run `porch run` again
60
-
61
- ### What You DON'T Do in Strict Mode
62
-
63
- - **Don't manually follow SPIR steps** - Porch handles this
64
- - **Don't run consult directly** - Porch runs 3-way reviews
65
- - **Don't edit status.yaml phase/iteration** - Only porch modifies state
66
- - **Don't call porch approve** - Only humans approve gates
67
- - **Don't skip gates** - Always stop and wait for approval
68
-
69
- ## Soft Mode
70
-
71
- Spawned with: `afx spawn XXXX --soft` or `afx spawn --task "..."`
72
-
73
- In soft mode, you follow the protocol document yourself. The architect monitors your work and verifies you're adhering to the protocol correctly.
74
-
75
- ### Startup Sequence
76
-
77
- ```bash
78
- # Read the spec and/or plan
79
- cat codev/specs/XXXX-*.md
80
- cat codev/plans/XXXX-*.md
81
-
82
- # (The full protocol text is inlined in your spawn prompt under the
83
- # "## Protocol Reference (full text)" heading; no need to fetch it.)
84
-
85
- # Start implementing
86
- ```
87
-
88
- ### The SPIR Protocol (Specify → Plan → Implement → Review (→ Verify))
89
-
90
- 1. **Specify**: Read or create the spec at `codev/specs/XXXX-name.md`
91
- 2. **Plan**: Read or create the plan at `codev/plans/XXXX-name.md`
92
- 3. **Implement**: Write code following the plan phases
93
- 4. **Review**: Write lessons learned and create PR
94
- 5. **Verify** (optional): After PR merge, verify the feature works in the integrated codebase
95
-
96
- ### Consultations
97
-
98
- Run 3-way consultations at checkpoints:
99
- ```bash
100
- # After writing spec
101
- consult -m gemini --protocol spir --type spec &
102
- consult -m codex --protocol spir --type spec &
103
- consult -m claude --protocol spir --type spec &
104
- wait
105
-
106
- # After writing plan
107
- consult -m gemini --protocol spir --type plan &
108
- consult -m codex --protocol spir --type plan &
109
- consult -m claude --protocol spir --type plan &
110
- wait
111
-
112
- # After implementation
113
- consult -m gemini --protocol spir --type pr &
114
- consult -m codex --protocol spir --type pr &
115
- consult -m claude --protocol spir --type pr &
116
- wait
117
- ```
25
+ Approval reaches you as a message from the architect. Then *you* run
26
+ `porch approve <id> <gate>`; the architect does not run it for you. Defer to your protocol's phase
27
+ prompts on who types `porch approve`.
118
28
 
119
29
  ## Deliverables
120
30
 
121
- - Spec at `codev/specs/XXXX-name.md`
122
- - Plan at `codev/plans/XXXX-name.md`
123
- - Review at `codev/reviews/XXXX-name.md`
124
- - Implementation code with tests
125
- - PR ready for architect review
126
-
127
- ## Communication
31
+ Same base filename in three directories, plus code and tests:
128
32
 
129
- ### With the Architect
130
-
131
- If you're blocked or need help:
132
- ```bash
133
- afx send architect "Question about the spec..."
134
33
  ```
135
-
136
- ### Checking Status
137
-
138
- ```bash
139
- porch status # (strict mode) Your project status
140
- afx status # All builders
34
+ codev/specs/<id>-<name>.md what and why
35
+ codev/plans/<id>-<name>.md how and in what order
36
+ codev/reviews/<id>-<name>.md what was learned
141
37
  ```
142
38
 
143
- ## Thread file
39
+ ## Your thread
144
40
 
145
- You maintain a free-text markdown log at `codev/state/<builder-id>_thread.md` (relative to your worktree). This is the cohort's collective situational-awareness surface — architects and sibling builders can read it via plain file I/O.
41
+ Keep a free-text log at `codev/state/<builder-id>_thread.md` — the cohort's shared situational
42
+ awareness, readable by architects and sibling builders. `<builder-id>` is `basename "$(pwd)"`.
43
+ Write at phase boundaries and whenever a future reader would want to know what happened:
44
+ decisions, blockers, surprises. No schema, no cadence requirement.
146
45
 
147
- **Path resolution**: `<builder-id>` is the basename of your worktree path. Resolve it once with `basename "$(pwd)"`. Example: if your worktree is `.builders/spir-823/`, the path is `codev/state/spir-823_thread.md`.
46
+ **Commit it with your PR.** Leaving it uncommitted by accident is a bug, not a choice.
148
47
 
149
- **Directory creation**: `codev/state/` likely doesn't exist when you start (it's greenfield). Your first write creates it — the Write tool's `mkdir -p` semantics handle this transparently. No need to pre-create the directory.
48
+ ## Telling the architect things
150
49
 
151
- **What to write**: phase transitions, decisions, blockers, anything worth recording for the cohort. Trust your own judgement about what's useful. There is no required schema, no required sections, no timestamp format. The thread is yours.
50
+ They are not watching. Send a message at each of these:
152
51
 
153
- **When to write**: at phase boundaries and at any other moment you think a future reader would want to know what happened. Don't over-engineer cadence — append when there's something to say.
52
+ | When | What |
53
+ |---|---|
54
+ | Gate reached | `afx send architect "Project <id>: <gate> ready for approval"` |
55
+ | PR ready | `afx send architect "PR #N ready for review"` |
56
+ | PR merged | `afx send architect "Project <id> complete. Entering verify phase."` |
57
+ | Blocked | `afx send architect "Blocked on X — need guidance"` |
154
58
 
155
- **Discovery**:
156
- - **In-flight** (while you're active): your thread lives in your worktree at `.builders/<builder-id>/codev/state/<builder-id>_thread.md` (from the main workspace root). Architects read it with `cat .builders/<id>/codev/state/<id>_thread.md`; they discover threads with `ls .builders/*/codev/state/*.md`.
157
- - **Sibling builders**: read each other's threads via `cat ../<sibling-id>/codev/state/<sibling-id>_thread.md` from your own worktree (the parent `.builders/` directory is shared between all builders in the workspace).
158
- - **Post-merge**: after your PR merges, your thread lands in `codev/state/` on `main` (parallel to `codev/reviews/`) and becomes part of the historical review record.
59
+ When blocked, state the problem and the options you see, then wait. Don't guess past a decision
60
+ that isn't yours.
159
61
 
160
- **Commit/retention rule**: **the default disposition is COMMIT.** Stage and commit your thread file as part of your PR. The rare exception — when your thread turned out to be noise rather than useful narrative — is an explicit decision to strip it before PR (via gitignore for the PR or by not staging the file). Silently leaving the thread uncommitted by accident is a bug, not an exercise of the exception. The cohort's situational-awareness goal depends on threads surviving to `main`.
62
+ ## Waiting on external work
161
63
 
162
- **Scope reminder**: this is for the cohort's situational awareness, not porch's tracking. Porch does not read this file. There are no hooks, no validation, no enforcement.
64
+ **A wait is a claim that a producer exists.** Before waiting on a file, a build, or a sibling's
65
+ output, confirm the process meant to produce it is alive. A builder once waited 45 minutes on a
66
+ file whose producer had already died — that wait was not slow, it was unsatisfiable.
163
67
 
164
- ## Notifications
68
+ **Run waits as background tasks that end your turn.** Every message sent to you — including an
69
+ order to stop — queues unread until your current turn ends. A turn that never ends is a builder
70
+ nobody can redirect, and you will not notice, because from inside it everything looks fine.
71
+ Never chain foreground poll loops.
165
72
 
166
- **ALWAYS notify the architect** via `afx send` at these key moments:
73
+ If you are wedged anyway, the architect can end your turn with `afx interrupt <your-id>`, or
74
+ `afx refresh <your-id>` to have you save state and re-orient. Worth knowing so you can suggest
75
+ them.
167
76
 
168
- | When | What to send |
169
- |------|-------------|
170
- | **Gate reached** | `afx send architect "Project XXXX: <gate-name> ready for approval"` |
171
- | **PR ready** | `afx send architect "PR #N ready for review"` |
172
- | **PR merged** | `afx send architect "Project XXXX complete. PR merged. Entering verify phase."` |
173
- | **Blocked/stuck** | `afx send architect "Blocked on X — need guidance"` |
174
- | **Escalation needed** | `afx send architect "Issue too complex — recommend escalating to SPIR"` |
77
+ ## PRs
175
78
 
176
- The architect may be working on other tasks and won't know you need attention unless you send a message. **Don't assume they're watching** — always notify explicitly.
79
+ Plan phases are **git commits inside one PR**, not a PR each. Open the PR during or after the
80
+ final phase unless the architect asks for one earlier — they may, to review a slice or get
81
+ feedback mid-flight. Record them with `porch done <id> --pr <N> --branch <name>` and
82
+ `porch done <id> --merged <N>`.
177
83
 
178
- ## When You're Blocked
84
+ For sequential PRs, branch from the integration branch without checking it out — a worktree
85
+ cannot check out a branch that is checked out elsewhere:
179
86
 
180
- If you encounter issues you can't resolve:
181
-
182
- 1. **Output a clear blocker message** describing the problem and options
183
- 2. **Use `afx send architect "..."` to notify the Architect**
184
- 3. **Wait for guidance** before proceeding
185
-
186
- Example:
187
- ```
188
- ## BLOCKED: Spec 0077
189
- Can't find the auth helper mentioned in spec. Options:
190
- 1. Create a new auth helper
191
- 2. Use a third-party library
192
- 3. Spec needs clarification
193
- Waiting for Architect guidance.
87
+ ```bash
88
+ git fetch origin main && git checkout -b <next-branch> origin/main
194
89
  ```
195
90
 
196
- ## Multi-PR Workflow
91
+ ## Worktree discipline
197
92
 
198
- Builders may submit multiple sequential PRs within a single worktree session. The worktree persists across PRs -- it is not cleaned up automatically after merge. This allows builders to do follow-up work (e.g., addressing review feedback in a second PR, or splitting large features across checkpoint PRs).
93
+ Your worktree is nested inside the main checkout and, at the branch base, byte-identical to it.
94
+ So a path that drops the `.builders/<id>/` segment silently reads and writes **main's** copy —
95
+ reads succeed, writes succeed, and nothing corrects you until a later `git add` fails.
199
96
 
200
- - **Worktree cleanup is architect-driven** -- the architect decides when to run `afx cleanup`, not the builder
201
- - If a builder session is interrupted, use `afx spawn XXXX --resume` to reconnect to the existing worktree
97
+ - Absolute paths for file writes must be rooted at your worktree. A guard blocks writes outside
98
+ it; if you see that denial, re-root the path.
99
+ - In Bash, prefer relative paths — `cwd` is your worktree, so a relative path cannot be anchored
100
+ to the wrong root.
202
101
 
203
- ## Worktree isolation: filesystem path discipline
102
+ ## Scope
204
103
 
205
- Your worktree (`.builders/<id>/`) is **nested inside the main checkout**, and at the
206
- branch base the two trees are **byte-identical**. This creates a silent failure mode:
104
+ Build what the spec says. If part of it is blocked, finish everything else and say plainly what
105
+ you left out and why — scaling the work down is the architect's call.
207
106
 
208
- - The `Write`/`Edit` tools require **absolute** paths. If you synthesize one rooted
209
- at the canonical repo root instead of your worktree, you drop the `.builders/<id>/`
210
- segment and write into the **main checkout** — a real, writable directory. The
211
- write *succeeds silently* and pollutes `main`; you only notice later when a
212
- `git add` in your worktree fails with a pathspec error.
213
- - Wrong-rooted **reads** also succeed silently (identical trees), so nothing
214
- corrects the mistake until that first failed write.
107
+ Never `git add -A` / `--all` / `.` — stage each file explicitly by path.
215
108
 
216
- Rules:
217
- - **Absolute paths for Write/Edit must be rooted at your worktree.** A deterministic
218
- PreToolUse guard now blocks out-of-worktree writes (allowing only temp dirs and
219
- `~/.claude`); if you see that denial, re-root the path under your worktree.
220
- - **Bash `cwd` is your worktree — prefer relative paths there.** A relative path
221
- cannot be anchored to the wrong root, which closes the Bash write surface
222
- (`>`, `cp`, `tee`, `sed -i`) the Write/Edit guard does not cover.
109
+ If the issue carries a **Baked Decisions** section, those are fixed. Don't relitigate them in
110
+ your spec, plan, or implementation; if one looks seriously wrong, raise it with `afx send`. If
111
+ two contradict each other, don't pick — flag the contradiction and wait.
223
112
 
224
- ## Constraints
113
+ ## Flaky tests
225
114
 
226
- - **Stay in scope** - Only implement what's in the spec
227
- - **Merge your own PRs** - After architect approves
228
- - **Keep worktree clean** - No untracked files, no debug code
229
- - **(Strict mode)** Run porch, don't bypass it
230
- - **(Strict mode)** Stop at gates - Human approval is required
231
- - **(Strict mode)** NEVER edit status.yaml directly
232
- - **(Strict mode)** NEVER call porch approve
115
+ If a pre-existing test fails intermittently and unrelated to your change: skip it with an
116
+ annotation naming it flaky, document it under `## Flaky Tests` in your review, and continue.
117
+ Never edit `status.yaml` or bypass a porch check to route around it.
@@ -134,6 +134,8 @@ Agents within a workspace communicate through `afx send`. Four addressing forms
134
134
  | `afx send architect:<name> "msg"` | Explicit per-architect addressing. **Architects (including `main`)**: open address grammar — any architect can address any other architect (sibling-architect messaging). **Builders**: allowed ONLY when `<name>` matches the builder's own spawning architect; mismatches are rejected by Tower's spoofing check. From a builder, this is an explicit form of the affinity routing, NOT an override. | Any sender (with the spoofing constraint above for builders). |
135
135
  | `afx send <workspace>:architect "msg"` | Cross-workspace addressing (e.g. `afx send marketmaker:architect "..."`). | Any sender. |
136
136
 
137
+ **Send outcomes (delivered vs held)**: `afx send` reports the real first outcome. **delivered** means the message was written to the recipient's prompt after a clean render-gate pass; **held** means the prompt wasn't clear, so the message was persisted in Tower's durable mailbox and delivers automatically once the prompt is clean — with a why-held reason (`busy`, `no-profile`, or `no-live-pty`) and a mailbox id. A held message is never force-injected onto a busy line, so it can't corrupt a half-typed draft, and held rows survive a Tower restart. List held messages with `afx inbox`, read one (including its body) with `afx inbox show <id>`, and clear one with `afx inbox dismiss <id>`; `afx send --interrupt` is the explicit bypass.
138
+
137
139
  **Sibling-architect messaging**: when a workspace hosts more than one architect (added via `afx workspace add-architect --name <name>`), sibling architects message each other via the `architect:<name>` form. Example: `main` running `afx send architect:ob-refine "PR-iter-2 feedback ready"` lands on the `ob-refine` architect's terminal. This works because sender = architect bypasses the spoofing check.
138
140
 
139
141
  **Builder spoofing-check**: a builder may only address its own spawning architect via `architect:<name>`. The spoofing check is enforced by Tower's message router; attempts to address a different architect from a builder are rejected.
@@ -132,6 +132,8 @@ Agents within a workspace communicate through `afx send`. Four addressing forms
132
132
  | `afx send architect:<name> "msg"` | Explicit per-architect addressing. **Architects (including `main`)**: open address grammar — any architect can address any other architect (sibling-architect messaging). **Builders**: allowed ONLY when `<name>` matches the builder's own spawning architect; mismatches are rejected by Tower's spoofing check. From a builder, this is an explicit form of the affinity routing, NOT an override. | Any sender (with the spoofing constraint above for builders). |
133
133
  | `afx send <workspace>:architect "msg"` | Cross-workspace addressing (e.g. `afx send marketmaker:architect "..."`). | Any sender. |
134
134
 
135
+ **Send outcomes (delivered vs held)**: `afx send` reports the real first outcome. **delivered** means the message was written to the recipient's prompt after a clean render-gate pass; **held** means the prompt wasn't clear, so the message was persisted in Tower's durable mailbox and delivers automatically once the prompt is clean — with a why-held reason (`busy`, `no-profile`, or `no-live-pty`) and a mailbox id. A held message is never force-injected onto a busy line, so it can't corrupt a half-typed draft, and held rows survive a Tower restart. List held messages with `afx inbox`, read one (including its body) with `afx inbox show <id>`, and clear one with `afx inbox dismiss <id>`; `afx send --interrupt` is the explicit bypass.
136
+
135
137
  **Sibling-architect messaging**: when a workspace hosts more than one architect (added via `afx workspace add-architect --name <name>`), sibling architects message each other via the `architect:<name>` form. Example: `main` running `afx send architect:ob-refine "PR-iter-2 feedback ready"` lands on the `ob-refine` architect's terminal. This works because sender = architect bypasses the spoofing check.
136
138
 
137
139
  **Builder spoofing-check**: a builder may only address its own spawning architect via `architect:<name>`. The spoofing check is enforced by Tower's message router; attempts to address a different architect from a builder are rejected.
@@ -218,12 +218,18 @@
218
218
  </div>
219
219
  </div>
220
220
 
221
- <!-- Three.js ES Modules via import map -->
221
+ <!-- Three.js ES Modules — vendored locally (three@0.160.0), served same-origin
222
+ from the annotator's vendor/ route. NO remote code runs in this page: it is
223
+ key-injected (advisory GHSA-xvjp-7748-v88v), so loading executable modules
224
+ from a CDN would expose window.__CODEV_TOWER_KEY__ to that CDN. -->
222
225
  <script type="importmap">
223
226
  {
224
227
  "imports": {
225
- "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
226
- "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
228
+ "three": "vendor/three.module.js",
229
+ "three/addons/loaders/STLLoader.js": "vendor/three-STLLoader.js",
230
+ "three/addons/loaders/3MFLoader.js": "vendor/three-3MFLoader.js",
231
+ "three/addons/controls/TrackballControls.js": "vendor/three-TrackballControls.js",
232
+ "fflate": "vendor/three-fflate.module.js"
227
233
  }
228
234
  }
229
235
  </script>
@@ -234,6 +240,24 @@
234
240
  import { ThreeMFLoader } from 'three/addons/loaders/3MFLoader.js';
235
241
  import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
236
242
 
243
+ // Request authentication (advisory GHSA-xvjp-7748-v88v): Tower injects the
244
+ // shared local key into this page same-origin; model/mtime requests send it
245
+ // via the codev-tower-key header. Three.js loaders carry it through
246
+ // loader.setRequestHeader(authHeaders()).
247
+ function getWebKey() {
248
+ if (window.__CODEV_TOWER_KEY__) {
249
+ try { localStorage.setItem('codev-tower-key', window.__CODEV_TOWER_KEY__); } catch (e) {}
250
+ return window.__CODEV_TOWER_KEY__;
251
+ }
252
+ return localStorage.getItem('codev-tower-key');
253
+ }
254
+ function authHeaders(extra) {
255
+ const key = getWebKey();
256
+ const headers = extra ? Object.assign({}, extra) : {};
257
+ if (key) headers['codev-tower-key'] = key;
258
+ return headers;
259
+ }
260
+
237
261
  // Configuration (injected by server with proper escaping)
238
262
  const FILE_PATH = {{FILE_PATH_JSON}}; // JSON-encoded by server
239
263
  const FILE_NAME = '{{FILE}}';
@@ -370,6 +394,7 @@
370
394
 
371
395
  function loadSTL() {
372
396
  const loader = new STLLoader();
397
+ loader.setRequestHeader(authHeaders());
373
398
 
374
399
  loader.load(
375
400
  'api/model',
@@ -412,6 +437,7 @@
412
437
 
413
438
  function load3MF() {
414
439
  const loader = new ThreeMFLoader();
440
+ loader.setRequestHeader(authHeaders());
415
441
 
416
442
  loader.load(
417
443
  'api/model',
@@ -715,7 +741,7 @@
715
741
 
716
742
  async function checkForChanges() {
717
743
  try {
718
- const res = await fetch('api/mtime');
744
+ const res = await fetch('api/mtime', { headers: authHeaders() });
719
745
  if (res.ok) {
720
746
  const data = await res.json();
721
747
  if (lastMtime === null) {
@@ -769,6 +795,7 @@
769
795
 
770
796
  function reloadSTL() {
771
797
  const loader = new STLLoader();
798
+ loader.setRequestHeader(authHeaders());
772
799
  loader.load('api/model?t=' + Date.now(), (geometry) => {
773
800
  // Center geometry in XY
774
801
  geometry.computeBoundingBox();
@@ -811,6 +838,7 @@
811
838
 
812
839
  function reload3MF() {
813
840
  const loader = new ThreeMFLoader();
841
+ loader.setRequestHeader(authHeaders());
814
842
  loader.load('api/model?t=' + Date.now(), (group) => {
815
843
  // 3MF uses Z-up natively, which matches our coordinate system
816
844
 
@@ -569,6 +569,51 @@
569
569
  <script src="vendor/prism-markup.min.js"></script>
570
570
 
571
571
  <script>
572
+ // Request authentication (advisory GHSA-xvjp-7748-v88v): Tower injects the
573
+ // shared local key into this page same-origin; every data/media fetch sends
574
+ // it via the codev-tower-key header. Media is fetched as an authenticated blob
575
+ // (img/video/pdf src cannot carry a header) and displayed via an object URL,
576
+ // revoked when replaced or on unload to avoid blob leaks.
577
+ function getWebKey() {
578
+ if (window.__CODEV_TOWER_KEY__) {
579
+ try { localStorage.setItem('codev-tower-key', window.__CODEV_TOWER_KEY__); } catch (e) {}
580
+ return window.__CODEV_TOWER_KEY__;
581
+ }
582
+ return localStorage.getItem('codev-tower-key');
583
+ }
584
+ function authHeaders(extra) {
585
+ const key = getWebKey();
586
+ const headers = extra ? Object.assign({}, extra) : {};
587
+ if (key) headers['codev-tower-key'] = key;
588
+ return headers;
589
+ }
590
+ function setMediaSrc(el, objectUrl) {
591
+ if (el.__objUrl) URL.revokeObjectURL(el.__objUrl);
592
+ el.__objUrl = objectUrl;
593
+ el.src = objectUrl;
594
+ }
595
+ async function loadMedia(el, path) {
596
+ try {
597
+ const res = await fetch(path, { headers: authHeaders() });
598
+ if (!res.ok) throw new Error('status ' + res.status);
599
+ const blob = await res.blob();
600
+ setMediaSrc(el, URL.createObjectURL(blob));
601
+ } catch (e) {
602
+ if (typeof el.onerror === 'function') el.onerror();
603
+ }
604
+ }
605
+ function revokeAllMediaUrls() {
606
+ ['image-display', 'video-display', 'pdf-display'].forEach(function(id) {
607
+ const el = document.getElementById(id);
608
+ if (el && el.__objUrl) URL.revokeObjectURL(el.__objUrl);
609
+ });
610
+ }
611
+ // pagehide fires on mobile / bfcache navigations where beforeunload does not.
612
+ // Skip revocation when the page is going into the bfcache (persisted): the
613
+ // object URLs must survive so restored media still renders on pageshow.
614
+ window.addEventListener('pagehide', function(e) { if (!e.persisted) revokeAllMediaUrls(); });
615
+ window.addEventListener('beforeunload', revokeAllMediaUrls);
616
+
572
617
  // State
573
618
  let fileLines = [];
574
619
  let currentLine = null;
@@ -673,8 +718,8 @@
673
718
  img.style.display = 'none';
674
719
  };
675
720
 
676
- // Add cache-busting query param to allow reload
677
- img.src = 'api/image?t=' + Date.now();
721
+ // Fetch as an authenticated blob (img.src cannot carry the key header).
722
+ loadMedia(img, 'api/image?t=' + Date.now());
678
723
  }
679
724
 
680
725
  // Initialize video viewer
@@ -707,8 +752,8 @@
707
752
  video.style.display = 'none';
708
753
  };
709
754
 
710
- // Add cache-busting query param to allow reload
711
- video.src = 'api/video?t=' + Date.now();
755
+ // Fetch as an authenticated blob (video.src cannot carry the key header).
756
+ loadMedia(video, 'api/video?t=' + Date.now());
712
757
  }
713
758
 
714
759
  // Initialize PDF viewer
@@ -726,9 +771,10 @@
726
771
  const pdfViewer = document.getElementById('pdf-viewer');
727
772
  pdfViewer.style.display = 'block';
728
773
 
729
- // Load PDF via raw endpoint
774
+ // Load PDF via raw endpoint as an authenticated blob (embed.src cannot
775
+ // carry the key header).
730
776
  const embed = document.getElementById('pdf-display');
731
- embed.src = 'api/pdf?t=' + Date.now();
777
+ loadMedia(embed, 'api/pdf?t=' + Date.now());
732
778
  }
733
779
 
734
780
  // Update image info display (in both header and controls)
@@ -1339,7 +1385,7 @@
1339
1385
  try {
1340
1386
  const response = await fetch('save', {
1341
1387
  method: 'POST',
1342
- headers: { 'Content-Type': 'application/json' },
1388
+ headers: authHeaders({ 'Content-Type': 'application/json' }),
1343
1389
  body: JSON.stringify({
1344
1390
  file: filePath,
1345
1391
  content: fileLines.join('\n')
@@ -1457,7 +1503,7 @@
1457
1503
  try {
1458
1504
  const response = await fetch('save', {
1459
1505
  method: 'POST',
1460
- headers: { 'Content-Type': 'application/json' },
1506
+ headers: authHeaders({ 'Content-Type': 'application/json' }),
1461
1507
  body: JSON.stringify({ file: filePath, content })
1462
1508
  });
1463
1509
 
@@ -1778,7 +1824,7 @@
1778
1824
  if (hasUnsavedChanges || editMode) return;
1779
1825
 
1780
1826
  try {
1781
- const res = await fetch('api/mtime');
1827
+ const res = await fetch('api/mtime', { headers: authHeaders() });
1782
1828
  if (res.ok) {
1783
1829
  const data = await res.json();
1784
1830
  if (lastMtime === null) {
@@ -1797,21 +1843,21 @@
1797
1843
  // For images and videos, just reload the source
1798
1844
  if (isImageFile) {
1799
1845
  const img = document.getElementById('image-display');
1800
- img.src = 'api/image?t=' + Date.now();
1846
+ loadMedia(img, 'api/image?t=' + Date.now());
1801
1847
  showNotification('Image reloaded');
1802
1848
  return;
1803
1849
  }
1804
1850
 
1805
1851
  if (isVideoFile) {
1806
1852
  const video = document.getElementById('video-display');
1807
- video.src = 'api/video?t=' + Date.now();
1853
+ loadMedia(video, 'api/video?t=' + Date.now());
1808
1854
  showNotification('Video reloaded');
1809
1855
  return;
1810
1856
  }
1811
1857
 
1812
1858
  // For text files, fetch new content
1813
1859
  try {
1814
- const res = await fetch('file');
1860
+ const res = await fetch('file', { headers: authHeaders() });
1815
1861
  if (res.ok) {
1816
1862
  const content = await res.text();
1817
1863
  currentContent = content;