elanous 0.2.22 → 0.2.23

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 (705) hide show
  1. package/NOTICE +7 -0
  2. package/README.md +32 -22
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
  9. package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
  11. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
  12. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
  14. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
  23. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
  24. package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
  27. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
  35. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
  39. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
  52. package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
  56. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
  64. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
  69. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
  71. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
  73. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
  74. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
  78. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
  83. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
  84. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
  85. package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
  86. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
  87. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
  90. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
  97. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
  99. package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
  101. package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
  105. package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
  110. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
  111. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
  112. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
  114. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
  116. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
  117. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
  120. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
  123. package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-6168a7c43e6ef8f5.js} +1 -1
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
  184. package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +1 -0
  185. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
  186. package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
  187. package/apps/pwa/out/approvals/index.html +1 -1
  188. package/apps/pwa/out/approvals/index.txt +23 -23
  189. package/apps/pwa/out/autopilot/index.html +1 -1
  190. package/apps/pwa/out/autopilot/index.txt +23 -23
  191. package/apps/pwa/out/board/index.html +1 -1
  192. package/apps/pwa/out/board/index.txt +23 -23
  193. package/apps/pwa/out/botlab/index.html +1 -1
  194. package/apps/pwa/out/botlab/index.txt +22 -22
  195. package/apps/pwa/out/bots/index.html +1 -1
  196. package/apps/pwa/out/bots/index.txt +22 -22
  197. package/apps/pwa/out/ceo/index.html +1 -1
  198. package/apps/pwa/out/ceo/index.txt +23 -23
  199. package/apps/pwa/out/chat/index.html +1 -1
  200. package/apps/pwa/out/chat/index.txt +22 -22
  201. package/apps/pwa/out/consult/index.html +1 -1
  202. package/apps/pwa/out/consult/index.txt +23 -23
  203. package/apps/pwa/out/control/index.html +1 -1
  204. package/apps/pwa/out/control/index.txt +23 -23
  205. package/apps/pwa/out/decisions/index.html +1 -1
  206. package/apps/pwa/out/decisions/index.txt +22 -22
  207. package/apps/pwa/out/design-check/index.html +1 -1
  208. package/apps/pwa/out/design-check/index.txt +23 -23
  209. package/apps/pwa/out/editor/index.html +1 -1
  210. package/apps/pwa/out/editor/index.txt +24 -23
  211. package/apps/pwa/out/exec/index.html +1 -1
  212. package/apps/pwa/out/exec/index.txt +23 -23
  213. package/apps/pwa/out/field/index.html +1 -1
  214. package/apps/pwa/out/field/index.txt +23 -23
  215. package/apps/pwa/out/healthz +1 -1
  216. package/apps/pwa/out/index.html +1 -1
  217. package/apps/pwa/out/index.txt +22 -22
  218. package/apps/pwa/out/inside/index.html +1 -1
  219. package/apps/pwa/out/inside/index.txt +22 -22
  220. package/apps/pwa/out/intake/index.html +1 -1
  221. package/apps/pwa/out/intake/index.txt +23 -23
  222. package/apps/pwa/out/live/index.html +1 -1
  223. package/apps/pwa/out/live/index.txt +23 -23
  224. package/apps/pwa/out/live-run/index.html +1 -1
  225. package/apps/pwa/out/live-run/index.txt +24 -23
  226. package/apps/pwa/out/loops/index.html +1 -1
  227. package/apps/pwa/out/loops/index.txt +22 -22
  228. package/apps/pwa/out/market/index.html +1 -1
  229. package/apps/pwa/out/market/index.txt +22 -22
  230. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  231. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  232. package/apps/pwa/out/morning/index.html +1 -1
  233. package/apps/pwa/out/morning/index.txt +23 -23
  234. package/apps/pwa/out/observatory/index.html +1 -1
  235. package/apps/pwa/out/observatory/index.txt +23 -23
  236. package/apps/pwa/out/ops/checklist/index.html +1 -1
  237. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  238. package/apps/pwa/out/ops/release/index.html +1 -1
  239. package/apps/pwa/out/ops/release/index.txt +22 -22
  240. package/apps/pwa/out/ops/seats/index.html +1 -1
  241. package/apps/pwa/out/ops/seats/index.txt +22 -22
  242. package/apps/pwa/out/outputs/index.html +1 -1
  243. package/apps/pwa/out/outputs/index.txt +22 -22
  244. package/apps/pwa/out/reflection/index.html +1 -1
  245. package/apps/pwa/out/reflection/index.txt +23 -23
  246. package/apps/pwa/out/scheduler/index.html +1 -1
  247. package/apps/pwa/out/scheduler/index.txt +23 -23
  248. package/apps/pwa/out/sessions/index.html +1 -1
  249. package/apps/pwa/out/sessions/index.txt +22 -22
  250. package/apps/pwa/out/settings/devices/index.html +1 -1
  251. package/apps/pwa/out/settings/devices/index.txt +23 -23
  252. package/apps/pwa/out/settings/index.html +1 -1
  253. package/apps/pwa/out/settings/index.txt +23 -23
  254. package/apps/pwa/out/setup/done/index.html +1 -1
  255. package/apps/pwa/out/setup/done/index.txt +23 -23
  256. package/apps/pwa/out/setup/index.html +1 -1
  257. package/apps/pwa/out/setup/index.txt +23 -23
  258. package/apps/pwa/out/share/index.html +1 -1
  259. package/apps/pwa/out/share/index.txt +23 -23
  260. package/apps/pwa/out/showroom/index.html +1 -1
  261. package/apps/pwa/out/showroom/index.txt +22 -22
  262. package/apps/pwa/out/tasks/index.html +1 -1
  263. package/apps/pwa/out/tasks/index.txt +23 -23
  264. package/apps/pwa/out/term/index.html +1 -1
  265. package/apps/pwa/out/term/index.txt +23 -23
  266. package/apps/pwa/out/today/index.html +1 -1
  267. package/apps/pwa/out/today/index.txt +23 -23
  268. package/apps/pwa/out/trace/index.html +1 -1
  269. package/apps/pwa/out/trace/index.txt +23 -23
  270. package/apps/pwa/out/vault/index.html +1 -1
  271. package/apps/pwa/out/vault/index.txt +23 -23
  272. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  273. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  274. package/apps/pwa/out/workflows/index.html +1 -1
  275. package/apps/pwa/out/workflows/index.txt +23 -23
  276. package/apps/pwa/out/workspace/index.html +1 -1
  277. package/apps/pwa/out/workspace/index.txt +23 -23
  278. package/apps/pwa/out/worktrees/index.html +1 -1
  279. package/apps/pwa/out/worktrees/index.txt +23 -23
  280. package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
  281. package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
  282. package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
  283. package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
  284. package/catalog/models/openai/gpt-6-astra.yaml +6 -0
  285. package/catalog/models/openai/gpt-6-luna.yaml +6 -0
  286. package/catalog/models/openai/gpt-6-sol.yaml +6 -0
  287. package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
  288. package/graphs/log-horizon/recipes.yaml +3 -0
  289. package/graphs/release/recipes.yaml +1 -1
  290. package/graphs/release/release-loop.yaml +6 -2
  291. package/graphs/release-rehearsal/recipes.yaml +12 -0
  292. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  293. package/package.json +4 -1
  294. package/scripts/bench-report.ts +82 -3
  295. package/scripts/ci-typecheck-changed.ts +10 -1
  296. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  297. package/scripts/lib/typecheck-ratchet.ts +51 -0
  298. package/scripts/openai-relay-server.ts +5 -1
  299. package/scripts/release-loop/docs-node.ts +258 -43
  300. package/scripts/release-loop/gate-method.ts +59 -0
  301. package/scripts/release-loop/gate-node.ts +73 -7
  302. package/scripts/release-loop/gate-wall.ts +208 -0
  303. package/scripts/release-loop/known-issues-node.ts +53 -8
  304. package/scripts/release-loop/publish-at.ts +14 -0
  305. package/scripts/release-loop/publish-node.ts +17 -2
  306. package/scripts/release-loop/resume-release.ts +34 -4
  307. package/scripts/release-loop/resume.ts +53 -0
  308. package/scripts/release-loop/shard-plan.ts +3 -11
  309. package/scripts/release-loop/tui-node-checks.ts +22 -0
  310. package/scripts/release-loop/unattended-release.ts +8 -1
  311. package/scripts/rhythm/daily.ts +51 -2
  312. package/scripts/rhythm/weekly.ts +3 -2
  313. package/scripts/tsc-main-safety-net.ts +189 -0
  314. package/scripts/usage-rollup.ts +8 -4
  315. package/src/acp/codex-plugins.ts +48 -6
  316. package/src/agent/monad-agent-turn.ts +67 -5
  317. package/src/agent/run-context.ts +10 -0
  318. package/src/agent/tool-profile.ts +28 -2
  319. package/src/agent-mission/acp-judge.ts +8 -2
  320. package/src/agent-mission/capabilities-cli.ts +16 -1
  321. package/src/agent-mission/driver.ts +1 -1
  322. package/src/agent-mission/pr-review-watch.ts +6 -2
  323. package/src/agent-mission/review-loop.ts +33 -5
  324. package/src/agent-substrate/acp-reviewer.ts +17 -8
  325. package/src/agent-substrate/pr-reviewer.ts +164 -28
  326. package/src/agent-substrate/review-intent.ts +6 -4
  327. package/src/agent-substrate/self-review-cli.ts +111 -16
  328. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  329. package/src/ask-user-question/pending-questions.ts +8 -2
  330. package/src/autopilot/build/llm-conflict-merge.ts +216 -12
  331. package/src/autopilot/codebase-grounding.ts +44 -0
  332. package/src/autopilot/llm-control-brain.ts +13 -1
  333. package/src/autopilot/mission-codebase-gate.ts +8 -77
  334. package/src/autopilot/pr-manager.ts +12 -3
  335. package/src/boot/acp-server.ts +4 -7
  336. package/src/boot/acp-socket-path.ts +7 -0
  337. package/src/briefing/brief-items.ts +21 -13
  338. package/src/chat/index.ts +12 -3
  339. package/src/cli/agent-cli.ts +20 -0
  340. package/src/cli/brief-cli.ts +27 -21
  341. package/src/cli/cli-user-error.ts +9 -2
  342. package/src/cli/log-event-names.ts +3 -0
  343. package/src/cli/logs-cli.ts +1 -0
  344. package/src/cli/mcp-login.ts +111 -37
  345. package/src/cli/plugin-cli.ts +21 -1
  346. package/src/cli/pod-cli.ts +26 -0
  347. package/src/cli/pr-cli.ts +30 -2
  348. package/src/cli/pr-land-overlap-evidence.ts +131 -0
  349. package/src/cli/release-cli.ts +53 -11
  350. package/src/cli/self-update.ts +173 -10
  351. package/src/cli/skills-cli.ts +12 -3
  352. package/src/cli/tasks-cli.ts +133 -27
  353. package/src/context-bus/context-first.ts +51 -2
  354. package/src/context-bus/context-now-surfaces.ts +13 -2
  355. package/src/context-bus/long-term-memory.ts +3 -1
  356. package/src/context-bus/nightly-condense.ts +3 -2
  357. package/src/core-turn/run-goal-loop.ts +86 -2
  358. package/src/dashboard/chat-fold.ts +20 -0
  359. package/src/dashboard/first-screen-band.ts +151 -1
  360. package/src/dashboard/index.ts +27 -5
  361. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
  362. package/src/dashboard/stale-install-check.ts +13 -2
  363. package/src/dashboard/turn-stream-formatter.ts +25 -0
  364. package/src/debug/log-diet.ts +159 -0
  365. package/src/debug/log.ts +52 -17
  366. package/src/display/coordinator.ts +25 -2
  367. package/src/domains/coo-admin-tool.ts +27 -0
  368. package/src/domains/cron-match.ts +1 -0
  369. package/src/domains/outbound-alert.ts +17 -6
  370. package/src/domains/release-tool.ts +119 -10
  371. package/src/domains/schedule-registry.ts +10 -7
  372. package/src/domains/schedule-runner.ts +1 -0
  373. package/src/elanous-config-dir.ts +2 -2
  374. package/src/elanous-daemon.ts +3 -3
  375. package/src/execution-loop/launch-gate.ts +1 -1
  376. package/src/expression/i18n/messages.en.ts +5 -0
  377. package/src/expression/i18n/messages.ja.ts +5 -0
  378. package/src/expression/i18n/messages.ko.ts +5 -0
  379. package/src/expression/i18n/messages.zh.ts +5 -0
  380. package/src/expression/i18n/types.ts +8 -0
  381. package/src/github/pr-labels.ts +1 -0
  382. package/src/graph-runner/runner.ts +54 -5
  383. package/src/harness/dispatch-backpressure.ts +259 -0
  384. package/src/harness/harness-cli-command.ts +107 -28
  385. package/src/harness/harness-seams.ts +2 -20
  386. package/src/harness/harness-substrate-default.ts +72 -1
  387. package/src/harness/nested-elanous-policy.ts +4 -2
  388. package/src/hq/fence-wrapper.ts +7 -0
  389. package/src/hq/hq.ts +33 -2
  390. package/src/hq/lease.ts +13 -0
  391. package/src/hq/seats.ts +114 -18
  392. package/src/index.ts +163 -64
  393. package/src/intake-plane/collect-github.ts +19 -1
  394. package/src/intake-plane/digest.ts +45 -20
  395. package/src/intake-plane/lens.ts +36 -8
  396. package/src/intelligence-map/model-alias.ts +6 -0
  397. package/src/intelligence-map/model-catalog.ts +41 -0
  398. package/src/knowledge/kgs/pack.ts +5 -2
  399. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  400. package/src/knowledge/tools/knowledge-query.ts +20 -2
  401. package/src/knowledge/write.ts +234 -2
  402. package/src/llm/bedrock-provider.ts +175 -0
  403. package/src/llm/bedrock.ts +345 -0
  404. package/src/llm/provider-credentials.ts +3 -1
  405. package/src/llm.ts +306 -35
  406. package/src/loops/budget.ts +150 -0
  407. package/src/loops/orchestrator/seat-share.ts +6 -49
  408. package/src/loops/orchestrator/traffic.ts +5 -81
  409. package/src/market/signed-index.ts +42 -0
  410. package/src/mcp/mcp-oauth.ts +136 -17
  411. package/src/model-tier/llm-tier-map.ts +48 -4
  412. package/src/models/prompts.ts +22 -1
  413. package/src/mss/logging/horizon-watch.ts +168 -0
  414. package/src/mss/logging/log-store.ts +204 -15
  415. package/src/native-tool-catalog.ts +1 -1
  416. package/src/nexus/api/consult-requests.ts +7 -10
  417. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  418. package/src/nexus/api/error-reports.ts +30 -8
  419. package/src/nexus/api/http-server.ts +8 -0
  420. package/src/nexus/api/loop-resources.ts +42 -0
  421. package/src/nexus/api/outbound-report.ts +8 -3
  422. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  423. package/src/nexus/index.ts +10 -0
  424. package/src/nexus/outbound/format.ts +2 -0
  425. package/src/nexus/outbound/router.ts +198 -13
  426. package/src/oauth/codex-account-rotation.ts +16 -18
  427. package/src/oauth/codex-account-store.ts +134 -5
  428. package/src/oauth/fallback-chain.ts +28 -6
  429. package/src/onboarding.ts +2 -1
  430. package/src/plugins/adapters/claude-package.ts +4 -12
  431. package/src/plugins/core/capability-policy.ts +141 -0
  432. package/src/plugins/core/host.ts +21 -8
  433. package/src/plugins/core/manifest.ts +19 -2
  434. package/src/plugins/core/trust-store.ts +15 -0
  435. package/src/plugins/core/types.ts +12 -0
  436. package/src/plugins/install/market-fetch.ts +68 -16
  437. package/src/plugins/install/plugin-install.ts +187 -16
  438. package/src/plugins/maker/plugin-maker.ts +25 -20
  439. package/src/plugins/maker/wizard-generate.ts +16 -2
  440. package/src/policy/llm-policy.ts +14 -1
  441. package/src/process/pid-liveness.ts +1 -1
  442. package/src/prompt-cache/openai.ts +10 -6
  443. package/src/prompt-cache/openrouter.ts +94 -0
  444. package/src/prompt-enhance/enhance.ts +46 -5
  445. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  446. package/src/prompt-library/universal-preamble.ts +2 -2
  447. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  448. package/src/registry/loader.ts +6 -1
  449. package/src/release-loop/checklist.ts +24 -9
  450. package/src/release-loop/feature-store.ts +3 -0
  451. package/src/release-loop/gate-shards.ts +48 -4
  452. package/src/release-loop/landed-to-green.ts +81 -0
  453. package/src/release-loop/light-rc.ts +11 -1
  454. package/src/release-loop/merged-pr-checklist.ts +10 -0
  455. package/src/release-loop/placement.ts +91 -22
  456. package/src/release-loop/rehearsal.ts +317 -0
  457. package/src/release-loop/release-schedule.ts +13 -1
  458. package/src/release-loop/rubric-types.ts +1 -0
  459. package/src/release-loop/rubric.ts +2 -2
  460. package/src/retro/daily.ts +23 -9
  461. package/src/seat-loop/seat-loop.ts +34 -1
  462. package/src/seat-loop/traffic-signal.ts +44 -0
  463. package/src/self-dev/ask-launch-flow.ts +2 -2
  464. package/src/self-dev/dev-cli.ts +67 -3
  465. package/src/self-dev/dev-pipeline.ts +4 -6
  466. package/src/self-dev/draft-residue.ts +463 -0
  467. package/src/self-dev/draft-sweep.ts +151 -10
  468. package/src/self-dev/draft-triage-rules.ts +27 -1
  469. package/src/self-dev/launch-preflight-text.ts +549 -0
  470. package/src/self-dev/launch-preflight.ts +10 -545
  471. package/src/self-dev/orchestrate-cli.ts +57 -2
  472. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  473. package/src/self-dev/orchestrate.ts +8 -135
  474. package/src/self-dev/review-provider-fallback.ts +115 -19
  475. package/src/self-dev/run-store.ts +1 -3
  476. package/src/self-dev/run-supervisor.ts +3 -22
  477. package/src/self-dev/run-types.ts +178 -0
  478. package/src/self-dev/shard-aggregate.ts +61 -13
  479. package/src/self-dev/shard-plan.ts +5 -1
  480. package/src/self-dev/shard-run.ts +23 -5
  481. package/src/self-dev/supervisor-verdict-edges.ts +2 -4
  482. package/src/self-implement/blocked-draft-policy.ts +3 -19
  483. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  484. package/src/self-implement/follow-up-goals.ts +114 -38
  485. package/src/self-implement/gate-baseline-reap.ts +157 -0
  486. package/src/self-implement/gate-baseline.ts +78 -16
  487. package/src/self-implement/gate-cli.ts +12 -2
  488. package/src/self-implement/gate-remote.ts +17 -6
  489. package/src/self-implement/goal-author.ts +24 -4
  490. package/src/self-implement/goal-digest.ts +19 -0
  491. package/src/self-implement/graph-overlay-condition.ts +4 -0
  492. package/src/self-implement/headless-elanous-driver.ts +11 -9
  493. package/src/self-implement/host-regate.ts +120 -29
  494. package/src/self-implement/l8-merge-queue.ts +67 -5
  495. package/src/self-implement/merge-train.ts +131 -0
  496. package/src/self-implement/off-diff-evidence.ts +9 -0
  497. package/src/self-implement/orchestrator.ts +133 -16
  498. package/src/self-implement/review-finding-recurrence.ts +28 -0
  499. package/src/self-implement/rework-policy.ts +2 -1
  500. package/src/self-implement/round-summary-card.ts +63 -0
  501. package/src/self-implement/run-ledger.ts +4 -3
  502. package/src/self-implement/run-step-projection.ts +147 -0
  503. package/src/self-implement/run-stop.ts +1 -1
  504. package/src/self-implement/seams.ts +36 -3
  505. package/src/self-implement/self-implement-cli.ts +3 -1
  506. package/src/self-implement/train-gate-remote.ts +158 -0
  507. package/src/session-runtime/index.ts +10 -1
  508. package/src/session-runtime/retry-api.ts +11 -1
  509. package/src/skills/gift-install.ts +119 -0
  510. package/src/skills/runner.ts +59 -2
  511. package/src/skills/skill-feedback.ts +31 -1
  512. package/src/skills/skill-tier.ts +1 -0
  513. package/src/smart-wizard/capability-index.ts +231 -0
  514. package/src/smart-wizard/rung.ts +74 -0
  515. package/src/steward/launch.ts +20 -9
  516. package/src/steward/triage.ts +4 -2
  517. package/src/storage/file-lock.ts +8 -1
  518. package/src/task-agent/actions.ts +4 -0
  519. package/src/task-agent/card-evidence.ts +59 -13
  520. package/src/task-agent/judge.ts +4 -3
  521. package/src/task-agent/land-worktree.ts +201 -0
  522. package/src/task-agent/live-move-history.ts +133 -0
  523. package/src/task-agent/live-moves.ts +106 -19
  524. package/src/task-agent/parent-host.ts +117 -8
  525. package/src/task-agent/rejudge-on-head.ts +297 -0
  526. package/src/task-agent/review-result-capture.ts +218 -0
  527. package/src/task-agent/shadow.ts +103 -7
  528. package/src/task-agent/task-hand.ts +136 -11
  529. package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
  530. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  531. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
  532. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  533. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
  534. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
  535. package/src/task-orchestrator/surfaces/pod-pool.ts +66 -14
  536. package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
  537. package/src/task-orchestrator/surfaces/self-implement.ts +6 -2
  538. package/src/telegram-service.ts +5 -1
  539. package/src/telegram.ts +17 -4
  540. package/src/time/format.ts +13 -4
  541. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  542. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  543. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  544. package/src/user-config.ts +132 -24
  545. package/src/ux-sim/slash-menu-frames.ts +168 -0
  546. package/src/version/packed-revision.json +1 -1
  547. package/src/web-terminal/preview-tap-registry.ts +5 -2
  548. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  549. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  550. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  551. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  552. package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  554. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  555. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  556. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  558. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  563. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  572. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  573. package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  586. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  594. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  599. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  601. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  605. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  610. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  615. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  616. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  618. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  619. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  627. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  630. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  640. package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  643. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  647. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  648. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  704. package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
  705. /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
