elanous 0.2.42 → 0.2.44

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 (764) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/08334415.f0e80896acbef722.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1032-78ba4f6391258cab.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1082-53f86a26e03d309d.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1109-7d0e264f6f2edbc7.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1124-7c26330402481143.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{2160.a097e7b138ae1c55.js → 118.2a89982fe4276880.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1244.6c435dbf1bf21d8a.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1252.9e665904d3aa3b1a.js +32 -0
  12. package/apps/pwa/out/_next/static/chunks/1266.a46cc33cb6a72d75.js +104 -0
  13. package/apps/pwa/out/_next/static/chunks/1306.967240ede9a0f757.js +24 -0
  14. package/apps/pwa/out/_next/static/chunks/1344.3b95f3bd1b77a3fe.js +94 -0
  15. package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 1401.22dfe92640a2b1ac.js} +4 -4
  16. package/apps/pwa/out/_next/static/chunks/1431-f7c78bd5be21e011.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1451-cdd35a8a0b31834b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 1694.18debfd77562e56d.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1708-f03d587b7a7545c8.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1775-fa7152bdeff6c95f.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/178-4da509cd7266672a.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1850-522de4ee34957210.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1876-c6f6e0ddcc76c6a1.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/1976.097066b072432242.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1978.eeb60a606dc5deac.js} +2 -2
  26. package/apps/pwa/out/_next/static/chunks/2043.e233e3b5a3e790f5.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2150.71b94e3348107c83.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2158.ebc6fc5a10280ab7.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2216.802962c04f40a26e.js +64 -0
  30. package/apps/pwa/out/_next/static/chunks/2294.7890edcfa046c97d.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/235.c89aaae4bcd6233a.js +74 -0
  32. package/apps/pwa/out/_next/static/chunks/{5885.0a3e52c8faccec98.js → 239.de075467b5523469.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/249.ba7051590d603c8f.js +226 -0
  34. package/apps/pwa/out/_next/static/chunks/2571.a6ac4e26c8618403.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/2610.e149cd564a08913e.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/2705.9816f3c244f8b85f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/2801.afeb8a4dae22f85f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/2954.bbefc95d6b20e0d8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/2e0f720a.a0697c08e3806a60.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3042.96ec235fe41c8d4e.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3097-8e358f158acef46b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3205-93b1abe28b4fb16a.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3273.b4434f0dcae7eb29.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3311.9cbc43ea0c90d60c.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 3349.b5f09ee474d9533e.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/3503.a47a9755fb4d97b0.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3506-5f429b3b7e1392b0.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/3843.bad404d008893291.js +77 -0
  49. package/apps/pwa/out/_next/static/chunks/3877-4b40e530b47e3bf9.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/435-ce2958253cf7de61.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4393.28fa5228d0eec217.js +149 -0
  52. package/apps/pwa/out/_next/static/chunks/4404.7281c847c6e10dfc.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 4415-b9d6a90960920a4a.js} +3 -3
  54. package/apps/pwa/out/_next/static/chunks/447-5b304de1fe098f43.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4484-8ebea83d431e6fae.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 4502.bdcc877abd437a05.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/4599-f95790fc5c65b8df.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 46.57c783fa4884714f.js} +2 -2
  59. package/apps/pwa/out/_next/static/chunks/463-b9114e411f33728e.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/4659.a57d1f0c5d754cd2.js +36 -0
  61. package/apps/pwa/out/_next/static/chunks/4722-a847e7a28115035f.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 4757.67c6d7473a038e78.js} +1 -1
  63. package/apps/pwa/out/_next/static/chunks/4874-c86f878ec4502ad3.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{6377.bc7df239edbff244.js → 4891.3f80ba517a3b2373.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/4998.810ca8833084caa9.js +62 -0
  66. package/apps/pwa/out/_next/static/chunks/4f98febc.ea5841d4d616bfb2.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5052.7dbb12a55d4f18f5.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/5166-ca73b3e361085a6d.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5180-039f4a18b07ad387.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/5232.5a2ce4daf7a9e11d.js +115 -0
  71. package/apps/pwa/out/_next/static/chunks/5439.3fec6dbce29ecb36.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5612-074d9a5e00dfac6a.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/5675-01989d524a84c505.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/5751.af641a1adf5ec697.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/5758-c6cb98714d18ab0c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/578eded8.b582637306e16964.js +122 -0
  77. package/apps/pwa/out/_next/static/chunks/5790.5eb06a653ebd8571.js +34 -0
  78. package/apps/pwa/out/_next/static/chunks/5853-4033e5bd5afbe06b.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/5904.97d70bb7f46b2db7.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 5989.7ecd362c5c44b747.js} +3 -3
  81. package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 5a34fb2f.52f1b4e1baebb48a.js} +3 -3
  82. package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 5a5078f8.2099200e5ea95e16.js} +1 -1
  83. package/apps/pwa/out/_next/static/chunks/6036-c302c34ff0b3d410.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/606.ef81c313381f4264.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/616.1af54a928b1ba704.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6201.bc936f71f613a8e9.js +41 -0
  87. package/apps/pwa/out/_next/static/chunks/6204-fdc86e0e64c4f92d.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 6245.1182e007e9d230d9.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 63699a35.17262e162bc514b2.js} +1 -1
  90. package/apps/pwa/out/_next/static/chunks/6420.494801a80030160c.js +27 -0
  91. package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → 6549dad0.2740b25e51bf8f05.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 6881.9e7955847640c7fe.js} +17 -17
  93. package/apps/pwa/out/_next/static/chunks/6931.fcdfb94141e67b3d.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/6991-8e081c6ce38c0ba1.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7010.1bbd17a7f2b3e376.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7029.d1466acf55fae2ed.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7152-a123aa8e129c131f.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7455.196168fffac3b9c4.js +24 -0
  99. package/apps/pwa/out/_next/static/chunks/7638.6ca4770dd1129138.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/7649-f37d76260e5e2a5a.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/7679.32c40cdd14f20b4a.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/7751.04bfbd16b4c6cd0a.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/7864.b1ff31d4030b8994.js +148 -0
  104. package/apps/pwa/out/_next/static/chunks/7869-c47bd2c075c1fefa.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 8442.2f09ca969d631615.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8445.2738dbd59a78c78c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8447.5510c439f9938c6d.js +286 -0
  108. package/apps/pwa/out/_next/static/chunks/{9415.69e4a21c60c7d2db.js → 8551.f762945c2cda2e95.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/8635-57a9d8d9db70f4f1.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/86961958-4b0689a5048f756b.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/8709.3c6019bb18f8554f.js +8 -0
  112. package/apps/pwa/out/_next/static/chunks/8759.c999528a0a907bf6.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9a852a62-6192a6ea9346ced3.js → 87f498e5-0881de09f2e44707.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/8843.c3197f904c952b81.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → 892fd990.456232f326cc39c2.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/8965-135a2c9eaa2464cb.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/8971-8d3b9c96f8a6c958.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9059.c8598d96f8e5e9cd.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9115.90447ae198b84eae.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9147.d9b0a02e0babc9b4.js +93 -0
  121. package/apps/pwa/out/_next/static/chunks/9204-83075f4b70c61cdc.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9244-c32ef14b5dc72bdf.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/930.2a9a30f964350c66.js +90 -0
  124. package/apps/pwa/out/_next/static/chunks/9398.1f56e3f17795f43f.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/9527.3e5ad31c891c5fcb.js +79 -0
  126. package/apps/pwa/out/_next/static/chunks/9571-4ac933e774d1225c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-9fc644de2d8edae3.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/approvals/page-0c9dace2db62bee8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f5e65c3dc9d89f2a.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/board/page-2a9c19b9a140b7b1.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/botlab/page-61533ad92141adfb.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/bots/page-112004ced6fd0329.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f733318c237a49d8.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/chat/page-51ea677d2d33bbc0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/consult/page-428b41f2f9566e3c.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/control/page-1b29396ea90a61e5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/decisions/page-cf83ec613ac904bf.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/design-check/page-3f4c0ecbc284bb5f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/editor/page-b63c322f54f70cc6.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/exec/page-fe328c4ee9aac6b4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/field/page-bfb855c584f0fb98.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/healthz/route-9fc644de2d8edae3.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/inside/page-47b1710c110eabd7.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/intake/page-42895214458bc6d2.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/layout-d03de0ebd8366e23.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/live/page-3ed6c47e4b1c61c2.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/live-run/page-ae653e9bf261c738.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/loops/page-23f3f0a0209c0ac4.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/market/page-88c691273aae66f9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e187ac52a95538b3.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/morning/page-6e45828daed1295e.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/not-found-edb5d7287bb46186.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/observatory/page-4a7eaacd93c3f6a5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ca073d43d74cc84.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1e9fee67b1199436.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-df1283ea963c6816.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/outputs/page-19fcf8d8301ccd18.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/page-5ab699e0303bbb40.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7cde0d29756984c5.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9d4c598e8ee22f7a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/sessions/page-cc1609a71f44ec62.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7659a9a1345bfaa9.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/settings/page-0afef60ecc0c4af5.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a3553949f8f34f5f.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/setup/layout-9fc644de2d8edae3.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/setup/page-057a69702f3c67c7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/share/page-c0f0e570f3f74c73.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/showroom/page-1825071ae34e3b89.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6244e3e135d8ccfc.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/term/page-da787e8a10b8a82e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/today/page-1316d32498e2be42.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/trace/page-4df94572e343de2e.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/vault/page-708969f7475e88c1.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c58add08c919a1dc.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a24847f45e5d5bf9.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/app/workspace/page-acfec65a3a60e22e.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-3dfc598e6fbde245.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-c658a626118411b7.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-4c73685fd891445b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-6310f7e5de7dd01d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-51c326bf48610be1.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-d0beadf754da59b0.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-acd243bfbf3f6732.js +1 -0
  184. package/apps/pwa/out/_next/static/css/d1f8bb401740a549.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/catalog/external-commands.yaml +5 -3
  279. package/catalog/meta/catalogVersion.yaml +2 -1
  280. package/catalog/signing/catalog-signing-public.pem +3 -0
  281. package/graphs/intake/intake-daily.yaml +16 -0
  282. package/graphs/intake/news-sources.yaml +1 -0
  283. package/graphs/intake/recipes.yaml +7 -0
  284. package/graphs/overlays/README.md +6 -0
  285. package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
  286. package/graphs/profiles/local.yaml +5 -0
  287. package/graphs/profiles/pod.yaml +4 -0
  288. package/graphs/release/release-loop.yaml +33 -17
  289. package/graphs/units/verbs/make-doc.yaml +1 -0
  290. package/package.json +6 -2
  291. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  292. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  293. package/plugins/demo-browser-hand/plugin.json +13 -0
  294. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  295. package/plugins/demo-linear-secretary/plugin.json +15 -0
  296. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  297. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  298. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  299. package/plugins/demo-research/plugin.json +16 -0
  300. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  301. package/plugins/demo-video-briefing/plugin.json +15 -0
  302. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  303. package/scripts/bench-metering-plan.ts +229 -0
  304. package/scripts/build-signed-catalog.ts +48 -0
  305. package/scripts/ci-typecheck-main-delta.sh +88 -0
  306. package/scripts/codex-fallback-live-probe.ts +1 -1
  307. package/scripts/demo/demo1104-parallel-host.ts +56 -0
  308. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  309. package/scripts/demo/demo1104-parallel.ts +72 -0
  310. package/scripts/demo/demo1104-stage.config.ts +21 -0
  311. package/scripts/demo/demo1104-stage.ts +316 -0
  312. package/scripts/goal-method-audit.ts +17 -1
  313. package/scripts/graph-units/land-enqueue.ts +90 -0
  314. package/scripts/hooks/codex-notify.sh +32 -0
  315. package/scripts/install.sh +10 -38
  316. package/scripts/landing-heal/land-plan.ts +57 -0
  317. package/scripts/public-leak-baseline.txt +0 -1
  318. package/scripts/release-loop/auto-approve-node.ts +1 -1
  319. package/scripts/release-loop/docs-node.ts +4 -2
  320. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  321. package/scripts/release-loop/gate-image-pin.ts +116 -2
  322. package/scripts/release-loop/gate-method.ts +139 -0
  323. package/scripts/release-loop/gate-node.ts +395 -43
  324. package/scripts/release-loop/gate-progress-sim.ts +73 -0
  325. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  326. package/scripts/release-loop/node-verdict.ts +38 -25
  327. package/scripts/release-loop/notes-repair.ts +18 -1
  328. package/scripts/release-loop/preflight.ts +544 -10
  329. package/scripts/release-loop/render-warm-control-manifest.ts +22 -0
  330. package/scripts/release-loop/resume-release.ts +9 -7
  331. package/scripts/release-loop/resume.ts +13 -4
  332. package/scripts/release-loop/unattended-release.ts +20 -9
  333. package/scripts/release-loop/warm-control-forward.ts +178 -0
  334. package/scripts/retro-cycle.ts +30 -8
  335. package/scripts/rhythm/daily.ts +39 -4
  336. package/scripts/rhythm/linear-progress-sync.ts +311 -0
  337. package/scripts/ux-sim.ts +7 -1
  338. package/scripts/video-pipeline.ts +9 -1
  339. package/scripts/warm-pool-provider-config.ts +35 -7
  340. package/src/acp/agent-manager.ts +1 -0
  341. package/src/acp/codex-app-server-agent.ts +33 -0
  342. package/src/acp/codex-app-server-client.ts +153 -16
  343. package/src/acp/core-turn-bridge.ts +17 -12
  344. package/src/acp/event-router.ts +20 -1
  345. package/src/acp/server.ts +6 -0
  346. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  347. package/src/agent-mission/claude-headless.ts +4 -1
  348. package/src/agent-mission/codex-exec.ts +105 -0
  349. package/src/agent-mission/driver.ts +192 -11
  350. package/src/agent-mission/grok-auth-status.ts +107 -0
  351. package/src/agent-mission/hand-hooks.ts +101 -0
  352. package/src/agent-mission/mission-cli.ts +56 -21
  353. package/src/agent-mission/mission-hand-reply.ts +118 -0
  354. package/src/agent-mission/mission-line.ts +180 -0
  355. package/src/agent-mission/mission-out.ts +256 -18
  356. package/src/agent-mission/tool-install.ts +122 -11
  357. package/src/agent-substrate/pr-reviewer.ts +147 -11
  358. package/src/agent-substrate/self-review-cli.ts +10 -2
  359. package/src/agents/general-purpose.md +1 -1
  360. package/src/auto-research/research-fanout.ts +221 -0
  361. package/src/auto-research/research-turn.ts +362 -31
  362. package/src/autopilot/mission-codebase-gate.ts +7 -3
  363. package/src/autopilot/pr-manager.ts +31 -3
  364. package/src/boot/daemon-tools/self-implement.ts +3 -1
  365. package/src/boot/daemon-tools/web-search.ts +1 -2
  366. package/src/briefing/brief-items.ts +55 -11
  367. package/src/cli/agent-cli.ts +2 -1
  368. package/src/cli/catalog-cli.ts +31 -0
  369. package/src/cli/connector-cli.ts +16 -0
  370. package/src/cli/control-cli.ts +15 -6
  371. package/src/cli/doctor-fix.ts +2 -2
  372. package/src/cli/intake-source-cli.ts +44 -8
  373. package/src/cli/log-event-names.ts +8 -0
  374. package/src/cli/msg-cli.ts +32 -3
  375. package/src/cli/pr-cli.ts +21 -1
  376. package/src/cli/pr-land-heavy-remote.ts +44 -6
  377. package/src/cli/pr-land-overlap-evidence.ts +13 -1
  378. package/src/cli/pr-land-pod-shadow-job.ts +143 -5
  379. package/src/cli/pr-land-pod-shadow.ts +9 -2
  380. package/src/cli/release-checklist-read-cli.ts +44 -16
  381. package/src/cli/release-cli.ts +23 -3
  382. package/src/cli/research-cli.ts +9 -0
  383. package/src/cli/setup-cli.ts +166 -6
  384. package/src/cli/setup-keys.ts +199 -0
  385. package/src/cli/task-plugin-wizard-host.ts +114 -0
  386. package/src/cli/tasks-cli.ts +54 -9
  387. package/src/cli/tui-test-cli.ts +190 -0
  388. package/src/config.ts +4 -2
  389. package/src/connectors/linear-daily-progress.ts +228 -0
  390. package/src/connectors/linear-projector.ts +34 -12
  391. package/src/connectors/linear.ts +151 -7
  392. package/src/control-plane/ledger.ts +42 -4
  393. package/src/control-plane/member-tokens.ts +25 -2
  394. package/src/control-plane/ports.ts +8 -3
  395. package/src/control-plane/server.ts +26 -5
  396. package/src/core-turn/deep-turn-bloom.ts +67 -0
  397. package/src/core-turn/research-policy.ts +43 -0
  398. package/src/core-turn/run-core-turn.ts +488 -51
  399. package/src/core-turn/types.ts +4 -0
  400. package/src/dashboard/chat/acp-chat.ts +10 -0
  401. package/src/dashboard/classic-sidetab-mission-job.ts +192 -0
  402. package/src/dashboard/classic-sidetab-mission-pair.ts +82 -0
  403. package/src/dashboard/classic-sidetab-mission-trio.ts +242 -0
  404. package/src/dashboard/classic-sidetab-mission.ts +169 -5
  405. package/src/dashboard/index.ts +387 -14
  406. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  407. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +8 -0
  408. package/src/dashboard/mission-cli-consumer.ts +20 -8
  409. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  410. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  411. package/src/dashboard/sidetab-runtime.ts +3 -1
  412. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  413. package/src/dashboard/visible-mission-diagnostics.ts +16 -0
  414. package/src/decisions/linear-progress-summary.ts +78 -0
  415. package/src/decisions/linear-progress-sync.ts +152 -0
  416. package/src/domains/outbound-alert.ts +49 -11
  417. package/src/domains/retro-cycle-observation.ts +43 -0
  418. package/src/domains/retro-cycle.ts +13 -2
  419. package/src/domains/retro-proposals.ts +92 -0
  420. package/src/domains/retro-report.ts +6 -1
  421. package/src/domains/telegram-kind-route.ts +16 -9
  422. package/src/graph-runner/arg-allowance.ts +13 -0
  423. package/src/graph-runner/graph-cli.ts +24 -1
  424. package/src/graph-runner/graph-grow-llm.ts +3 -1
  425. package/src/graph-runner/graph-run-api.ts +3 -1
  426. package/src/graph-runner/runner.ts +310 -46
  427. package/src/graph-wizard/mission-compose.ts +407 -12
  428. package/src/harness/dispatch-backpressure.ts +54 -1
  429. package/src/harness/dispatch-shadow-compare.ts +74 -0
  430. package/src/harness/harness-cli-command.ts +15 -3
  431. package/src/harness/harness-pod-dispatch.ts +3 -0
  432. package/src/harness/skill-exec.ts +21 -9
  433. package/src/harness/skill-select.ts +1 -1
  434. package/src/hooks/error-report-cloud.ts +101 -0
  435. package/src/hooks/receiver.ts +29 -2
  436. package/src/index.ts +129 -12
  437. package/src/intake-plane/actions.ts +354 -0
  438. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  439. package/src/intake-plane/intake-sources.ts +78 -8
  440. package/src/intake-plane/items.ts +14 -4
  441. package/src/intake-plane/linear-mission-sync.ts +80 -0
  442. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  443. package/src/intake-plane/linear-wish.ts +227 -1
  444. package/src/life/life-cli.ts +168 -0
  445. package/src/life/life-kinds.ts +160 -0
  446. package/src/live-supply/budget-consumer.ts +78 -0
  447. package/src/live-supply/read.ts +3 -0
  448. package/src/live-supply/snapshot.ts +45 -0
  449. package/src/llm/child-first-llm-observation.ts +112 -0
  450. package/src/llm/provider-credentials.ts +68 -6
  451. package/src/llm/provider-failure-evidence.ts +44 -0
  452. package/src/llm.ts +172 -12
  453. package/src/maturity/feature-maturity.ts +3 -3
  454. package/src/mcp/client.ts +7 -0
  455. package/src/mcp/proxy-runtime.ts +6 -1
  456. package/src/mcp/server.ts +54 -0
  457. package/src/msg/msg-sse-server.ts +3 -3
  458. package/src/msg/msg-store.ts +177 -19
  459. package/src/native-tool-catalog.ts +36 -2
  460. package/src/nexus/api/consult-requests.ts +18 -6
  461. package/src/nexus/api/discord-trigger-bot.ts +6 -6
  462. package/src/nexus/api/graphs-api.ts +4 -2
  463. package/src/nexus/api/grokbot-trigger-bot.ts +206 -0
  464. package/src/nexus/api/http-server.ts +37 -1
  465. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  466. package/src/nexus/api/telegram-trigger-bot.ts +6 -6
  467. package/src/nexus/boot/register-mcp-clients.ts +114 -8
  468. package/src/nexus/index.ts +22 -2
  469. package/src/nexus/outbound/format.ts +9 -0
  470. package/src/nexus/outbound/grokbot-adapter.ts +71 -0
  471. package/src/nexus/outbound/router.ts +121 -16
  472. package/src/nexus/setup-status.ts +9 -0
  473. package/src/nexus/state/state.ts +3 -0
  474. package/src/oauth/codex-account-store.ts +20 -7
  475. package/src/oauth/codex-owner-mirror.ts +81 -0
  476. package/src/oauth/codex.ts +17 -2
  477. package/src/oauth/fallback-chain.ts +47 -17
  478. package/src/onboarding/first-run-doctor.ts +8 -1
  479. package/src/onboarding/first-run.ts +126 -29
  480. package/src/onboarding/key-setup.ts +103 -0
  481. package/src/onboarding/menu-answer.ts +13 -0
  482. package/src/onboarding/secret-prompt.ts +37 -0
  483. package/src/plugins/install/plugin-install.ts +59 -0
  484. package/src/pr-tool/census.ts +130 -0
  485. package/src/preview/terminal.ts +22 -7
  486. package/src/prompt-enhance/enhance.ts +10 -0
  487. package/src/pty-shell/pty-control-ipc.ts +4 -1
  488. package/src/pty-shell/pty-write-provenance.ts +21 -3
  489. package/src/pty-shell/registry.ts +9 -2
  490. package/src/registry/catalog-server.ts +232 -0
  491. package/src/registry/loader.ts +45 -1
  492. package/src/registry/types.ts +1 -2
  493. package/src/release-loop/proposal-auto-place.ts +83 -0
  494. package/src/research/axis-fanout.ts +79 -29
  495. package/src/research/lenses/second-order.ts +312 -0
  496. package/src/self-dev/ask-launch-flow.ts +72 -1
  497. package/src/self-dev/dev-cli.ts +7 -2
  498. package/src/self-dev/dev-pipeline.ts +5 -0
  499. package/src/self-dev/draft-residue.ts +64 -5
  500. package/src/self-dev/draft-sweep.ts +31 -10
  501. package/src/self-dev/draft-triage-rules.ts +60 -3
  502. package/src/self-dev/graph-front-nodes.ts +2 -1
  503. package/src/self-dev/graph-journey-route.ts +76 -21
  504. package/src/self-dev/launch-preflight.ts +58 -0
  505. package/src/self-dev/orchestrate.ts +1 -1
  506. package/src/self-dev/run-supervisor.ts +152 -2
  507. package/src/self-dev/shard-aggregate.ts +4 -0
  508. package/src/self-dev/shard-run.ts +36 -15
  509. package/src/self-implement/abandoned-classification.ts +12 -3
  510. package/src/self-implement/budget-gate.ts +7 -0
  511. package/src/self-implement/child-llm-preference.ts +10 -1
  512. package/src/self-implement/doctor-visit.ts +30 -8
  513. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  514. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  515. package/src/self-implement/gate-artifacts.ts +2 -1
  516. package/src/self-implement/goal-author-cli.ts +4 -2
  517. package/src/self-implement/goal-author.ts +549 -10
  518. package/src/self-implement/graph-overlay-yaml.ts +181 -4
  519. package/src/self-implement/graph-overlay.ts +3 -1
  520. package/src/self-implement/graph-profile-yaml.ts +107 -0
  521. package/src/self-implement/graph-yaml.ts +94 -5
  522. package/src/self-implement/off-diff-evidence.ts +249 -5
  523. package/src/self-implement/orchestrator.ts +298 -26
  524. package/src/self-implement/run-chart.ts +6 -3
  525. package/src/self-implement/run-ledger.ts +51 -1
  526. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  527. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  528. package/src/self-implement/test-scenario-request.ts +37 -6
  529. package/src/self-implement/train-gate-receipt.ts +166 -0
  530. package/src/self-implement/train-gate-remote.ts +62 -18
  531. package/src/session/chat.ts +6 -4
  532. package/src/session/session-fanout.ts +2 -0
  533. package/src/session/streaming/acp-stream-sink.ts +2 -1
  534. package/src/session/streaming/chunk-producer.ts +6 -0
  535. package/src/session/streaming/stream-compositor.ts +3 -2
  536. package/src/session-runtime/index.ts +74 -6
  537. package/src/session-runtime/retry-policy.ts +1 -1
  538. package/src/setup/llm-env-detect.ts +3 -0
  539. package/src/setup/service-key-catalog.ts +46 -0
  540. package/src/setup/service-keys.ts +241 -0
  541. package/src/sidetab-core/model.ts +205 -10
  542. package/src/sidetab-core/visible-agent-mission-pair.ts +51 -0
  543. package/src/sidetab-core/visible-agent-mission.ts +182 -48
  544. package/src/skills/tools/agent.ts +23 -4
  545. package/src/skills/tools/omni-search.ts +127 -27
  546. package/src/task-agent/parent-host.ts +29 -1
  547. package/src/task-agent/recall-inject.ts +98 -0
  548. package/src/task-agent/repair-outcomes.ts +65 -0
  549. package/src/task-agent/task-hand.ts +46 -14
  550. package/src/task-orchestrator/dispatcher.ts +14 -1
  551. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  552. package/src/task-orchestrator/store.ts +16 -5
  553. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +23 -1
  554. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +107 -1
  555. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  556. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +21 -9
  557. package/src/task-orchestrator/surfaces/pod-source-receive.ts +23 -11
  558. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  559. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +1 -1
  560. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +467 -77
  561. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +45 -3
  562. package/src/task-orchestrator/surfaces/self-implement-pod.ts +210 -14
  563. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  564. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  565. package/src/task-orchestrator/types.ts +14 -0
  566. package/src/telegram.ts +14 -16
  567. package/src/terminal/coding-agent.ts +14 -5
  568. package/src/terminal/session-registry.ts +1 -1
  569. package/src/tool-hints/gate.ts +46 -14
  570. package/src/tool-hints/signals.ts +1 -1
  571. package/src/tool-hints/types.ts +2 -0
  572. package/src/tool-runtime/agent-runtime.ts +1 -0
  573. package/src/tool-runtime/browser-hand-runtime.ts +391 -0
  574. package/src/tool-runtime/browser-runtime.ts +33 -19
  575. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  576. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +173 -0
  577. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  578. package/src/tool-runtime/index.ts +6 -0
  579. package/src/tool-runtime/types.ts +5 -0
  580. package/src/tui/entry.ts +51 -8
  581. package/src/tui/sidetab/attach.ts +252 -11
  582. package/src/tui/sidetab/herdr-portal.ts +225 -0
  583. package/src/tui/sidetab/list.ts +3 -2
  584. package/src/tui-client/next-dashboard-runtime.ts +52 -0
  585. package/src/user-config.ts +34 -9
  586. package/src/user-intent/types.ts +4 -3
  587. package/src/ux-sim/browser-hand.ts +165 -0
  588. package/src/ux-sim/draft-inventory-builder.ts +199 -0
  589. package/src/ux-sim/fake-browser-page.ts +81 -0
  590. package/src/ux-sim/fake-linear-device.ts +31 -0
  591. package/src/ux-sim/graph-engine-sim.ts +47 -0
  592. package/src/ux-sim/linear-secretary.ts +208 -0
  593. package/src/ux-sim/mock-scenario-catalog.json +81 -26
  594. package/src/ux-sim/mock-scenario-catalog.ts +175 -5
  595. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  596. package/src/ux-sim/release-sim-rig.ts +62 -18
  597. package/src/ux-sim/scenario.ts +70 -26
  598. package/src/ux-sim/service-key-setup.ts +113 -0
  599. package/src/ux-sim/term-slash-device.ts +74 -0
  600. package/src/ux-sim/turn-throw-sim.ts +31 -0
  601. package/src/version/packed-revision.json +1 -1
  602. package/src/web-search/exa.ts +77 -0
  603. package/src/web-search/index.ts +30 -9
  604. package/src/web-search/provider.ts +4 -1
  605. package/src/web-search/x-intent.ts +5 -0
  606. package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +0 -36
  608. package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +0 -32
  614. package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +0 -286
  620. package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +0 -34
  623. package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/2690.0521c738b7749931.js +0 -115
  629. package/apps/pwa/out/_next/static/chunks/2974.595d1e29d040cb6a.js +0 -64
  630. package/apps/pwa/out/_next/static/chunks/3207.a756c95e9ec8c3c8.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/3285.89ee2f298682f5e5.js +0 -93
  632. package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +0 -41
  633. package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +0 -24
  635. package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/3837.a210d7d0db8d8abd.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +0 -77
  641. package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +0 -148
  647. package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
  648. package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +0 -122
  649. package/apps/pwa/out/_next/static/chunks/5112.4b9f300124fab7b3.js +0 -149
  650. package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +0 -27
  652. package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +0 -226
  664. package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +0 -90
  665. package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +0 -104
  671. package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +0 -94
  672. package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/7279-c199ea83f34338fa.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +0 -24
  679. package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +0 -8
  687. package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +0 -79
  689. package/apps/pwa/out/_next/static/chunks/8546-6f03f8ea34dd61d9.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/9249.976f1e69a9d80754.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/9353-12bfff0c130104cf.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/9656-374232558fd528d0.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/9832.f4a98c878ecf2c0a.js +0 -62
  705. package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +0 -1
  763. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  764. /package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_ssgManifest.js +0 -0
@@ -1,6 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import type { Task, TaskExecution, TaskStatus } from '../task-orchestrator/types.js';
3
3
  import { EventLedger } from './event-ledger.js';
4
+ import { parseLinearSecretaryManifest, readApprovedLinearCapture, updateLinearSecretaryProgress } from '../intake-plane/linear-wish.js';
4
5
 
5
6
  const LINEAR_GRAPHQL_URL = 'https://api.linear.app/graphql';
6
7
  const STATE_NAMES: Partial<Record<TaskStatus, string>> = {
@@ -10,7 +11,7 @@ const STATE_NAMES: Partial<Record<TaskStatus, string>> = {
10
11
  failed: 'Todo',
11
12
  };
12
13
 
13
- type ProjectableTask = Pick<Task, 'id' | 'status' | 'generatedBy' | 'lastExecutionId' | 'notes'>;
14
+ type ProjectableTask = Pick<Task, 'id' | 'status' | 'generatedBy' | 'lastExecutionId' | 'notes'> & Pick<Partial<Task>, 'description' | 'title'>;
14
15
 
15
16
  export interface LinearProjectionOptions {
16
17
  task: ProjectableTask;
@@ -19,7 +20,7 @@ export interface LinearProjectionOptions {
19
20
  ledger?: EventLedger;
20
21
  /** Linear user ID for the elanous agent, when configured. */
21
22
  assigneeId?: string;
22
- execution?: Pick<TaskExecution, 'output' | 'error'>;
23
+ execution?: Pick<TaskExecution, 'output' | 'error' | 'runId' | 'captureArtifacts'>;
23
24
  }
24
25
 
25
26
  async function graphql<T>(apiKey: string, fetchFn: typeof fetch, query: string, variables: Record<string, unknown>): Promise<T> {
@@ -34,25 +35,46 @@ async function graphql<T>(apiKey: string, fetchFn: typeof fetch, query: string,
34
35
  return result.data;
35
36
  }
36
37
 
37
- function projectionComment(task: ProjectableTask, execution?: LinearProjectionOptions['execution']): string | null {
38
+ function projectionComment(task: ProjectableTask): string | null {
38
39
  switch (task.status) {
39
40
  case 'running': return `elanous 실행 시작 (task: ${task.id}${task.lastExecutionId ? `, execution: ${task.lastExecutionId}` : ''}).`;
40
- case 'review': return `elanous 실행 결과가 사람 확인을 기다립니다 (task: ${task.id}).${execution?.output ? `\n\n${execution.output.slice(0, 2000)}` : ''}`;
41
- case 'done': return `elanous 실행 완료 (task: ${task.id}).${execution?.output ? `\n\n${execution.output.slice(0, 2000)}` : ''}`;
42
- case 'failed': {
43
- const reason = execution?.error?.message ?? task.notes.at(-1);
44
- return `elanous 실행 실패 (task: ${task.id}).${reason ? `\n\n${reason.slice(0, 2000)}` : ''}`;
45
- }
41
+ case 'review': return `elanous 실행 결과가 사람 확인을 기다립니다 (task: ${task.id}).`;
42
+ case 'done': return `elanous 실행 완료 (task: ${task.id}).`;
43
+ case 'failed': return `elanous 실행 실패 (task: ${task.id}).`;
46
44
  default: return null;
47
45
  }
48
46
  }
49
47
 
50
48
  /** Project only Linear-origin task transitions. Every successful write is recorded for inbound echo filtering. */
51
49
  export async function projectLinearTask({ task, apiKey, fetch: fetchFn = fetch, ledger, assigneeId, execution }: LinearProjectionOptions): Promise<boolean> {
52
- if (task.generatedBy?.kind !== 'external' || task.generatedBy.provider !== 'linear' || !task.generatedBy.ref || !STATE_NAMES[task.status]) return false;
53
- if (!apiKey) throw new Error('Linear API key is required for projection');
50
+ if (task.generatedBy?.kind !== 'external' || task.generatedBy.provider !== 'linear' || !task.generatedBy.ref) return false;
54
51
  const issueId = task.generatedBy.ref;
55
52
  const events = ledger ?? new EventLedger();
53
+ const secretary = parseLinearSecretaryManifest(task.description ?? '', issueId);
54
+ if (secretary) {
55
+ if (task.status !== 'running' && task.status !== 'review' && task.status !== 'done' && task.status !== 'failed') return false;
56
+ if (!apiKey) throw new Error('Linear API key is required for projection');
57
+ const state = task.status === 'running' ? 'started' : task.status === 'done' ? 'completed' : 'comment';
58
+ const captureCandidate = execution?.captureArtifacts?.find(capture =>
59
+ capture.runId === execution.runId && capture.runId.trim().length > 0 &&
60
+ capture.linearIssueId === secretary.parentIssueId && capture.externalShare === true && capture.sensitivity === 'public');
61
+ let captureArtifact: typeof captureCandidate;
62
+ if (captureCandidate) {
63
+ try { readApprovedLinearCapture(captureCandidate); captureArtifact = captureCandidate; }
64
+ catch { /* Invalid, stale, or unavailable captures fail closed; progress still syncs without a URL. */ }
65
+ }
66
+ await updateLinearSecretaryProgress({ apiKey, parentIssueId: secretary.parentIssueId, taskIssueId: issueId,
67
+ taskTitle: secretary.tasks.find(item => item.issueId === issueId)!.title, tasks: secretary.tasks, state,
68
+ summary: task.status === 'running' ? '하위 작업을 시작했습니다.'
69
+ : task.status === 'done' ? '하위 작업을 완료했습니다.'
70
+ : task.status === 'failed' ? '하위 작업이 실패했습니다.' : '하위 작업 진행 상태를 갱신했습니다.',
71
+ workaround: task.status === 'failed' ? 'Linear 상태는 In Progress로 유지하고 실패 내용을 기록했습니다.' : undefined,
72
+ captureArtifact,
73
+ ledger: events, fetch: fetchFn });
74
+ return true;
75
+ }
76
+ if (!STATE_NAMES[task.status]) return false;
77
+ if (!apiKey) throw new Error('Linear API key is required for projection');
56
78
  const { issue, viewer } = await graphql<{
57
79
  issue?: { team?: { states?: { nodes?: Array<{ id: string; name: string }> } } };
58
80
  viewer?: { id?: string };
@@ -72,7 +94,7 @@ export async function projectLinearTask({ task, apiKey, fetch: fetchFn = fetch,
72
94
  events.record('linear', `outgoing:state:${issueId}:${update.issueUpdate.issue.updatedAt}:${stateHash}`,
73
95
  { ref: issueId, occurredAt: update.issueUpdate.issue.updatedAt });
74
96
 
75
- const comment = projectionComment(task, execution);
97
+ const comment = projectionComment(task);
76
98
  if (comment) {
77
99
  const created = await graphql<{ commentCreate?: { success?: boolean; comment?: { id?: string; updatedAt?: string; issue?: { updatedAt?: string } } } }>(apiKey, fetchFn,
78
100
  'mutation ProjectorComment($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { id updatedAt issue { updatedAt } } } }',
@@ -180,6 +180,12 @@ export async function resolveLinearProjectId({ apiKey, project, fetch: fetchFn =
180
180
  return projectId;
181
181
  }
182
182
 
183
+ export async function resolveLinearViewerId({ apiKey, fetch: fetchFn = fetch }: LinearRequestOptions): Promise<string> {
184
+ const data = await linearRequest<{ viewer?: { id?: string } }>({ apiKey, fetch: fetchFn }, 'query LinearSecretaryViewer { viewer { id } }', {});
185
+ if (!data.viewer?.id) throw new Error('Linear viewer id could not be resolved');
186
+ return data.viewer.id;
187
+ }
188
+
183
189
  /** Read-only project lookup. A name is resolved uniquely before querying its issues. */
184
190
  export async function fetchLinearProjectIssues({ apiKey, project, includeDone = false, fetch: fetchFn = fetch }: {
185
191
  apiKey: string; project: string; includeDone?: boolean; fetch?: typeof fetch;
@@ -234,17 +240,47 @@ export async function findLinearDecisionIssue({ apiKey, projectId, decisionId, f
234
240
  return match;
235
241
  }
236
242
 
237
- /** Create in the COO project; Linear requires a team from that project for issueCreate. */
238
- export async function createLinearIssue({ apiKey, projectId, title, description, dueDate, fetch: fetchFn = fetch }: LinearRequestOptions & {
239
- projectId: string; title: string; description: string; dueDate?: string;
243
+ /** Create in a project or directly in an explicitly selected team. */
244
+ export async function createLinearIssue({ apiKey, projectId, teamKey, title, description, dueDate, parentId, assigneeId, stateType, fetch: fetchFn = fetch }: LinearRequestOptions & {
245
+ projectId?: string; teamKey?: string; title: string; description: string; dueDate?: string; parentId?: string; assigneeId?: string;
246
+ stateType?: 'started' | 'unstarted' | 'completed' | 'canceled';
240
247
  }): Promise<string> {
241
- const data = await linearRequest<{ project?: { teams?: { nodes?: Array<{ id: string }> } } }>({ apiKey, fetch: fetchFn },
242
- 'query DecisionProjectTeam($id: String!) { project(id: $id) { teams { nodes { id } } } }', { id: projectId });
248
+ if (!apiKey.trim() || (!projectId?.trim() && !teamKey?.trim())) throw new Error('Linear project or team and API key are required');
249
+ if (!projectId?.trim()) return createLinearTeamIssue({ apiKey, teamKey: teamKey!.trim(), title, description, dueDate, parentId, assigneeId, stateType, fetch: fetchFn });
250
+ type Team = { id: string; states?: { nodes?: Array<{ id: string; type: string }> } };
251
+ const data = await linearRequest<{ project?: { teams?: { nodes?: Team[] } } }>({ apiKey, fetch: fetchFn },
252
+ 'query DecisionProjectTeam($id: String!) { project(id: $id) { teams { nodes { id states { nodes { id type } } } } } }', { id: projectId });
243
253
  const teams = data.project?.teams?.nodes;
244
254
  if (!teams?.[0]?.id) throw new Error('Linear project has no team');
255
+ const stateId = stateType ? teams[0].states?.nodes?.find(state => state.type === stateType)?.id : undefined;
256
+ if (stateType && !stateId) throw new Error(`Linear team workflow state not found: ${stateType}`);
245
257
  const created = await linearRequest<{ issueCreate?: { success?: boolean; issue?: { id?: string } } }>({ apiKey, fetch: fetchFn },
246
258
  'mutation DecisionIssueCreate($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id } } }',
247
- { input: { teamId: teams[0].id, projectId, title, description, ...(dueDate ? { dueDate } : {}) } });
259
+ { input: {
260
+ teamId: teams[0].id, projectId, title, description,
261
+ ...(dueDate ? { dueDate } : {}), ...(parentId ? { parentId } : {}), ...(assigneeId ? { assigneeId } : {}), ...(stateId ? { stateId } : {}),
262
+ } });
263
+ const id = created.issueCreate?.issue?.id;
264
+ if (!created.issueCreate?.success || !id) throw new Error('Linear issueCreate did not return an issue id');
265
+ return id;
266
+ }
267
+
268
+ /** Create an issue directly in a team, without requiring a project. */
269
+ export async function createLinearTeamIssue({ apiKey, teamKey, title, description, dueDate, parentId, assigneeId, stateType, fetch: fetchFn = fetch }: LinearRequestOptions & {
270
+ teamKey: string; title: string; description?: string; dueDate?: string; parentId?: string; assigneeId?: string;
271
+ stateType?: 'started' | 'unstarted' | 'completed' | 'canceled';
272
+ }): Promise<string> {
273
+ if (!apiKey.trim() || !teamKey.trim() || !title.trim()) throw new Error('Linear team, title and API key are required');
274
+ const data = await linearRequest<{ teams?: { nodes?: Array<{ id?: string; states?: { nodes?: Array<{ id: string; type: string }> } }> } }>({ apiKey, fetch: fetchFn },
275
+ 'query LinearTeamByKey($key: String!) { teams(filter: { key: { eq: $key } }) { nodes { id states { nodes { id type } } } } }', { key: teamKey.trim() });
276
+ const teams = data.teams?.nodes ?? [];
277
+ if (teams.length !== 1 || !teams[0]?.id) throw new Error(teams.length ? 'Linear team key is ambiguous' : 'Linear team key was not found');
278
+ const stateId = stateType ? teams[0].states?.nodes?.find(state => state.type === stateType)?.id : undefined;
279
+ if (stateType && !stateId) throw new Error(`Linear team workflow state not found: ${stateType}`);
280
+ const created = await linearRequest<{ issueCreate?: { success?: boolean; issue?: { id?: string } } }>({ apiKey, fetch: fetchFn },
281
+ 'mutation LinearTeamIssueCreate($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id } } }',
282
+ { input: { teamId: teams[0].id, title: title.trim(), ...(description?.trim() ? { description: description.trim() } : {}),
283
+ ...(dueDate ? { dueDate } : {}), ...(parentId ? { parentId } : {}), ...(assigneeId ? { assigneeId } : {}), ...(stateId ? { stateId } : {}) } });
248
284
  const id = created.issueCreate?.issue?.id;
249
285
  if (!created.issueCreate?.success || !id) throw new Error('Linear issueCreate did not return an issue id');
250
286
  return id;
@@ -257,8 +293,74 @@ export async function commentLinearIssue({ apiKey, issueId, body, fetch: fetchFn
257
293
  if (!data.commentCreate?.success || !data.commentCreate.comment?.id) throw new Error('Linear commentCreate failed');
258
294
  }
259
295
 
296
+ export async function createLinearAttachment({ apiKey, issueId, title, url, subtitle, fetch: fetchFn = fetch }: LinearRequestOptions & {
297
+ issueId: string; title: string; url: string; subtitle?: string;
298
+ }): Promise<string> {
299
+ const parsed = new URL(url);
300
+ if (parsed.protocol !== 'https:') throw new Error('Linear attachment URL must use HTTPS');
301
+ const data = await linearRequest<{ attachmentCreate?: { success?: boolean; attachment?: { id?: string } } }>({ apiKey, fetch: fetchFn },
302
+ 'mutation LinearAttachmentCreate($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }',
303
+ { input: { issueId, title, url: parsed.toString(), ...(subtitle ? { subtitle } : {}) } });
304
+ const id = data.attachmentCreate?.attachment?.id;
305
+ if (!data.attachmentCreate?.success || !id) throw new Error('Linear attachmentCreate did not return an attachment id');
306
+ return id;
307
+ }
308
+
309
+ /** Request a signed Linear upload URL and stream a generated artifact from the server. */
310
+ export async function uploadLinearFile({ apiKey, filename, contentType, body, fetch: fetchFn = fetch }: LinearRequestOptions & {
311
+ filename: string; contentType: string; body: Buffer;
312
+ }): Promise<string> {
313
+ const data = await linearRequest<{ fileUpload?: { success?: boolean; uploadFile?: {
314
+ uploadUrl?: string; assetUrl?: string; headers?: Array<{ key: string; value: string }>;
315
+ } } }>({ apiKey, fetch: fetchFn },
316
+ `mutation LinearFileUpload($contentType: String!, $filename: String!, $size: Int!) {
317
+ fileUpload(contentType: $contentType, filename: $filename, size: $size) {
318
+ success uploadFile { uploadUrl assetUrl headers { key value } }
319
+ }
320
+ }`,
321
+ { contentType, filename, size: body.byteLength });
322
+ const upload = data.fileUpload?.uploadFile;
323
+ if (!data.fileUpload?.success || !upload?.uploadUrl || !upload.assetUrl || !Array.isArray(upload.headers)) {
324
+ throw new Error('Linear fileUpload did not return an upload URL');
325
+ }
326
+ const uploadUrl = new URL(upload.uploadUrl);
327
+ const assetUrl = new URL(upload.assetUrl);
328
+ if (uploadUrl.protocol !== 'https:' || assetUrl.protocol !== 'https:') throw new Error('Linear file upload URLs must use HTTPS');
329
+ const headers = new Headers({ 'Content-Type': contentType, 'Cache-Control': 'public, max-age=31536000' });
330
+ for (const header of upload.headers) {
331
+ if (!header || typeof header.key !== 'string' || typeof header.value !== 'string') throw new Error('Linear fileUpload returned invalid headers');
332
+ headers.set(header.key, header.value);
333
+ }
334
+ let response: Response;
335
+ try {
336
+ const uploadBody = new Uint8Array(body.byteLength);
337
+ uploadBody.set(body);
338
+ response = await fetchFn(uploadUrl, { method: 'PUT', headers, body: uploadBody, redirect: 'error' });
339
+ } catch {
340
+ throw new Error('Linear file upload PUT failed');
341
+ }
342
+ if (!response.ok) throw new Error(`Linear file upload PUT HTTP ${response.status}`);
343
+ return assetUrl.toString();
344
+ }
345
+
346
+ export async function updateLinearIssueDescription({ apiKey, issueId, description, fetch: fetchFn = fetch }: LinearRequestOptions & {
347
+ issueId: string; description: string;
348
+ }): Promise<void> {
349
+ const data = await linearRequest<{ issueUpdate?: { success?: boolean } }>({ apiKey, fetch: fetchFn },
350
+ 'mutation LinearIssueDescriptionUpdate($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }',
351
+ { id: issueId, input: { description } });
352
+ if (!data.issueUpdate?.success) throw new Error('Linear issue description update failed');
353
+ }
354
+
355
+ export async function fetchLinearIssueDescription({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<string> {
356
+ const data = await linearRequest<{ issue?: { description?: string | null } }>({ apiKey, fetch: fetchFn },
357
+ 'query LinearIssueDescription($id: String!) { issue(id: $id) { description } }', { id: issueId });
358
+ if (typeof data.issue?.description !== 'string') throw new Error('Linear issue description is missing');
359
+ return data.issue.description;
360
+ }
361
+
260
362
  export async function moveLinearIssueToStateType({ apiKey, issueId, type, fetch: fetchFn = fetch }: LinearRequestOptions & {
261
- issueId: string; type: 'completed' | 'canceled';
363
+ issueId: string; type: 'unstarted' | 'started' | 'completed' | 'canceled';
262
364
  }): Promise<void> {
263
365
  const data = await linearRequest<{ issue?: { team?: { states?: { nodes?: Array<{ id: string; type: string }> } } } }>({ apiKey, fetch: fetchFn },
264
366
  'query DecisionIssueStates($id: String!) { issue(id: $id) { team { states { nodes { id type } } } } }', { id: issueId });
@@ -270,6 +372,48 @@ export async function moveLinearIssueToStateType({ apiKey, issueId, type, fetch:
270
372
  if (!updated.issueUpdate?.success) throw new Error('Linear issueUpdate failed');
271
373
  }
272
374
 
375
+ /** Check the issue's current workflow state and transition in one fresh read/write operation. */
376
+ export async function transitionLinearIssueStateType({ apiKey, issueId, type, fromTypes, fetch: fetchFn = fetch }: LinearRequestOptions & {
377
+ issueId: string; type: 'unstarted' | 'started' | 'completed' | 'canceled'; fromTypes?: readonly string[];
378
+ }): Promise<boolean> {
379
+ const data = await linearRequest<{ issue?: { state?: { type?: string } | null; team?: { states?: { nodes?: Array<{ id: string; type: string }> } } } }>({ apiKey, fetch: fetchFn },
380
+ 'query LinearIssueTransitionGuard($id: String!) { issue(id: $id) { state { type } team { states { nodes { id type } } } } }', { id: issueId });
381
+ const currentType = data.issue?.state?.type;
382
+ if (!currentType || currentType === 'completed' || currentType === 'canceled' || (fromTypes && !fromTypes.includes(currentType))) return false;
383
+ const state = data.issue?.team?.states?.nodes?.find(node => node.type === type);
384
+ if (!state?.id) throw new Error(`Linear team workflow state not found: ${type}`);
385
+ const updated = await linearRequest<{ issueUpdate?: { success?: boolean } }>({ apiKey, fetch: fetchFn },
386
+ 'mutation LinearIssueTransition($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }',
387
+ { id: issueId, input: { stateId: state.id } });
388
+ if (!updated.issueUpdate?.success) throw new Error('Linear issueUpdate failed');
389
+ return true;
390
+ }
391
+
392
+ export async function fetchLinearIssueStateType({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<string> {
393
+ const data = await linearRequest<{ issue?: { state?: { type?: string } | null } }>({ apiKey, fetch: fetchFn },
394
+ 'query LinearIssueStatus($id: String!) { issue(id: $id) { state { type } } }', { id: issueId });
395
+ const type = data.issue?.state?.type;
396
+ if (!type) throw new Error('Linear issue state type is missing');
397
+ return type;
398
+ }
399
+
400
+ /** Read the immutable identity needed to bind a demo mission to a real child issue. */
401
+ export async function fetchLinearMissionIssueIdentity({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<{ id: string; teamKey: string; parentId: string | null }> {
402
+ const data = await linearRequest<{ issue?: { id?: string; team?: { key?: string } | null; parent?: { id?: string } | null } }>({ apiKey, fetch: fetchFn },
403
+ 'query LinearMissionIssueIdentity($id: String!) { issue(id: $id) { id team { key } parent { id } } }', { id: issueId });
404
+ const issue = data.issue;
405
+ if (!issue?.id || !issue.team?.key) throw new Error('Linear issue identity is incomplete');
406
+ return { id: issue.id, teamKey: issue.team.key, parentId: issue.parent?.id ?? null };
407
+ }
408
+
409
+ export async function fetchLinearIssueUpdatedAt({ apiKey, issueId, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string }): Promise<string> {
410
+ const data = await linearRequest<{ issue?: { updatedAt?: string } }>({ apiKey, fetch: fetchFn },
411
+ 'query LinearIssueUpdatedAt($id: String!) { issue(id: $id) { updatedAt } }', { id: issueId });
412
+ const updatedAt = data.issue?.updatedAt;
413
+ if (!updatedAt || !Number.isFinite(Date.parse(updatedAt))) throw new Error('Linear issue updatedAt is missing');
414
+ return updatedAt;
415
+ }
416
+
273
417
  export function toTaskRequest(event: ExternalTaskEvent): {
274
418
  title: string; description: string; priority: 'high' | 'medium' | 'low';
275
419
  external: { provider: 'linear'; ref: string; url?: string; team?: string };
@@ -20,7 +20,7 @@ export interface ResourceRecord {
20
20
  export type ResourceView = ResourceRecord & { ageMs: number; expired: boolean };
21
21
 
22
22
  export interface PodWorkerKey { context: string; imageDigest: string; lockHash: string; architecture: string }
23
- type PodWorkerState = 'idle' | 'leased' | 'sanitizing' | 'timeout-fenced' | 'quarantined';
23
+ type PodWorkerState = 'idle' | 'leased' | 'sanitizing' | 'timeout-fenced' | 'quarantined' | 'reaping';
24
24
  interface PodWorkerLeaseAttrs {
25
25
  key: PodWorkerKey;
26
26
  podUid: string;
@@ -35,6 +35,8 @@ interface PodWorkerLeaseAttrs {
35
35
  timeoutFenceUntil?: number;
36
36
  timeoutRunId?: string;
37
37
  timeoutAttemptId?: string;
38
+ timeoutPreviousObservedAt?: number;
39
+ timeoutPreviousTtlMs?: number;
38
40
  runId?: string;
39
41
  attemptId?: string;
40
42
  reason?: string;
@@ -216,6 +218,13 @@ export class ResourceLedger {
216
218
  now ??= Date.now();
217
219
  const rows = this.read();
218
220
  const id = `pod-worker-lease:${request.workerId}`;
221
+ if (rows.some(row => {
222
+ if (row.kind !== 'pod-worker-lease' || row.name === request.workerId) return false;
223
+ const attrs = workerAttrs(row);
224
+ return attrs.podUid === request.podUid
225
+ && (attrs.state === 'quarantined' || attrs.state === 'timeout-fenced' || attrs.state === 'reaping');
226
+ }))
227
+ throw new ResourceLedgerError(409, 'pod-uid-already-registered');
219
228
  const index = rows.findIndex(row => row.id === id);
220
229
  const previous = index < 0 ? undefined : rows[index]!;
221
230
  if (previous && previous.kind !== 'pod-worker-lease') throw new ResourceLedgerError(409, 'worker-id-conflict');
@@ -244,8 +253,10 @@ export class ResourceLedger {
244
253
  const idleAttrs: PodWorkerLeaseAttrs = { ...candidateAttrs, state: 'idle' };
245
254
  delete idleAttrs.leaseId; delete idleAttrs.leaseOwner; delete idleAttrs.runId; delete idleAttrs.attemptId;
246
255
  delete idleAttrs.timeoutFenceUntil; delete idleAttrs.timeoutRunId; delete idleAttrs.timeoutAttemptId;
247
- rows[rowIndex] = { ...candidate, attrs: idleAttrs as unknown as Record<string, unknown>, observedAt: at,
248
- ttlMs: candidateAttrs.idleTtlMs };
256
+ const observedAt = candidateAttrs.timeoutPreviousObservedAt ?? at;
257
+ const ttlMs = candidateAttrs.timeoutPreviousTtlMs ?? candidateAttrs.idleTtlMs;
258
+ delete idleAttrs.timeoutPreviousObservedAt; delete idleAttrs.timeoutPreviousTtlMs;
259
+ rows[rowIndex] = { ...candidate, attrs: idleAttrs as unknown as Record<string, unknown>, observedAt, ttlMs };
249
260
  expiredFenceChanged = true;
250
261
  }
251
262
  const index = rows.findIndex(row => row.kind === 'pod-worker-lease' && (!request.machine || row.machine === request.machine)
@@ -283,12 +294,16 @@ export class ResourceLedger {
283
294
  && attrs.timeoutAttemptId === request.attemptId;
284
295
  const sameLease = attrs.state === 'leased' && attrs.leaseOwner === request.owner
285
296
  && attrs.runId === request.runId && attrs.attemptId === request.attemptId;
286
- const available = attrs.state === 'idle';
297
+ const available = attrs.state === 'idle' && Math.max(0, at - row.observedAt) < row.ttlMs;
287
298
  if (!request.owner || !request.runId || !request.attemptId || !Number.isSafeInteger(request.fenceMs)
288
299
  || request.fenceMs < 1 || !(sameFence || sameLease || available))
289
300
  throw new ResourceLedgerError(409, 'stale-timeout-fence');
290
301
  const nextAttrs: PodWorkerLeaseAttrs = { ...attrs, state: 'timeout-fenced',
291
302
  timeoutFenceUntil: at + request.fenceMs, timeoutRunId: request.runId, timeoutAttemptId: request.attemptId };
303
+ if (available) {
304
+ nextAttrs.timeoutPreviousObservedAt = row.observedAt;
305
+ nextAttrs.timeoutPreviousTtlMs = row.ttlMs;
306
+ }
292
307
  const next: ResourceRecord = { ...row, attrs: nextAttrs as unknown as Record<string, unknown>, observedAt: at };
293
308
  rows[index] = next;
294
309
  this.write(rows);
@@ -296,6 +311,29 @@ export class ResourceLedger {
296
311
  });
297
312
  }
298
313
 
314
+ /** Atomically reserves a fenced Pod UID so a timeout-fence expiry cannot make it leasable during deletion. */
315
+ reservePodWorkerReap(id: string, request: { machine: string; podUid: string }, now?: number): ResourceRecord {
316
+ return this.mutate(() => {
317
+ now ??= Date.now();
318
+ const rows = this.read();
319
+ const index = rows.findIndex(row => row.id === id && row.kind === 'pod-worker-lease');
320
+ if (index < 0) throw new ResourceLedgerError(404, 'not-found');
321
+ const row = rows[index]!;
322
+ const attrs = workerAttrs(row);
323
+ if (row.machine !== request.machine || attrs.podUid !== request.podUid || attrs.leaseId
324
+ || !['quarantined', 'timeout-fenced', 'reaping'].includes(attrs.state))
325
+ throw new ResourceLedgerError(409, 'pod-worker-reap-not-eligible');
326
+ if (rows.some((other, otherIndex) => otherIndex !== index && other.kind === 'pod-worker-lease'
327
+ && workerAttrs(other).podUid === request.podUid))
328
+ throw new ResourceLedgerError(409, 'pod-worker-uid-has-other-lease');
329
+ const next: ResourceRecord = { ...row,
330
+ attrs: { ...attrs, state: 'reaping' } as unknown as Record<string, unknown>, observedAt: now };
331
+ rows[index] = next;
332
+ this.write(rows);
333
+ return next;
334
+ });
335
+ }
336
+
299
337
  transitionPodWorker(id: string, request: { owner: string; leaseId: string; generation: number; action: 'renew' | 'release' | 'sanitize' | 'quarantine'; ttlMs?: number; reason?: string }, now?: number): ResourceRecord {
300
338
  return this.mutate(() => {
301
339
  now ??= Date.now();
@@ -1,6 +1,6 @@
1
1
  import { createHash, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
2
- import { chmodSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
3
- import { dirname, join } from 'node:path';
2
+ import { chmodSync, closeSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, fsyncSync } from 'node:fs';
3
+ import { dirname, isAbsolute, join } from 'node:path';
4
4
  import { effectiveInstanceRoot } from '../instance/resolve.js';
5
5
 
6
6
  interface MemberTokenEntry { sha256: string; issuedAt: string }
@@ -65,6 +65,29 @@ export function issueMemberToken(machine: string, root: string = effectiveInstan
65
65
  return token;
66
66
  }
67
67
 
68
+ /** Issue a member credential into a new private file without sending the value to stdout. */
69
+ export function issueMemberTokenToFile(machine: string, tokenFile: string, root: string = effectiveInstanceRoot()): void {
70
+ checkMachine(machine);
71
+ if (!isAbsolute(tokenFile)) throw new Error('token file path must be absolute');
72
+ const token = randomBytes(32).toString('hex');
73
+ mkdirSync(dirname(tokenFile), { recursive: true, mode: 0o700 });
74
+ let outputCreated = false;
75
+ try {
76
+ const fd = openSync(tokenFile, 'wx', 0o600);
77
+ outputCreated = true;
78
+ try {
79
+ writeFileSync(fd, `${token}\n`, 'utf8');
80
+ fsyncSync(fd);
81
+ } finally { closeSync(fd); }
82
+ const entries = readStore(root);
83
+ entries[machine] = { sha256: createHash('sha256').update(token).digest('hex'), issuedAt: new Date().toISOString() };
84
+ writeStore(root, entries);
85
+ } catch (error) {
86
+ if (outputCreated) try { unlinkSync(tokenFile); } catch { /* retain the original failure */ }
87
+ throw error;
88
+ }
89
+ }
90
+
68
91
  export function revokeMemberToken(machine: string, root: string = effectiveInstanceRoot()): void {
69
92
  checkMachine(machine);
70
93
  const entries = readStore(root);
@@ -1,9 +1,12 @@
1
1
  import { ResourceLedger, ResourceLedgerError, type ResourceRecord } from './ledger.js';
2
2
  import { DEFAULT_NEXUS_HTTP_PORT } from '../nexus/default-port.js';
3
3
 
4
- /** Inclusive port bands; only the test band is allocated by the coordinator. */
4
+ /** Release PWA bind configured by OP; isolated test leases must never claim it. */
5
+ export const RELEASE_PWA_FIXED_HTTP_PORT = 31453;
6
+
7
+ /** Inclusive port bands. Fixed release PWA ports are reserved from every isolated test allocator. */
5
8
  export const PORT_BANDS = {
6
- reserved: [31413, DEFAULT_NEXUS_HTTP_PORT, 31420],
9
+ reserved: [31413, DEFAULT_NEXUS_HTTP_PORT, 31420, RELEASE_PWA_FIXED_HTTP_PORT],
7
10
  test: { start: 31450, end: 31499 },
8
11
  offline: { start: 31500, end: 31509 },
9
12
  } as const;
@@ -36,5 +39,7 @@ export function leasePort(request: PortLeaseRequest, ledger: ResourceLedger, now
36
39
  throw new ResourceLedgerError(400, 'invalid-port-lease');
37
40
  }
38
41
  const owner = request.owner ?? machine;
39
- return ledger.leaseTestPort({ machine, purpose, ttlMs: Math.min(ttlMs, MAX_PORT_LEASE_TTL_MS), owner }, PORT_BANDS.test, now, request.excluded);
42
+ const reservedTestPorts = PORT_BANDS.reserved.filter(port => port >= PORT_BANDS.test.start && port <= PORT_BANDS.test.end);
43
+ const excluded = [...new Set([...(request.excluded ?? []), ...reservedTestPorts])];
44
+ return ledger.leaseTestPort({ machine, purpose, ttlMs: Math.min(ttlMs, MAX_PORT_LEASE_TTL_MS), owner }, PORT_BANDS.test, now, excluded);
40
45
  }
@@ -12,12 +12,17 @@ export const CONTROL_HOSTNAME = '127.0.0.1';
12
12
  const MAX_POD_WORKER_TTL_MS = 24 * 60 * 60 * 1000;
13
13
  const POD_WORKER_TIMEOUT_FENCE_MS = 150_000;
14
14
 
15
- export function allowedControlHostname(hostname: string): boolean {
15
+ function controlHostnameAllowed(hostname: string, allowClusterBind: boolean): boolean {
16
+ // Cluster-facing binds require an explicit opt-in; wildcard exposure is never inferred from the address.
17
+ if (hostname === '0.0.0.0') return allowClusterBind;
16
18
  if (hostname === '127.0.0.1' || hostname === '::1') return true;
17
19
  const parts = hostname.split('.');
18
20
  if (parts.length !== 4 || !parts.every(part => /^(0|[1-9]\d{0,2})$/.test(part) && Number(part) <= 255)) return false;
19
21
  return parts[0] === '100' && Number(parts[1]) >= 64 && Number(parts[1]) <= 127;
20
22
  }
23
+ export function allowedControlHostname(hostname: string): boolean {
24
+ return controlHostnameAllowed(hostname, false);
25
+ }
21
26
  export type ControlScope = 'admin' | 'member' | 'query';
22
27
  export type ControlTokens = Record<ControlScope, string>;
23
28
 
@@ -89,6 +94,7 @@ export interface ControlServerOptions {
89
94
  root?: string;
90
95
  port?: number;
91
96
  hostname?: string;
97
+ allowClusterBind?: boolean;
92
98
  leaseView?: LeaseHolderView;
93
99
  requireKnownLeaseForWrites?: boolean;
94
100
  }
@@ -99,7 +105,7 @@ export function startControlServer(opts: ControlServerOptions = {}): {
99
105
  stop(): void;
100
106
  } {
101
107
  const hostname = opts.hostname ?? CONTROL_HOSTNAME;
102
- if (!allowedControlHostname(hostname)) throw new Error('invalid control hostname');
108
+ if (!controlHostnameAllowed(hostname, opts.allowClusterBind ?? false)) throw new Error('invalid control hostname');
103
109
  const root = opts.root ?? effectiveInstanceRoot();
104
110
  const tokens = ensureControlTokens(root);
105
111
  const ledger = new ResourceLedger(root);
@@ -127,7 +133,7 @@ export function startControlServer(opts: ControlServerOptions = {}): {
127
133
  const leaseRenewal = /^\/v1\/leases\/port\/([^/]+)\/heartbeat$/.exec(path);
128
134
  const workerRegister = path === '/v1/workers/pod' && method === 'POST';
129
135
  const workerAcquire = path === '/v1/leases/pod-worker' && method === 'POST';
130
- const workerTransition = /^\/v1\/leases\/pod-worker\/([^/]+)\/(renew|release|sanitize|quarantine|timeout)$/.exec(path);
136
+ const workerTransition = /^\/v1\/leases\/pod-worker\/([^/]+)\/(renew|release|sanitize|quarantine|timeout|reap)$/.exec(path);
131
137
  if (!resourcePath && !registerPath && !leaseRequest && !workerRegister && !workerAcquire && !(workerTransition && method === 'POST') && !(leaseDeletion && method === 'DELETE') && !(leaseRenewal && method === 'POST') && !(heartbeat && method === 'POST') && !(deletion && method === 'DELETE')) {
132
138
  return json({ error: 'not-found' }, 404);
133
139
  }
@@ -177,10 +183,13 @@ export function startControlServer(opts: ControlServerOptions = {}): {
177
183
  () => ledger.registerPodWorker({ workerId, machine: workerMachine, podUid, key: podWorkerKey(key), ttlMs, owner })));
178
184
  }
179
185
  if (workerAcquire) {
180
- if (scope !== 'member') throw new ResourceLedgerError(403, 'worker-consumer-required');
186
+ // A host-scoped provider may acquire only its own worker lease. Global consumers
187
+ // retain the member scope; a machine credential can never select another host.
188
+ if (scope !== 'member' && !machine) throw new ResourceLedgerError(403, 'worker-consumer-required');
181
189
  const body = podWorkerBody(await req.json());
182
190
  const { machine: workerMachine, key, runId, attemptId, ttlMs } = body;
183
191
  if (workerMachine !== undefined && (typeof workerMachine !== 'string' || !workerMachine.trim())) throw new ResourceLedgerError(400, 'invalid-pod-worker-lease');
192
+ if (machine && workerMachine !== machine) throw new ResourceLedgerError(403, 'machine-scope');
184
193
  if (typeof runId !== 'string' || !runId.trim() || typeof attemptId !== 'string' || !attemptId.trim()
185
194
  || typeof ttlMs !== 'number' || !Number.isSafeInteger(ttlMs) || ttlMs <= 0 || ttlMs > MAX_POD_WORKER_TTL_MS) throw new ResourceLedgerError(400, 'invalid-pod-worker-lease');
186
195
  const stale = await currentWorkerPrimary();
@@ -192,7 +201,19 @@ export function startControlServer(opts: ControlServerOptions = {}): {
192
201
  if (workerTransition) {
193
202
  const workerId = decodeURIComponent(workerTransition[1]!);
194
203
  if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,95}$/.test(workerId)) throw new ResourceLedgerError(400, 'invalid-worker-id');
195
- const action = workerTransition[2] as 'renew' | 'release' | 'sanitize' | 'quarantine' | 'timeout';
204
+ const action = workerTransition[2] as 'renew' | 'release' | 'sanitize' | 'quarantine' | 'timeout' | 'reap';
205
+ if (action === 'reap') {
206
+ if (!machine) throw new ResourceLedgerError(403, 'worker-reap-host-required');
207
+ const body = podWorkerBody(await req.json());
208
+ const podUid = body.podUid;
209
+ if (typeof podUid !== 'string' || !podUid.trim()) throw new ResourceLedgerError(400, 'invalid-pod-worker-reap');
210
+ const id = `pod-worker-lease:${workerId}`;
211
+ requireTarget(id);
212
+ const stale = await currentWorkerPrimary();
213
+ if (stale) return stale;
214
+ return json(await ledger.withGuardedWorkerMutation(async () => !(await currentWorkerPrimary()),
215
+ () => ledger.reservePodWorkerReap(id, { machine, podUid })));
216
+ }
196
217
  if (action === 'timeout') {
197
218
  if (scope !== 'member') throw new ResourceLedgerError(403, 'worker-timeout-scope');
198
219
  const body = podWorkerBody(await req.json());
@@ -0,0 +1,67 @@
1
+ export type DeepBloomTrigger = 'research-intent' | 'deep-question' | 'high-reasoning-effort';
2
+
3
+ export type DeepBloomDecision =
4
+ | { apply: true; reason: DeepBloomTrigger }
5
+ | { apply: false; reason: 'lightweight' | 'no-deep-signal' };
6
+
7
+ export type DeepBloomInstruction = Extract<DeepBloomDecision, { apply: true }> & {
8
+ levels: readonly [4, 5];
9
+ questionCount: 3 | 4 | 5;
10
+ prompt?: string;
11
+ exemplarDomain?: string;
12
+ exemplarLevels?: number[];
13
+ };
14
+
15
+ const LIGHTWEIGHT_TEXT = /^(?:hi|hello|hey|thanks|thank you|good morning|good night|안녕(?:하세요)?|고마워(?:요)?|감사합니다|잘 자(?:요)?)[.!?\s]*$/iu;
16
+ const LIGHTWEIGHT_FACT = /^(?:what(?:'s| is)\s+(?:the\s+)?(?:capital|time|date|meaning|definition)\b.*|who is\b.*|where is\b.*|몇 시(?:야|인가요)?|오늘 날짜(?:는|가)?|\S+의 뜻(?:은|이)?)[??.!\s]*$/iu;
17
+ const LIGHTWEIGHT_COMMAND = /^(?:please\s+)?(?:open|show|list|translate|convert|print|set|turn on|turn off)\b|^(?:열어(?:줘|주세요)|보여(?:줘|주세요)|나열해(?:줘|주세요)|번역해(?:줘|주세요)|계산해(?:줘|주세요)|켜(?:줘|주세요)|꺼(?:줘|주세요))\s*$/iu;
18
+ const DEEP_QUESTION = /\b(?:analy[sz]e|analysis|evaluate|evaluation|compare|comparison|outlook|forecast|cause|causes|why|impact|trade-?offs?|pros and cons|design|strategy|scenario|counterargument|assess|judge)\b|분석|평가|비교|전망|예측|원인|영향|장단점|설계|전략|시나리오|반박|판단|어떻게 봐야|왜\b/iu;
19
+
20
+ /** Lightweight turns have precedence so effort settings never inflate greetings, simple facts, or direct commands. */
21
+ export function selectDeepBloom(
22
+ request: string | undefined,
23
+ options: { researchIntent?: boolean; reasoningEffort?: string } = {},
24
+ ): DeepBloomDecision {
25
+ const text = request?.trim() ?? '';
26
+ if (!text || LIGHTWEIGHT_TEXT.test(text) || LIGHTWEIGHT_FACT.test(text) || LIGHTWEIGHT_COMMAND.test(text))
27
+ return { apply: false, reason: 'lightweight' };
28
+ if (options.researchIntent) return { apply: true, reason: 'research-intent' };
29
+ if (options.reasoningEffort && ['high', 'xhigh', 'max'].includes(options.reasoningEffort))
30
+ return { apply: true, reason: 'high-reasoning-effort' };
31
+ if (DEEP_QUESTION.test(text)) return { apply: true, reason: 'deep-question' };
32
+ return { apply: false, reason: 'no-deep-signal' };
33
+ }
34
+
35
+ /** Build a hidden same-call analysis/evaluation instruction with the existing KGS Bloom cells and exemplar bank. */
36
+ export async function buildDeepBloomInstruction(
37
+ request: string,
38
+ trigger: DeepBloomTrigger,
39
+ ): Promise<DeepBloomInstruction> {
40
+ const [{ BLOOM_2D_SCOPED }, { getBloomExemplarContext }] = await Promise.all([
41
+ import('../knowledge/kgs/types.js'), import('../research/bloom-exemplars.js'),
42
+ ]);
43
+ const analyze = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'analyze')!;
44
+ const evaluate = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'evaluate')!;
45
+ const exemplar = getBloomExemplarContext(request);
46
+ const prompt = [
47
+ 'Before answering, silently ask yourself 3–5 short questions and answer them from the available context.',
48
+ `Analysis focus (${analyze.cognitive}/${analyze.knowledge}): break the subject into components, relationships, and causal mechanisms.`,
49
+ `Evaluation focus (${evaluate.cognitive}/${evaluate.knowledge}): set explicit criteria, compare alternatives or claims, and test at least one counterargument.`,
50
+ 'Use those answers to produce a clear conclusion. Do not expose these internal labels or a checklist unless the user asks for the reasoning process.',
51
+ exemplar.context,
52
+ ].filter(Boolean).join('\n\n');
53
+ return { apply: true, reason: trigger, levels: [4, 5], questionCount: 4,
54
+ prompt, exemplarDomain: exemplar.domain, exemplarLevels: exemplar.levels };
55
+ }
56
+
57
+ /** Ensure the existing research ladder gives levels 4 and 5 distinct analysis/evaluation work. */
58
+ export async function buildResearchBloom45Directive(): Promise<string> {
59
+ const { BLOOM_2D_SCOPED } = await import('../knowledge/kgs/types.js');
60
+ const analyze = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'analyze')!;
61
+ const evaluate = BLOOM_2D_SCOPED.find((cell) => cell.cognitive === 'evaluate')!;
62
+ return [
63
+ `For Bloom level 4 (${analyze.cognitive}/${analyze.knowledge}), ask about components, relationships, and causal mechanisms.`,
64
+ `For Bloom level 5 (${evaluate.cognitive}/${evaluate.knowledge}), ask for criteria-based judgment across alternatives and a counterargument.`,
65
+ 'Keep both questions request-specific and ensure each has search terms; do not duplicate level 3 or level 6 work.',
66
+ ].join('\n');
67
+ }
@@ -0,0 +1,43 @@
1
+ /** Shared guardrails for every core-turn research surface. */
2
+ export const RESEARCH_TURN_MAX_TOOL_TURNS = 20;
3
+ export const RESEARCH_TURN_FIRST_REPLY_BUDGET_MS = 15_000;
4
+ /** Research returns its best partial evidence before the parent has to abort the turn. */
5
+ export const RESEARCH_TURN_FINAL_ANSWER_DEADLINE_MS = 8 * 60_000;
6
+ export const RESEARCH_TURN_DEEP_BUDGET_MS = 9 * 60_000;
7
+ export const RESEARCH_TURN_SHALLOW_BUDGET_MS = 3 * 60_000;
8
+ /** Leave time for shallow partial-answer synthesis before the unchanged parent timeout. */
9
+ export const RESEARCH_TURN_SHALLOW_FINAL_ANSWER_DEADLINE_MS = RESEARCH_TURN_SHALLOW_BUDGET_MS - 10_000;
10
+ export const RESEARCH_TURN_DEADLINE_STOP_ERROR = 'research stopped by its deadline';
11
+
12
+ /** Research turns only receive these tools; unrelated writers are never implicit. */
13
+ export const RESEARCH_TOOL_ALLOWLIST = [
14
+ 'OmniSearch',
15
+ 'WebSearch',
16
+ 'WebFetch',
17
+ 'Agent',
18
+ 'Read',
19
+ // TUI quick-route contracts: every quick turn can recall memory, and the
20
+ // investigation route may list (but never mutate) the seat mailbox.
21
+ 'memory_recall',
22
+ 'MsgList',
23
+ ] as const;
24
+
25
+ const RESEARCH_TOOL_NAMES: ReadonlySet<string> = new Set(RESEARCH_TOOL_ALLOWLIST);
26
+ export const RESEARCH_DOCUMENT_WRITE_TOOLS = ['Edit', 'Write'] as const;
27
+
28
+ /** A research turn may write only when the user explicitly asks for a document at a concrete path. */
29
+ const DOCUMENT_OUTPUT_PATH = /(?:^|[\s"'\x60])(?:\.{1,2}\/)?(?:[\w.-]+\/)*[\w.-]+\.(?:md|mdx|txt|rst|adoc|html|json|ya?ml|csv)\b/i;
30
+ const DOCUMENT_OUTPUT_PATH_GLOBAL = /(?:^|[\s"'\x60])(?:\.{1,2}\/)?(?:[\w.-]+\/)*[\w.-]+\.(?:md|mdx|txt|rst|adoc|html|json|ya?ml|csv)\b/gi;
31
+ const POSITIVE_DOCUMENT_WRITE_INTENT = /\b(?:write|writes|writing|written|draft|drafts|drafting|create|creates|creating|author|authors|authoring|produce|produces|producing|save|saves|saving)\b|작성|초안|생성|기록/i;
32
+ const NEGATED_DOCUMENT_WRITE_INTENT = /\b(?:do\s+not|don['’]?t|never|must\s+not|should\s+not|avoid)\s+(?:(?:be|to)\s+)*(?:write|writes|writing|written|draft|drafts|drafting|create|creates|creating|author|authors|authoring|produce|produces|producing|save|saves|saving)\b|(?:작성|초안|생성|기록)(?:\s*(?:을|를))?\s*(?:하지\s*마|하지\s*말|하지\s*않|금지)/i;
33
+
34
+ /** A research turn may write only when the user explicitly asks for a document at a concrete path. */
35
+ export function requestsResearchDocumentWrite(text: string | undefined): boolean {
36
+ if (!text || !DOCUMENT_OUTPUT_PATH.test(text)) return false;
37
+ const intentText = text.replace(DOCUMENT_OUTPUT_PATH_GLOBAL, ' ');
38
+ return POSITIVE_DOCUMENT_WRITE_INTENT.test(intentText)
39
+ && !NEGATED_DOCUMENT_WRITE_INTENT.test(intentText);
40
+ }
41
+ export function isResearchToolAllowed(name: string): boolean {
42
+ return RESEARCH_TOOL_NAMES.has(name);
43
+ }