elanous 0.2.42 → 0.2.43

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 (685) 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 → Om5xS9jpjSXJCeTNGYEi4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 0966f8a1.745fcd44f64a87ea.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 0ad6802e.ae7afb63fdcb4491.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/114.2b90424d1a3ce84c.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1151-5c2bb8f002ca2dd6.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1200.6a37c202f9f17e9a.js +226 -0
  9. package/apps/pwa/out/_next/static/chunks/1261-a616d5728e02e624.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1313-19f737e0222c4444.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1357.3bbef3976c37f94a.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1362-20adddfaf662b0fa.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1406.a1dc2ab6f8449374.js} +2 -2
  14. package/apps/pwa/out/_next/static/chunks/1737-9491fc6ab29b9ec6.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1803-4f91a8e7dcaf042c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1961.a81b12872c3e93a9.js +23 -0
  17. package/apps/pwa/out/_next/static/chunks/{53c73f84.373b6160adfa89a4.js → 1970cf59.2d4d8ce5d6c81853.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/1971-8890f3962ba7ee0a.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{9211-330b6736a63d4cb3.js → 2073-ba274e00e4f9efb4.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 2144.25b292396712196d.js} +2 -2
  21. package/apps/pwa/out/_next/static/chunks/2268-53861f339e0b65a2.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2312.0c8b61e22d3136d7.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 2573.387a707f6f9d720c.js} +2 -2
  24. package/apps/pwa/out/_next/static/chunks/273.f156eee28f11af77.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2873.d2140e5a82546401.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 3072.01338851ca21a6f7.js} +2 -2
  27. package/apps/pwa/out/_next/static/chunks/3091.a5a4143dea33d197.js +90 -0
  28. package/apps/pwa/out/_next/static/chunks/{2456.b6de0e1c05f28843.js → 3095.dc44586a5f83b86d.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{3207.a756c95e9ec8c3c8.js → 3113.d7472bbc27d580c7.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/3228-9650b6447b6fa288.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3402.44b565b314f2263c.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3557ac4a.c8931684475018ad.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{8505.fd803c6c33b54cc3.js → 360.ae9f9f4c33c395e8.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3638.80412ea63aae8f3f.js +286 -0
  35. package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 363bfab3.9623b9f89363541f.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/3694.e0099884345f0198.js +64 -0
  37. package/apps/pwa/out/_next/static/chunks/3744.54f87db52acfd1ab.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3903.3ef4656c67572764.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3935.16701e33f8982dc9.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3955.6922286237f2ac2b.js +24 -0
  41. package/apps/pwa/out/_next/static/chunks/3969.272ee7f9fd6c62e5.js +34 -0
  42. package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 4199.ce86b281fd0a60b7.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/4311-6dd3144002cc0c2d.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4426-2b230fad00c88930.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{2690.0521c738b7749931.js → 4445.7990c76b3751a918.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4447-14c5161fa59166c7.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4856-b0b8075bba8c53f4.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4870-de370d65e73c0bb5.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4885-2c989165c4b29fad.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/{1945.7b54990d578c119b.js → 4894.fec2ca9e99caefa2.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/5093.8f04b7f8cb899a95.js +94 -0
  52. package/apps/pwa/out/_next/static/chunks/5122-2bb177cebf89e19a.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5154.5f56dc3902e3d275.js +36 -0
  54. package/apps/pwa/out/_next/static/chunks/529.64ff7257180b2ac9.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5394.5dabeb0c62293a28.js +93 -0
  56. package/apps/pwa/out/_next/static/chunks/5461.08bf2404ff38ec85.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5474-22e08a85583209b2.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 5564.9e72532188f57586.js} +16 -16
  59. package/apps/pwa/out/_next/static/chunks/5567-265df39ed8fe9dcb.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5570-a94ae19811cb2046.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5574-b47c9ef2dceff1fd.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 5628.6ddb2d5ffba4ff4c.js} +4 -4
  63. package/apps/pwa/out/_next/static/chunks/{1319.b9b815ae0f181e06.js → 5730.43d7ccc09988e646.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5789.2da35c258292e1e5.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5824.da9527b15a3221e5.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5866.366966af47fdde5d.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 5930.8b4df3b46c32b05a.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/5963-c4d8469c52a0828b.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/6001.ec4049ceb3c43418.js +27 -0
  70. package/apps/pwa/out/_next/static/chunks/6120-471f03db1e299c0c.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6175-41479e643aca1878.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6291.a2de4f9787637075.js +104 -0
  73. package/apps/pwa/out/_next/static/chunks/6400-6699907c3537436a.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6428.1f4327d6ae5fdf9a.js +287 -0
  75. package/apps/pwa/out/_next/static/chunks/644.02cb026fa44bcd0a.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6466-6c87d60d3dd174fb.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 6540.c7bef57ad8f90a87.js} +3 -3
  78. package/apps/pwa/out/_next/static/chunks/6773.d4264665ab31bec0.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6822.3c789f1a8443e774.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 6944.309f4e3ea54d1537.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/7261-8ff69d3b2ee671fd.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7266.084c6bbc70035140.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7271.5c0100e7320aa856.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7429-bf5731358c8f2f68.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7464.01f7a0ae1215fbe7.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7479.0fcad5f37eb64f0c.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/{4770.769c9cd9c7034eba.js → 7483.427a2fe2049e388d.js} +2 -2
  88. package/apps/pwa/out/_next/static/chunks/{1147-5196d19c222051b3.js → 7502-be74718178e13e56.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7530.0889722b19572065.js +24 -0
  90. package/apps/pwa/out/_next/static/chunks/7645.5b2ee3ad45c55ea3.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7788.7d1c79f1a8e18946.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7900.096f455c7c1efc53.js +77 -0
  93. package/apps/pwa/out/_next/static/chunks/7910-6f139bcafd238b9f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7966.f71c8958d1637548.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 8062-7cd0bcc7f01455ba.js} +3 -3
  96. package/apps/pwa/out/_next/static/chunks/8073.f6cf2f2c71aafbd0.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8201.190b94088980f430.js +74 -0
  98. package/apps/pwa/out/_next/static/chunks/8205.282ca4bb62d54a0a.js +62 -0
  99. package/apps/pwa/out/_next/static/chunks/8313-dfa1021bb58a46d6.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/837-81336ebaca8198a8.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8447.7963352ef5f71b76.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8574-868e8129525ef6d9.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8588.d1c6a2903727ce87.js +149 -0
  104. package/apps/pwa/out/_next/static/chunks/8637.90f92d5c8db4732c.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/868.6e953be05bcf6dca.js +41 -0
  106. package/apps/pwa/out/_next/static/chunks/8706-e1fe0309343a2273.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8749-06384cdfc4520add.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{9656-374232558fd528d0.js → 8861-cc1fa1c7b920fa8e.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/{5440-4236de26c5ea5856.js → 8967-7dfebf710c9dec9d.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 8986.8e2e4efbfa655c59.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/8997-3c564dbb3b58b055.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/{4320.583cbab64db6be02.js → 923.2034d10ae91e9c20.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/9312.bc1b89c5d4368033.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{1574.878c18ecc97b1bd4.js → 943.39ae5e82f4f1893f.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9469.0500480de55fb205.js +32 -0
  116. package/apps/pwa/out/_next/static/chunks/9770.5f75bc6088b16109.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9810-2543267050e58b82.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9870.8419702475254745.js +8 -0
  119. package/apps/pwa/out/_next/static/chunks/9941-376d1b74d51b01a4.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9958.385434ab04241758.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/aa57532f.510551854ff239b1.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-deea1450b17cb8dc.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-70985b904f8650ef.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a2e15e33e56a4353.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-fc72ce2db12d6ca9.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-be03e41f9436ebd9.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-35a35999382da3f2.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-3ff5b1e6ca88b848.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-a65101300a0ee5c1.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-3aca5b6d67dba511.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-45b8ab0a71e61314.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-53046e282d4cda8e.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-17809e60e8354c17.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-fd2442d347bf5898.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-e9d720d6fc082e21.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-6b8b4267bab0a677.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-deea1450b17cb8dc.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-8bcf6233ac7c17af.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-7cc25591cfc2126f.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-053e871f35c9beba.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-eff819f0c2d5e084.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-4d7e9d8db5274a87.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-2b2d8f5aa5f69ad4.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-0b8f92c5062e68b1.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1bd9d0fdac2ced3d.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/{page-0f291d3c8fd55a3a.js → page-9ee28f7df07428ea.js} +1 -1
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-44b7a1ff468c6648.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-cbc6523711dc1b65.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-fdad47899c2695be.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-79a8b5fee4c20871.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-03e8ac9606aeaffb.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-4cd55c55ec287e2f.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-db17b4305404161e.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-30041d848350fd02.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c540da022dbf86b0.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9399efc538da057f.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ca2d09128c585ca4.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-0e2635aecd343038.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ef7f4399b6b7726e.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-deea1450b17cb8dc.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-caf530535b875468.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-eaa20c1543a5fd8e.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c541eb1b75120f61.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-ab5e213eda9479f4.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-0a815f34367b6db6.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-e858ba0ed9393b68.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-1638ee9dd6e0582f.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-4cf5a399109391f2.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b4396321238798ec.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-cb72bfd21006781a.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6135d0242afbc434.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a1dccf907eddb856.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/c7945435-b44d4dbe90ba0dcb.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → cb0f8df8.09a4a6be97e3fc5f.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → d96660fb.cbc21a2a88539dbb.js} +7 -7
  176. package/apps/pwa/out/_next/static/chunks/{50061469.0326382241ef3b2d.js → ea514caa.05a24f78d9dffe5f.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/fb7d20d5-6892502b6ee39ca6.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-e8a911e19b1be41f.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7022f418fabba021.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-e5f15df755756a1e.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-4525f91e36940c9b.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-140f0e519c085b0f.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-8f22ef63dcb865b1.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/examples/research-runtime-empty-terminal.yaml +28 -0
  285. package/graphs/profiles/local.yaml +5 -0
  286. package/graphs/profiles/pod.yaml +4 -0
  287. package/package.json +6 -2
  288. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  289. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  290. package/plugins/demo-browser-hand/plugin.json +13 -0
  291. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  292. package/plugins/demo-linear-secretary/plugin.json +15 -0
  293. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  294. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  295. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  296. package/plugins/demo-research/plugin.json +16 -0
  297. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  298. package/plugins/demo-video-briefing/plugin.json +15 -0
  299. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  300. package/scripts/build-signed-catalog.ts +48 -0
  301. package/scripts/ci-typecheck-main-delta.sh +88 -0
  302. package/scripts/codex-fallback-live-probe.ts +1 -1
  303. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  304. package/scripts/demo/demo1104-stage.config.ts +21 -0
  305. package/scripts/demo/demo1104-stage.ts +316 -0
  306. package/scripts/goal-method-audit.ts +17 -1
  307. package/scripts/graph-units/land-enqueue.ts +90 -0
  308. package/scripts/hooks/codex-notify.sh +32 -0
  309. package/scripts/install.sh +10 -38
  310. package/scripts/landing-heal/land-plan.ts +57 -0
  311. package/scripts/release-loop/auto-approve-node.ts +1 -1
  312. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  313. package/scripts/release-loop/gate-method.ts +139 -0
  314. package/scripts/release-loop/gate-node.ts +180 -20
  315. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  316. package/scripts/release-loop/node-verdict.ts +38 -25
  317. package/scripts/release-loop/preflight.ts +362 -8
  318. package/scripts/release-loop/unattended-release.ts +20 -9
  319. package/scripts/rhythm/daily.ts +36 -4
  320. package/scripts/rhythm/linear-progress-sync.ts +298 -0
  321. package/scripts/video-pipeline.ts +9 -1
  322. package/scripts/warm-pool-provider-config.ts +29 -6
  323. package/src/acp/agent-manager.ts +1 -0
  324. package/src/acp/codex-app-server-agent.ts +33 -0
  325. package/src/acp/codex-app-server-client.ts +153 -16
  326. package/src/acp/core-turn-bridge.ts +17 -12
  327. package/src/acp/event-router.ts +20 -1
  328. package/src/acp/server.ts +6 -0
  329. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  330. package/src/agent-mission/claude-headless.ts +4 -1
  331. package/src/agent-mission/codex-exec.ts +105 -0
  332. package/src/agent-mission/driver.ts +192 -11
  333. package/src/agent-mission/grok-auth-status.ts +47 -0
  334. package/src/agent-mission/hand-hooks.ts +101 -0
  335. package/src/agent-mission/mission-cli.ts +56 -21
  336. package/src/agent-mission/mission-hand-reply.ts +118 -0
  337. package/src/agent-mission/mission-line.ts +180 -0
  338. package/src/agent-mission/mission-out.ts +256 -18
  339. package/src/agent-mission/tool-install.ts +122 -11
  340. package/src/agents/general-purpose.md +1 -1
  341. package/src/auto-research/research-turn.ts +95 -10
  342. package/src/autopilot/pr-manager.ts +31 -3
  343. package/src/boot/daemon-tools/self-implement.ts +3 -1
  344. package/src/boot/daemon-tools/web-search.ts +1 -2
  345. package/src/briefing/brief-items.ts +55 -11
  346. package/src/cli/agent-cli.ts +2 -1
  347. package/src/cli/catalog-cli.ts +31 -0
  348. package/src/cli/connector-cli.ts +16 -0
  349. package/src/cli/doctor-fix.ts +2 -2
  350. package/src/cli/intake-source-cli.ts +44 -8
  351. package/src/cli/msg-cli.ts +32 -3
  352. package/src/cli/pr-cli.ts +21 -1
  353. package/src/cli/pr-land-heavy-remote.ts +44 -6
  354. package/src/cli/pr-land-overlap-evidence.ts +13 -1
  355. package/src/cli/pr-land-pod-shadow-job.ts +143 -5
  356. package/src/cli/pr-land-pod-shadow.ts +9 -2
  357. package/src/cli/release-checklist-read-cli.ts +44 -16
  358. package/src/cli/release-cli.ts +23 -3
  359. package/src/cli/research-cli.ts +9 -0
  360. package/src/cli/setup-cli.ts +166 -6
  361. package/src/cli/setup-keys.ts +187 -0
  362. package/src/cli/task-plugin-wizard-host.ts +114 -0
  363. package/src/cli/tasks-cli.ts +54 -9
  364. package/src/cli/tui-test-cli.ts +186 -0
  365. package/src/config.ts +4 -2
  366. package/src/connectors/linear-daily-progress.ts +228 -0
  367. package/src/connectors/linear-projector.ts +34 -12
  368. package/src/connectors/linear.ts +151 -7
  369. package/src/core-turn/deep-turn-bloom.ts +67 -0
  370. package/src/core-turn/research-policy.ts +37 -0
  371. package/src/core-turn/run-core-turn.ts +320 -30
  372. package/src/core-turn/types.ts +2 -0
  373. package/src/dashboard/chat/acp-chat.ts +10 -0
  374. package/src/dashboard/classic-sidetab-mission-job.ts +103 -0
  375. package/src/dashboard/classic-sidetab-mission-pair.ts +81 -0
  376. package/src/dashboard/classic-sidetab-mission-trio.ts +219 -0
  377. package/src/dashboard/classic-sidetab-mission.ts +167 -5
  378. package/src/dashboard/index.ts +378 -13
  379. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  380. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +8 -0
  381. package/src/dashboard/mission-cli-consumer.ts +20 -8
  382. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  383. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  384. package/src/dashboard/sidetab-runtime.ts +1 -1
  385. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  386. package/src/decisions/linear-progress-summary.ts +78 -0
  387. package/src/decisions/linear-progress-sync.ts +152 -0
  388. package/src/domains/outbound-alert.ts +49 -11
  389. package/src/domains/telegram-kind-route.ts +16 -9
  390. package/src/graph-runner/arg-allowance.ts +13 -0
  391. package/src/graph-runner/graph-run-api.ts +3 -1
  392. package/src/graph-runner/runner.ts +85 -17
  393. package/src/graph-wizard/mission-compose.ts +407 -12
  394. package/src/harness/dispatch-backpressure.ts +54 -1
  395. package/src/harness/dispatch-shadow-compare.ts +74 -0
  396. package/src/harness/harness-cli-command.ts +11 -1
  397. package/src/harness/skill-exec.ts +21 -9
  398. package/src/harness/skill-select.ts +1 -1
  399. package/src/hooks/error-report-cloud.ts +101 -0
  400. package/src/hooks/receiver.ts +29 -2
  401. package/src/index.ts +127 -10
  402. package/src/intake-plane/actions.ts +354 -0
  403. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  404. package/src/intake-plane/intake-sources.ts +78 -8
  405. package/src/intake-plane/items.ts +14 -4
  406. package/src/intake-plane/linear-mission-sync.ts +80 -0
  407. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  408. package/src/intake-plane/linear-wish.ts +227 -1
  409. package/src/life/life-cli.ts +168 -0
  410. package/src/life/life-kinds.ts +160 -0
  411. package/src/live-supply/budget-consumer.ts +78 -0
  412. package/src/live-supply/read.ts +3 -0
  413. package/src/live-supply/snapshot.ts +45 -0
  414. package/src/llm/provider-credentials.ts +8 -2
  415. package/src/llm.ts +2 -1
  416. package/src/maturity/feature-maturity.ts +3 -3
  417. package/src/msg/msg-sse-server.ts +3 -3
  418. package/src/msg/msg-store.ts +177 -19
  419. package/src/native-tool-catalog.ts +36 -2
  420. package/src/nexus/api/http-server.ts +37 -1
  421. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  422. package/src/nexus/index.ts +7 -2
  423. package/src/nexus/outbound/format.ts +9 -0
  424. package/src/nexus/outbound/router.ts +98 -13
  425. package/src/nexus/setup-status.ts +9 -0
  426. package/src/nexus/state/state.ts +3 -0
  427. package/src/oauth/codex-account-store.ts +20 -7
  428. package/src/oauth/codex-owner-mirror.ts +44 -0
  429. package/src/oauth/codex.ts +17 -2
  430. package/src/oauth/fallback-chain.ts +47 -17
  431. package/src/onboarding/first-run-doctor.ts +8 -1
  432. package/src/onboarding/first-run.ts +85 -26
  433. package/src/onboarding/key-setup.ts +103 -0
  434. package/src/onboarding/menu-answer.ts +13 -0
  435. package/src/onboarding/secret-prompt.ts +37 -0
  436. package/src/plugins/install/plugin-install.ts +59 -0
  437. package/src/pr-tool/census.ts +130 -0
  438. package/src/pty-shell/pty-control-ipc.ts +4 -1
  439. package/src/registry/catalog-server.ts +232 -0
  440. package/src/registry/loader.ts +45 -1
  441. package/src/registry/types.ts +1 -2
  442. package/src/research/axis-fanout.ts +43 -28
  443. package/src/self-dev/ask-launch-flow.ts +72 -1
  444. package/src/self-dev/dev-cli.ts +4 -1
  445. package/src/self-dev/dev-pipeline.ts +5 -0
  446. package/src/self-dev/draft-residue.ts +64 -5
  447. package/src/self-dev/graph-front-nodes.ts +2 -1
  448. package/src/self-dev/graph-journey-route.ts +76 -21
  449. package/src/self-dev/launch-preflight.ts +58 -0
  450. package/src/self-dev/orchestrate.ts +1 -1
  451. package/src/self-dev/shard-aggregate.ts +4 -0
  452. package/src/self-dev/shard-run.ts +36 -15
  453. package/src/self-implement/abandoned-classification.ts +12 -3
  454. package/src/self-implement/budget-gate.ts +7 -0
  455. package/src/self-implement/child-llm-preference.ts +10 -1
  456. package/src/self-implement/doctor-visit.ts +30 -8
  457. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  458. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  459. package/src/self-implement/gate-artifacts.ts +2 -1
  460. package/src/self-implement/goal-author-cli.ts +4 -2
  461. package/src/self-implement/goal-author.ts +358 -4
  462. package/src/self-implement/graph-overlay-yaml.ts +30 -4
  463. package/src/self-implement/graph-overlay.ts +3 -1
  464. package/src/self-implement/graph-profile-yaml.ts +107 -0
  465. package/src/self-implement/graph-yaml.ts +26 -3
  466. package/src/self-implement/off-diff-evidence.ts +249 -5
  467. package/src/self-implement/orchestrator.ts +240 -15
  468. package/src/self-implement/run-chart.ts +6 -3
  469. package/src/self-implement/run-ledger.ts +51 -1
  470. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  471. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  472. package/src/self-implement/train-gate-receipt.ts +166 -0
  473. package/src/self-implement/train-gate-remote.ts +62 -18
  474. package/src/session/chat.ts +4 -2
  475. package/src/session/session-fanout.ts +2 -0
  476. package/src/session/streaming/acp-stream-sink.ts +2 -1
  477. package/src/session/streaming/chunk-producer.ts +6 -0
  478. package/src/session/streaming/stream-compositor.ts +3 -2
  479. package/src/session-runtime/index.ts +37 -1
  480. package/src/session-runtime/retry-policy.ts +1 -1
  481. package/src/setup/llm-env-detect.ts +3 -0
  482. package/src/setup/service-key-catalog.ts +46 -0
  483. package/src/setup/service-keys.ts +241 -0
  484. package/src/sidetab-core/visible-agent-mission.ts +98 -22
  485. package/src/skills/tools/agent.ts +23 -4
  486. package/src/skills/tools/omni-search.ts +123 -25
  487. package/src/task-agent/parent-host.ts +10 -0
  488. package/src/task-agent/repair-outcomes.ts +65 -0
  489. package/src/task-agent/task-hand.ts +20 -7
  490. package/src/task-orchestrator/dispatcher.ts +14 -1
  491. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  492. package/src/task-orchestrator/store.ts +16 -5
  493. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +4 -0
  494. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +92 -1
  495. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  496. package/src/task-orchestrator/surfaces/pod-source-receive.ts +23 -11
  497. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  498. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +35 -9
  499. package/src/task-orchestrator/surfaces/self-implement-pod.ts +172 -6
  500. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  501. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  502. package/src/task-orchestrator/types.ts +14 -0
  503. package/src/telegram.ts +14 -16
  504. package/src/terminal/coding-agent.ts +14 -5
  505. package/src/terminal/session-registry.ts +1 -1
  506. package/src/tool-hints/gate.ts +1 -0
  507. package/src/tool-runtime/agent-runtime.ts +1 -0
  508. package/src/tool-runtime/browser-hand-runtime.ts +381 -0
  509. package/src/tool-runtime/browser-runtime.ts +2 -1
  510. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  511. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +57 -0
  512. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  513. package/src/tool-runtime/index.ts +6 -0
  514. package/src/tool-runtime/types.ts +3 -0
  515. package/src/tui/entry.ts +24 -1
  516. package/src/tui/sidetab/attach.ts +140 -11
  517. package/src/tui/sidetab/herdr-portal.ts +225 -0
  518. package/src/user-config.ts +34 -9
  519. package/src/user-intent/types.ts +4 -3
  520. package/src/ux-sim/browser-hand.ts +165 -0
  521. package/src/ux-sim/draft-inventory-builder.ts +198 -0
  522. package/src/ux-sim/fake-browser-page.ts +81 -0
  523. package/src/ux-sim/fake-linear-device.ts +31 -0
  524. package/src/ux-sim/graph-engine-sim.ts +47 -0
  525. package/src/ux-sim/linear-secretary.ts +216 -0
  526. package/src/ux-sim/mock-scenario-catalog.json +75 -23
  527. package/src/ux-sim/mock-scenario-catalog.ts +120 -2
  528. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  529. package/src/ux-sim/scenario.ts +70 -26
  530. package/src/ux-sim/service-key-setup.ts +50 -0
  531. package/src/ux-sim/term-slash-device.ts +74 -0
  532. package/src/ux-sim/turn-throw-sim.ts +31 -0
  533. package/src/version/packed-revision.json +1 -1
  534. package/src/web-search/exa.ts +77 -0
  535. package/src/web-search/index.ts +30 -9
  536. package/src/web-search/provider.ts +4 -1
  537. package/src/web-search/x-intent.ts +5 -0
  538. package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +0 -36
  540. package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +0 -32
  543. package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +0 -286
  548. package/apps/pwa/out/_next/static/chunks/2160.a097e7b138ae1c55.js +0 -23
  549. package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +0 -34
  552. package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/2974.595d1e29d040cb6a.js +0 -64
  557. package/apps/pwa/out/_next/static/chunks/3285.89ee2f298682f5e5.js +0 -93
  558. package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +0 -41
  559. package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +0 -24
  561. package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/3837.a210d7d0db8d8abd.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +0 -77
  567. package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
  572. package/apps/pwa/out/_next/static/chunks/5112.4b9f300124fab7b3.js +0 -149
  573. package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +0 -27
  575. package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/5885.0a3e52c8faccec98.js +0 -287
  583. package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +0 -226
  586. package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +0 -90
  587. package/apps/pwa/out/_next/static/chunks/6377.bc7df239edbff244.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +0 -104
  594. package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +0 -94
  595. package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/7279-c199ea83f34338fa.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +0 -24
  602. package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +0 -8
  610. package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/8546-6f03f8ea34dd61d9.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/9249.976f1e69a9d80754.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/9353-12bfff0c130104cf.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/9415.69e4a21c60c7d2db.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/9832.f4a98c878ecf2c0a.js +0 -62
  626. package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/9a852a62-6192a6ea9346ced3.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +0 -1
  684. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  685. /package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → Om5xS9jpjSXJCeTNGYEi4}/_ssgManifest.js +0 -0
@@ -2,6 +2,7 @@ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
2
  import { tmpdir } from 'node:os';
3
3
  import { join } from 'node:path';
4
4
  import { spawnElanous } from '../instance/spawn-elanous.js';
5
+ import type { AgentCliPreparation } from '../agent-mission/tool-install.js';
5
6
 
6
7
  export interface ClassicMissionCliResult {
7
8
  ok: boolean;
@@ -58,6 +59,7 @@ export interface MissionCliConsumerDeps {
58
59
  runCli?: typeof runCli;
59
60
  delay?: (ms: number) => Promise<void>;
60
61
  now?: () => number;
62
+ prepareAgentCli?: (agent: 'codex' | 'claude') => Promise<AgentCliPreparation>;
61
63
  }
62
64
 
63
65
  export interface StartedClassicMissionCliJob {
@@ -92,11 +94,20 @@ export async function cancelClassicMissionCli(interactionId: string, executeCli:
92
94
  export async function startClassicMissionCli(input: {
93
95
  agent: 'codex' | 'claude';
94
96
  prompt: string;
97
+ linearIssueId?: string;
95
98
  onInteractionId?: (interactionId: string) => void;
96
99
  }, deps: MissionCliConsumerDeps = {}): Promise<StartClassicMissionCliResult> {
97
100
  const executeCli = deps.runCli ?? runCli;
98
101
  const wait = deps.delay ?? delay;
99
102
  const now = deps.now ?? Date.now;
103
+ if (deps.prepareAgentCli) {
104
+ try {
105
+ const prepared = await deps.prepareAgentCli(input.agent);
106
+ if (!prepared.ready) return { ok: false, status: 'failed', path: '', error: prepared.message };
107
+ } catch {
108
+ return { ok: false, status: 'failed', path: '', error: `${input.agent}: 설치·로그인 상태를 확인하지 못했습니다` };
109
+ }
110
+ }
100
111
  const tempRoot = mkdtempSync(join(tmpdir(), 'elanous-classic-mission-'));
101
112
  const promptPath = join(tempRoot, 'prompt.txt');
102
113
  const outputPath = join(tempRoot, 'result.md');
@@ -105,7 +116,8 @@ export async function startClassicMissionCli(input: {
105
116
  try {
106
117
  writeFileSync(promptPath, input.prompt, { encoding: 'utf8', mode: 0o600 });
107
118
  const launched = parseJson<{ missionId: string; status: 'running' }>(await executeCli([
108
- 'mission', 'run', '--agent', input.agent, '--prompt-file', promptPath, '--out', outputPath, '--json',
119
+ 'mission', 'run', '--agent', input.agent, '--prompt-file', promptPath, '--out', outputPath,
120
+ ...(input.linearIssueId ? ['--linear-issue-id', input.linearIssueId] : []), '--json',
109
121
  ]));
110
122
  if (!isClassicMissionId(launched.missionId) || launched.status !== 'running') throw new Error('Mission CLI returned an invalid interaction ID');
111
123
  interactionId = launched.missionId;
@@ -113,17 +125,17 @@ export async function startClassicMissionCli(input: {
113
125
  const completion = (async (): Promise<ClassicMissionCliResult> => {
114
126
  try {
115
127
  while (now() - startedAt < MAX_WAIT_MS) {
116
- const status: MissionStatus = parseJson<MissionStatus>(await executeCli(['mission', 'status', interactionId!, '--json']));
117
- if (status.missionId !== interactionId) throw new Error('Mission status did not match its interaction ID');
128
+ const missionStatus: MissionStatus = parseJson<MissionStatus>(await executeCli(['mission', 'status', interactionId!, '--json']));
129
+ if (missionStatus.missionId !== interactionId) throw new Error('Mission status did not match its interaction ID');
118
130
  // `eln mission status --json` exposes completed records as `done`.
119
131
  // Keep `completed` accepted for compatible bridges and existing callers.
120
- if (status.status === 'done' || status.status === 'completed') {
121
- if (typeof status.result !== 'string' || !status.result.trim()) throw new Error('Mission completed without a final answer');
122
- return { ok: true, status: 'completed', interactionId, path: outputPath, content: status.result };
132
+ if (missionStatus.status === 'done' || missionStatus.status === 'completed') {
133
+ if (typeof missionStatus.result !== 'string' || !missionStatus.result.trim()) throw new Error('Mission completed without a final answer');
134
+ return { ok: true, status: 'completed', interactionId, path: outputPath, content: missionStatus.result };
123
135
  }
124
- if (status.status !== 'running') return {
136
+ if (missionStatus.status !== 'running') return {
125
137
  ok: false,
126
- status: status.status === 'cancelled' ? 'cancelled' : 'failed',
138
+ status: missionStatus.status === 'cancelled' ? 'cancelled' : 'failed',
127
139
  interactionId,
128
140
  path: outputPath,
129
141
  error: 'Mission did not complete successfully',
@@ -0,0 +1,50 @@
1
+ import { debug } from '../debug/log.js';
2
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
3
+ import { createTaskPluginWizardHostDeps, type TaskPluginWizardHostResult } from '../cli/task-plugin-wizard-host.js';
4
+ import { defaultTaskLauncher } from '../cli/tasks-cli.js';
5
+ import { handTask, type HandTaskOptions } from '../task-agent/task-hand.js';
6
+ import { TASK_CARD_PREFIX } from '../task-agent/task-card-prefix.js';
7
+ import type { PluginMaker, PluginWizardDeps } from '../graph-wizard/mission-compose.js';
8
+ import { createTuiPluginWizardTool, type TuiPluginWizardTool } from './plugin-wizard-tool.js';
9
+ import type { TuiPluginWizardRequest } from './plugin-wizard-tool.js';
10
+
11
+ export interface DashboardPluginWizardRuntimePorts {
12
+ runMissionPair: (request: {
13
+ runId: string;
14
+ prompt: string;
15
+ context?: TuiPluginWizardRequest['context'];
16
+ }) => Promise<Partial<Record<PluginMaker, TaskPluginWizardHostResult>>>;
17
+ getWorkspace: () => string;
18
+ taskHand?: (options: HandTaskOptions) => Promise<unknown>;
19
+ launcher?: HandTaskOptions['launcher'];
20
+ onEvent?: PluginWizardDeps['onEvent'];
21
+ }
22
+
23
+ /** Connect the TUI entry tool to handTask and the existing plugin composer without blocking the ACP turn. */
24
+ export function createDashboardPluginWizardRuntime(ports: DashboardPluginWizardRuntimePorts): TuiPluginWizardTool {
25
+ return createTuiPluginWizardTool(async (request) => {
26
+ const pluginWizardDeps = createTaskPluginWizardHostDeps({
27
+ runMissionPair: ({ prompt }) => ports.runMissionPair({ runId: request.runId, prompt, ...(request.context ? { context: request.context } : {}) }),
28
+ onEvent: ports.onEvent ?? ((event) => {
29
+ if (event.step !== 'validate' || !event.detail || typeof event.detail !== 'object') return;
30
+ const winner = (event.detail as { winner?: unknown }).winner;
31
+ if (winner) debug.log('wizard.validate', 'winner-adopted', { runId: event.wizardId, ts: event.ts, winner });
32
+ }),
33
+ });
34
+ const runHandTask = ports.taskHand ?? handTask;
35
+ await runHandTask({
36
+ id: `${TASK_CARD_PREFIX}plugin-${request.runId.replaceAll('-', '').slice(0, 20)}`,
37
+ text: request.mission,
38
+ seat: 'TC',
39
+ live: true,
40
+ launcher: ports.launcher ?? defaultTaskLauncher,
41
+ pluginWizard: {
42
+ missing: request.missing,
43
+ root: effectiveInstanceRoot(),
44
+ workspace: ports.getWorkspace(),
45
+ wizardId: request.runId,
46
+ },
47
+ pluginWizardDeps,
48
+ });
49
+ });
50
+ }
@@ -0,0 +1,55 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { debug } from '../debug/log.js';
3
+ import type { LLMToolSpec } from '../llm.js';
4
+ import type { ClassicSidetabMissionDispatchContext } from './classic-sidetab-mission.js';
5
+
6
+ export const TUI_PLUGIN_WIZARD_TOOL_NAME = 'StartPluginWizard';
7
+
8
+ export interface TuiPluginWizardRequest {
9
+ runId: string;
10
+ mission: string;
11
+ missing: string;
12
+ context?: ClassicSidetabMissionDispatchContext;
13
+ }
14
+
15
+ export interface TuiPluginWizardTool {
16
+ getTools(existing: readonly LLMToolSpec[]): LLMToolSpec[];
17
+ dispatchTool(name: string, args: unknown, context?: ClassicSidetabMissionDispatchContext): Promise<unknown> | undefined;
18
+ }
19
+
20
+ /** Add a non-blocking TUI entry point; the injected host runs the shared task/plugin-wizard path. */
21
+ export function createTuiPluginWizardTool(start: (request: TuiPluginWizardRequest) => Promise<void>, createId: () => string = randomUUID): TuiPluginWizardTool {
22
+ const spec: LLMToolSpec = {
23
+ name: TUI_PLUGIN_WIZARD_TOOL_NAME,
24
+ description: 'When a needed capability is missing, start the plugin wizard in this TUI session. It asks a short question, searches trusted plugins, and if needed launches the visible Codex and Claude side-tab pair. Returns a run ID immediately; check the task notification for completion.',
25
+ parameters: {
26
+ type: 'object',
27
+ properties: {
28
+ mission: { type: 'string', minLength: 1, description: 'The active task to complete after installing or creating the tool.' },
29
+ missing: { type: 'string', minLength: 1, description: 'The missing tool or capability.' },
30
+ },
31
+ required: ['mission', 'missing'],
32
+ additionalProperties: false,
33
+ },
34
+ };
35
+
36
+ return {
37
+ getTools: (existing) => [...existing, spec],
38
+ dispatchTool(name, args, context) {
39
+ if (name !== TUI_PLUGIN_WIZARD_TOOL_NAME) return undefined;
40
+ const output = (status: 'running' | 'error', body: string, id: string | null = null) => ({ status, body, artifacts: [], id });
41
+ if (!args || typeof args !== 'object' || Array.isArray(args)) return Promise.resolve(output('error', 'arguments must be an object'));
42
+ const input = args as Record<string, unknown>;
43
+ if (Object.keys(input).some((key) => key !== 'mission' && key !== 'missing')) return Promise.resolve(output('error', 'arguments contain unsupported fields'));
44
+ const mission = typeof input.mission === 'string' ? input.mission.trim() : '';
45
+ const missing = typeof input.missing === 'string' ? input.missing.trim() : '';
46
+ if (!mission || !missing) return Promise.resolve(output('error', 'mission and missing capability are required'));
47
+ const runId = createId();
48
+ void Promise.resolve().then(() => start({ runId, mission, missing, ...(context ? { context } : {}) })).catch((error) => {
49
+ try { debug.log('plugin-wizard.tool', 'start-failed', { runId, reason: error instanceof Error ? error.message : String(error) }, { level: 'error' }); }
50
+ catch { /* failure reporting must not re-enter the tool boundary */ }
51
+ });
52
+ return Promise.resolve(output('running', `Plugin wizard started in the background (run ${runId}).`, runId));
53
+ },
54
+ };
55
+ }
@@ -7,7 +7,7 @@ export interface DashboardLocalAgentSession {
7
7
  id: string;
8
8
  title: string;
9
9
  kind: 'shell' | 'coding-agent';
10
- agentBrand?: 'claude-code' | 'codex' | 'gemini';
10
+ agentBrand?: 'claude-code' | 'codex' | 'gemini' | 'grok';
11
11
  state: 'foreground' | 'background' | 'exited';
12
12
  }
13
13
 
@@ -1,10 +1,10 @@
1
1
  import type { TerminalSession } from '../terminal/session-registry.js';
2
2
 
3
- export type DashboardTerminalPopupAgentBrand = 'claude-code' | 'codex' | 'gemini';
3
+ export type DashboardTerminalPopupAgentBrand = 'claude-code' | 'codex' | 'gemini' | 'grok';
4
4
 
5
5
  export type DashboardTerminalPopupRequest =
6
6
  | { kind: 'shell'; cwd: string; command?: string; env?: Record<string, string> }
7
- | { kind: 'coding-agent'; brand: DashboardTerminalPopupAgentBrand; cwd: string; extraArgs?: readonly string[] };
7
+ | { kind: 'coding-agent'; brand: DashboardTerminalPopupAgentBrand; cwd: string; extraArgs?: readonly string[]; env?: Record<string, string>; id?: string };
8
8
 
9
9
  export interface DashboardTerminalPopupRuntimeDeps {
10
10
  onMissingCwd: () => void;
@@ -15,6 +15,7 @@ export interface DashboardTerminalPopupBuilder {
15
15
  cwd(cwd: string): DashboardTerminalPopupBuilder;
16
16
  command(command: string): DashboardTerminalPopupBuilder;
17
17
  env(env: Record<string, string>): DashboardTerminalPopupBuilder;
18
+ id(id: string): DashboardTerminalPopupBuilder;
18
19
  args(extraArgs: readonly string[]): DashboardTerminalPopupBuilder;
19
20
  open(): TerminalSession | null;
20
21
  }
@@ -34,11 +35,13 @@ export function createDashboardTerminalPopupRuntime(
34
35
  let cwd: string | null = null;
35
36
  let command: string | undefined;
36
37
  let env: Record<string, string> | undefined;
38
+ let id: string | undefined;
37
39
  let args: readonly string[] | undefined;
38
40
  return {
39
41
  cwd(next) { cwd = next; return this; },
40
42
  command(next) { command = next; return this; },
41
43
  env(next) { env = next; return this; },
44
+ id(next) { id = next; return this; },
42
45
  args(next) { args = next; return this; },
43
46
  open() {
44
47
  if (cwd === null) {
@@ -47,7 +50,7 @@ export function createDashboardTerminalPopupRuntime(
47
50
  }
48
51
  const req: DashboardTerminalPopupRequest = kind === 'shell'
49
52
  ? { kind: 'shell', cwd, command, env }
50
- : { kind: 'coding-agent', brand: kind, cwd, extraArgs: args };
53
+ : { kind: 'coding-agent', brand: kind, cwd, ...(args ? { extraArgs: args } : {}), ...(env ? { env } : {}), ...(id ? { id } : {}) };
51
54
  return deps.openInteractiveTerminalPopup(req);
52
55
  },
53
56
  };
@@ -0,0 +1,78 @@
1
+ import type { DecisionEntry } from './decision-ledger.js';
2
+ import type { Checklist, ChecklistHistory, ChecklistItem } from '../release-loop/checklist.js';
3
+
4
+ const LINEAR_ISSUE = /\bELA-[A-Z0-9]+\b/gi;
5
+ const PULL_URL = /https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/pull\/\d+/g;
6
+
7
+ export interface LinearProgressSummary {
8
+ issue: string;
9
+ day: string;
10
+ body: string;
11
+ }
12
+
13
+ function issueRefs(text: string): string[] {
14
+ return [...new Set(text.match(LINEAR_ISSUE) ?? [])].map(value => value.toUpperCase());
15
+ }
16
+
17
+ function eventIssues(item: ChecklistItem): string[] {
18
+ return issueRefs(`${item.title}\n${item.evidence ?? ''}\n${item.refs?.join('\n') ?? ''}`);
19
+ }
20
+
21
+ function short(value: unknown): string {
22
+ return typeof value === 'string' ? value.replace(/[\r\n]+/g, ' ').trim().slice(0, 80) : '미상';
23
+ }
24
+
25
+ /** Build non-sensitive daily summaries from local ledgers; this function performs no network or file writes. */
26
+ export function buildLinearProgressSummaries(input: {
27
+ checklist: Checklist;
28
+ history: readonly ChecklistHistory[];
29
+ decisions: readonly DecisionEntry[];
30
+ since: string;
31
+ now?: Date;
32
+ }): LinearProgressSummary[] {
33
+ const since = Date.parse(input.since);
34
+ if (!Number.isFinite(since)) throw new Error('since must be a valid timestamp');
35
+ const now = input.now ?? new Date();
36
+ const day = now.toISOString().slice(0, 10);
37
+ const cells = new Map(input.checklist.items.map(item => [item.id, item]));
38
+ const grouped = new Map<string, string[]>();
39
+ const add = (issue: string, line: string) => {
40
+ const lines = grouped.get(issue) ?? [];
41
+ if (!lines.includes(line)) lines.push(line);
42
+ grouped.set(issue, lines);
43
+ };
44
+
45
+ for (const event of input.history) {
46
+ if (Date.parse(event.at) < since) continue;
47
+ const item = cells.get(event.id);
48
+ if (!item || event.field !== 'status') continue;
49
+ for (const issue of eventIssues(item)) add(issue, `칸 ${item.id}: ${short(event.from)} → ${short(event.to)}`);
50
+ }
51
+
52
+ for (const decision of input.decisions) {
53
+ const changed = decision.history.filter(event => event.at && Date.parse(event.at) >= since);
54
+ if (!changed.length) continue;
55
+ for (const ref of decision.refs ?? []) for (const issue of issueRefs(ref)) {
56
+ const latest = changed.at(-1)!;
57
+ add(issue, `결정 ${decision.id}: ${latest.type === 'decided' ? `확정 ${short(latest.choice)}` : latest.type}`);
58
+ }
59
+ }
60
+
61
+ for (const item of input.checklist.items) {
62
+ if (item.status === 'green' || item.status === 'done') continue;
63
+ for (const issue of eventIssues(item)) add(issue, `다음: ${item.id}`);
64
+ }
65
+
66
+ for (const event of input.history) {
67
+ if (Date.parse(event.at) < since || !['evidence', 'evidence.add'].includes(event.field)) continue;
68
+ const item = cells.get(event.id);
69
+ if (!item) continue;
70
+ const pulls = String(event.to ?? '').match(PULL_URL) ?? [];
71
+ for (const issue of eventIssues(item)) for (const url of pulls) add(issue, `PR: ${url}`);
72
+ }
73
+
74
+ return [...grouped].sort(([a], [b]) => a.localeCompare(b)).map(([issue, lines]) => {
75
+ const body = [`진행 요약 · ${day}`, ...lines].join('\n');
76
+ return { issue, day, body };
77
+ });
78
+ }
@@ -0,0 +1,152 @@
1
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, writeFileSync, writeSync, renameSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { commentLinearIssue } from '../connectors/linear.js';
4
+ import { debug } from '../debug/log.js';
5
+ import { getSecretAsync } from '../nexus/config/secrets/index.js';
6
+ import { releaseLedgerRoot } from '../instance/resolve.js';
7
+ import { DecisionLedger } from './decision-ledger.js';
8
+ import { buildLinearProgressSummaries, type LinearProgressSummary } from './linear-progress-summary.js';
9
+ import { checklistHistory, listChecklist } from '../release-loop/checklist.js';
10
+
11
+ type SentState = Record<string, true>;
12
+ type IssueLookup = { issue?: { id?: string; team?: { key?: string }; comments?: { nodes?: Array<{ body?: string }> } } };
13
+
14
+ export interface LinearProgressSyncResult {
15
+ day: string;
16
+ planned: number;
17
+ posted: number;
18
+ skipped: number;
19
+ failed: number;
20
+ plan: Array<{ issue: string; body: string; action: 'post' | 'already-posted' | 'team-mismatch' }>;
21
+ }
22
+
23
+ function readState(path: string): SentState {
24
+ if (!existsSync(path)) return {};
25
+ const value: unknown = JSON.parse(readFileSync(path, 'utf8'));
26
+ const invalid = !value || typeof value !== 'object' || Array.isArray(value)
27
+ || Object.entries(value).some(([key, row]) => !/^\d{4}-\d{2}-\d{2}:ELA-[A-Z0-9]+$/.test(key)
28
+ || (row !== true && (!row || typeof row !== 'object' || Array.isArray(row))));
29
+ if (invalid) {
30
+ throw new Error('invalid Linear progress sync state');
31
+ }
32
+ // Older entries stored write-only fingerprint/postedAt metadata. Normalize them to the marker that skip logic reads.
33
+ return Object.fromEntries(Object.keys(value).map(key => [key, true]));
34
+ }
35
+
36
+ function saveState(path: string, state: SentState): void {
37
+ const temp = `${path}.${process.pid}.tmp`;
38
+ try {
39
+ writeFileSync(temp, JSON.stringify(state), { mode: 0o600 });
40
+ renameSync(temp, path);
41
+ } finally { if (existsSync(temp)) unlinkSync(temp); }
42
+ }
43
+
44
+ async function lookupIssue(apiKey: string, identifier: string, fetchFn: typeof fetch): Promise<IssueLookup['issue']> {
45
+ const response = await fetchFn('https://api.linear.app/graphql', {
46
+ method: 'POST', headers: { Authorization: apiKey, 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({ query: 'query ProgressIssue($id: String!) { issue(id: $id) { id team { key } comments(first: 100) { nodes { body } } } }', variables: { id: identifier } }),
48
+ });
49
+ if (!response.ok) throw new Error(`Linear GraphQL HTTP ${response.status}`);
50
+ const body = await response.json() as { data?: IssueLookup; errors?: unknown[] };
51
+ if (body.errors?.length || !body.data) throw new Error('Linear GraphQL issue lookup failed');
52
+ return body.data.issue;
53
+ }
54
+
55
+ function marker(summary: LinearProgressSummary): string { return `progress-sync:${summary.day}:${summary.issue}`; }
56
+
57
+ function summaries(version: string, now: Date): LinearProgressSummary[] {
58
+ const checklist = listChecklist(version);
59
+ const history = [...new Set(checklist.items.map(item => item.id))].flatMap(id => checklistHistory(id));
60
+ const since = `${now.toISOString().slice(0, 10)}T00:00:00.000Z`;
61
+ return buildLinearProgressSummaries({ checklist, history, decisions: new DecisionLedger().list({ status: 'all' }), since, now });
62
+ }
63
+
64
+ /** Plan is read-only by default. `live` sends at most one marked comment per issue per UTC day. */
65
+ export async function syncLinearProgress(options: {
66
+ version: string;
67
+ live?: boolean;
68
+ now?: Date;
69
+ fetch?: typeof fetch;
70
+ getSecret?: (name: string) => Promise<string | undefined>;
71
+ ledgerRoot?: string;
72
+ /** Injection seam for deterministic sync tests; normal callers use the local ledgers. */
73
+ buildSummaries?: (version: string, now: Date) => LinearProgressSummary[];
74
+ }): Promise<LinearProgressSyncResult> {
75
+ const now = options.now ?? new Date();
76
+ const plans = (options.buildSummaries ?? summaries)(options.version, now);
77
+ const result: LinearProgressSyncResult = { day: now.toISOString().slice(0, 10), planned: plans.length, posted: 0, skipped: 0, failed: 0,
78
+ plan: plans.map(summary => ({ issue: summary.issue, body: summary.body, action: 'post' })) };
79
+ if (!options.live) {
80
+ for (const item of result.plan) debug.log('linear.progress-sync', 'planned', { issue: item.issue, day: result.day });
81
+ return result;
82
+ }
83
+
84
+ const apiKey = await (options.getSecret ?? getSecretAsync)('connector.linear.apiKey');
85
+ if (!apiKey) throw new Error('Linear credential missing');
86
+ const ledgerRoot = options.ledgerRoot ?? releaseLedgerRoot();
87
+ const directory = join(ledgerRoot, 'release');
88
+ mkdirSync(directory, { recursive: true });
89
+ const path = join(directory, 'linear-progress-sync.json');
90
+ const lockPath = `${path}.lock`;
91
+ let lock: number | undefined;
92
+ const deadline = Date.now() + 10_000;
93
+ for (;;) {
94
+ try { lock = openSync(lockPath, 'wx', 0o600); writeSync(lock, `${process.pid}`); break; }
95
+ catch (error) {
96
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
97
+ try {
98
+ const pid = Number(readFileSync(lockPath, 'utf8'));
99
+ if (Number.isSafeInteger(pid) && pid > 0 && Date.now() - statSync(lockPath).mtimeMs > 30_000) {
100
+ try { process.kill(pid, 0); }
101
+ catch (probe) { if ((probe as NodeJS.ErrnoException).code === 'ESRCH') { unlinkSync(lockPath); continue; } }
102
+ }
103
+ } catch (probe) { if ((probe as NodeJS.ErrnoException).code === 'ENOENT') continue; }
104
+ if (Date.now() >= deadline) throw new Error('Linear progress sync lock timeout');
105
+ await Bun.sleep(25);
106
+ }
107
+ }
108
+ try {
109
+ const state = readState(path);
110
+ const fetchFn = options.fetch ?? fetch;
111
+ for (const summary of plans) {
112
+ const key = `${summary.day}:${summary.issue}`;
113
+ if (state[key]) {
114
+ result.skipped++;
115
+ result.plan.find(item => item.issue === summary.issue)!.action = 'already-posted';
116
+ debug.log('linear.progress-sync', 'skipped', { issue: summary.issue, day: summary.day, reason: 'already-posted' });
117
+ continue;
118
+ }
119
+ try {
120
+ const issue = await lookupIssue(apiKey, summary.issue, fetchFn);
121
+ if (!issue?.id) throw new Error('Linear issue not found');
122
+ if (issue.team?.key !== 'DEMO') {
123
+ result.skipped++;
124
+ result.plan.find(item => item.issue === summary.issue)!.action = 'team-mismatch';
125
+ debug.log('linear.progress-sync', 'skipped', { issue: summary.issue, day: summary.day, reason: 'team-not-allowed' });
126
+ continue;
127
+ }
128
+ if ((issue.comments?.nodes ?? []).some(comment => comment.body?.includes(marker(summary)))) {
129
+ state[key] = true;
130
+ saveState(path, state);
131
+ result.skipped++;
132
+ result.plan.find(item => item.issue === summary.issue)!.action = 'already-posted';
133
+ debug.log('linear.progress-sync', 'skipped', { issue: summary.issue, day: summary.day, reason: 'remote-marker-found' });
134
+ continue;
135
+ }
136
+ const body = `${summary.body}\n\n_${marker(summary)}_`;
137
+ await commentLinearIssue({ apiKey, issueId: issue.id, body, fetch: fetchFn });
138
+ state[key] = true;
139
+ saveState(path, state);
140
+ result.posted++;
141
+ debug.log('linear.progress-sync', 'posted', { issue: summary.issue, day: summary.day });
142
+ } catch (error) {
143
+ result.failed++;
144
+ const reason = error instanceof Error ? (/^Linear GraphQL HTTP \d{3}$/.test(error.message) ? error.message : error.name) : 'unknown';
145
+ debug.log('linear.progress-sync', 'failed', { issue: summary.issue, day: summary.day, reason });
146
+ }
147
+ }
148
+ return result;
149
+ } finally {
150
+ if (lock !== undefined) { closeSync(lock); unlinkSync(lockPath); }
151
+ }
152
+ }
@@ -119,10 +119,42 @@ export function kstMinutes(now: Date = new Date()): number {
119
119
  return ((h ?? 0) % 24) * 60 + (m ?? 0);
120
120
  }
121
121
 
122
- /** 야간 무음 창(00:00 ≤ t < 06:30 KST). 아침리포트(06:25)는 별도 경로라 비대상. */
122
+ export const OUTBOUND_QUIET_HOURS_ENV = 'ELANOUS_OUTBOUND_QUIET_HOURS';
123
+ const DEFAULT_QUIET_HOURS = '00:00-06:30';
124
+ type QuietHours = 'off' | { start: number; end: number; label: string };
125
+
126
+ /** `off` 또는 HH:MM-HH:MM 을 분 범위로 해석한다. 잘못된 설정은 기본값에 맡긴다. */
127
+ function parseQuietHours(value: unknown): QuietHours | null {
128
+ if (value === 'off') return 'off';
129
+ if (typeof value !== 'string') return null;
130
+ const match = /^(\d{2}):(\d{2})-(\d{2}):(\d{2})$/.exec(value.trim());
131
+ if (!match) return null;
132
+ const [, sh, sm, eh, em] = match;
133
+ const startHour = Number(sh), startMinute = Number(sm), endHour = Number(eh), endMinute = Number(em);
134
+ if (startHour > 23 || endHour > 23 || startMinute > 59 || endMinute > 59) return null;
135
+ const start = startHour * 60 + startMinute, end = endHour * 60 + endMinute;
136
+ if (start === end) return null;
137
+ return { start, end, label: `${sh}:${sm}-${eh}:${em}` };
138
+ }
139
+
140
+ /** config.outbound.quietHours > ELANOUS_OUTBOUND_QUIET_HOURS > 기존 기본 창. */
141
+ function configuredQuietHours(): QuietHours {
142
+ try {
143
+ const configValue = parseQuietHours(getUserConfig().outbound?.quietHours);
144
+ if (configValue) return configValue;
145
+ } catch { /* use env/default */ }
146
+ const envValue = parseQuietHours(process.env[OUTBOUND_QUIET_HOURS_ENV]?.trim());
147
+ return envValue ?? parseQuietHours(DEFAULT_QUIET_HOURS)!;
148
+ }
149
+
150
+ /** 야간 무음 창. 기본은 기존 00:00 ≤ t < 06:30 KST. */
123
151
  export function inQuietHours(now: Date = new Date()): boolean {
124
- const m = kstMinutes(now);
125
- return m >= 0 && m < 390;
152
+ const quiet = configuredQuietHours();
153
+ if (quiet === 'off') return false;
154
+ const minute = kstMinutes(now);
155
+ return quiet.start < quiet.end
156
+ ? minute >= quiet.start && minute < quiet.end
157
+ : minute >= quiet.start || minute < quiet.end;
126
158
  }
127
159
 
128
160
  /** 최근 사용자 활동 우회 창(분) — 이 시간 내 genuine 사용자 인텐트가 있으면 무음이어도 즉시 발송. */
@@ -465,11 +497,14 @@ export function flushDeferred(path = DEFERRED_PATH, deps: FlushDeferredDeps = {}
465
497
 
466
498
  /** TEST-PROD-LEAK — a test process may not reach a real bot or the ops daemon. `external` = a third-party bot API
467
499
  * (refused unless curl is a test double replacing the real one); the local daemon is refused only when ops-routed. */
468
- function assertTestSendFaked(what: string, external = true): void {
500
+ function assertTestSendFaked(what: string, external = true, injectedTransport?: unknown): void {
469
501
  let roots: string[] = [];
470
502
  try { roots = [getElanousConfigDir(), dirname(ACP_TOKEN_PATH), effectiveInstanceRoot(), conatusDataDir(), dirname(DEFERRED_PATH)]; }
471
503
  catch { roots = [dirname(ACP_TOKEN_PATH), dirname(DEFERRED_PATH)]; }
472
- assertNoRealSendFromTest(what, { transportFaked: isTestDouble(childProcess.execFileSync, REAL_EXEC_FILE_SYNC), routingRoots: roots, external });
504
+ const transportFaked = injectedTransport === undefined
505
+ ? isTestDouble(childProcess.execFileSync, REAL_EXEC_FILE_SYNC)
506
+ : isTestDouble(injectedTransport);
507
+ assertNoRealSendFromTest(what, { transportFaked, routingRoots: roots, external });
473
508
  }
474
509
 
475
510
  /** 동기 curl(POST). body 는 stdin. 파싱 실패/에러 → null. `what` names the send for the test guard (never the URL — it carries the token). */
@@ -509,25 +544,28 @@ export function sendOutbound(text: string, kind = 'alert', origin?: (MissionOrig
509
544
  : 'unknown');
510
545
  ensureOutboundLogSink();
511
546
  let bot = origin?.channel === 'discord' ? 'discord:configured' : 'unknown';
547
+ const quietConfig = configuredQuietHours();
548
+ const quietMode = quietConfig === 'off' ? 'off' : `window:${quietConfig.label}`;
512
549
  const logOutcome = (event: 'sent' | 'deferred' | 'failed', path?: string): void => {
513
- try { debug.log('outbound.send', event, { kind: safeObservationLabel(kind), source: safeObservationLabel(source), chars: text.length, bot, ...(path ? { path } : {}) }); } catch { /* fail-open */ }
550
+ try { debug.log('outbound.send', event, { kind: safeObservationLabel(kind), source: safeObservationLabel(source), chars: text.length, bot, quietMode, ...(path ? { path } : {}) }); } catch { /* fail-open */ }
514
551
  };
515
552
  // ★ 무음 우회(대표 2026-07-14) — 사용자가 최근(기본 30분) genuine 인텐트(타이핑/버튼탭)를 냈으면
516
553
  // 깨어있으므로 야간 무음이어도 즉시 발송(사용자 발원 흐름의 결과물이 아침까지 묶이지 않게).
517
554
  // 우회 시 flushDeferred 로 그간 보류분도 함께 전달(사용자가 지금 볼 수 있음).
518
- if (inQuietHours() && !userRecentlyActive()) {
555
+ const quietNow = inQuietHours();
556
+ if (quietNow && !userRecentlyActive()) {
519
557
  const queued = deferOutbound(text, kind, origin);
520
558
  if (queued) recordOutbound(text, kind); // 성공한 보류만 회상 대상
521
559
  logOutcome(queued ? 'deferred' : 'failed', queued ? 'deferred' : 'queue-failed');
522
560
  return queued; // 적재가 성공했을 때만 보류 수락
523
561
  }
524
- const bypass = inQuietHours();
562
+ const bypass = quietNow;
525
563
  if (bypass) console.error('[outbound] 야간 무음 우회 — 최근 사용자 활동(깨어있음) → 즉시 발송 + 보류분 flush');
526
564
  try { flushDeferred(); } catch { /* fail-soft */ }
527
565
  // ★ 발송 관측(대표 지시) — 발송 시각·mode·밀림(burst) 판정을 logs.db 에. burst=최근 2분 5건+
528
566
  // (몰려 나가는 중 = 밀림 의심). `elanous logs --category outbound.send` 로 실시간/밀림 구분.
529
567
  const { recentCount, burst } = recentSendBurst();
530
- logSend(bypass ? 'quiet-bypass' : 'realtime', kind, { burst, recentCount, ...(burst ? { backlog: true } : {}) });
568
+ logSend(bypass ? 'quiet-bypass' : 'realtime', kind, { burst, recentCount, quietMode, ...(burst ? { backlog: true } : {}) });
531
569
  // ★ origin 되돌림(무음 밖) — 발신 채널로 직접 발송. 성공 시 종료, 실패면 report 폴백.
532
570
  if (origin && deliverToOrigin(origin, text, (label) => { bot = label; })) {
533
571
  recordOutbound(text, kind);
@@ -706,8 +744,8 @@ export function sendTelegramDirect(
706
744
  onBot?: (bot: string) => void,
707
745
  ): boolean {
708
746
  const sendRaw = (token: string, chatId: string | number, body: string): boolean => {
709
- // The transport is checked only after a route is eligible; a test double cannot target the ops universe.
710
- assertTestSendFaked('send a real Telegram message', !deps.sendRaw);
747
+ // The transport is checked only after a route is eligible; injected transports must themselves be test doubles.
748
+ assertTestSendFaked('send a real Telegram message', true, deps.sendRaw);
711
749
  return (deps.sendRaw ?? sendTelegramRaw)(token, chatId, body);
712
750
  };
713
751
  let cfg: UserConfig | undefined;
@@ -36,16 +36,23 @@ function operationsBotToken(cfg: UserConfig): string | undefined {
36
36
  const tradingTokens = new Set(channels.filter(c => c.roles.includes('report')).map(c => c.botToken));
37
37
  // The report (trading) bot is never the operations bot — with or without a channels table (review must-fix · OUT1).
38
38
  if (cfg.telegram.reportChannel?.botToken) tradingTokens.add(cfg.telegram.reportChannel.botToken);
39
+ // An explicit operational channel is authoritative even when env/tokenRef/legacy botToken
40
+ // resolves first; those older sources can point at a different (or trading) bot.
41
+ const operationalChannels = channels.filter(c => (c.name === 'ops' && c.roles.includes('system'))
42
+ || (c.name === 'main' && c.roles.some(r => r === 'system' || r === 'qa' || r === 'default')));
43
+ if (operationalChannels.length > 0) {
44
+ const tokens = new Set(operationalChannels.filter(c => !tradingTokens.has(c.botToken)).map(c => c.botToken));
45
+ if (tokens.size !== 1) return undefined;
46
+ const explicitToken = tokens.values().next().value;
47
+ // The explicitly named operational channel outranks the generic tab's tokenRef;
48
+ // legacy/env conflicts without a trading identity remain ambiguous and fail closed.
49
+ if (main.source !== 'channels.main' && main.source !== 'tokenRef'
50
+ && main.token && main.token !== explicitToken && !tradingTokens.has(main.token)) return undefined;
51
+ return explicitToken;
52
+ }
53
+
39
54
  if (main.source !== 'channels.main') return main.token && !tradingTokens.has(main.token) ? main.token : undefined;
40
- // channels.main may mean "first channel", which can be the trading bot.
41
- // Only a named operations channel (or the named main channel) with an
42
- // operational role establishes identity; array order and role alone do not.
43
- const tokens = new Set(channels
44
- .filter(c => (c.name === 'ops' && c.roles.includes('system'))
45
- || (c.name === 'main' && c.roles.some(r => r === 'system' || r === 'qa' || r === 'default')))
46
- .filter(c => !tradingTokens.has(c.botToken))
47
- .map(c => c.botToken));
48
- return tokens.size === 1 ? tokens.values().next().value : undefined;
55
+ return undefined;
49
56
  }
50
57
 
51
58
  function isAllowedBot(cfg: UserConfig, kind: string | undefined, token: string): boolean {
@@ -0,0 +1,13 @@
1
+ export type AllowanceDecision =
2
+ | { readonly kind: 'run'; readonly requested: number; readonly granted: number; readonly clamped: boolean }
3
+ | { readonly kind: 'needs-human'; readonly requested: number; readonly remaining: 0 };
4
+
5
+ /** Resolve a child allowance against the parent's remaining steps before spawning the child. */
6
+ export function resolveChildAllowance(requested: number, parentRemaining: number): AllowanceDecision {
7
+ if (!Number.isSafeInteger(requested) || requested < 1) throw new Error('requested allowance must be a positive safe integer');
8
+ if (!(parentRemaining === Infinity || (Number.isSafeInteger(parentRemaining) && parentRemaining >= 0)))
9
+ throw new Error('parent remaining allowance must be a non-negative safe integer or Infinity');
10
+ if (parentRemaining === 0) return { kind: 'needs-human', requested, remaining: 0 };
11
+ const granted = Math.min(requested, parentRemaining);
12
+ return { kind: 'run', requested, granted, clamped: granted < requested };
13
+ }
@@ -29,6 +29,8 @@ export interface GraphRunApiDeps {
29
29
  root?: string;
30
30
  run?: typeof runGraph;
31
31
  now?: () => number;
32
+ /** Allows a host-owned preview/demo request to stop an in-flight editor graph run. */
33
+ signal?: AbortSignal;
32
34
  }
33
35
 
34
36
  /** 시작 전에 죽은 런(레시피 없음 등)은 원장 파일이 안 생긴다 — 그 이유를 여기 잠깐 들고 있다가 상태 조회에 돌려준다. */
@@ -187,7 +189,7 @@ export function handleGraphRunStart(rawId: string, deps: GraphRunApiDeps = {}):
187
189
  return jsonResponse({ error: 'run-workspace-failed', reason: error instanceof Error ? error.message.slice(0, 200) : 'unknown' }, 500);
188
190
  }
189
191
  debug.log('graphs.run', 'started', { id, runId });
190
- void (deps.run ?? runGraph)(join(work, 'graph.yaml'), { runId, input: { source: 'editor' }, deps: { root } })
192
+ void (deps.run ?? runGraph)(join(work, 'graph.yaml'), { runId, input: { source: 'editor' }, ...(deps.signal ? { signal: deps.signal } : {}), deps: { root } })
191
193
  .then((state) => debug.log('graphs.run', 'finished', { id, runId, status: state.status, executed: state.executed }))
192
194
  .catch((error: unknown) => {
193
195
  const message = error instanceof Error ? error.message : String(error);