@@ -1,4 +1,61 @@
1
1
  import { ORCHESTRATOR_DEFAULTS, type OrchestratorSeat } from '../user-config.js';
2
+ import type { ChecklistItem } from '../release-loop/checklist.js';
3
+ import type { TrafficCell, TrafficProcess, TrafficResult, TrafficSeatRow } from './orchestrator/traffic.js';
4
+
5
+ const RESOURCE_SEATS: readonly OrchestratorSeat[] = ['OP', 'TC', 'MK', 'UX'];
6
+
7
+ type WorkCell = Pick<ChecklistItem, 'owner' | 'status'>;
8
+
9
+ /** Allocate whole base slots by remaining work; this calculation does not decide launches. */
10
+ export function calculateSeatBaseShares({ totalSlots, currentRound, nextRound, seatCaps }: {
11
+ totalSlots: number;
12
+ currentRound: readonly WorkCell[];
13
+ nextRound: readonly WorkCell[];
14
+ seatCaps: Readonly<Record<OrchestratorSeat, number>>;
15
+ }): Record<OrchestratorSeat, number> {
16
+ if (!Number.isSafeInteger(totalSlots) || totalSlots < 0 ||
17
+ RESOURCE_SEATS.some(seat => !Number.isSafeInteger(seatCaps[seat]) || seatCaps[seat] < 0)) {
18
+ throw new RangeError('totalSlots and seatCaps must be nonnegative safe integers');
19
+ }
20
+ const shares: Record<OrchestratorSeat, number> = { OP: 0, TC: 0, MK: 0, UX: 0 };
21
+ const weights: Record<OrchestratorSeat, number> = { OP: 0, TC: 0, MK: 0, UX: 0 };
22
+ for (const [cells, weight] of [[currentRound, 2], [nextRound, 1]] as const) {
23
+ for (const cell of cells) {
24
+ if (cell.status !== 'yellow') continue;
25
+ const seat = cell.owner?.split('/')[0];
26
+ if (RESOURCE_SEATS.some(id => id === seat)) weights[seat as OrchestratorSeat] += weight;
27
+ }
28
+ }
29
+
30
+ let available = Math.min(totalSlots, RESOURCE_SEATS.reduce((sum, seat) => sum + seatCaps[seat], 0));
31
+ let eligible = RESOURCE_SEATS.filter(seat => weights[seat] > 0 && seatCaps[seat] > 0);
32
+ while (available > 0 && eligible.length > 0) {
33
+ const totalWeight = eligible.reduce((sum, seat) => sum + weights[seat], 0);
34
+ const ideal = (seat: OrchestratorSeat) => available * weights[seat] / totalWeight;
35
+ const capped = eligible.filter(seat => ideal(seat) >= seatCaps[seat]);
36
+ if (capped.length > 0) {
37
+ for (const seat of capped) {
38
+ shares[seat] = seatCaps[seat];
39
+ available -= seatCaps[seat];
40
+ }
41
+ eligible = eligible.filter(seat => !capped.includes(seat));
42
+ continue;
43
+ }
44
+ const remainders = eligible.map(seat => ({ seat, exact: ideal(seat) }));
45
+ for (const { seat, exact } of remainders) {
46
+ shares[seat] = Math.floor(exact);
47
+ available -= shares[seat];
48
+ }
49
+ remainders.sort((a, b) => (b.exact - Math.floor(b.exact)) - (a.exact - Math.floor(a.exact)));
50
+ for (const { seat } of remainders) {
51
+ if (available === 0) break;
52
+ shares[seat]++;
53
+ available--;
54
+ }
55
+ break;
56
+ }
57
+ return shares;
58
+ }
2
59
 
