elanous 0.2.41 → 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 (796) 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/{GiOLWmt4MqDZePubBjA4Q → Om5xS9jpjSXJCeTNGYEi4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{2fe2c302.41b517f88d6fe502.js → 0966f8a1.745fcd44f64a87ea.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{385e4574.e9886ab32759eda3.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/{6874.d5cf7eb8edb2cabe.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/{5744.b9415e18ad623100.js → 1961.a81b12872c3e93a9.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/1970cf59.2d4d8ce5d6c81853.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1971-8890f3962ba7ee0a.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/2073-ba274e00e4f9efb4.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/{5471.1e611302ed3a7c53.js → 2144.25b292396712196d.js} +2 -2
  21. package/apps/pwa/out/_next/static/chunks/{3230-49298c3b73ef2268.js → 2268-53861f339e0b65a2.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/{9834.63ab2bbc3153172e.js → 2312.0c8b61e22d3136d7.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/{1800.f7ff51dc4978a958.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/{9048.212083de42d25be3.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/3095.dc44586a5f83b86d.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{2263.e09b6edea33bad2d.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/{addc2b32.8c4ff8f0aefe987d.js → 3557ac4a.c8931684475018ad.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/360.ae9f9f4c33c395e8.js +79 -0
  34. package/apps/pwa/out/_next/static/chunks/3638.80412ea63aae8f3f.js +286 -0
  35. package/apps/pwa/out/_next/static/chunks/{a0a01613.6d1cca322238d7fe.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/4199.ce86b281fd0a60b7.js +1 -0
  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/{530.d26346e18089640a.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/4894.fec2ca9e99caefa2.js +1 -0
  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/{1219.7e17964e0e7cd8e5.js → 5564.9e72532188f57586.js} +3 -3
  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/5628.6ddb2d5ffba4ff4c.js +309 -0
  63. package/apps/pwa/out/_next/static/chunks/5730.43d7ccc09988e646.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{1178.1aa9cad0e7695427.js → 5789.2da35c258292e1e5.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/{4133.2056bb4d78f621af.js → 5824.da9527b15a3221e5.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/5866.366966af47fdde5d.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{4527.a69f2894d1bc9f4a.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/{9507.7026657a2f47eb64.js → 6540.c7bef57ad8f90a87.js} +16 -16
  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/{5574.f35accf4f132b29d.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/7483.427a2fe2049e388d.js +148 -0
  88. package/apps/pwa/out/_next/static/chunks/7502-be74718178e13e56.js +1 -0
  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/{5947-135e26537d80a6b9.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/{2743.5d3f76948be32b34.js → 868.6e953be05bcf6dca.js} +2 -2
  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/{5964-7e21164a8f2cf0ce.js → 8861-cc1fa1c7b920fa8e.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/8967-7dfebf710c9dec9d.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{5159.115f1c2ca471386c.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/923.2034d10ae91e9c20.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9312.bc1b89c5d4368033.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/943.39ae5e82f4f1893f.js +1 -0
  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/{b2271e54.c1de3347976e90b0.js → aa57532f.510551854ff239b1.js} +1 -1
  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-9ee28f7df07428ea.js +1 -0
  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-40f9e19149024298.js → page-79a8b5fee4c20871.js} +1 -1
  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-a142dfb0331a05f5.js → page-ca2d09128c585ca4.js} +1 -1
  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/{53aeb4ee-51c92f8d683f5220.js → c7945435-b44d4dbe90ba0dcb.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/{2fdf2931.b431eee4fb468bc3.js → cb0f8df8.09a4a6be97e3fc5f.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{c0c1a699.0ba79f97005965d4.js → d96660fb.cbc21a2a88539dbb.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/ea514caa.05a24f78d9dffe5f.js +122 -0
  177. package/apps/pwa/out/_next/static/chunks/{83184dcd-0ee6247ff41eb3f2.js → fb7d20d5-6892502b6ee39ca6.js} +1 -1
  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/{b9d8151e48998417.css → 62c858ad53854f47.css} +1 -1
  185. package/apps/pwa/out/_next/static/css/d1f8bb401740a549.css +1 -0
  186. package/apps/pwa/out/approvals/index.html +1 -1
  187. package/apps/pwa/out/approvals/index.txt +23 -23
  188. package/apps/pwa/out/autopilot/index.html +1 -1
  189. package/apps/pwa/out/autopilot/index.txt +23 -23
  190. package/apps/pwa/out/board/index.html +1 -1
  191. package/apps/pwa/out/board/index.txt +23 -23
  192. package/apps/pwa/out/botlab/index.html +1 -1
  193. package/apps/pwa/out/botlab/index.txt +22 -22
  194. package/apps/pwa/out/bots/index.html +1 -1
  195. package/apps/pwa/out/bots/index.txt +22 -22
  196. package/apps/pwa/out/ceo/index.html +1 -1
  197. package/apps/pwa/out/ceo/index.txt +23 -23
  198. package/apps/pwa/out/chat/index.html +1 -1
  199. package/apps/pwa/out/chat/index.txt +22 -22
  200. package/apps/pwa/out/consult/index.html +1 -1
  201. package/apps/pwa/out/consult/index.txt +23 -23
  202. package/apps/pwa/out/control/index.html +1 -1
  203. package/apps/pwa/out/control/index.txt +23 -23
  204. package/apps/pwa/out/decisions/index.html +1 -1
  205. package/apps/pwa/out/decisions/index.txt +22 -22
  206. package/apps/pwa/out/design-check/index.html +1 -1
  207. package/apps/pwa/out/design-check/index.txt +23 -23
  208. package/apps/pwa/out/editor/index.html +1 -1
  209. package/apps/pwa/out/editor/index.txt +24 -25
  210. package/apps/pwa/out/exec/index.html +1 -1
  211. package/apps/pwa/out/exec/index.txt +23 -23
  212. package/apps/pwa/out/field/index.html +1 -1
  213. package/apps/pwa/out/field/index.txt +23 -23
  214. package/apps/pwa/out/healthz +1 -1
  215. package/apps/pwa/out/index.html +1 -1
  216. package/apps/pwa/out/index.txt +22 -22
  217. package/apps/pwa/out/inside/index.html +1 -1
  218. package/apps/pwa/out/inside/index.txt +23 -23
  219. package/apps/pwa/out/intake/index.html +1 -1
  220. package/apps/pwa/out/intake/index.txt +23 -23
  221. package/apps/pwa/out/live/index.html +1 -1
  222. package/apps/pwa/out/live/index.txt +24 -25
  223. package/apps/pwa/out/live-run/index.html +1 -1
  224. package/apps/pwa/out/live-run/index.txt +24 -25
  225. package/apps/pwa/out/loops/index.html +1 -1
  226. package/apps/pwa/out/loops/index.txt +22 -22
  227. package/apps/pwa/out/market/index.html +1 -1
  228. package/apps/pwa/out/market/index.txt +22 -22
  229. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  230. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  231. package/apps/pwa/out/morning/index.html +1 -1
  232. package/apps/pwa/out/morning/index.txt +23 -23
  233. package/apps/pwa/out/observatory/index.html +1 -1
  234. package/apps/pwa/out/observatory/index.txt +23 -23
  235. package/apps/pwa/out/ops/checklist/index.html +1 -1
  236. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  237. package/apps/pwa/out/ops/release/index.html +1 -1
  238. package/apps/pwa/out/ops/release/index.txt +22 -22
  239. package/apps/pwa/out/ops/seats/index.html +1 -1
  240. package/apps/pwa/out/ops/seats/index.txt +22 -22
  241. package/apps/pwa/out/outputs/index.html +1 -1
  242. package/apps/pwa/out/outputs/index.txt +22 -22
  243. package/apps/pwa/out/reflection/index.html +1 -1
  244. package/apps/pwa/out/reflection/index.txt +23 -23
  245. package/apps/pwa/out/scheduler/index.html +1 -1
  246. package/apps/pwa/out/scheduler/index.txt +23 -23
  247. package/apps/pwa/out/sessions/index.html +1 -1
  248. package/apps/pwa/out/sessions/index.txt +22 -22
  249. package/apps/pwa/out/settings/devices/index.html +1 -1
  250. package/apps/pwa/out/settings/devices/index.txt +23 -23
  251. package/apps/pwa/out/settings/index.html +1 -1
  252. package/apps/pwa/out/settings/index.txt +23 -23
  253. package/apps/pwa/out/setup/done/index.html +1 -1
  254. package/apps/pwa/out/setup/done/index.txt +23 -23
  255. package/apps/pwa/out/setup/index.html +1 -1
  256. package/apps/pwa/out/setup/index.txt +23 -23
  257. package/apps/pwa/out/share/index.html +1 -1
  258. package/apps/pwa/out/share/index.txt +23 -23
  259. package/apps/pwa/out/showroom/index.html +1 -1
  260. package/apps/pwa/out/showroom/index.txt +22 -22
  261. package/apps/pwa/out/tasks/index.html +1 -1
  262. package/apps/pwa/out/tasks/index.txt +23 -23
  263. package/apps/pwa/out/term/index.html +1 -1
  264. package/apps/pwa/out/term/index.txt +23 -23
  265. package/apps/pwa/out/today/index.html +1 -1
  266. package/apps/pwa/out/today/index.txt +23 -23
  267. package/apps/pwa/out/trace/index.html +1 -1
  268. package/apps/pwa/out/trace/index.txt +23 -23
  269. package/apps/pwa/out/vault/index.html +1 -1
  270. package/apps/pwa/out/vault/index.txt +23 -23
  271. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  272. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  273. package/apps/pwa/out/workflows/index.html +1 -1
  274. package/apps/pwa/out/workflows/index.txt +23 -23
  275. package/apps/pwa/out/workspace/index.html +1 -1
  276. package/apps/pwa/out/workspace/index.txt +23 -23
  277. package/apps/pwa/out/worktrees/index.html +1 -1
  278. package/apps/pwa/out/worktrees/index.txt +23 -23
  279. package/catalog/external-commands.yaml +5 -3
  280. package/catalog/meta/catalogVersion.yaml +2 -1
  281. package/catalog/signing/catalog-signing-public.pem +3 -0
  282. package/docs/goal-context/04-mock-scenarios.md +13 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/heal/heal-loop.yaml +1 -0
  285. package/graphs/intake/intake-daily.yaml +16 -0
  286. package/graphs/intake/news-sources.yaml +1 -0
  287. package/graphs/intake/recipes.yaml +7 -0
  288. package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
  289. package/graphs/overlays/stop-heal-ladder.yaml +113 -0
  290. package/graphs/profiles/local.yaml +5 -0
  291. package/graphs/profiles/pod.yaml +4 -0
  292. package/graphs/units/verbs/recipes.yaml +11 -11
  293. package/graphs/work/research-report.yaml +10 -2
  294. package/package.json +6 -2
  295. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  296. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  297. package/plugins/demo-browser-hand/plugin.json +13 -0
  298. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  299. package/plugins/demo-linear-secretary/plugin.json +15 -0
  300. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  301. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  302. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  303. package/plugins/demo-research/plugin.json +16 -0
  304. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  305. package/plugins/demo-video-briefing/plugin.json +15 -0
  306. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  307. package/scripts/build-signed-catalog.ts +48 -0
  308. package/scripts/ci-typecheck-main-delta.sh +88 -0
  309. package/scripts/codex-fallback-live-probe.ts +1 -1
  310. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  311. package/scripts/demo/demo1104-stage.config.ts +21 -0
  312. package/scripts/demo/demo1104-stage.ts +316 -0
  313. package/scripts/goal-method-audit.ts +17 -1
  314. package/scripts/graph-units/land-enqueue.ts +90 -0
  315. package/scripts/heal/run-role.ts +99 -5
  316. package/scripts/hooks/codex-notify.sh +32 -0
  317. package/scripts/install.sh +10 -38
  318. package/scripts/land-global-checks.ts +6 -1
  319. package/scripts/landing-heal/land-plan.ts +57 -0
  320. package/scripts/lib/decompose-ab.ts +1 -0
  321. package/scripts/lib/fixtures/tui-regress/help-insufficient-commands.txt +15 -0
  322. package/scripts/lib/fixtures/tui-regress/help-live.txt +42 -0
  323. package/scripts/lib/fixtures/tui-regress/help-missing-keys.txt +21 -0
  324. package/scripts/lib/fixtures/tui-regress/help-original.txt +51 -0
  325. package/scripts/lib/fixtures/tui-regress/help-shifted-input.txt +26 -0
  326. package/scripts/lib/tui-regress-checks.ts +33 -13
  327. package/scripts/release-loop/auto-approve-node.ts +1 -1
  328. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  329. package/scripts/release-loop/gate-baseline-receipt.ts +47 -9
  330. package/scripts/release-loop/gate-image-pin.ts +81 -0
  331. package/scripts/release-loop/gate-method.ts +139 -0
  332. package/scripts/release-loop/gate-node-sim.ts +207 -0
  333. package/scripts/release-loop/gate-node.ts +463 -64
  334. package/scripts/release-loop/gate-pod-image-sticky-plan.ts +99 -0
  335. package/scripts/release-loop/gate-radius-live.ts +97 -13
  336. package/scripts/release-loop/gate-shard-dispatch.ts +43 -0
  337. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  338. package/scripts/release-loop/gate-train-receipts.ts +122 -0
  339. package/scripts/release-loop/node-verdict.ts +38 -25
  340. package/scripts/release-loop/preflight.ts +362 -8
  341. package/scripts/release-loop/resume-release.ts +83 -8
  342. package/scripts/release-loop/unattended-release.ts +20 -9
  343. package/scripts/rhythm/daily.ts +36 -4
  344. package/scripts/rhythm/linear-progress-sync.ts +298 -0
  345. package/scripts/ux-sim.ts +18 -1
  346. package/scripts/video-pipeline.ts +9 -1
  347. package/scripts/warm-pool-provider-config.ts +286 -0
  348. package/skills/omni-crawl/SKILL.md +5 -2
  349. package/skills/omni-crawl/scripts/main.ts +84 -23
  350. package/src/acp/agent-manager.ts +1 -0
  351. package/src/acp/codex-app-server-agent.ts +33 -0
  352. package/src/acp/codex-app-server-client.ts +153 -16
  353. package/src/acp/core-turn-bridge.ts +27 -9
  354. package/src/acp/event-router.ts +20 -1
  355. package/src/acp/server.ts +6 -0
  356. package/src/agent/registry.ts +2 -0
  357. package/src/agent/task-notification.ts +25 -5
  358. package/src/agent/types.ts +6 -0
  359. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  360. package/src/agent-mission/claude-headless.ts +4 -1
  361. package/src/agent-mission/codex-exec.ts +105 -0
  362. package/src/agent-mission/driver.ts +192 -11
  363. package/src/agent-mission/grok-auth-status.ts +47 -0
  364. package/src/agent-mission/hand-hooks.ts +101 -0
  365. package/src/agent-mission/mission-cli.ts +63 -4
  366. package/src/agent-mission/mission-hand-reply.ts +118 -0
  367. package/src/agent-mission/mission-line.ts +180 -0
  368. package/src/agent-mission/mission-out.ts +833 -0
  369. package/src/agent-mission/tool-install.ts +200 -3
  370. package/src/agent-substrate/context-strategy.ts +4 -4
  371. package/src/agent-substrate/self-review-cli.ts +178 -13
  372. package/src/agents/general-purpose.md +1 -1
  373. package/src/auto-research/research-turn.ts +211 -53
  374. package/src/autopilot/pr-manager.ts +69 -10
  375. package/src/autopilot/pty-control-loop.ts +2 -0
  376. package/src/boot/daemon-tools/self-implement.ts +3 -1
  377. package/src/boot/daemon-tools/web-search.ts +1 -2
  378. package/src/briefing/brief-items.ts +55 -11
  379. package/src/capture/tui-self-report.ts +22 -6
  380. package/src/chat/index.ts +1 -1
  381. package/src/cli/agent-cli.ts +2 -1
  382. package/src/cli/catalog-cli.ts +31 -0
  383. package/src/cli/connector-cli.ts +16 -0
  384. package/src/cli/doctor-fix.ts +2 -2
  385. package/src/cli/fixtures/review-loop-breaker/opwaiver-32646-1694ccc7a170.json +1 -0
  386. package/src/cli/fixtures/review-loop-breaker/opwaiver-32853-bd8f73595c83.json +1 -0
  387. package/src/cli/fixtures/review-loop-breaker/opwaiver-33097-1cc85900413c.json +1 -0
  388. package/src/cli/fixtures/review-loop-breaker/opwaiver-33106-972f31e4a3ca.json +1 -0
  389. package/src/cli/fixtures/review-loop-breaker/opwaiver-33113-3ab51f05968f.json +1 -0
  390. package/src/cli/fixtures/review-loop-breaker/pr-33097-1cc85900413c.json +1 -0
  391. package/src/cli/intake-source-cli.ts +44 -8
  392. package/src/cli/msg-cli.ts +32 -3
  393. package/src/cli/pr-cli.ts +21 -1
  394. package/src/cli/pr-land-heavy-remote.ts +75 -5
  395. package/src/cli/pr-land-overlap-evidence.ts +113 -2
  396. package/src/cli/pr-land-pod-shadow-job.ts +202 -4
  397. package/src/cli/pr-land-pod-shadow.ts +9 -2
  398. package/src/cli/release-checklist-read-cli.ts +57 -19
  399. package/src/cli/release-cli.ts +23 -3
  400. package/src/cli/research-cli.ts +13 -5
  401. package/src/cli/setup-cli.ts +166 -6
  402. package/src/cli/setup-keys.ts +187 -0
  403. package/src/cli/task-plugin-wizard-host.ts +114 -0
  404. package/src/cli/tasks-cli.ts +61 -9
  405. package/src/cli/tui-test-cli.ts +186 -0
  406. package/src/compact/auto.ts +8 -1
  407. package/src/config.ts +4 -2
  408. package/src/connectors/linear-daily-progress.ts +228 -0
  409. package/src/connectors/linear-projector.ts +34 -12
  410. package/src/connectors/linear.ts +151 -7
  411. package/src/control-plane/ledger.ts +52 -2
  412. package/src/control-plane/server.ts +16 -2
  413. package/src/core-turn/deep-turn-bloom.ts +67 -0
  414. package/src/core-turn/research-policy.ts +37 -0
  415. package/src/core-turn/run-core-turn.ts +606 -95
  416. package/src/core-turn/run-goal-loop.ts +18 -0
  417. package/src/core-turn/types.ts +4 -0
  418. package/src/dashboard/chat/acp-chat.ts +10 -0
  419. package/src/dashboard/classic-sidetab-mission-job.ts +161 -0
  420. package/src/dashboard/classic-sidetab-mission-pair.ts +81 -0
  421. package/src/dashboard/classic-sidetab-mission-trio.ts +219 -0
  422. package/src/dashboard/classic-sidetab-mission.ts +347 -0
  423. package/src/dashboard/index.ts +517 -18
  424. package/src/dashboard/input/agent-wake.ts +23 -1
  425. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  426. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +17 -0
  427. package/src/dashboard/mission-cli-consumer.ts +165 -0
  428. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  429. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  430. package/src/dashboard/seat-boot-preamble.ts +171 -1
  431. package/src/dashboard/side-basic-runtime.ts +54 -1
  432. package/src/dashboard/sidetab-runtime.ts +90 -1
  433. package/src/dashboard/skill-catalog-preamble.ts +101 -0
  434. package/src/dashboard/skill-detection-runtime.ts +55 -15
  435. package/src/dashboard/slash-runtime/dashboard-handlers.ts +15 -0
  436. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  437. package/src/dashboard/turn-preamble.ts +53 -15
  438. package/src/dashboard/turn-prompt-runtime.ts +4 -2
  439. package/src/decisions/linear-progress-summary.ts +78 -0
  440. package/src/decisions/linear-progress-sync.ts +152 -0
  441. package/src/domains/outbound-alert.ts +49 -11
  442. package/src/domains/telegram-kind-route.ts +16 -9
  443. package/src/graph-runner/arg-allowance.ts +13 -0
  444. package/src/graph-runner/graph-cli.ts +23 -7
  445. package/src/graph-runner/graph-run-api.ts +3 -1
  446. package/src/graph-runner/graph-tick.ts +10 -2
  447. package/src/graph-runner/runner.ts +86 -18
  448. package/src/graph-wizard/mission-compose.ts +407 -12
  449. package/src/grok/agent-search.ts +14 -4
  450. package/src/grok/credential.ts +28 -11
  451. package/src/harness/dispatch-backpressure.ts +54 -1
  452. package/src/harness/dispatch-shadow-compare.ts +74 -0
  453. package/src/harness/harness-cli-command.ts +11 -1
  454. package/src/harness/harness-pod-dispatch.ts +81 -15
  455. package/src/harness/harness-stop.ts +155 -11
  456. package/src/harness/skill-exec.ts +21 -9
  457. package/src/harness/skill-select.ts +1 -1
  458. package/src/hooks/error-report-cloud.ts +101 -0
  459. package/src/hooks/receiver.ts +29 -2
  460. package/src/index.ts +159 -13
  461. package/src/instance/spawn-elanous.ts +6 -4
  462. package/src/intake-plane/actions.ts +354 -0
  463. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  464. package/src/intake-plane/intake-sources.ts +78 -8
  465. package/src/intake-plane/items.ts +14 -4
  466. package/src/intake-plane/linear-mission-sync.ts +80 -0
  467. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  468. package/src/intake-plane/linear-wish.ts +227 -1
  469. package/src/life/life-cli.ts +168 -0
  470. package/src/life/life-kinds.ts +160 -0
  471. package/src/live-supply/budget-consumer.ts +78 -0
  472. package/src/live-supply/read.ts +3 -0
  473. package/src/live-supply/snapshot.ts +45 -0
  474. package/src/llm/provider-credentials.ts +8 -2
  475. package/src/llm.ts +168 -9
  476. package/src/loops/orchestrator/coordinator-shadow.ts +226 -0
  477. package/src/loops/orchestrator/tick.ts +13 -0
  478. package/src/maturity/feature-maturity.ts +4 -4
  479. package/src/msg/msg-sse-server.ts +3 -3
  480. package/src/msg/msg-store.ts +177 -19
  481. package/src/native-tool-catalog.ts +38 -4
  482. package/src/nexus/api/harness-traversal.ts +11 -0
  483. package/src/nexus/api/http-server.ts +37 -1
  484. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  485. package/src/nexus/index.ts +7 -2
  486. package/src/nexus/outbound/format.ts +9 -0
  487. package/src/nexus/outbound/router.ts +98 -13
  488. package/src/nexus/setup-status.ts +9 -0
  489. package/src/nexus/state/state.ts +3 -0
  490. package/src/oauth/codex-account-store.ts +20 -7
  491. package/src/oauth/codex-owner-mirror.ts +44 -0
  492. package/src/oauth/codex.ts +17 -2
  493. package/src/oauth/fallback-chain.ts +47 -17
  494. package/src/onboarding/first-run-doctor.ts +8 -1
  495. package/src/onboarding/first-run.ts +85 -26
  496. package/src/onboarding/key-setup.ts +103 -0
  497. package/src/onboarding/menu-answer.ts +13 -0
  498. package/src/onboarding/secret-prompt.ts +37 -0
  499. package/src/plugins/install/plugin-install.ts +59 -0
  500. package/src/pr-tool/census.ts +133 -2
  501. package/src/pty-shell/pty-control-ipc.ts +4 -1
  502. package/src/pty-shell/tui-run-state.ts +188 -2
  503. package/src/registry/catalog-server.ts +232 -0
  504. package/src/registry/loader.ts +45 -1
  505. package/src/registry/types.ts +1 -2
  506. package/src/release-loop/checklist-target-path-hint.ts +13 -0
  507. package/src/release-loop/checklist.ts +9 -1
  508. package/src/repl/index.ts +43 -2
  509. package/src/research/axis-fanout.ts +136 -16
  510. package/src/research/bloom-exemplars.ts +3 -1
  511. package/src/research/gap-followup.ts +13 -1
  512. package/src/research/plugin-discovery.ts +36 -14
  513. package/src/research-bridge/invoke.ts +22 -5
  514. package/src/research-bridge/types.ts +2 -0
  515. package/src/self-dev/ask-launch-flow.ts +72 -1
  516. package/src/self-dev/decompose.ts +119 -5
  517. package/src/self-dev/dev-cli.ts +4 -1
  518. package/src/self-dev/dev-pipeline.ts +5 -0
  519. package/src/self-dev/draft-residue.ts +64 -5
  520. package/src/self-dev/graph-front-nodes.ts +2 -1
  521. package/src/self-dev/graph-journey-route.ts +76 -21
  522. package/src/self-dev/launch-preflight-text.ts +5 -6
  523. package/src/self-dev/launch-preflight.ts +58 -0
  524. package/src/self-dev/orchestrate.ts +13 -3
  525. package/src/self-dev/review-provider-fallback.ts +9 -2
  526. package/src/self-dev/run-supervisor.ts +42 -4
  527. package/src/self-dev/run-types.ts +4 -0
  528. package/src/self-dev/shard-aggregate.ts +4 -0
  529. package/src/self-dev/shard-run.ts +36 -15
  530. package/src/self-implement/abandoned-classification.ts +12 -3
  531. package/src/self-implement/budget-gate.ts +7 -0
  532. package/src/self-implement/child-llm-preference.ts +10 -1
  533. package/src/self-implement/doctor-visit.ts +118 -8
  534. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  535. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  536. package/src/self-implement/gate-artifacts.ts +2 -1
  537. package/src/self-implement/goal-author-cli.ts +4 -2
  538. package/src/self-implement/goal-author.ts +684 -7
  539. package/src/self-implement/graph-overlay-yaml.ts +37 -4
  540. package/src/self-implement/graph-overlay.ts +3 -1
  541. package/src/self-implement/graph-profile-yaml.ts +107 -0
  542. package/src/self-implement/graph-yaml.ts +26 -3
  543. package/src/self-implement/headless-elanous-driver.ts +31 -2
  544. package/src/self-implement/heal-intake.ts +112 -4
  545. package/src/self-implement/heal-triage.ts +20 -0
  546. package/src/self-implement/host-regate.ts +27 -4
  547. package/src/self-implement/merge-train.ts +5 -0
  548. package/src/self-implement/off-diff-evidence.ts +249 -5
  549. package/src/self-implement/orchestrator.ts +365 -25
  550. package/src/self-implement/regate-detail.ts +38 -1
  551. package/src/self-implement/rework-child-provider.ts +25 -0
  552. package/src/self-implement/run-chart.ts +122 -0
  553. package/src/self-implement/run-ledger.ts +162 -11
  554. package/src/self-implement/run-stop.ts +188 -4
  555. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  556. package/src/self-implement/stop-autoheal.ts +13 -0
  557. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  558. package/src/self-implement/train-gate-receipt.ts +166 -0
  559. package/src/self-implement/train-gate-remote.ts +62 -18
  560. package/src/session/chat.ts +40 -4
  561. package/src/session/session-fanout.ts +2 -0
  562. package/src/session/streaming/acp-stream-sink.ts +2 -1
  563. package/src/session/streaming/chunk-producer.ts +6 -0
  564. package/src/session/streaming/stream-compositor.ts +3 -2
  565. package/src/session-runtime/index.ts +135 -5
  566. package/src/session-runtime/retry-policy.ts +1 -1
  567. package/src/session-runtime/tier-flip.ts +3 -3
  568. package/src/setup/llm-env-detect.ts +3 -0
  569. package/src/setup/service-key-catalog.ts +46 -0
  570. package/src/setup/service-keys.ts +241 -0
  571. package/src/sidetab-core/model.ts +19 -5
  572. package/src/sidetab-core/visible-agent-mission.ts +262 -0
  573. package/src/skills/name-match.ts +20 -0
  574. package/src/skills/tools/agent.ts +53 -6
  575. package/src/skills/tools/omni-search.ts +173 -13
  576. package/src/task-agent/parent-host.ts +10 -0
  577. package/src/task-agent/pod-distributor-entry.ts +3 -0
  578. package/src/task-agent/repair-outcomes.ts +65 -0
  579. package/src/task-agent/task-hand.ts +47 -7
  580. package/src/task-orchestrator/dispatcher.ts +14 -1
  581. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  582. package/src/task-orchestrator/store.ts +16 -5
  583. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +4 -0
  584. package/src/task-orchestrator/surfaces/pod-distributor.ts +48 -0
  585. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +92 -1
  586. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +38 -1
  587. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  588. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +33 -6
  589. package/src/task-orchestrator/surfaces/pod-source-bundle.ts +45 -9
  590. package/src/task-orchestrator/surfaces/pod-source-receive.ts +178 -16
  591. package/src/task-orchestrator/surfaces/pod-source-spec.ts +3 -3
  592. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  593. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +237 -41
  594. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +80 -3
  595. package/src/task-orchestrator/surfaces/self-implement-pod.ts +337 -51
  596. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  597. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  598. package/src/task-orchestrator/types.ts +14 -0
  599. package/src/telegram.ts +14 -16
  600. package/src/terminal/coding-agent.ts +14 -5
  601. package/src/terminal/session-registry.ts +1 -1
  602. package/src/tokens.ts +35 -2
  603. package/src/tool-hints/gate.ts +1 -0
  604. package/src/tool-runtime/agent-runtime.ts +2 -0
  605. package/src/tool-runtime/browser-hand-runtime.ts +381 -0
  606. package/src/tool-runtime/browser-runtime.ts +2 -1
  607. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  608. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +57 -0
  609. package/src/tool-runtime/elanous-skills-list-runtime.ts +5 -1
  610. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  611. package/src/tool-runtime/index.ts +6 -0
  612. package/src/tool-runtime/skill-exec-runtime.ts +33 -13
  613. package/src/tool-runtime/types.ts +4 -0
  614. package/src/tui/entry.ts +38 -5
  615. package/src/tui/sidetab/attach.ts +177 -1
  616. package/src/tui/sidetab/herdr-portal.ts +225 -0
  617. package/src/tui-client/local-chat-turn.ts +26 -13
  618. package/src/tui.ts +22 -0
  619. package/src/user-config.ts +34 -9
  620. package/src/user-intent/types.ts +4 -3
  621. package/src/ux-sim/browser-hand.ts +165 -0
  622. package/src/ux-sim/draft-inventory-builder.ts +198 -0
  623. package/src/ux-sim/fake-browser-page.ts +81 -0
  624. package/src/ux-sim/fake-kubectl.ts +37 -3
  625. package/src/ux-sim/fake-linear-device.ts +31 -0
  626. package/src/ux-sim/fault-pool-cap.ts +11 -6
  627. package/src/ux-sim/graph-engine-sim.ts +47 -0
  628. package/src/ux-sim/linear-secretary.ts +216 -0
  629. package/src/ux-sim/mock-scenario-catalog.json +93 -0
  630. package/src/ux-sim/mock-scenario-catalog.ts +274 -0
  631. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  632. package/src/ux-sim/scenario.ts +185 -48
  633. package/src/ux-sim/service-key-setup.ts +50 -0
  634. package/src/ux-sim/term-slash-device.ts +74 -0
  635. package/src/ux-sim/turn-throw-sim.ts +31 -0
  636. package/src/version/packed-revision.json +1 -1
  637. package/src/voice/voice-tts-singleton.ts +18 -3
  638. package/src/web-search/exa.ts +77 -0
  639. package/src/web-search/grok.ts +5 -9
  640. package/src/web-search/index.ts +30 -9
  641. package/src/web-search/provider.ts +4 -1
  642. package/src/web-search/x-intent.ts +5 -0
  643. package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +0 -149
  644. package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +0 -36
  645. package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +0 -287
  647. package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +0 -90
  652. package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/1765.679b29625c8e88d4.js +0 -77
  654. package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/2073.689dcb2680113d76.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +0 -32
  665. package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +0 -79
  667. package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +0 -74
  671. package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +0 -148
  681. package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +0 -226
  682. package/apps/pwa/out/_next/static/chunks/4667.97e31aa38c95c475.js +0 -309
  683. package/apps/pwa/out/_next/static/chunks/4702.4a4adc1f16d7c93b.js +0 -64
  684. package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +0 -94
  691. package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +0 -8
  693. package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +0 -24
  696. package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/5937.c2df9e3447e1f667.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +0 -286
  699. package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +0 -27
  703. package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +0 -62
  705. package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +0 -24
  706. package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +0 -122
  708. package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/7191.fdc955f7d96064a4.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/8050-9b364bdef8f71927.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +0 -104
  720. package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +0 -93
  733. package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +0 -34
  738. package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/botlab/page-14949db884bfa672.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +0 -1
  794. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  795. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +0 -1
  796. /package/apps/pwa/out/_next/static/{GiOLWmt4MqDZePubBjA4Q → Om5xS9jpjSXJCeTNGYEi4}/_ssgManifest.js +0 -0
@@ -9,6 +9,18 @@ import { leaseKubectl, measurePoolLease, recommendConcurrency } from '../task-or
9
9
  import { parsePodPool, resolvePodPoolSpec } from '../task-orchestrator/surfaces/pod-pool.js';
10
10
  import { listCodexAccountsInStore } from '../oauth/codex-account-store.js';
11
11
  import { defaultSshRunner, resolveParentHosts, type SshRunner } from '../task-agent/parent-host.js';
12
+ import { debug } from '../debug/log.js';
13
+ import type { LiveSupplySnapshot } from '../live-supply/snapshot.js';
14
+
15
+ // Backpressure is a synchronous CLI command. Load supply only when that command runs so its
16
+ // collector graph does not enter the static TUI startup path.
17
+ function supplyReader(): typeof import('../live-supply/snapshot.js') {
18
+ return require('../live-supply/snapshot.js') as typeof import('../live-supply/snapshot.js');
19
+ }
20
+
21
+ function observeSupply(event: string, data: Record<string, unknown>): void {
22
+ try { debug.log('live-supply', event, data); } catch { /* observation never changes admission */ }
23
+ }
12
24
 
13
25
  export const BUILD_STOP = 4;
14
26
  export const BUILD_SLOW = 2;
@@ -126,8 +138,49 @@ function readPodRecommendation(): number | null {
126
138
  const measure = measurePoolLease(members, { measureUsage: true, skipDnsProbe: true });
127
139
  let accounts = -1;
128
140
  try { accounts = listCodexAccountsInStore().length; } catch { /* Accounts are only observed, not a limit. */ }
129
- return recommendConcurrency(measure, { capacity: members.reduce((sum, member) => sum + member.capacity, 0),
141
+ const direct = recommendConcurrency(measure, { capacity: members.reduce((sum, member) => sum + member.capacity, 0),
130
142
  accounts, perAccount: config.pod?.lease?.perAccount ?? 4 }).recommended;
143
+ return narrowPodRecommendationFromSupply(direct, members, supplyReader().loadLiveSupplySnapshot());
144
+ }
145
+
146
+ /** Pool supply can only reduce a direct recommendation when every member matches the current spec. */
147
+ export function narrowPodRecommendationFromSupply(
148
+ direct: number | null,
149
+ members: readonly { context: string; capacity: number }[],
150
+ snapshot: LiveSupplySnapshot | null,
151
+ nowMs = Date.now(),
152
+ ): number | null {
153
+ const supply = supplyReader().freshSupplyAxis(snapshot, 'pool', nowMs);
154
+ if (supply.status !== 'fresh') {
155
+ observeSupply('snapshot-unavailable', { site: 'harness-backpressure', axis: 'pool', reason: supply.reason });
156
+ return direct;
157
+ }
158
+ // A pool sample can only narrow current admission, never override memory/DNS policy or raise its result.
159
+ if (!Array.isArray(supply.value?.members)) {
160
+ observeSupply('snapshot-unavailable', { site: 'harness-backpressure', axis: 'pool', reason: 'malformed' });
161
+ return direct;
162
+ }
163
+ const sampleRows = supply.value.members;
164
+ const sampled = new Map(sampleRows
165
+ .filter(member => member && typeof member.context === 'string')
166
+ .map(member => [member.context, member]));
167
+ if (sampled.size !== sampleRows.length || sampled.size !== members.length
168
+ || new Set(members.map(member => member.context)).size !== members.length) {
169
+ observeSupply('snapshot-unavailable', { site: 'harness-backpressure', axis: 'pool', reason: 'pool-spec-mismatch' });
170
+ return direct;
171
+ }
172
+ const cap = members.reduce<number | null>((sum, member) => {
173
+ const seen = sampled.get(member.context);
174
+ if (sum === null || !seen || seen.capacity !== member.capacity || typeof seen.occupied !== 'number'
175
+ || !Number.isSafeInteger(seen.occupied) || seen.occupied < 0) return null;
176
+ return sum + Math.max(0, member.capacity - seen.occupied);
177
+ }, 0);
178
+ if (cap === null) {
179
+ observeSupply('snapshot-unavailable', { site: 'harness-backpressure', axis: 'pool', reason: 'pool-spec-mismatch' });
180
+ return direct;
181
+ }
182
+ observeSupply('snapshot-consumed', { site: 'harness-backpressure', axis: 'pool', sequence: supply.sequence, cap });
183
+ return direct === null ? null : Math.min(direct, cap);
131
184
  }
132
185
 
133
186
  function readLocalAdmission(query: LogQuery): readonly AdmissionRow[] {
@@ -0,0 +1,74 @@
1
+ import { debug } from '../debug/log.js';
2
+
3
+ /** Input contract for a dispatcher decision to be compared at the product entry. */
4
+ export const DISPATCH_SHADOW_COMPARE_ENV = 'ELANOUS_DISPATCH_SHADOW_COMPARE';
5
+
6
+ export interface DispatchShadowCompareContext {
7
+ requestId: string;
8
+ cellId: string;
9
+ tickId: string;
10
+ snapshotHash: string;
11
+ dispatcherAction: string;
12
+ dispatcherReason: string;
13
+ loopShadowAction: string;
14
+ loopShadowReason: string;
15
+ policyVersion: string;
16
+ runId: string;
17
+ }
18
+
19
+ export interface DispatchShadowCompareEntry {
20
+ entrance: string;
21
+ productEntryAction: 'queue' | 'launch-gate';
22
+ productEntryReason: string;
23
+ }
24
+
25
+ const CONTEXT_FIELDS = [
26
+ 'requestId', 'cellId', 'tickId', 'snapshotHash', 'dispatcherAction', 'dispatcherReason',
27
+ 'loopShadowAction', 'loopShadowReason', 'policyVersion', 'runId',
28
+ ] as const;
29
+ const MAX_CONTEXT_BYTES = 2048;
30
+ const MAX_VALUE_LENGTH = 240;
31
+
32
+ function compactString(value: unknown): string | undefined {
33
+ if (typeof value !== 'string') return undefined;
34
+ const compact = value.replace(/[\r\n\t]+/g, ' ').trim();
35
+ return compact.length > 0 && compact.length <= MAX_VALUE_LENGTH ? compact : undefined;
36
+ }
37
+
38
+ /** Parse the dispatcher handoff without making malformed optional metadata affect launches. */
39
+ export function parseDispatchShadowCompareContext(raw: string | undefined): DispatchShadowCompareContext | undefined {
40
+ if (!raw || Buffer.byteLength(raw, 'utf8') > MAX_CONTEXT_BYTES) return undefined;
41
+ let value: unknown;
42
+ try { value = JSON.parse(raw); } catch { return undefined; }
43
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;
44
+ const row = value as Record<string, unknown>;
45
+ const fields = Object.fromEntries(CONTEXT_FIELDS.map(field => [field, compactString(row[field])])) as
46
+ Record<(typeof CONTEXT_FIELDS)[number], string | undefined>;
47
+ if (CONTEXT_FIELDS.some(field => fields[field] === undefined)) return undefined;
48
+ if (!/^[a-f0-9]{64}$/i.test(fields.snapshotHash!)) return undefined;
49
+ return fields as DispatchShadowCompareContext;
50
+ }
51
+
52
+ /** One fail-soft comparison row; it only observes the product entry's selected route. */
53
+ export function recordDispatchShadowCompare(
54
+ context: DispatchShadowCompareContext | undefined,
55
+ entry: DispatchShadowCompareEntry,
56
+ log: (category: string, event: string, data: unknown) => void = (category, event, data) => debug.log(category, event, data),
57
+ ): void {
58
+ if (!context) return;
59
+ try {
60
+ log('harness', 'dispatch.shadow.compare', {
61
+ ...context,
62
+ ...entry,
63
+ agreement: context.dispatcherAction === context.loopShadowAction,
64
+ });
65
+ } catch { /* Measurement must not alter the harness entry or launch decision. */ }
66
+ }
67
+
68
+ export function recordDispatchShadowCompareFromEnv(
69
+ raw: string | undefined,
70
+ entry: DispatchShadowCompareEntry,
71
+ log?: (category: string, event: string, data: unknown) => void,
72
+ ): void {
73
+ recordDispatchShadowCompare(parseDispatchShadowCompareContext(raw), entry, log);
74
+ }
@@ -56,6 +56,7 @@ import { installHarnessCliSinkHook } from './harness-cli-sink.js';
56
56
  import { addHarnessQueue, HarnessQueueDuplicateError, harnessQueueReceiptPath, listHarnessQueue, queueSeatForCwd, reconcileHarnessQueue, removeHarnessQueue, setHarnessQueuePriority, tickHarnessQueue, type HarnessQueueDeps, type QueueItem, type QueueSeat } from './harness-queue.js';
57
57
  import { writeHarnessQueueReceipt } from './harness-queue-child.js';
58
58
  import { decideBackpressure, readBackpressureSignals, type BackpressureReadDeps } from './dispatch-backpressure.js';
59
+ import { DISPATCH_SHADOW_COMPARE_ENV, recordDispatchShadowCompareFromEnv } from './dispatch-shadow-compare.js';
59
60
  import { parseDoorSince, queryLaunchDoors, renderLaunchDoors, type DoorTable } from './launch-stamp.js';
60
61
  import { resolveHarnessSubstrate, type ResolvedHarnessSubstrate } from './harness-substrate-default.js';
61
62
  import { podChildProviderRefusal } from '../task-orchestrator/surfaces/pod-child-providers.js';
@@ -1061,6 +1062,13 @@ async function dispatchHarnessAskSay(
1061
1062
  const takeQueue = intakeTakesQueue(intakeLabel, intakeRoute, queueEligible);
1062
1063
  // 실제로 탄 간선을 전제 검사 «뒤»에 남긴다(그래프 답과 다르면 honored=false · 이유).
1063
1064
  recordJourneyEdge(intakeRoute, takeQueue ? 'queue' : 'launch-gate', intakeRoute.to === 'queue' && !takeQueue ? (opts.queue === false ? '--no-queue' : process.env.ELANOUS_HARNESS_QUEUE_LAUNCH ? 'queue-child' : 'no-seat') : undefined);
1065
+ // OP TA dispatcher injects its decision snapshot. Join both policies at the product entry;
1066
+ // this is observation only and must not change queue/direct routing.
1067
+ recordDispatchShadowCompareFromEnv(process.env[DISPATCH_SHADOW_COMPARE_ENV], {
1068
+ entrance: dryRunPreview.entrance,
1069
+ productEntryAction: takeQueue ? 'queue' : 'launch-gate',
1070
+ productEntryReason: takeQueue ? 'graph-intake-queue' : `graph-intake-${intakeRoute.to}`,
1071
+ });
1064
1072
  if (directSay && opts.queue === false) {
1065
1073
  try { debug.log('harness.queue', 'bypass', { seat: stampedSeat ?? null, reason: '--no-queue' }); }
1066
1074
  catch { /* Observation must not prevent an emergency launch. */ }
@@ -1190,7 +1198,9 @@ async function dispatchHarnessAskSay(
1190
1198
  delete process.env[LAUNCH_DOOR_RECEIPT_ENV];
1191
1199
  // 주입된 문이 없으면 생산 우주의 기본 문을 쓴다(시험 환경은 관문 관례와 같이 건너뛴다 — 시험 단언이 단일문 때문에 바뀌지 않는다).
1192
1200
  const launchDoor = gate.launchDoor ?? (process.env.NODE_ENV === 'test' ? undefined : openLaunchRequestDoor({ source: dryRunPreview.entrance }));
1193
- const launchDoorRequestId = launchDoor?.requestId(identity);
1201
+ // A hand parent already consumed a card/attempt-scoped request id. Reuse that id here;
1202
+ // direct harness requests still derive their stable id from the authored ask.
1203
+ const launchDoorRequestId = inheritedLaunchDoorReceipt ?? launchDoor?.requestId(identity);
1194
1204
  const decision = await withJourneyNode('launch-gate', journey, async () => {
1195
1205
  const { budget, budgetSource, snapshotAgeSec } = await resolveLaunchBudget({
1196
1206
  provider: opts.childLlmProvider,
@@ -107,7 +107,29 @@ export function podOrchestrateArgs(input: HarnessPodDispatchInput, goalFile: str
107
107
  ];
108
108
  }
109
109
 
110
- type PodDispatchDeps = { run?: (cmd: string, args: readonly string[], env: NodeJS.ProcessEnv) => number | null; readFile?: (path: string) => string; cwd?: string; spawnChild?: typeof spawn; onOutput?: (text: string) => void; recordRunLedgerEntry?: typeof appendRunLedgerEntry; nowMs?: number };
110
+ type PodDispatchExitObservation = {
111
+ status: number | null;
112
+ parentSignalReceived: NodeJS.Signals | null;
113
+ parentSignalReceivedAt: string | null;
114
+ parentSignalLastReceived?: NodeJS.Signals | null;
115
+ parentSignalLastReceivedAt?: string | null;
116
+ signalDelivery: 'requested' | 'child-not-running' | 'kill-failed' | null;
117
+ signalDeliveryFor?: NodeJS.Signals | null;
118
+ orchestratorProcessSignal: NodeJS.Signals | null;
119
+ observedAt: string;
120
+ };
121
+ type PodDispatchRunResult = number | null | PodDispatchExitObservation;
122
+ type PodDispatchDeps = { run?: (cmd: string, args: readonly string[], env: NodeJS.ProcessEnv) => PodDispatchRunResult; readFile?: (path: string) => string; cwd?: string; spawnChild?: typeof spawn; onOutput?: (text: string) => void; recordRunLedgerEntry?: typeof appendRunLedgerEntry; nowMs?: number };
123
+
124
+ export function classifyPodDispatchSignalSource(observation: Pick<PodDispatchExitObservation, 'parentSignalReceived' | 'signalDelivery' | 'orchestratorProcessSignal' | 'status'> & Partial<Pick<PodDispatchExitObservation, 'parentSignalLastReceived' | 'signalDeliveryFor'>>): 'parent-signal-forward-requested' | 'orchestrator-process-signaled' | 'unknown-143' | 'unknown-signal-exit' | 'non-signal-exit' {
125
+ const lastSignal = observation.parentSignalLastReceived ?? observation.parentSignalReceived;
126
+ const deliveryFor = observation.signalDeliveryFor ?? lastSignal;
127
+ if (lastSignal && observation.signalDelivery === 'requested' && deliveryFor === lastSignal) return 'parent-signal-forward-requested';
128
+ if (observation.orchestratorProcessSignal) return 'orchestrator-process-signaled';
129
+ if (observation.status === 143) return 'unknown-143';
130
+ if (observation.status === 130 || observation.status === null) return 'unknown-signal-exit';
131
+ return 'non-signal-exit';
132
+ }
111
133
 
112
134
  /** Default Pod source clones origin HEAD. Never infer its file occupation from an unrelated worktree. */
113
135
  function defaultPodSourceHeadAt(root: string): string | undefined {
@@ -294,39 +316,83 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
294
316
  childLlmProvider: input.childLlmProvider ?? null, childLlmModel: input.childLlmModel ?? null,
295
317
  goalChars, ...(input.entrance === 'cli-harness-ask' ? { goalPath: input.input } : {}),
296
318
  });
297
- const run = deps.run ?? ((cmd: string, a: readonly string[], childEnv: NodeJS.ProcessEnv) => new Promise<number>((resolveStatus) => {
319
+ const run = deps.run ?? ((cmd: string, a: readonly string[], childEnv: NodeJS.ProcessEnv) => new Promise<PodDispatchExitObservation>((resolveStatus) => {
298
320
  const ownsOutput = Boolean(deps.onOutput);
299
321
  const child = (deps.spawnChild ?? spawn)(cmd, [...a], {
300
- stdio: ownsOutput ? ['ignore', 'pipe', 'pipe'] : 'inherit',
301
- env: childEnv,
322
+ stdio: ownsOutput ? ['ignore', 'pipe', 'pipe'] : 'inherit', env: childEnv,
302
323
  });
303
324
  child.stdout?.setEncoding('utf8');
304
325
  child.stdout?.on('data', (chunk: string) => { process.stdout.write(chunk); deps.onOutput?.(chunk); });
305
326
  if (ownsOutput) forwardChildStderr(child.stderr);
306
- let forwarded: NodeJS.Signals | undefined;
327
+ let parentSignalReceived: NodeJS.Signals | undefined;
328
+ let parentSignalReceivedAt: string | undefined;
329
+ let parentSignalLastReceived: NodeJS.Signals | undefined;
330
+ let parentSignalLastReceivedAt: string | undefined;
331
+ let signalDelivery: PodDispatchExitObservation['signalDelivery'];
332
+ let signalDeliveryFor: NodeJS.Signals | undefined;
307
333
  const forward = (signal: NodeJS.Signals) => {
308
- forwarded = signal;
309
- if (child.exitCode === null && child.signalCode === null) child.kill(signal);
334
+ const receivedAt = new Date().toISOString();
335
+ parentSignalReceived ??= signal;
336
+ parentSignalReceivedAt ??= receivedAt;
337
+ parentSignalLastReceived = signal;
338
+ parentSignalLastReceivedAt = receivedAt;
339
+ signalDeliveryFor = signal;
340
+ if (child.exitCode !== null || child.signalCode !== null) {
341
+ signalDelivery = 'child-not-running';
342
+ return;
343
+ }
344
+ try { signalDelivery = child.kill(signal) ? 'requested' : 'kill-failed'; }
345
+ catch { signalDelivery = 'kill-failed'; }
310
346
  };
311
347
  const onTerm = () => forward('SIGTERM');
312
348
  const onInt = () => forward('SIGINT');
313
349
  process.on('SIGTERM', onTerm);
314
350
  process.on('SIGINT', onInt);
315
351
  const cleanup = () => { process.off('SIGTERM', onTerm); process.off('SIGINT', onInt); };
316
- child.once('error', () => { cleanup(); resolveStatus(1); });
317
- child.once('close', (code, signal) => { cleanup(); resolveStatus(code ?? ((signal ?? forwarded) === 'SIGINT' ? 130 : 143)); });
352
+ child.once('error', () => {
353
+ cleanup();
354
+ resolveStatus({ status: 1, parentSignalReceived: parentSignalReceived ?? null, parentSignalReceivedAt: parentSignalReceivedAt ?? null,
355
+ parentSignalLastReceived: parentSignalLastReceived ?? null, parentSignalLastReceivedAt: parentSignalLastReceivedAt ?? null,
356
+ signalDelivery: signalDelivery ?? null, signalDeliveryFor: signalDeliveryFor ?? null,
357
+ orchestratorProcessSignal: null, observedAt: new Date().toISOString() });
358
+ });
359
+ child.once('close', (code, signal) => {
360
+ cleanup();
361
+ resolveStatus({
362
+ status: code ?? ((signal ?? parentSignalReceived) === 'SIGINT' ? 130 : 143),
363
+ parentSignalReceived: parentSignalReceived ?? null,
364
+ parentSignalReceivedAt: parentSignalReceivedAt ?? null,
365
+ parentSignalLastReceived: parentSignalLastReceived ?? null,
366
+ parentSignalLastReceivedAt: parentSignalLastReceivedAt ?? null,
367
+ signalDelivery: signalDelivery ?? null,
368
+ signalDeliveryFor: signalDeliveryFor ?? null,
369
+ orchestratorProcessSignal: signal ?? null,
370
+ observedAt: new Date().toISOString(),
371
+ });
372
+ });
318
373
  }));
374
+ const recordExit = (result: PodDispatchRunResult): number => {
375
+ const observation = typeof result === 'number' || result === null
376
+ ? { status: result, parentSignalReceived: null, parentSignalReceivedAt: null, parentSignalLastReceived: null, parentSignalLastReceivedAt: null,
377
+ signalDelivery: null, signalDeliveryFor: null, orchestratorProcessSignal: null, observedAt: new Date().toISOString() }
378
+ : result;
379
+ debug.log('harness.substrate', 'dispatch-pod-exit', {
380
+ entrance: input.entrance,
381
+ reporterSeat: input.seat ?? process.env.ELANOUS_HARNESS_SEAT ?? null,
382
+ reporterCommand: input.entrance === 'cli-harness-ask' ? 'harness ask' : 'harness say',
383
+ ...observation, signalSource: classifyPodDispatchSignalSource(observation),
384
+ });
385
+ return observation.status ?? 1;
386
+ };
319
387
  const cleanup = () => { if (tempDir) rmSync(tempDir, { recursive: true, force: true }); };
320
388
  try {
321
389
  const status = run(process.execPath, args, env);
322
- if (typeof status === 'number' || status === null) {
390
+ if (typeof status === 'number' || status === null || !('then' in status)) {
323
391
  cleanup();
324
- debug.log('harness.substrate', 'dispatch-pod-exit', { entrance: input.entrance, status });
325
- return status ?? 1;
392
+ return recordExit(status);
326
393
  }
327
- return status.then((code) => {
328
- debug.log('harness.substrate', 'dispatch-pod-exit', { entrance: input.entrance, status: code });
329
- return code;
394
+ return status.then((result) => {
395
+ return recordExit(result);
330
396
  }).finally(cleanup);
331
397
  } catch (error) {
332
398
  cleanup();
@@ -16,12 +16,14 @@ import { isAbsolute, join, resolve } from 'node:path';
16
16
  import { spawnSync } from 'node:child_process';
17
17
  import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
18
18
  import { debug } from '../debug/log.js';
19
+ import { incidentLastLines } from './harness-incidents.js';
19
20
  import { selfDevRunsDir } from '../self-dev/run-store.js';
20
21
  import { launchBindingRunIds, launchRegistryDir, readLaunchBinding } from './launch-registry.js';
21
22
  import { loadRunLedger, resolveFederatedRunLedgerDirectories, runLedgerDir } from '../self-implement/run-ledger.js';
22
23
 
23
24
  const RUN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
24
25
  const FULL_RUN_ID = /^run-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
26
+ const STOP_POD_OBSERVATION_BUDGET_MS = 4_000;
25
27
 
26
28
  export class AmbiguousHarnessStopRunIdError extends Error {
27
29
  constructor(given: string, candidates: readonly string[]) {
@@ -151,12 +153,14 @@ export interface HarnessStopDeps {
151
153
  kill: (pid: number, signal: NodeJS.Signals) => void;
152
154
  sleep: (ms: number) => Promise<void>;
153
155
  kubeContexts: () => string[];
154
- kubectl: (args: readonly string[]) => { status: number | null; stdout: string; stderr: string };
156
+ kubectl: (args: readonly string[], timeoutMs?: number) => { status: number | null; stdout: string; stderr: string };
155
157
  namespace: string;
156
158
  graceMs: number;
159
+ observePodsBeforeDelete?: (runId: string, context: string, label: HarnessStopJobMatchedBy, budget: HarnessStopObservationBudget) => void;
157
160
  }
158
161
 
159
162
  export type HarnessStopJobMatchedBy = 'elanous.run' | 'elanous.child-run';
163
+ type HarnessStopObservationBudget = { startedAt: number | null; budgetMs: number; observedPods: number };
160
164
 
161
165
  /**
162
166
  * 문맥 하나의 Pod Job 삭제 결과(HARNESS-STOP-POD-LABEL) — «0개 지움» 의 종류를 가른다.
@@ -218,12 +222,130 @@ export function psProcessStartMs(pid: number): number | null {
218
222
 
219
223
  export function defaultHarnessStopDeps(overrides: Partial<HarnessStopDeps> = {}, opts: { launchRegistryDir?: string } = {}): HarnessStopDeps {
220
224
  const registry = opts.launchRegistryDir ?? launchRegistryDir();
225
+ const namespace = overrides.namespace ?? 'elanous-test';
226
+ const graceMs = overrides.graceMs ?? 10_000;
221
227
  const env = { ...process.env };
222
228
  for (const key of ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'ALL_PROXY', 'all_proxy']) delete env[key];
223
- const kubectl = (args: readonly string[]) => {
224
- const r = spawnSync('kubectl', [...args], { encoding: 'utf8', timeout: 15_000, env, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
229
+ const kubectl = (args: readonly string[], timeoutMs = 15_000) => {
230
+ const r = spawnSync('kubectl', [...args], { encoding: 'utf8', timeout: timeoutMs, env, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
225
231
  return { status: r.status, stdout: r.stdout ?? '', stderr: r.stderr ?? String(r.error ?? '') };
226
232
  };
233
+ const runKubectl = overrides.kubectl ?? kubectl;
234
+ const maxObservedPods = 2;
235
+ const listTimeoutMs = 1_500;
236
+ const logTimeoutMs = 750;
237
+ const observePodsBeforeDelete = (runId: string, context: string, label: HarnessStopJobMatchedBy, budget: HarnessStopObservationBudget): void => {
238
+ const requestedAt = new Date().toISOString();
239
+ const reporterSeat = process.env.ELANOUS_HARNESS_SEAT ?? null;
240
+ budget.startedAt ??= performance.now();
241
+ const remainingMs = () => Math.max(0, budget.budgetMs - (performance.now() - budget.startedAt!));
242
+ const emit = (data: Record<string, unknown>) => debug.log('harness.stop', 'job-termination-predelete', {
243
+ runId, context, matchedBy: label, requestedAt, reporter: 'harness-stop', reporterSeat, reporterCommand: 'harness stop', ...data,
244
+ });
245
+ if (remainingMs() <= 0) {
246
+ emit({ status: 'budget-exhausted', pods: [], omittedPods: null, observationBudgetMs: budget.budgetMs });
247
+ return;
248
+ }
249
+ try {
250
+ const listed = runKubectl(['--context', context, '-n', namespace, 'get', 'pods', '-l', `${label}=${runId}`, '-o', 'json'], Math.min(listTimeoutMs, remainingMs()));
251
+ let pods: unknown[] = [];
252
+ let listStatus: 'observed' | 'unavailable' | 'invalid' = 'observed';
253
+ if (listed.status !== 0) listStatus = 'unavailable';
254
+ else {
255
+ try {
256
+ const parsed = JSON.parse(listed.stdout) as { items?: unknown };
257
+ if (!Array.isArray(parsed.items)) listStatus = 'invalid';
258
+ else pods = parsed.items;
259
+ } catch { listStatus = 'invalid'; }
260
+ }
261
+ const selectedPods = pods.slice(0, Math.max(0, maxObservedPods - budget.observedPods));
262
+ budget.observedPods += selectedPods.length;
263
+ const evidence = selectedPods.map((raw) => {
264
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return { status: 'invalid-pod-record' };
265
+ const pod = raw as {
266
+ metadata?: { name?: unknown; labels?: unknown; ownerReferences?: unknown };
267
+ spec?: { nodeName?: unknown; activeDeadlineSeconds?: unknown; containers?: unknown };
268
+ status?: { phase?: unknown; reason?: unknown; message?: unknown; startTime?: unknown; conditions?: unknown; containerStatuses?: unknown };
269
+ };
270
+ const meta = pod.metadata && typeof pod.metadata === 'object' ? pod.metadata : {};
271
+ const spec = pod.spec && typeof pod.spec === 'object' ? pod.spec : {};
272
+ const status = pod.status && typeof pod.status === 'object' ? pod.status : {};
273
+ const arraysValid = (meta.ownerReferences === undefined || Array.isArray(meta.ownerReferences))
274
+ && (spec.containers === undefined || Array.isArray(spec.containers))
275
+ && (status.conditions === undefined || Array.isArray(status.conditions))
276
+ && (status.containerStatuses === undefined || Array.isArray(status.containerStatuses));
277
+ if (!arraysValid) return { status: 'invalid-pod-record' };
278
+ const name = typeof meta.name === 'string' ? meta.name : null;
279
+ const deadlineSeconds = typeof spec.activeDeadlineSeconds === 'number' && Number.isFinite(spec.activeDeadlineSeconds) && spec.activeDeadlineSeconds >= 0 ? spec.activeDeadlineSeconds : null;
280
+ const startedAt = typeof status.startTime === 'string' ? status.startTime : null;
281
+ let deadlineAt: string | null = null;
282
+ if (deadlineSeconds !== null && startedAt) {
283
+ const startMs = Date.parse(startedAt);
284
+ const deadlineMs = startMs + deadlineSeconds * 1000;
285
+ if (Number.isFinite(startMs) && Number.isFinite(deadlineMs)) {
286
+ try { deadlineAt = new Date(deadlineMs).toISOString(); } catch { deadlineAt = null; }
287
+ }
288
+ }
289
+ let tail: string[] | null = null;
290
+ let tailStatus: 'observed' | 'unavailable' | 'not-requested' | 'budget-exhausted' = 'not-requested';
291
+ if (name && remainingMs() > 0) {
292
+ const logs = runKubectl(['--context', context, '-n', namespace, 'logs', `pod/${name}`, '-c', 'child', '--tail=20'], Math.min(logTimeoutMs, remainingMs()));
293
+ if (logs.status === 0) { tail = incidentLastLines(logs.stdout); tailStatus = 'observed'; }
294
+ else { tail = incidentLastLines(logs.stderr); tailStatus = 'unavailable'; }
295
+ } else if (name) tailStatus = 'budget-exhausted';
296
+ const owners = Array.isArray(meta.ownerReferences) ? (meta.ownerReferences as Array<{ kind?: unknown; name?: unknown }>).slice(0, 20) : [];
297
+ const labels = meta.labels && typeof meta.labels === 'object' ? meta.labels as Record<string, unknown> : {};
298
+ const containers = Array.isArray(spec.containers) ? (spec.containers as Array<{ name?: unknown; image?: unknown; imagePullPolicy?: unknown }>).slice(0, 20) : [];
299
+ const conditions = Array.isArray(status.conditions) ? (status.conditions as Array<{ type?: unknown; status?: unknown; reason?: unknown; message?: unknown; lastTransitionTime?: unknown }>).slice(0, 20) : [];
300
+ const containerStatuses = Array.isArray(status.containerStatuses) ? (status.containerStatuses as Array<{ name?: unknown; imageID?: unknown; state?: unknown }>).slice(0, 20) : [];
301
+ return {
302
+ pod: name,
303
+ job: owners.find((owner) => owner?.kind === 'Job' && typeof owner.name === 'string')?.name ?? null,
304
+ childRunId: typeof labels['elanous.child-run'] === 'string' ? labels['elanous.child-run'] : null,
305
+ nodeName: typeof spec.nodeName === 'string' ? spec.nodeName : null,
306
+ images: containers.map((container) => container && typeof container === 'object' ? ({
307
+ name: typeof container.name === 'string' ? container.name : null,
308
+ image: typeof container.image === 'string' ? container.image : null,
309
+ imagePullPolicy: typeof container.imagePullPolicy === 'string' ? container.imagePullPolicy : null,
310
+ }) : { status: 'invalid-container-record' }),
311
+ phase: typeof status.phase === 'string' ? status.phase : null,
312
+ reason: typeof status.reason === 'string' ? status.reason : null,
313
+ message: typeof status.message === 'string' ? incidentLastLines(status.message).at(-1) ?? null : null,
314
+ startTime: startedAt, activeDeadlineSeconds: deadlineSeconds, deadlineAt,
315
+ conditions: conditions.map((condition) => condition && typeof condition === 'object' ? ({
316
+ type: typeof condition.type === 'string' ? condition.type : null,
317
+ status: typeof condition.status === 'string' ? condition.status : null,
318
+ reason: typeof condition.reason === 'string' ? condition.reason : null,
319
+ message: typeof condition.message === 'string' ? incidentLastLines(condition.message).at(-1) ?? null : null,
320
+ lastTransitionTime: typeof condition.lastTransitionTime === 'string' ? condition.lastTransitionTime : null,
321
+ }) : { status: 'invalid-condition-record' }),
322
+ containers: containerStatuses.map((container) => {
323
+ if (!container || typeof container !== 'object') return { status: 'invalid-container-status-record' };
324
+ const state = container.state && typeof container.state === 'object' ? container.state as Record<string, unknown> : {};
325
+ const waiting = state.waiting && typeof state.waiting === 'object' ? state.waiting as { reason?: unknown; message?: unknown } : null;
326
+ const terminated = state.terminated && typeof state.terminated === 'object' ? state.terminated as { reason?: unknown; exitCode?: unknown; signal?: unknown; finishedAt?: unknown } : null;
327
+ return {
328
+ name: typeof container.name === 'string' ? container.name : null,
329
+ imageID: typeof container.imageID === 'string' ? container.imageID : null,
330
+ waiting: waiting ? { reason: typeof waiting.reason === 'string' ? waiting.reason : null, message: typeof waiting.message === 'string' ? incidentLastLines(waiting.message).at(-1) ?? null : null } : null,
331
+ terminated: terminated ? {
332
+ reason: typeof terminated.reason === 'string' ? terminated.reason : null,
333
+ exitCode: typeof terminated.exitCode === 'number' && Number.isFinite(terminated.exitCode) ? terminated.exitCode : null,
334
+ signal: typeof terminated.signal === 'number' && Number.isFinite(terminated.signal) ? terminated.signal : null,
335
+ finishedAt: typeof terminated.finishedAt === 'string' ? terminated.finishedAt : null,
336
+ } : null,
337
+ };
338
+ }),
339
+ tailSource: 'kubectl-logs-merged-streams', tailStatus, tail,
340
+ };
341
+ });
342
+ emit({ status: listStatus, pods: evidence, omittedPods: Math.max(0, pods.length - selectedPods.length), observationBudgetMs: budget.budgetMs,
343
+ ...(listStatus === 'unavailable' ? { reason: incidentLastLines(listed.stderr).at(-1) ?? 'kubectl failed' } : {}) });
344
+ } catch (error) {
345
+ emit({ status: 'invalid', pods: [], omittedPods: null, observationBudgetMs: budget.budgetMs,
346
+ reason: incidentLastLines(error instanceof Error ? error.message : String(error)).at(-1) ?? 'observation failed' });
347
+ }
348
+ };
227
349
  return {
228
350
  // This universe first; then the host-wide launch binding, so a run launched from another worktree is still found.
229
351
  readPidRecord: (runId) => readPidRecordFrom(selfDevRunsDir(), runId) ?? pidRecordFromLaunchBinding(runId, registry),
@@ -243,12 +365,13 @@ export function defaultHarnessStopDeps(overrides: Partial<HarnessStopDeps> = {},
243
365
  kill: (pid, signal) => { process.kill(pid, signal); },
244
366
  sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
245
367
  kubeContexts: () => {
246
- const r = kubectl(['config', 'get-contexts', '-o', 'name']);
368
+ const r = runKubectl(['config', 'get-contexts', '-o', 'name']);
247
369
  return r.status === 0 ? r.stdout.split('\n').map((l) => l.trim()).filter(Boolean) : [];
248
370
  },
249
- kubectl,
250
- namespace: 'elanous-test',
251
- graceMs: 10_000,
371
+ kubectl: runKubectl,
372
+ observePodsBeforeDelete,
373
+ namespace,
374
+ graceMs,
252
375
  ...overrides,
253
376
  };
254
377
  }
@@ -271,7 +394,7 @@ function countDeletedJobLines(stdout: string): number {
271
394
  }
272
395
 
273
396
  /** 문맥 하나의 Pod Job 삭제 — 결과를 넷(deleted·none·unreachable·pods-only)으로 가르고 문맥마다 관측 `harness.stop` `job-delete` 를 남긴다. */
274
- function deleteRunPodJobs(deps: HarnessStopDeps, runId: string, context: string): HarnessStopJobDelete {
397
+ function deleteRunPodJobs(deps: HarnessStopDeps, runId: string, context: string, budget: HarnessStopObservationBudget): HarnessStopJobDelete {
275
398
  const unreachable = (stderr: string): HarnessStopJobDelete => {
276
399
  const error = stderr.slice(0, 200);
277
400
  debug.log('harness.stop', 'job-delete', { runId, context, outcome: 'unreachable', matchedBy: null, error }, { level: 'warn' });
@@ -281,6 +404,14 @@ function deleteRunPodJobs(deps: HarnessStopDeps, runId: string, context: string)
281
404
  for (const label of POD_JOB_LABELS) {
282
405
  // `-o name` → «job.batch/<name>» 한 줄씩. 맨 출력은 «job.batch "<name>" deleted» 라 «job.batch/» 로만 세면
283
406
  // 지워도 늘 0 이었다(10-11 · 여섯 번 «0개 지움» 뒤 Pod Terminating). 두 꼴을 다 센다(#26194).
407
+ try { deps.observePodsBeforeDelete?.(runId, context, label, budget); }
408
+ catch (error) {
409
+ debug.log('harness.stop', 'job-termination-predelete', {
410
+ runId, context, matchedBy: label, reporter: 'harness-stop', reporterSeat: process.env.ELANOUS_HARNESS_SEAT ?? null,
411
+ reporterCommand: 'harness stop', status: 'invalid', pods: [], omittedPods: null,
412
+ reason: incidentLastLines(error instanceof Error ? error.message : String(error)).at(-1) ?? 'observation failed',
413
+ }, { level: 'warn' });
414
+ }
284
415
  const r = deps.kubectl(['--context', context, '-n', deps.namespace, 'delete', 'job', '-l', `${label}=${runId}`, '--wait=false', '-o', 'name']);
285
416
  if (r.status !== 0) return unreachable(r.stderr);
286
417
  const deleted = countDeletedJobLines(r.stdout);
@@ -326,6 +457,18 @@ export async function stopHarnessRun(runId: string, deps: HarnessStopDeps, conte
326
457
  const add = (candidate: StopProcessCandidate) => {
327
458
  if (!seen.has(candidate.pid)) { seen.add(candidate.pid); candidates.push(candidate); }
328
459
  };
460
+ const requestSignal = (candidate: StopProcessCandidate, signal: NodeJS.Signals) => {
461
+ const requestAt = new Date().toISOString();
462
+ let delivery: 'accepted' | 'failed' = 'accepted';
463
+ try { deps.kill(candidate.pid, signal); }
464
+ catch { delivery = 'failed'; }
465
+ debug.log('harness.stop', 'process-signal-request', {
466
+ runId, signal, requestAt, targetPid: candidate.pid, targetStartedAt: new Date(candidate.startedAt).toISOString(),
467
+ targetDiscovery: candidate.via, delivery, reporter: 'harness-stop',
468
+ reporterSeat: process.env.ELANOUS_HARNESS_SEAT ?? null, reporterCommand: 'harness stop',
469
+ });
470
+ return delivery === 'accepted';
471
+ };
329
472
  let recordMismatch = false;
330
473
  if (record) {
331
474
  const recordedStart = deps.processStartMs(record.pid);
@@ -350,7 +493,7 @@ export async function stopHarnessRun(runId: string, deps: HarnessStopDeps, conte
350
493
  verified.push(candidate);
351
494
  }
352
495
  for (const candidate of verified) {
353
- try { deps.kill(candidate.pid, 'SIGTERM'); } catch { /* 방금 끝났다 */ }
496
+ requestSignal(candidate, 'SIGTERM');
354
497
  }
355
498
  for (const candidate of verified) {
356
499
  processState = 'stopped';
@@ -362,14 +505,15 @@ export async function stopHarnessRun(runId: string, deps: HarnessStopDeps, conte
362
505
  const still = deps.processStartMs(candidate.pid);
363
506
  const expectedStart = candidate.via === 'pid.json' ? record!.startedAt : candidate.startedAt;
364
507
  if (still !== null && Math.abs(still - expectedStart) <= START_TOLERANCE_MS) {
365
- try { deps.kill(candidate.pid, 'SIGKILL'); processState = 'killed'; } catch { /* 끝났다 */ }
508
+ if (requestSignal(candidate, 'SIGKILL')) processState = 'killed';
366
509
  }
367
510
  }
368
511
  if (processState === 'absent' && (scan.status === 'failed' || candidates.length > 0)) processState = 'unmeasured';
369
512
  }
370
513
  // ── ⓑ Pod Job (라벨로만) ───────────────────────────────────
371
514
  const targets = dryRun ? [] : contexts && contexts.length > 0 ? [...contexts] : deps.kubeContexts();
372
- const jobDeletes = targets.map((context) => deleteRunPodJobs(deps, runId, context));
515
+ const observationBudget: HarnessStopObservationBudget = { startedAt: null, budgetMs: STOP_POD_OBSERVATION_BUDGET_MS, observedPods: 0 };
516
+ const jobDeletes = targets.map((context) => deleteRunPodJobs(deps, runId, context, observationBudget));
373
517
  const jobsDeleted = jobDeletes.reduce((sum, job) => sum + job.deleted, 0);
374
518
  const result: HarnessStopResult = { runId, ...(given !== runId ? { givenRunId: given } : {}), process: processState, ...(record ? { pid: record.pid } : {}), candidates, scanned: scan.status === 'ok', pidRecordFound: record !== null, dryRun, jobsDeleted, jobDeletes, contexts: targets };
375
519
  debug.log('harness.stop', 'stopped', { runId, process: processState, jobsDeleted, contexts: targets.length });
@@ -4,26 +4,31 @@
4
4
  // allowlist skill 을 강하게 가리키면 그 skill 을 격리 실행(invokeResearch·Write/Edit deny)해 실제 출력을
5
5
  // Planner grounding 에 얹는다("총동원" 북극성 인프라).
6
6
  //
7
- // ★★ 안전 경계 (조사 실측: executeSkill 은 무겁다 — 에이전트 배치 spawn·비용):
8
- // ① **allowlist** — 자동 실행은 read-only·경량·에이전트 배치 안 하는 skill 만(stochastic-*·*-panel·
9
- // consensus 류 제외). 나머지는 실행 안 함(skill-hint 가 힌트만 준다).
7
+ // ★★ 안전 경계 (allowlist 로만 자동 skill 실행을 열고, 강한 트리거·격리·fail-soft 유지):
8
+ // ① **allowlist** — 명시적으로 승인한 research·market·scoring skills 만 자동 경로에 편입한다.
9
+ // stochastic consensus 배치는 제외하고, 아래 기본 목록의 attractiveness-panel 은 OP 승인 예외다.
10
10
  // ② **격리** — invokeResearch 경유 = withResearchIsolation(Write/Edit/NotebookEdit deny). 부작용 봉쇄.
11
11
  // ③ **강한 게이트** — unambiguous + score>=2.0 + 명시 트리거 히트(설명 보너스만으론 안 뜸).
12
12
  // ④ **fail-soft** — 실패/빈 출력 = null(상위가 skill-hint 로 폴백·plan 안 막음).
13
- // ⚠️ omni-crawl 은 research seam 이 이미 커버 → allowlist 제외(중복 회피).
14
- // ⚠️ 코딩 objective 에선 트리거 빈도 낮음(대개 코드 변경) — 이는 북극성 "총동원" 인프라이지 상시 경로 아님.
15
13
 
16
14
  import { detectSkillTrigger } from '../skills/router.js';
17
15
  import type { SkillIndexEntry } from '../skills/index.js';
18
16
  import { invokeResearch } from '../research-bridge/invoke.js';
19
17
  import { SKILL_HINT_MIN_SCORE } from './skill-hint.js';
20
18
 
21
- /** 하니스 plan 단계에서 **자동 실행** 허용된 skill 기본값 — read-only·경량·에이전트 배치 spawn 안 함.
22
- * ⚠️ 확장 시 신중: Agent 배치/mutating/고비용 skill 금지. omni-crawl 은 research seam 이 커버(제외). */
19
+ /** 하니스 plan 단계에서 **자동 실행** 허용된 skill 기본값.
20
+ * Research·market·scoring skill 은 OP 승인 목록이며, 실제 자동 실행은 아래 strong-trigger 및 isolation 게이트를 통과해야 한다. */
23
21
  export const HARNESS_EXEC_ALLOWLIST: ReadonlySet<string> = new Set<string>([
22
+ // Parent planning is grounding, not a child tool call. A child does not repeat
23
+ // it automatically; an explicit child crawl is a separately scoped follow-up.
24
+ 'omni-crawl', // OP 2026-10-30: research child skill access
24
25
  'omni-digest', // URL/문서 요약(참조 자료 확보)
25
26
  'omni-market', // 금융 데이터 조회(read-only)
26
27
  'kr-flow', // 한국 시장 수급(read-only)
28
+ 'asset-attractiveness', // OP 2026-10-30: scoring research
29
+ 'social-pulse', // OP 2026-10-30: social evidence research
30
+ 'attractiveness-panel', // OP-approved exception to the generic -panel config block
31
+ 'factor-backtest', // OP 2026-10-30: market research/backtesting
27
32
  // 📧 Gmail·Calendar·Drive·Sheets. ⚠️ ***읽기 전용이 «아니다»*** — 이 목록의 앞 셋과 다른 성질이다.
28
33
  // ⛔ 그래서 SKILL.md 가 규율을 못 박았다: 사용자가 「보내라·잡아라·지워라」를 «명시»하지 않으면
29
34
  // ***초안까지만*** 한다(메일 전송·일정 생성·삭제는 되돌릴 수 없다).
@@ -40,6 +45,11 @@ const HARNESS_EXEC_BLOCK_PATTERNS: readonly RegExp[] = [
40
45
  /consensus/i, // *-consensus — 다수 에이전트 투표
41
46
  ];
42
47
 
48
+ /** Explicitly OP-approved defaults may bypass a broad config pattern block. */
49
+ const HARNESS_EXEC_BLOCK_EXCEPTIONS: ReadonlySet<string> = new Set([
50
+ 'attractiveness-panel',
51
+ ]);
52
+
43
53
  /** 선언된 속성만으로 자동실행 안전한가(순수). 미선언은 false(보수 기본·fail-safe).
44
54
  * `SkillIndexEntry`의 선언값은 실행기와 같은 `parseSkillMd`가 같은 아티팩트에서 읽는다.
45
55
  * 선언은 skill 저자의 authorization 신호다. 읽기만 + 경량일 때만 true. */
@@ -63,7 +73,9 @@ export function resolveHarnessExecAllowlist(
63
73
  const addIfAllowed = (raw: string): void => {
64
74
  const name = raw.trim();
65
75
  if (!name) return;
66
- const blocked = HARNESS_EXEC_BLOCK_PATTERNS.find((p) => p.test(name));
76
+ const blocked = HARNESS_EXEC_BLOCK_EXCEPTIONS.has(name)
77
+ ? undefined
78
+ : HARNESS_EXEC_BLOCK_PATTERNS.find((p) => p.test(name));
67
79
  if (blocked) {
68
80
  onReject?.(name, `자동 실행 대상 아님: 블록패턴 ${blocked} (Agent 배치·고비용 자동실행 금지). 대신 skill-hint 경로를 사용하세요. 이 판정을 넓히려면 skillRouter.harnessExecAllowlist와 HARNESS_EXEC_BLOCK_PATTERNS를 검토하세요.`);
69
81
  return;
@@ -92,7 +104,7 @@ export async function execHarnessSkill(
92
104
  index: readonly SkillIndexEntry[],
93
105
  invoke: (objective: string, skill: string) => Promise<{ ok: boolean; output: string }> =
94
106
  (obj, skill) => invokeResearch(obj, { skill }).then((r) => ({ ok: r.ok, output: r.output })),
95
- allowlist: ReadonlySet<string> = HARNESS_EXEC_ALLOWLIST, // S2 — config 확장 주입(기본=하드코딩 3개·무회귀)
107
+ allowlist: ReadonlySet<string> = HARNESS_EXEC_ALLOWLIST, // S2 — config 확장 주입(기본 목록·무회귀)
96
108
  ): Promise<SkillExecResult | null> {
97
109
  if (!objective.trim() || index.length === 0) return null;
98
110
  const detect = detectSkillTrigger(objective, index as SkillIndexEntry[]);