3
60
  export interface SpawnBudgetInput {
4
61
  seat: OrchestratorSeat;
@@ -97,3 +154,96 @@ export function seatCapExclusion(subject: SeatCapSubject, now: number,
97
154
  if (idle !== null && now - subject.progressAt! >= staleRunMinutes * 60_000) return { reason: 'stale', idleMin: idle };
98
155
  return null;
99
156
  }
157
+
158
+ /** Only harness ask/say launches occupy ORCH traffic seats. */
159
+ export const isTrafficLaunch = (command: string): boolean =>
160
+ /(?:^|\s)(?:\S*\/)?elanous\.mjs\s+(?:(?:--test|--config-dir\s+\S+)\s+)?harness\s+(?:ask|say)(?=\s|$)/.test(command);
161
+
162
+ /** ORCH traffic supplies a physical cap, which can exceed the default spawn release gate. */
163
+ function decideTrafficLaunch(row: TrafficSeatRow): boolean {
164
+ return decideSpawn({ seat: row.seat, running: row.running, caps: { [row.seat]: row.cap },
165
+ gate: { [row.seat]: row.cap }, injectedCap: row.launchCap }).allow;
166
+ }
167
+
168
+ /** Process-to-seat resolution occurs at the boundary; this decision does no IO. */
169
+ export function budgetTrafficTick({ processes, now, caps, lastLaunchAt, idleSince, openCells, nextRound, totalSlots, idleMinutes = 30, retainQueuedCells = false }: {
170
+ processes: readonly TrafficProcess[];
171
+ now: Date;
172
+ caps: Readonly<Record<OrchestratorSeat, number>>;
173
+ lastLaunchAt?: Partial<Record<OrchestratorSeat, Date | null>>;
174
+ idleSince?: Partial<Record<OrchestratorSeat, Date | null>>;
175
+ openCells: readonly TrafficCell[];
176
+ nextRound?: readonly TrafficCell[];
177
+ totalSlots?: number;
178
+ idleMinutes?: number;
179
+ /** Observation only: expose queued work even when no launch has been observed yet. */
180
+ retainQueuedCells?: boolean;
181
+ }): TrafficResult {
182
+ const launches = processes.filter(process => isTrafficLaunch(process.command));
183
+ const slotBudget = totalSlots ?? RESOURCE_SEATS.reduce((sum, seat) => sum + caps[seat], 0);
184
+ // A missing next round is unknown, not an empty round with zero remaining work.
185
+ const baseShares = nextRound === undefined ? null : calculateSeatBaseShares({
186
+ totalSlots: slotBudget, currentRound: openCells, nextRound, seatCaps: caps,
187
+ });
188
+ const seats = RESOURCE_SEATS.map((seat): TrafficSeatRow => {
189
+ const owned = launches.filter(process => process.seat === seat);
190
+ const latest = owned.reduce<number | null>((current, process) => {
191
+ if (!Number.isFinite(process.elapsedSeconds) || process.elapsedSeconds < 0) return current;
192
+ const start = now.getTime() - process.elapsedSeconds * 1000;
193
+ return current === null ? start : Math.max(current, start);
194
+ }, null);
195
+ const fallback = owned.length ? lastLaunchAt?.[seat]?.getTime() : undefined;
196
+ const idleStart = idleSince?.[seat]?.getTime();
197
+ const last = idleStart !== undefined && Number.isFinite(idleStart) ? idleStart
198
+ : latest ?? (fallback !== undefined && Number.isFinite(fallback) ? fallback : null);
199
+ const idleFor = last === null ? null : Math.max(0, Math.floor((now.getTime() - last) / 60_000));
200
+ const nextCell = openCells.find(cell => cell.status !== 'done' && cell.owner?.split('/')[0] === seat) ?? null;
201
+ const baseShare = baseShares?.[seat] ?? null;
202
+ return { seat, running: owned.length, cap: caps[seat], baseShare, borrowed: 0, lent: 0,
203
+ launchCap: baseShare === null ? caps[seat] : Math.max(owned.length, baseShare), idleFor,
204
+ idle: decideSpawn({ seat, running: owned.length, caps: { [seat]: caps[seat] },
205
+ gate: { [seat]: caps[seat] } }).allow && last !== null && now.getTime() - last > idleMinutes * 60_000, nextCell };
206
+ });
207
+ if (baseShares !== null) {
208
+ // Account for outstanding loans before lending new capacity. A returning
209
+ // lender cannot launch into a slot still occupied by the borrower's run.
210
+ for (const borrower of seats) {
211
+ let excess = Math.max(0, borrower.running - borrower.baseShare!);
212
+ borrower.borrowed += excess;
213
+ for (const lender of seats) {
214
+ if (!excess) break;
215
+ if (lender === borrower) continue;
216
+ const amount = Math.min(excess, Math.max(0, lender.baseShare! - lender.running - lender.lent));
217
+ lender.lent += amount;
218
+ excess -= amount;
219
+ }
220
+ }
221
+ for (const lender of seats) {
222
+ if (lender.nextCell) continue;
223
+ let available = Math.max(0, lender.baseShare! - lender.running - lender.lent);
224
+ for (const borrower of seats) {
225
+ if (!available) break;
226
+ if (borrower === lender || !borrower.nextCell) continue;
227
+ const needed = Math.max(0, Math.min(borrower.cap, borrower.running + 1) - borrower.launchCap);
228
+ const amount = Math.min(available, needed);
229
+ lender.lent += amount;
230
+ borrower.borrowed += amount;
231
+ borrower.launchCap += amount;
232
+ available -= amount;
233
+ }
234
+ }
235
+ for (const lender of seats) lender.launchCap = Math.max(lender.running, lender.launchCap - lender.lent);
236
+ }
237
+ // Reserve one available global slot per possible request, including unknown-seat
238
+ // launches in the occupied count; returning a lent share does not end its old run.
239
+ let freeSlots = Math.max(0, slotBudget - launches.length);
240
+ for (const row of seats) {
241
+ if (row.nextCell && row.idle && decideTrafficLaunch(row)) {
242
+ if (freeSlots > 0) freeSlots--;
243
+ else row.launchCap = row.running;
244
+ }
245
+ row.idle = row.idle && (row.nextCell === null || decideTrafficLaunch(row));
246
+ if (!row.idle && !retainQueuedCells) row.nextCell = null;
247
+ }
248
+ return { seats, unassigned: launches.filter(process => process.seat === null).length, now, idleMinutes };
249
+ }
@@ -1,56 +1,13 @@
1
1
  import type { ChecklistItem } from '../../release-loop/checklist.js';
2
2
  import type { OrchestratorSeat } from '../../user-config.js';
3
+ import { calculateSeatBaseShares as budgetSeatBaseShares } from '../budget.js';
3
4
 
4
- const SEATS: readonly OrchestratorSeat[] = ['OP', 'TC', 'MK', 'UX'];
5
- type WorkCell = Pick<ChecklistItem, 'owner' | 'status'>;
6
-
7
- /** Allocate whole base slots by remaining work; this calculation does not decide launches. */
8
- export function calculateSeatBaseShares({ totalSlots, currentRound, nextRound, seatCaps }: {
5
+ /** Existing orchestrator callers keep their signature; the resource loop owns the decision. */
6
+ export function calculateSeatBaseShares(input: {
9
7
  totalSlots: number;
10
- currentRound: readonly WorkCell[];
11
- nextRound: readonly WorkCell[];
8
+ currentRound: readonly Pick<ChecklistItem, 'owner' | 'status'>[];
9
+ nextRound: readonly Pick<ChecklistItem, 'owner' | 'status'>[];
12
10
  seatCaps: Readonly<Record<OrchestratorSeat, number>>;
13
11
  }): Record<OrchestratorSeat, number> {
14
- if (!Number.isSafeInteger(totalSlots) || totalSlots < 0 ||
15
- SEATS.some(seat => !Number.isSafeInteger(seatCaps[seat]) || seatCaps[seat] < 0)) {
16
- throw new RangeError('totalSlots and seatCaps must be nonnegative safe integers');
17
- }
18
- const shares: Record<OrchestratorSeat, number> = { OP: 0, TC: 0, MK: 0, UX: 0 };
19
- const weights: Record<OrchestratorSeat, number> = { OP: 0, TC: 0, MK: 0, UX: 0 };
20
- for (const [cells, weight] of [[currentRound, 2], [nextRound, 1]] as const) {
21
- for (const cell of cells) {
22
- if (cell.status !== 'yellow') continue;
23
- const seat = cell.owner?.split('/')[0];
24
- if (SEATS.some(id => id === seat)) weights[seat as OrchestratorSeat] += weight;
25
- }
26
- }
27
-
28
- let available = Math.min(totalSlots, SEATS.reduce((sum, seat) => sum + seatCaps[seat], 0));
29
- let eligible = SEATS.filter(seat => weights[seat] > 0 && seatCaps[seat] > 0);
30
- while (available > 0 && eligible.length > 0) {
31
- const totalWeight = eligible.reduce((sum, seat) => sum + weights[seat], 0);
32
- const ideal = (seat: OrchestratorSeat) => available * weights[seat] / totalWeight;
33
- const capped = eligible.filter(seat => ideal(seat) >= seatCaps[seat]);
34
- if (capped.length > 0) {
35
- for (const seat of capped) {
36
- shares[seat] = seatCaps[seat];
37
- available -= seatCaps[seat];
38
- }
39
- eligible = eligible.filter(seat => !capped.includes(seat));
40
- continue;
41
- }
42
- const remainders = eligible.map(seat => ({ seat, exact: ideal(seat) }));
43
- for (const { seat, exact } of remainders) {
44
- shares[seat] = Math.floor(exact);
45
- available -= shares[seat];
46
- }
47
- remainders.sort((a, b) => (b.exact - Math.floor(b.exact)) - (a.exact - Math.floor(a.exact)));
48
- for (const { seat } of remainders) {
49
- if (available === 0) break;
50
- shares[seat]++;
51
- available--;
52
- }
53
- break;
54
- }
55
- return shares;
12
+ return budgetSeatBaseShares(input);
56
13
  }
@@ -9,7 +9,7 @@ import { withFileLockSync } from '../../storage/file-lock.js';
9
9
  import { getUserConfig, ORCHESTRATOR_DEFAULTS, type OrchestratorLoopConfig, type OrchestratorSeat } from '../../user-config.js';
10
10
  import { finishAdvice, measureFinish, type FinishAdvice, type FinishMetrics, type MeasureFinishDeps } from './finish-rate.js';
11
11
  import { collectAuthorDepth, type AuthorDepthResult, type CollectAuthorDepthDeps } from './author-depth.js';
12
- import { calculateSeatBaseShares } from './seat-share.js';
12
+ import { budgetTrafficTick } from '../budget.js';
13
13
 
14
14
  export const TRAFFIC_SEATS = ['OP', 'TC', 'MK', 'UX'] as const;
15
15
  export type TrafficCell = Pick<ChecklistItem, 'id' | 'title' | 'owner' | 'status'>;
@@ -49,88 +49,12 @@ function realOrResolved(path: string): string {
49
49
  try { return realpathSync(path); } catch { return resolve(path); }
50
50
  }
51
51
 
52
- const IS_LAUNCH = /(?:^|\s)(?:\S*\/)?elanous\.mjs\s+(?:(?:--test|--config-dir\s+\S+)\s+)?harness\s+(?:ask|say)(?=\s|$)/;
53
52
  /** A `harness ask|say` launch command line — the only processes `trafficTick` counts. */
54
- export const isTrafficLaunch = (command: string): boolean => IS_LAUNCH.test(command);
53
+ export { isTrafficLaunch } from '../budget.js';
55
54
 
56
- /** Process-to-seat resolution occurs at the boundary; this decision does no IO. */
57
- export function trafficTick({ processes, now, caps, lastLaunchAt, idleSince, openCells, nextRound, totalSlots, idleMinutes = 30 }: {
58
- processes: readonly TrafficProcess[];
59
- now: Date;
60
- caps: Readonly<Record<OrchestratorSeat, number>>;
61
- lastLaunchAt?: Partial<Record<OrchestratorSeat, Date | null>>;
62
- idleSince?: Partial<Record<OrchestratorSeat, Date | null>>;
63
- openCells: readonly TrafficCell[];
64
- nextRound?: readonly TrafficCell[];
65
- totalSlots?: number;
66
- idleMinutes?: number;
67
- }): TrafficResult {
68
- const launches = processes.filter(process => IS_LAUNCH.test(process.command));
69
- const slotBudget = totalSlots ?? TRAFFIC_SEATS.reduce((sum, seat) => sum + caps[seat], 0);
70
- // A missing next round is unknown, not an empty round with zero remaining work.
71
- const baseShares = nextRound === undefined ? null : calculateSeatBaseShares({
72
- totalSlots: slotBudget, currentRound: openCells, nextRound, seatCaps: caps,
73
- });
74
- const seats = TRAFFIC_SEATS.map((seat): TrafficSeatRow => {
75
- const owned = launches.filter(process => process.seat === seat);
76
- const latest = owned.reduce<number | null>((current, process) => {
77
- if (!Number.isFinite(process.elapsedSeconds) || process.elapsedSeconds < 0) return current;
78
- const start = now.getTime() - process.elapsedSeconds * 1000;
79
- return current === null ? start : Math.max(current, start);
80
- }, null);
81
- const fallback = owned.length ? lastLaunchAt?.[seat]?.getTime() : undefined;
82
- const idleStart = idleSince?.[seat]?.getTime();
83
- const last = idleStart !== undefined && Number.isFinite(idleStart) ? idleStart
84
- : latest ?? (fallback !== undefined && Number.isFinite(fallback) ? fallback : null);
85
- const idleFor = last === null ? null : Math.max(0, Math.floor((now.getTime() - last) / 60_000));
86
- const nextCell = openCells.find(cell => cell.status !== 'done' && cell.owner?.split('/')[0] === seat) ?? null;
87
- const baseShare = baseShares?.[seat] ?? null;
88
- return { seat, running: owned.length, cap: caps[seat], baseShare, borrowed: 0, lent: 0,
89
- launchCap: baseShare === null ? caps[seat] : Math.max(owned.length, baseShare), idleFor,
90
- idle: owned.length < caps[seat] && last !== null && now.getTime() - last > idleMinutes * 60_000, nextCell };
91
- });
92
- if (baseShares !== null) {
93
- // Account for outstanding loans before lending new capacity. A returning
94
- // lender cannot launch into a slot still occupied by the borrower's run.
95
- for (const borrower of seats) {
96
- let excess = Math.max(0, borrower.running - borrower.baseShare!);
97
- borrower.borrowed += excess;
98
- for (const lender of seats) {
99
- if (!excess) break;
100
- if (lender === borrower) continue;
101
- const amount = Math.min(excess, Math.max(0, lender.baseShare! - lender.running - lender.lent));
102
- lender.lent += amount;
103
- excess -= amount;
104
- }
105
- }
106
- for (const lender of seats) {
107
- if (lender.nextCell) continue;
108
- let available = Math.max(0, lender.baseShare! - lender.running - lender.lent);
109
- for (const borrower of seats) {
110
- if (!available) break;
111
- if (borrower === lender || !borrower.nextCell) continue;
112
- const needed = Math.max(0, Math.min(borrower.cap, borrower.running + 1) - borrower.launchCap);
113
- const amount = Math.min(available, needed);
114
- lender.lent += amount;
115
- borrower.borrowed += amount;
116
- borrower.launchCap += amount;
117
- available -= amount;
118
- }
119
- }
120
- for (const lender of seats) lender.launchCap = Math.max(lender.running, lender.launchCap - lender.lent);
121
- }
122
- // Reserve one available global slot per possible request, including unknown-seat
123
- // launches in the occupied count; returning a lent share does not end its old run.
124
- let freeSlots = Math.max(0, slotBudget - launches.length);
125
- for (const row of seats) {
126
- if (row.nextCell && row.idle && row.running < row.launchCap) {
127
- if (freeSlots > 0) freeSlots--;
128
- else row.launchCap = row.running;
129
- }
130
- row.idle = row.idle && (row.nextCell === null || row.running < row.launchCap);
131
- if (!row.idle) row.nextCell = null;
132
- }
133
- return { seats, unassigned: launches.filter(process => process.seat === null).length, now, idleMinutes };
55
+ /** Process observation stays at the boundary; the shared resource loop owns the decision. */
56
+ export function trafficTick(input: Parameters<typeof budgetTrafficTick>[0]): TrafficResult {
57
+ return budgetTrafficTick(input);
134
58
  }
135
59
 
136
60
  export function withFinishAdvice(result: TrafficResult, deps: MeasureFinishDeps = {}): TrafficResult {
@@ -1,10 +1,31 @@
1
1
  import { createHash, createPublicKey, generateKeyPairSync, sign, verify } from 'node:crypto';
2
2
 
3
+ export interface MarketplaceArtifact {
4
+ sha256: string;
5
+ bytes: number;
6
+ key: string;
7
+ }
8
+
9
+ export interface MarketplaceScopedPack {
10
+ name: string;
11
+ version: string;
12
+ description?: string;
13
+ artifact: MarketplaceArtifact;
14
+ visibility: 'public' | 'internal';
15
+ enterpriseId?: string;
16
+ }
17
+
18
+ export interface MarketplaceLoopBundle extends MarketplaceScopedPack {
19
+ graphs?: string[];
20
+ }
21
+
3
22
  export interface MarketplaceIndex {
4
23
  name: string;
5
24
  interface: { displayName: string };
6
25
  sequence: number;
7
26
  generatedAt?: string;
27
+ knowledgePacks?: MarketplaceScopedPack[];
28
+ loopBundles?: MarketplaceLoopBundle[];
8
29
  plugins: Array<{
9
30
  name: string;
10
31
  source: { source: string; [key: string]: unknown };
@@ -57,6 +78,27 @@ function invalidIndex(value: unknown): string | null {
57
78
  if (value.generatedAt !== undefined && !string(value.generatedAt)) return 'generatedAt: expected string';
58
79
  if (!Array.isArray(value.plugins)) return 'plugins: expected array';
59
80
 
81
+ for (const collection of ['knowledgePacks', 'loopBundles'] as const) {
82
+ const entries = value[collection];
83
+ if (entries === undefined) continue;
84
+ if (!Array.isArray(entries)) return `${collection}: expected array`;
85
+ for (const [i, entry] of entries.entries()) {
86
+ const field = (name: string) => `${collection}[${i}] (${record(entry) && string(entry.name) ? entry.name : 'unnamed'}).${name}`;
87
+ if (!record(entry)) return field('expected object');
88
+ if (!string(entry.name) || !entry.name.trim()) return field('name: expected non-empty string');
89
+ if (!string(entry.version) || !entry.version.trim()) return field('version: expected non-empty string');
90
+ if (entry.description !== undefined && !string(entry.description)) return field('description: expected string');
91
+ if (entry.visibility !== 'public' && entry.visibility !== 'internal') return field('visibility: expected public or internal');
92
+ if (entry.visibility === 'internal' && (!string(entry.enterpriseId) || !entry.enterpriseId.trim())) return field('enterpriseId: required for internal entry');
93
+ if (entry.visibility === 'public' && entry.enterpriseId !== undefined) return field('enterpriseId: not allowed for public entry');
94
+ if (!record(entry.artifact)) return field('artifact: expected object');
95
+ if (!string(entry.artifact.sha256) || !/^[a-fA-F0-9]{64}$/.test(entry.artifact.sha256)) return field('artifact.sha256: expected 64 hex characters');
96
+ if (!Number.isSafeInteger(entry.artifact.bytes) || (entry.artifact.bytes as number) < 0) return field('artifact.bytes: expected non-negative integer');
97
+ if (!string(entry.artifact.key) || !entry.artifact.key.trim()) return field('artifact.key: expected non-empty string');
98
+ if (collection === 'loopBundles' && entry.graphs !== undefined && !stringArray(entry.graphs)) return field('graphs: expected string array');
99
+ }
100
+ }
101
+
60
102
  for (const [i, plugin] of value.plugins.entries()) {
61
103
  const field = (name: string) => `plugins[${i}] (${record(plugin) && string(plugin.name) ? plugin.name : 'unnamed'}).${name}`;
62
104
  if (!record(plugin)) return field('expected object');
@@ -5,9 +5,8 @@
5
5
  // 다시 실어 보내는 «잇는» 모듈. 주소를 코드에 박지 않는다 — 호스트는
6
6
  // 전부 그 401 안내에서 그때 얻는다.
7
7
  //
8
- // 경계: 브라우저에서 누르는 구간은 만들지 않는다. 인가 주소를 조립해
9
- // AuthorizeHandler 로 돌려주는 데까지가 이 착지다.
10
- // 경계: 장치 코드 흐름은 다루지 않는다.
8
+ // 브라우저 승인은 호출자(aside/CLI)의 책임이다. 브라우저를 쓸 수 없고
9
+ // 인가 서버가 RFC 8628 을 광고할 때는 장치 코드로 자격을 얻는다.
11
10
  // 경계: 새 CLI 하위 명령은 더하지 않는다.
12
11
 
13
12
  import { join } from 'node:path';
@@ -36,6 +35,7 @@ export type McpOAuthErrorCode =
36
35
  | 'identity-mismatch'
37
36
  | 's256-unsupported'
38
37
  | 'registration'
38
+ | 'device'
39
39
  | 'state-mismatch'
40
40
  | 'token'
41
41
  | 'refresh';
@@ -70,9 +70,10 @@ export interface ProtectedResourceMetadata {
70
70
 
71
71
  export interface AuthorizationServerMetadata {
72
72
  issuer: string;
73
- authorizationEndpoint: string;
73
+ authorizationEndpoint?: string;
74
74
  tokenEndpoint: string;
75
75
  registrationEndpoint?: string;
76
+ deviceAuthorizationEndpoint?: string;
76
77
  codeChallengeMethodsSupported: string[];
77
78
  }
78
79
 
@@ -81,6 +82,9 @@ export interface ClientRegistration {
81
82
  clientSecret?: string;
82
83
  /** 동적 등록 때 쓴 redirect_uri. 옛 등록에는 없다. */
83
84
  redirectUri?: string;
85
+ /** Registered now but not stored yet: the store still holds another client's tokens, so this registration is
86
+ * committed only with its own tokens (exchangeAuthorizationCode). A cancelled login leaves the store as it was. */
87
+ pending?: boolean;
84
88
  }
85
89
 
86
90
  export interface AuthorizationRequest {
@@ -90,6 +94,8 @@ export interface AuthorizationRequest {
90
94
  redirectUri: string;
91
95
  issuer: string;
92
96
  clientId: string;
97
+ /** Set when the client registration is pending (see ClientRegistration.pending); in memory only. */
98
+ pendingRegistration?: { clientSecret?: string };
93
99
  scope?: string;
94
100
  resource?: string;
95
101
  }
@@ -364,14 +370,14 @@ export async function discoverAuthorizationServer(
364
370
  const issuer = stringField(body, 'issuer');
365
371
  const authorizationEndpoint = stringField(body, 'authorization_endpoint');
366
372
  const tokenEndpoint = stringField(body, 'token_endpoint');
367
- if (!issuer || !authorizationEndpoint || !tokenEndpoint) {
373
+ if (!issuer || !tokenEndpoint || (!authorizationEndpoint && !stringField(body, 'device_authorization_endpoint'))) {
368
374
  throw new McpOAuthError(
369
375
  'discovery',
370
376
  'authorization server metadata is missing issuer, authorization_endpoint, or token_endpoint',
371
377
  );
372
378
  }
373
379
  requireHttpUrl(issuer, 'issuer');
374
- requireHttpUrl(authorizationEndpoint, 'authorization_endpoint');
380
+ if (authorizationEndpoint) requireHttpUrl(authorizationEndpoint, 'authorization_endpoint');
375
381
  requireHttpUrl(tokenEndpoint, 'token_endpoint');
376
382
  // ⛔⭐⭐ RFC 8414 §3.3 — 돌려받은 `issuer` 는 «우리가 물어본» 인가서버
377
383
  // 식별자와 «같아야» 한다. 안 대조하면 metadata 를 쥔 쪽이 남의 issuer 를
@@ -385,11 +391,14 @@ export async function discoverAuthorizationServer(
385
391
  }
386
392
  const registrationEndpoint = stringField(body, 'registration_endpoint');
387
393
  if (registrationEndpoint) requireHttpUrl(registrationEndpoint, 'registration_endpoint');
394
+ const deviceAuthorizationEndpoint = stringField(body, 'device_authorization_endpoint');
395
+ if (deviceAuthorizationEndpoint) requireHttpUrl(deviceAuthorizationEndpoint, 'device_authorization_endpoint');
388
396
  return {
389
397
  issuer,
390
- authorizationEndpoint,
398
+ ...(authorizationEndpoint ? { authorizationEndpoint } : {}),
391
399
  tokenEndpoint,
392
400
  ...(registrationEndpoint ? { registrationEndpoint } : {}),
401
+ ...(deviceAuthorizationEndpoint ? { deviceAuthorizationEndpoint } : {}),
393
402
  codeChallengeMethodsSupported: stringList(body, 'code_challenge_methods_supported'),
394
403
  };
395
404
  }
@@ -468,13 +477,15 @@ export function loadStoredRegistration(
468
477
 
469
478
  export async function ensureClientRegistration(
470
479
  metadata: AuthorizationServerMetadata,
471
- opts: McpOAuthRuntimeOpts & { forceReregister?: boolean } = {},
480
+ opts: McpOAuthRuntimeOpts & { forceReregister?: boolean; deviceCode?: boolean } = {},
472
481
  ): Promise<ClientRegistration> {
473
482
  const path = storePath(opts);
474
483
  if (!opts.forceReregister) {
475
484
  const stored = loadStoredRegistration(metadata.issuer, { storePath: path });
476
- // 옛 등록은 redirect_uri 기록이 없다 — 재사용하면 포트 불일치로 영원히 막힌다.
477
- if (stored?.redirectUri) return stored;
485
+ // Browser registrations require a bound loopback URI. Device authorization reuses a client without one
486
+ // (a prior device client — its stored refresh token stays paired with it), or any client when it cannot register.
487
+ if (stored && opts.deviceCode && (!stored.redirectUri || !metadata.registrationEndpoint)) return stored;
488
+ if (stored?.redirectUri && !opts.deviceCode) return stored;
478
489
  }
479
490
  if (!metadata.registrationEndpoint) {
480
491
  throw new McpOAuthError(
@@ -493,9 +504,9 @@ export async function ensureClientRegistration(
493
504
  },
494
505
  body: JSON.stringify({
495
506
  client_name: CLIENT_NAME,
496
- redirect_uris: [redirectUri],
497
- grant_types: ['authorization_code', 'refresh_token'],
498
- response_types: ['code'],
507
+ ...(opts.deviceCode ? {} : { redirect_uris: [redirectUri] }),
508
+ grant_types: opts.deviceCode ? ['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token'] : ['authorization_code', 'refresh_token'],
509
+ response_types: opts.deviceCode ? [] : ['code'],
499
510
  token_endpoint_auth_method: 'none',
500
511
  application_type: 'native',
501
512
  }),
@@ -519,8 +530,15 @@ export async function ensureClientRegistration(
519
530
  const registration: ClientRegistration = {
520
531
  clientId,
521
532
  ...(clientSecret ? { clientSecret } : {}),
522
- redirectUri,
533
+ ...(opts.deviceCode ? {} : { redirectUri }),
523
534
  };
535
+ // A device client is stored only with its first tokens (authorizeMcpDevice): until a device login succeeds,
536
+ // the stored registration and the refresh token paired with it stay as they were.
537
+ if (opts.deviceCode) return registration;
538
+ // A browser registration over another client's live tokens (e.g. after a device login) waits for its own
539
+ // tokens: storing it now would orphan the stored refresh token if this approval is cancelled or fails.
540
+ const existing = loadTokens(metadata.issuer, path);
541
+ if (existing?.tokens.refreshToken && existing.accountUuid && existing.accountUuid !== clientId) return { ...registration, pending: true };
524
542
  persistRegistration(metadata.issuer, registration, path);
525
543
  return registration;
526
544
  }
@@ -546,6 +564,7 @@ export function buildAuthorizationRequest(
546
564
  'authorization server does not advertise code_challenge_methods_supported=S256',
547
565
  );
548
566
  }
567
+ if (!metadata.authorizationEndpoint) throw new McpOAuthError('discovery', 'authorization server has no authorization_endpoint for browser login');
549
568
  const pkce = generatePkcePair();
550
569
  const redirectUri = opts.redirectUri ?? DEFAULT_REDIRECT_URI;
551
570
  const url = new URL(metadata.authorizationEndpoint);
@@ -565,6 +584,7 @@ export function buildAuthorizationRequest(
565
584
  redirectUri,
566
585
  issuer: metadata.issuer,
567
586
  clientId: registration.clientId,
587
+ ...(registration.pending ? { pendingRegistration: registration.clientSecret ? { clientSecret: registration.clientSecret } : {} } : {}),
568
588
  ...(scope ? { scope } : {}),
569
589
  ...(opts.resource ? { resource: opts.resource } : {}),
570
590
  };
@@ -673,13 +693,107 @@ function persistTokens(
673
693
  authMode: AUTH_MODE,
674
694
  ...(clientId ? { accountUuid: clientId } : {}),
675
695
  ...(clientSecret ? { organizationUuid: clientSecret } : {}),
676
- ...(existing?.redirectUri ? { redirectUri: existing.redirectUri } : {}),
696
+ // A loopback URI belongs to the client that registered it — never carry it onto a different (device) client.
697
+ ...(existing?.redirectUri && (!registration || registration.clientId === existing.accountUuid) ? { redirectUri: existing.redirectUri } : {}),
677
698
  mirrorCodex: false,
678
699
  },
679
700
  path,
680
701
  );
681
702
  }
682
703
 
704
+ export interface McpDeviceAuthorization {
705
+ userCode: string;
706
+ verificationUri: string;
707
+ verificationUriComplete?: string;
708
+ }
709
+
710
+ /** RFC 8628: only an advertised endpoint enables the fallback; tokens use the same issuer store. */
711
+ export async function authorizeMcpDevice(
712
+ metadata: AuthorizationServerMetadata,
713
+ registration: ClientRegistration,
714
+ opts: McpOAuthRuntimeOpts & {
715
+ scope?: string;
716
+ resource?: string;
717
+ onDeviceCode: (code: McpDeviceAuthorization) => Promise<void> | void;
718
+ sleep?: (ms: number) => Promise<void>;
719
+ now?: () => number;
720
+ },
721
+ ): Promise<OAuthTokens> {
722
+ const endpoint = metadata.deviceAuthorizationEndpoint;
723
+ if (!endpoint) throw new McpOAuthError('device', 'authorization server does not advertise device_authorization_endpoint');
724
+ const fetchFn = fetchImpl(opts);
725
+ const post = async (url: string, fields: Record<string, string | undefined>) => {
726
+ let response: Awaited<ReturnType<McpOAuthFetch>>;
727
+ try {
728
+ response = await fetchFn(url, {
729
+ method: 'POST',
730
+ headers: { accept: 'application/json', 'content-type': 'application/x-www-form-urlencoded' },
731
+ body: formBody(fields),
732
+ });
733
+ } catch (error) {
734
+ throw new McpOAuthError('device', `device authorization request failed: ${error instanceof Error ? error.message : String(error)}`);
735
+ }
736
+ const text = await response.text();
737
+ return { status: response.status, body: parseJsonObject(text, 'device authorization response', 'device') };
738
+ };
739
+ const started = await post(endpoint, {
740
+ client_id: registration.clientId,
741
+ client_secret: registration.clientSecret,
742
+ scope: opts.scope,
743
+ resource: opts.resource,
744
+ });
745
+ const deviceCode = stringField(started.body, 'device_code');
746
+ const userCode = stringField(started.body, 'user_code');
747
+ const verificationUri = stringField(started.body, 'verification_uri');
748
+ if (started.status < 200 || started.status >= 300 || !deviceCode || !userCode || !verificationUri) {
749
+ const error = stringField(started.body, 'error');
750
+ throw new McpOAuthError('device', `device authorization returned HTTP ${started.status}${error ? ` (${error})` : ''} or missing required fields`);
751
+ }
752
+ requireHttpUrl(verificationUri, 'verification_uri');
753
+ const verificationUriComplete = stringField(started.body, 'verification_uri_complete');
754
+ if (verificationUriComplete) requireHttpUrl(verificationUriComplete, 'verification_uri_complete');
755
+ const seconds = started.body.expires_in;
756
+ if (typeof seconds !== 'number' || !Number.isFinite(seconds) || seconds <= 0) {
757
+ throw new McpOAuthError('device', 'device authorization response has invalid expires_in');
758
+ }
759
+ const now = opts.now ?? Date.now;
760
+ const deadline = now() + Math.min(seconds * 1000, 15 * 60_000);
761
+ let interval = typeof started.body.interval === 'number' && Number.isFinite(started.body.interval) && started.body.interval > 0
762
+ ? Math.max(1000, started.body.interval * 1000) : 5000;
763
+ await opts.onDeviceCode({ userCode, verificationUri, ...(verificationUriComplete ? { verificationUriComplete } : {}) });
764
+ const sleep = opts.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
765
+ let attempts = 0;
766
+ while (now() < deadline) {
767
+ if (++attempts > Math.ceil(Math.min(seconds, 900)) + 1) throw new McpOAuthError('device', 'device authorization polling limit exceeded');
768
+ await sleep(Math.min(interval, deadline - now()));
769
+ if (now() >= deadline) break;
770
+ const polled = await post(metadata.tokenEndpoint, {
771
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
772
+ device_code: deviceCode,
773
+ client_id: registration.clientId,
774
+ client_secret: registration.clientSecret,
775
+ resource: opts.resource,
776
+ });
777
+ if (polled.status >= 200 && polled.status < 300) {
778
+ const accessToken = stringField(polled.body, 'access_token');
779
+ if (!accessToken) throw new McpOAuthError('token', 'device token response is missing access_token');
780
+ const tokens: OAuthTokens = {
781
+ accessToken,
782
+ refreshToken: stringField(polled.body, 'refresh_token') ?? '',
783
+ expiresAt: expiresAtFromSeconds(polled.body.expires_in),
784
+ tokenType: stringField(polled.body, 'token_type') ?? 'Bearer',
785
+ ...(stringField(polled.body, 'scope') ? { scope: stringField(polled.body, 'scope') } : {}),
786
+ };
787
+ persistTokens(metadata.issuer, tokens, registration, storePath(opts));
788
+ return tokens;
789
+ }
790
+ const error = stringField(polled.body, 'error');
791
+ if (error === 'slow_down') interval += 5000;
792
+ else if (error !== 'authorization_pending') throw new McpOAuthError('device', `device token request returned HTTP ${polled.status} (${error ?? 'unknown'})`);
793
+ }
794
+ throw new McpOAuthError('device', 'device authorization expired before approval');
795
+ }
796
+
683
797
  export async function exchangeAuthorizationCode(
684
798
  metadata: AuthorizationServerMetadata,
685
799
  request: AuthorizationRequest,
@@ -688,7 +802,10 @@ export async function exchangeAuthorizationCode(
688
802
  ): Promise<OAuthTokens> {
689
803
  const code = verifyAuthorizationCallback(request, callback);
690
804
  const path = storePath(opts);
691
- const registration = loadStoredRegistration(metadata.issuer, { storePath: path });
805
+ const pending = request.pendingRegistration;
806
+ const registration: ClientRegistration | null = pending
807
+ ? { clientId: request.clientId, ...(pending.clientSecret ? { clientSecret: pending.clientSecret } : {}), redirectUri: request.redirectUri }
808
+ : loadStoredRegistration(metadata.issuer, { storePath: path });
692
809
  const tokens = await postToken(
693
810
  metadata.tokenEndpoint,
694
811
  {
@@ -703,7 +820,9 @@ export async function exchangeAuthorizationCode(
703
820
  fetchImpl(opts),
704
821
  'token',
705
822
  );
706
- persistTokens(
823
+ // A pending registration is committed together with the tokens it just earned.
824
+ if (pending) persistRegistration(metadata.issuer, registration!, path, tokens);
825
+ else persistTokens(
707
826
  metadata.issuer,
708
827
  tokens,
709
828
  registration ?? { clientId: request.clientId },