elanous 0.2.42 → 0.2.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (685) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → Om5xS9jpjSXJCeTNGYEi4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 0966f8a1.745fcd44f64a87ea.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 0ad6802e.ae7afb63fdcb4491.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/114.2b90424d1a3ce84c.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1151-5c2bb8f002ca2dd6.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1200.6a37c202f9f17e9a.js +226 -0
  9. package/apps/pwa/out/_next/static/chunks/1261-a616d5728e02e624.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1313-19f737e0222c4444.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1357.3bbef3976c37f94a.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1362-20adddfaf662b0fa.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1406.a1dc2ab6f8449374.js} +2 -2
  14. package/apps/pwa/out/_next/static/chunks/1737-9491fc6ab29b9ec6.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1803-4f91a8e7dcaf042c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1961.a81b12872c3e93a9.js +23 -0
  17. package/apps/pwa/out/_next/static/chunks/{53c73f84.373b6160adfa89a4.js → 1970cf59.2d4d8ce5d6c81853.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/1971-8890f3962ba7ee0a.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{9211-330b6736a63d4cb3.js → 2073-ba274e00e4f9efb4.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 2144.25b292396712196d.js} +2 -2
  21. package/apps/pwa/out/_next/static/chunks/2268-53861f339e0b65a2.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2312.0c8b61e22d3136d7.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 2573.387a707f6f9d720c.js} +2 -2
  24. package/apps/pwa/out/_next/static/chunks/273.f156eee28f11af77.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2873.d2140e5a82546401.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 3072.01338851ca21a6f7.js} +2 -2
  27. package/apps/pwa/out/_next/static/chunks/3091.a5a4143dea33d197.js +90 -0
  28. package/apps/pwa/out/_next/static/chunks/{2456.b6de0e1c05f28843.js → 3095.dc44586a5f83b86d.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{3207.a756c95e9ec8c3c8.js → 3113.d7472bbc27d580c7.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/3228-9650b6447b6fa288.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3402.44b565b314f2263c.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3557ac4a.c8931684475018ad.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{8505.fd803c6c33b54cc3.js → 360.ae9f9f4c33c395e8.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3638.80412ea63aae8f3f.js +286 -0
  35. package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 363bfab3.9623b9f89363541f.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/3694.e0099884345f0198.js +64 -0
  37. package/apps/pwa/out/_next/static/chunks/3744.54f87db52acfd1ab.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3903.3ef4656c67572764.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3935.16701e33f8982dc9.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3955.6922286237f2ac2b.js +24 -0
  41. package/apps/pwa/out/_next/static/chunks/3969.272ee7f9fd6c62e5.js +34 -0
  42. package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 4199.ce86b281fd0a60b7.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/4311-6dd3144002cc0c2d.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4426-2b230fad00c88930.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{2690.0521c738b7749931.js → 4445.7990c76b3751a918.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4447-14c5161fa59166c7.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4856-b0b8075bba8c53f4.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4870-de370d65e73c0bb5.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4885-2c989165c4b29fad.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/{1945.7b54990d578c119b.js → 4894.fec2ca9e99caefa2.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/5093.8f04b7f8cb899a95.js +94 -0
  52. package/apps/pwa/out/_next/static/chunks/5122-2bb177cebf89e19a.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5154.5f56dc3902e3d275.js +36 -0
  54. package/apps/pwa/out/_next/static/chunks/529.64ff7257180b2ac9.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5394.5dabeb0c62293a28.js +93 -0
  56. package/apps/pwa/out/_next/static/chunks/5461.08bf2404ff38ec85.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5474-22e08a85583209b2.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 5564.9e72532188f57586.js} +16 -16
  59. package/apps/pwa/out/_next/static/chunks/5567-265df39ed8fe9dcb.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5570-a94ae19811cb2046.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5574-b47c9ef2dceff1fd.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 5628.6ddb2d5ffba4ff4c.js} +4 -4
  63. package/apps/pwa/out/_next/static/chunks/{1319.b9b815ae0f181e06.js → 5730.43d7ccc09988e646.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5789.2da35c258292e1e5.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5824.da9527b15a3221e5.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5866.366966af47fdde5d.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 5930.8b4df3b46c32b05a.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/5963-c4d8469c52a0828b.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/6001.ec4049ceb3c43418.js +27 -0
  70. package/apps/pwa/out/_next/static/chunks/6120-471f03db1e299c0c.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6175-41479e643aca1878.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6291.a2de4f9787637075.js +104 -0
  73. package/apps/pwa/out/_next/static/chunks/6400-6699907c3537436a.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6428.1f4327d6ae5fdf9a.js +287 -0
  75. package/apps/pwa/out/_next/static/chunks/644.02cb026fa44bcd0a.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6466-6c87d60d3dd174fb.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 6540.c7bef57ad8f90a87.js} +3 -3
  78. package/apps/pwa/out/_next/static/chunks/6773.d4264665ab31bec0.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6822.3c789f1a8443e774.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 6944.309f4e3ea54d1537.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/7261-8ff69d3b2ee671fd.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7266.084c6bbc70035140.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7271.5c0100e7320aa856.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7429-bf5731358c8f2f68.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7464.01f7a0ae1215fbe7.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7479.0fcad5f37eb64f0c.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/{4770.769c9cd9c7034eba.js → 7483.427a2fe2049e388d.js} +2 -2
  88. package/apps/pwa/out/_next/static/chunks/{1147-5196d19c222051b3.js → 7502-be74718178e13e56.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7530.0889722b19572065.js +24 -0
  90. package/apps/pwa/out/_next/static/chunks/7645.5b2ee3ad45c55ea3.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7788.7d1c79f1a8e18946.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7900.096f455c7c1efc53.js +77 -0
  93. package/apps/pwa/out/_next/static/chunks/7910-6f139bcafd238b9f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7966.f71c8958d1637548.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 8062-7cd0bcc7f01455ba.js} +3 -3
  96. package/apps/pwa/out/_next/static/chunks/8073.f6cf2f2c71aafbd0.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8201.190b94088980f430.js +74 -0
  98. package/apps/pwa/out/_next/static/chunks/8205.282ca4bb62d54a0a.js +62 -0
  99. package/apps/pwa/out/_next/static/chunks/8313-dfa1021bb58a46d6.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/837-81336ebaca8198a8.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8447.7963352ef5f71b76.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8574-868e8129525ef6d9.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8588.d1c6a2903727ce87.js +149 -0
  104. package/apps/pwa/out/_next/static/chunks/8637.90f92d5c8db4732c.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/868.6e953be05bcf6dca.js +41 -0
  106. package/apps/pwa/out/_next/static/chunks/8706-e1fe0309343a2273.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8749-06384cdfc4520add.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{9656-374232558fd528d0.js → 8861-cc1fa1c7b920fa8e.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/{5440-4236de26c5ea5856.js → 8967-7dfebf710c9dec9d.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 8986.8e2e4efbfa655c59.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/8997-3c564dbb3b58b055.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/{4320.583cbab64db6be02.js → 923.2034d10ae91e9c20.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/9312.bc1b89c5d4368033.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{1574.878c18ecc97b1bd4.js → 943.39ae5e82f4f1893f.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9469.0500480de55fb205.js +32 -0
  116. package/apps/pwa/out/_next/static/chunks/9770.5f75bc6088b16109.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9810-2543267050e58b82.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9870.8419702475254745.js +8 -0
  119. package/apps/pwa/out/_next/static/chunks/9941-376d1b74d51b01a4.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9958.385434ab04241758.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/aa57532f.510551854ff239b1.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-deea1450b17cb8dc.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-70985b904f8650ef.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a2e15e33e56a4353.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-fc72ce2db12d6ca9.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-be03e41f9436ebd9.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-35a35999382da3f2.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-3ff5b1e6ca88b848.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-a65101300a0ee5c1.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-3aca5b6d67dba511.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-45b8ab0a71e61314.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-53046e282d4cda8e.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-17809e60e8354c17.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-fd2442d347bf5898.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-e9d720d6fc082e21.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-6b8b4267bab0a677.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-deea1450b17cb8dc.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-8bcf6233ac7c17af.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-7cc25591cfc2126f.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-053e871f35c9beba.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-eff819f0c2d5e084.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-4d7e9d8db5274a87.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-2b2d8f5aa5f69ad4.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-0b8f92c5062e68b1.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1bd9d0fdac2ced3d.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/{page-0f291d3c8fd55a3a.js → page-9ee28f7df07428ea.js} +1 -1
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-44b7a1ff468c6648.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-cbc6523711dc1b65.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-fdad47899c2695be.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-79a8b5fee4c20871.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-03e8ac9606aeaffb.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-4cd55c55ec287e2f.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-db17b4305404161e.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-30041d848350fd02.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c540da022dbf86b0.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9399efc538da057f.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ca2d09128c585ca4.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-0e2635aecd343038.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ef7f4399b6b7726e.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-deea1450b17cb8dc.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-caf530535b875468.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-eaa20c1543a5fd8e.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c541eb1b75120f61.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-ab5e213eda9479f4.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-0a815f34367b6db6.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-e858ba0ed9393b68.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-1638ee9dd6e0582f.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-4cf5a399109391f2.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b4396321238798ec.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-cb72bfd21006781a.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6135d0242afbc434.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a1dccf907eddb856.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/c7945435-b44d4dbe90ba0dcb.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → cb0f8df8.09a4a6be97e3fc5f.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → d96660fb.cbc21a2a88539dbb.js} +7 -7
  176. package/apps/pwa/out/_next/static/chunks/{50061469.0326382241ef3b2d.js → ea514caa.05a24f78d9dffe5f.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/fb7d20d5-6892502b6ee39ca6.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-e8a911e19b1be41f.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7022f418fabba021.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-e5f15df755756a1e.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-4525f91e36940c9b.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-140f0e519c085b0f.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-8f22ef63dcb865b1.js +1 -0
  184. package/apps/pwa/out/_next/static/css/d1f8bb401740a549.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/catalog/external-commands.yaml +5 -3
  279. package/catalog/meta/catalogVersion.yaml +2 -1
  280. package/catalog/signing/catalog-signing-public.pem +3 -0
  281. package/graphs/intake/intake-daily.yaml +16 -0
  282. package/graphs/intake/news-sources.yaml +1 -0
  283. package/graphs/intake/recipes.yaml +7 -0
  284. package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
  285. package/graphs/profiles/local.yaml +5 -0
  286. package/graphs/profiles/pod.yaml +4 -0
  287. package/package.json +6 -2
  288. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  289. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  290. package/plugins/demo-browser-hand/plugin.json +13 -0
  291. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  292. package/plugins/demo-linear-secretary/plugin.json +15 -0
  293. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  294. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  295. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  296. package/plugins/demo-research/plugin.json +16 -0
  297. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  298. package/plugins/demo-video-briefing/plugin.json +15 -0
  299. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  300. package/scripts/build-signed-catalog.ts +48 -0
  301. package/scripts/ci-typecheck-main-delta.sh +88 -0
  302. package/scripts/codex-fallback-live-probe.ts +1 -1
  303. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  304. package/scripts/demo/demo1104-stage.config.ts +21 -0
  305. package/scripts/demo/demo1104-stage.ts +316 -0
  306. package/scripts/goal-method-audit.ts +17 -1
  307. package/scripts/graph-units/land-enqueue.ts +90 -0
  308. package/scripts/hooks/codex-notify.sh +32 -0
  309. package/scripts/install.sh +10 -38
  310. package/scripts/landing-heal/land-plan.ts +57 -0
  311. package/scripts/release-loop/auto-approve-node.ts +1 -1
  312. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  313. package/scripts/release-loop/gate-method.ts +139 -0
  314. package/scripts/release-loop/gate-node.ts +180 -20
  315. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  316. package/scripts/release-loop/node-verdict.ts +38 -25
  317. package/scripts/release-loop/preflight.ts +362 -8
  318. package/scripts/release-loop/unattended-release.ts +20 -9
  319. package/scripts/rhythm/daily.ts +36 -4
  320. package/scripts/rhythm/linear-progress-sync.ts +298 -0
  321. package/scripts/video-pipeline.ts +9 -1
  322. package/scripts/warm-pool-provider-config.ts +29 -6
  323. package/src/acp/agent-manager.ts +1 -0
  324. package/src/acp/codex-app-server-agent.ts +33 -0
  325. package/src/acp/codex-app-server-client.ts +153 -16
  326. package/src/acp/core-turn-bridge.ts +17 -12
  327. package/src/acp/event-router.ts +20 -1
  328. package/src/acp/server.ts +6 -0
  329. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  330. package/src/agent-mission/claude-headless.ts +4 -1
  331. package/src/agent-mission/codex-exec.ts +105 -0
  332. package/src/agent-mission/driver.ts +192 -11
  333. package/src/agent-mission/grok-auth-status.ts +47 -0
  334. package/src/agent-mission/hand-hooks.ts +101 -0
  335. package/src/agent-mission/mission-cli.ts +56 -21
  336. package/src/agent-mission/mission-hand-reply.ts +118 -0
  337. package/src/agent-mission/mission-line.ts +180 -0
  338. package/src/agent-mission/mission-out.ts +256 -18
  339. package/src/agent-mission/tool-install.ts +122 -11
  340. package/src/agents/general-purpose.md +1 -1
  341. package/src/auto-research/research-turn.ts +95 -10
  342. package/src/autopilot/pr-manager.ts +31 -3
  343. package/src/boot/daemon-tools/self-implement.ts +3 -1
  344. package/src/boot/daemon-tools/web-search.ts +1 -2
  345. package/src/briefing/brief-items.ts +55 -11
  346. package/src/cli/agent-cli.ts +2 -1
  347. package/src/cli/catalog-cli.ts +31 -0
  348. package/src/cli/connector-cli.ts +16 -0
  349. package/src/cli/doctor-fix.ts +2 -2
  350. package/src/cli/intake-source-cli.ts +44 -8
  351. package/src/cli/msg-cli.ts +32 -3
  352. package/src/cli/pr-cli.ts +21 -1
  353. package/src/cli/pr-land-heavy-remote.ts +44 -6
  354. package/src/cli/pr-land-overlap-evidence.ts +13 -1
  355. package/src/cli/pr-land-pod-shadow-job.ts +143 -5
  356. package/src/cli/pr-land-pod-shadow.ts +9 -2
  357. package/src/cli/release-checklist-read-cli.ts +44 -16
  358. package/src/cli/release-cli.ts +23 -3
  359. package/src/cli/research-cli.ts +9 -0
  360. package/src/cli/setup-cli.ts +166 -6
  361. package/src/cli/setup-keys.ts +187 -0
  362. package/src/cli/task-plugin-wizard-host.ts +114 -0
  363. package/src/cli/tasks-cli.ts +54 -9
  364. package/src/cli/tui-test-cli.ts +186 -0
  365. package/src/config.ts +4 -2
  366. package/src/connectors/linear-daily-progress.ts +228 -0
  367. package/src/connectors/linear-projector.ts +34 -12
  368. package/src/connectors/linear.ts +151 -7
  369. package/src/core-turn/deep-turn-bloom.ts +67 -0
  370. package/src/core-turn/research-policy.ts +37 -0
  371. package/src/core-turn/run-core-turn.ts +320 -30
  372. package/src/core-turn/types.ts +2 -0
  373. package/src/dashboard/chat/acp-chat.ts +10 -0
  374. package/src/dashboard/classic-sidetab-mission-job.ts +103 -0
  375. package/src/dashboard/classic-sidetab-mission-pair.ts +81 -0
  376. package/src/dashboard/classic-sidetab-mission-trio.ts +219 -0
  377. package/src/dashboard/classic-sidetab-mission.ts +167 -5
  378. package/src/dashboard/index.ts +378 -13
  379. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  380. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +8 -0
  381. package/src/dashboard/mission-cli-consumer.ts +20 -8
  382. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  383. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  384. package/src/dashboard/sidetab-runtime.ts +1 -1
  385. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  386. package/src/decisions/linear-progress-summary.ts +78 -0
  387. package/src/decisions/linear-progress-sync.ts +152 -0
  388. package/src/domains/outbound-alert.ts +49 -11
  389. package/src/domains/telegram-kind-route.ts +16 -9
  390. package/src/graph-runner/arg-allowance.ts +13 -0
  391. package/src/graph-runner/graph-run-api.ts +3 -1
  392. package/src/graph-runner/runner.ts +85 -17
  393. package/src/graph-wizard/mission-compose.ts +407 -12
  394. package/src/harness/dispatch-backpressure.ts +54 -1
  395. package/src/harness/dispatch-shadow-compare.ts +74 -0
  396. package/src/harness/harness-cli-command.ts +11 -1
  397. package/src/harness/skill-exec.ts +21 -9
  398. package/src/harness/skill-select.ts +1 -1
  399. package/src/hooks/error-report-cloud.ts +101 -0
  400. package/src/hooks/receiver.ts +29 -2
  401. package/src/index.ts +127 -10
  402. package/src/intake-plane/actions.ts +354 -0
  403. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  404. package/src/intake-plane/intake-sources.ts +78 -8
  405. package/src/intake-plane/items.ts +14 -4
  406. package/src/intake-plane/linear-mission-sync.ts +80 -0
  407. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  408. package/src/intake-plane/linear-wish.ts +227 -1
  409. package/src/life/life-cli.ts +168 -0
  410. package/src/life/life-kinds.ts +160 -0
  411. package/src/live-supply/budget-consumer.ts +78 -0
  412. package/src/live-supply/read.ts +3 -0
  413. package/src/live-supply/snapshot.ts +45 -0
  414. package/src/llm/provider-credentials.ts +8 -2
  415. package/src/llm.ts +2 -1
  416. package/src/maturity/feature-maturity.ts +3 -3
  417. package/src/msg/msg-sse-server.ts +3 -3
  418. package/src/msg/msg-store.ts +177 -19
  419. package/src/native-tool-catalog.ts +36 -2
  420. package/src/nexus/api/http-server.ts +37 -1
  421. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  422. package/src/nexus/index.ts +7 -2
  423. package/src/nexus/outbound/format.ts +9 -0
  424. package/src/nexus/outbound/router.ts +98 -13
  425. package/src/nexus/setup-status.ts +9 -0
  426. package/src/nexus/state/state.ts +3 -0
  427. package/src/oauth/codex-account-store.ts +20 -7
  428. package/src/oauth/codex-owner-mirror.ts +44 -0
  429. package/src/oauth/codex.ts +17 -2
  430. package/src/oauth/fallback-chain.ts +47 -17
  431. package/src/onboarding/first-run-doctor.ts +8 -1
  432. package/src/onboarding/first-run.ts +85 -26
  433. package/src/onboarding/key-setup.ts +103 -0
  434. package/src/onboarding/menu-answer.ts +13 -0
  435. package/src/onboarding/secret-prompt.ts +37 -0
  436. package/src/plugins/install/plugin-install.ts +59 -0
  437. package/src/pr-tool/census.ts +130 -0
  438. package/src/pty-shell/pty-control-ipc.ts +4 -1
  439. package/src/registry/catalog-server.ts +232 -0
  440. package/src/registry/loader.ts +45 -1
  441. package/src/registry/types.ts +1 -2
  442. package/src/research/axis-fanout.ts +43 -28
  443. package/src/self-dev/ask-launch-flow.ts +72 -1
  444. package/src/self-dev/dev-cli.ts +4 -1
  445. package/src/self-dev/dev-pipeline.ts +5 -0
  446. package/src/self-dev/draft-residue.ts +64 -5
  447. package/src/self-dev/graph-front-nodes.ts +2 -1
  448. package/src/self-dev/graph-journey-route.ts +76 -21
  449. package/src/self-dev/launch-preflight.ts +58 -0
  450. package/src/self-dev/orchestrate.ts +1 -1
  451. package/src/self-dev/shard-aggregate.ts +4 -0
  452. package/src/self-dev/shard-run.ts +36 -15
  453. package/src/self-implement/abandoned-classification.ts +12 -3
  454. package/src/self-implement/budget-gate.ts +7 -0
  455. package/src/self-implement/child-llm-preference.ts +10 -1
  456. package/src/self-implement/doctor-visit.ts +30 -8
  457. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  458. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  459. package/src/self-implement/gate-artifacts.ts +2 -1
  460. package/src/self-implement/goal-author-cli.ts +4 -2
  461. package/src/self-implement/goal-author.ts +358 -4
  462. package/src/self-implement/graph-overlay-yaml.ts +30 -4
  463. package/src/self-implement/graph-overlay.ts +3 -1
  464. package/src/self-implement/graph-profile-yaml.ts +107 -0
  465. package/src/self-implement/graph-yaml.ts +26 -3
  466. package/src/self-implement/off-diff-evidence.ts +249 -5
  467. package/src/self-implement/orchestrator.ts +240 -15
  468. package/src/self-implement/run-chart.ts +6 -3
  469. package/src/self-implement/run-ledger.ts +51 -1
  470. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  471. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  472. package/src/self-implement/train-gate-receipt.ts +166 -0
  473. package/src/self-implement/train-gate-remote.ts +62 -18
  474. package/src/session/chat.ts +4 -2
  475. package/src/session/session-fanout.ts +2 -0
  476. package/src/session/streaming/acp-stream-sink.ts +2 -1
  477. package/src/session/streaming/chunk-producer.ts +6 -0
  478. package/src/session/streaming/stream-compositor.ts +3 -2
  479. package/src/session-runtime/index.ts +37 -1
  480. package/src/session-runtime/retry-policy.ts +1 -1
  481. package/src/setup/llm-env-detect.ts +3 -0
  482. package/src/setup/service-key-catalog.ts +46 -0
  483. package/src/setup/service-keys.ts +241 -0
  484. package/src/sidetab-core/visible-agent-mission.ts +98 -22
  485. package/src/skills/tools/agent.ts +23 -4
  486. package/src/skills/tools/omni-search.ts +123 -25
  487. package/src/task-agent/parent-host.ts +10 -0
  488. package/src/task-agent/repair-outcomes.ts +65 -0
  489. package/src/task-agent/task-hand.ts +20 -7
  490. package/src/task-orchestrator/dispatcher.ts +14 -1
  491. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  492. package/src/task-orchestrator/store.ts +16 -5
  493. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +4 -0
  494. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +92 -1
  495. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  496. package/src/task-orchestrator/surfaces/pod-source-receive.ts +23 -11
  497. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  498. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +35 -9
  499. package/src/task-orchestrator/surfaces/self-implement-pod.ts +172 -6
  500. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  501. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  502. package/src/task-orchestrator/types.ts +14 -0
  503. package/src/telegram.ts +14 -16
  504. package/src/terminal/coding-agent.ts +14 -5
  505. package/src/terminal/session-registry.ts +1 -1
  506. package/src/tool-hints/gate.ts +1 -0
  507. package/src/tool-runtime/agent-runtime.ts +1 -0
  508. package/src/tool-runtime/browser-hand-runtime.ts +381 -0
  509. package/src/tool-runtime/browser-runtime.ts +2 -1
  510. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  511. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +57 -0
  512. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  513. package/src/tool-runtime/index.ts +6 -0
  514. package/src/tool-runtime/types.ts +3 -0
  515. package/src/tui/entry.ts +24 -1
  516. package/src/tui/sidetab/attach.ts +140 -11
  517. package/src/tui/sidetab/herdr-portal.ts +225 -0
  518. package/src/user-config.ts +34 -9
  519. package/src/user-intent/types.ts +4 -3
  520. package/src/ux-sim/browser-hand.ts +165 -0
  521. package/src/ux-sim/draft-inventory-builder.ts +198 -0
  522. package/src/ux-sim/fake-browser-page.ts +81 -0
  523. package/src/ux-sim/fake-linear-device.ts +31 -0
  524. package/src/ux-sim/graph-engine-sim.ts +47 -0
  525. package/src/ux-sim/linear-secretary.ts +216 -0
  526. package/src/ux-sim/mock-scenario-catalog.json +75 -23
  527. package/src/ux-sim/mock-scenario-catalog.ts +120 -2
  528. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  529. package/src/ux-sim/scenario.ts +70 -26
  530. package/src/ux-sim/service-key-setup.ts +50 -0
  531. package/src/ux-sim/term-slash-device.ts +74 -0
  532. package/src/ux-sim/turn-throw-sim.ts +31 -0
  533. package/src/version/packed-revision.json +1 -1
  534. package/src/web-search/exa.ts +77 -0
  535. package/src/web-search/index.ts +30 -9
  536. package/src/web-search/provider.ts +4 -1
  537. package/src/web-search/x-intent.ts +5 -0
  538. package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +0 -36
  540. package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +0 -32
  543. package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +0 -286
  548. package/apps/pwa/out/_next/static/chunks/2160.a097e7b138ae1c55.js +0 -23
  549. package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +0 -34
  552. package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/2974.595d1e29d040cb6a.js +0 -64
  557. package/apps/pwa/out/_next/static/chunks/3285.89ee2f298682f5e5.js +0 -93
  558. package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +0 -41
  559. package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +0 -24
  561. package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/3837.a210d7d0db8d8abd.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +0 -77
  567. package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
  572. package/apps/pwa/out/_next/static/chunks/5112.4b9f300124fab7b3.js +0 -149
  573. package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +0 -27
  575. package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/5885.0a3e52c8faccec98.js +0 -287
  583. package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +0 -226
  586. package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +0 -90
  587. package/apps/pwa/out/_next/static/chunks/6377.bc7df239edbff244.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +0 -104
  594. package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +0 -94
  595. package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/7279-c199ea83f34338fa.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +0 -24
  602. package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +0 -8
  610. package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/8546-6f03f8ea34dd61d9.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/9249.976f1e69a9d80754.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/9353-12bfff0c130104cf.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/9415.69e4a21c60c7d2db.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/9832.f4a98c878ecf2c0a.js +0 -62
  626. package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/9a852a62-6192a6ea9346ced3.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +0 -1
  684. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  685. /package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → Om5xS9jpjSXJCeTNGYEi4}/_ssgManifest.js +0 -0
@@ -1,23 +1,44 @@
1
1
  import type { Command } from 'commander';
2
2
  import { randomUUID } from 'node:crypto';
3
+ import { resolve } from 'node:path';
3
4
  import { effectiveInstanceRoot } from '../instance/resolve.js';
4
- import { addSource, canonicalSeat, dueSources, expiredSource, listSources, removeSource, runDue, type SourceKind } from '../intake-plane/intake-sources.js';
5
+ import { addSource, canonicalSeat, dueSources, expiredSource, listSources, removeSource, runDue, type RunDueDeps, type SourceKind } from '../intake-plane/intake-sources.js';
6
+ import { projectTopicBriefing, subscribeTopicSearch, type SubscribeTopicSearchInput } from '../intake-plane/actions.js';
7
+ import { runIntakeIssueBriefing } from '../intake-plane/actions.js';
5
8
 
6
- export function registerIntakeSourceCommands(intake: Command, root: () => string = effectiveInstanceRoot): void {
9
+ export function registerIntakeSourceCommands(intake: Command, root: () => string = effectiveInstanceRoot,
10
+ deps: { subscribeTopicSearch?: (input: SubscribeTopicSearchInput, options?: { stateDir?: string; runDeps?: RunDueDeps }) => ReturnType<typeof subscribeTopicSearch> } = {}): void {
7
11
  const source = intake.command('source').description('자리별 흡수 원천과 주기 등록·조회·실행');
8
12
  const fail = (error: unknown) => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 2; };
9
13
  source.command('add')
10
14
  .requiredOption('--seat <id>', '자리 id 또는 별칭')
11
- .requiredOption('--kind <kind>', 'github-query | rss | command')
15
+ .requiredOption('--kind <kind>', 'github-query | rss | command | topic-search')
12
16
  .requiredOption('--spec <spec>', 'GitHub 질의 · 피드 URL · 명령')
13
17
  .requiredOption('--every <cadence>', 'Nh | Nd | Nw')
14
18
  .option('--until <date>', '만료 시작 날짜 YYYY-MM-DD (UTC)')
15
19
  .option('--why <reason>', '등록 이유')
16
20
  .option('--id <id>', '원천 id')
17
- .action((opts: { seat: string; kind: string; spec: string; every: string; until?: string; why?: string; id?: string }) => {
21
+ .option('--linear-issue-id <uuid>', 'topic-search parent Linear issue UUID')
22
+ .option('--schedule-cron <expression>', 'topic-search schedule registry cron (e.g. 0 8 * * 1)')
23
+ .option('--telegram-dry-run-file <path>', 'Telegram 브리핑 본문을 이 파일에 기록하고 실제 발송은 하지 않음 (topic-search)')
24
+ .action(async (opts: { seat: string; kind: string; spec: string; every: string; until?: string; why?: string; id?: string; linearIssueId?: string; scheduleCron?: string; telegramDryRunFile?: string }) => {
18
25
  try {
26
+ if (opts.kind === 'topic-search') {
27
+ if (!opts.linearIssueId || !opts.scheduleCron) throw new Error('topic-search 는 --linear-issue-id 와 --schedule-cron 이 필요하다');
28
+ const telegramDryRunFile = opts.telegramDryRunFile ? resolve(opts.telegramDryRunFile) : undefined;
29
+ const result = await (deps.subscribeTopicSearch ?? subscribeTopicSearch)({ seat: opts.seat, topic: opts.spec,
30
+ linearIssueId: opts.linearIssueId, every: opts.every, scheduleCron: opts.scheduleCron,
31
+ ...(telegramDryRunFile ? { telegramDryRunFile } : {}) },
32
+ { stateDir: root(), runDeps: { projectTopicBriefing: telegramDryRunFile
33
+ ? (registered, items, stateDir) => projectTopicBriefing(registered, items, stateDir, { telegramDryRunFile })
34
+ : projectTopicBriefing } });
35
+ console.log(`${result.source.id} ${result.source.seat} topic-search ${result.source.every} schedule=${result.scheduleId} immediate=${result.immediate.ran.map(row => row.items).join(',')}`);
36
+ return;
37
+ }
19
38
  const added = addSource({ id: opts.id ?? `src-${randomUUID().slice(0, 8)}`, seat: opts.seat, kind: opts.kind as SourceKind,
20
- spec: opts.spec, every: opts.every, ...(opts.until ? { until: opts.until } : {}), ...(opts.why ? { why: opts.why } : {}) }, root());
39
+ spec: opts.spec, every: opts.every, ...(opts.until ? { until: opts.until } : {}), ...(opts.why ? { why: opts.why } : {}),
40
+ ...(opts.linearIssueId ? { linearIssueId: opts.linearIssueId } : {}),
41
+ ...(opts.scheduleCron ? { scheduleCron: opts.scheduleCron } : {}) }, root());
21
42
  console.log(`${added.id} ${added.seat} ${added.kind} ${added.every}`);
22
43
  } catch (error) { fail(error); }
23
44
  });
@@ -38,18 +59,33 @@ export function registerIntakeSourceCommands(intake: Command, root: () => string
38
59
  });
39
60
  source.command('run-due')
40
61
  .option('--seat <id>', '자리 id 또는 별칭')
62
+ .option('--source-id <id>', '단일 입력원만 실행 (스케줄 레지스트리 호출용)')
63
+ .option('--project-issue-briefing', 'topic-search 결과를 관련 Linear 이슈의 Telegram·코멘트에 투영')
64
+ .option('--telegram-dry-run-file <path>', 'Telegram 브리핑 본문을 이 파일에 기록하고 실제 발송은 하지 않음')
41
65
  .option('--dry-run', '기한 원천 목록만 · 수집·원장·마지막 실행 시각 무변')
42
66
  .option('--json', 'JSON 출력')
43
- .action(async (opts: { seat?: string; dryRun?: boolean; json?: boolean }) => {
67
+ .action(async (opts: { seat?: string; sourceId?: string; projectIssueBriefing?: boolean; telegramDryRunFile?: string; dryRun?: boolean; json?: boolean }) => {
44
68
  try {
45
69
  const seat = opts.seat === undefined ? undefined : canonicalSeat(opts.seat);
46
70
  if (opts.dryRun) {
47
- const sources = dueSources(new Date(), root()).filter((entry) => seat === undefined || entry.seat === seat);
71
+ const sources = dueSources(new Date(), root(), opts.sourceId).filter((entry) => seat === undefined || entry.seat === seat);
48
72
  if (opts.json) console.log(JSON.stringify(sources));
49
73
  else for (const entry of sources) console.log(`${entry.id} ${entry.seat} ${entry.kind} ${entry.every}`);
50
74
  return;
51
75
  }
52
- const result = await runDue({ seat, deps: { stateDir: root() } });
76
+ const telegramDryRunFile = opts.telegramDryRunFile ? resolve(opts.telegramDryRunFile) : undefined;
77
+ const result = await runDue({ seat, sourceId: opts.sourceId, deps: { stateDir: root(),
78
+ ...(opts.projectIssueBriefing || telegramDryRunFile ? { projectTopicBriefing: telegramDryRunFile
79
+ ? (registered, items, stateDir) => projectTopicBriefing(registered, items, stateDir, { telegramDryRunFile })
80
+ : projectTopicBriefing } : {}),
81
+ onCollected: async (source, raws) => {
82
+ if (!source.issueRef) return;
83
+ await runIntakeIssueBriefing({
84
+ issueRef: source.issueRef, topic: source.spec, state: 'open', collected: true,
85
+ evidence: raws.filter(raw => typeof raw.url === 'string' && raw.url.trim().length > 0)
86
+ .map(raw => ({ title: raw.title || source.spec, url: raw.url!, summary: raw.text || raw.title || source.spec })),
87
+ }, { stateDir: root() });
88
+ } } });
53
89
  if (opts.json) console.log(JSON.stringify(result));
54
90
  else for (const row of result.ran) console.log(`${row.id} ${row.items}${row.error ? ` 실패: ${row.error}` : ''}`);
55
91
  if (result.ran.some((row) => row.error)) process.exitCode = 1;
@@ -3,7 +3,7 @@ import { mkdirSync } from 'node:fs';
3
3
  import { dirname } from 'node:path';
4
4
  import { ensureAuthToken } from '../auth/acp-token.js';
5
5
  import { elanousStateRoot } from '../autopilot/state-paths.js';
6
- import { canonicalSeatId, openMsgStore, openMsgStoreReadOnly, type Message, type MsgStore } from '../msg/msg-store.js';
6
+ import { canonicalMessageAddress, canonicalSeatId, openMsgStore, openMsgStoreReadOnly, type Message, type MsgStore } from '../msg/msg-store.js';
7
7
  import { clearPostOffice, ensurePostOffice, writePostOffice } from '../msg/msg-post-office.js';
8
8
  import { acquireLockSync } from '../storage/file-lock.js';
9
9
  import { GitHubMsgMirrorTransport } from '../msg/msg-mirror-github.js';
@@ -325,7 +325,8 @@ export function registerMsgCommands(program: Command, deps: MsgCliDeps = {}): vo
325
325
  const from = seat(opts.from, '--from');
326
326
  const unsupported = opts.to === undefined ? null : unsupportedLoopAddressNotice(opts.to);
327
327
  if (unsupported) out.error(unsupported);
328
- const to = seat(opts.to, '--to');
328
+ if (opts.to === undefined) throw new Error('--to is required');
329
+ const to = canonicalMessageAddress(opts.to);
329
330
  // Validate the auto-reply target before saving — a mismatched flag must not leave a stored message behind.
330
331
  const agentAddress = agentReplyAddress(opts.agentReply);
331
332
  if (agentAddress !== null) requireAgentTarget(agentAddress, to);
@@ -364,7 +365,7 @@ export function registerMsgCommands(program: Command, deps: MsgCliDeps = {}): vo
364
365
  msg.command('route <address>').description('Show how a post to this address is read (replyBody) and woken (wake)')
365
366
  .option('--json')
366
367
  .action((address: string, opts: CommonOptions) => run(() => {
367
- const to = canonicalSeatId(address);
368
+ const to = canonicalMessageAddress(address);
368
369
  const wake = resolveWake(to, deps.wakeDeps);
369
370
  const row = { msgAddress: to, replyBody: messageRouteFor(to)?.replyBody ?? null, ...wake };
370
371
  emit(row, opts.json, () => out.log(`${to}\treplyBody=${row.replyBody ?? '모름'}\twake=${wake.wake}`
@@ -372,6 +373,34 @@ export function registerMsgCommands(program: Command, deps: MsgCliDeps = {}): vo
372
373
  + `\t(${wake.source}${wake.reason ? `: ${wake.reason}` : ''})`));
373
374
  })());
374
375
 
376
+ const group = msg.command('group').description('Manage local message group subscriptions');
377
+ group.command('create <name>').description('Create a group and subscribe its owner')
378
+ .requiredOption('--from <seat>', 'seat creating and owning the group').option('--json')
379
+ .action((name: string, opts: { from: string; json?: boolean }) => run(() => {
380
+ const address = withStore(store => store.createGroup(name, opts.from));
381
+ emit({ address, owner: canonicalSeatId(opts.from) }, opts.json, () => out.log(`${address} created; ${canonicalSeatId(opts.from)} subscribed`));
382
+ })());
383
+ group.command('join <name>').description('Subscribe a seat to a group')
384
+ .requiredOption('--seat <seat>').option('--json')
385
+ .action((name: string, opts: { seat: string; json?: boolean }) => run(() => {
386
+ const joined = withStore(store => store.joinGroup(name, opts.seat));
387
+ const row = { group: canonicalMessageAddress(name.startsWith('group:') ? name : `group:${name}`), seat: canonicalSeatId(opts.seat), joined };
388
+ emit(row, opts.json, () => out.log(`${row.seat} ${row.joined ? 'joined' : 'already subscribed'} ${row.group}`));
389
+ })());
390
+ group.command('leave <name>').description('Unsubscribe a seat from a group')
391
+ .requiredOption('--seat <seat>').option('--json')
392
+ .action((name: string, opts: { seat: string; json?: boolean }) => run(() => {
393
+ const left = withStore(store => store.leaveGroup(name, opts.seat));
394
+ const row = { group: canonicalMessageAddress(name.startsWith('group:') ? name : `group:${name}`), seat: canonicalSeatId(opts.seat), left };
395
+ emit(row, opts.json, () => out.log(`${row.seat} ${row.left ? 'left' : 'was not subscribed to'} ${row.group}`));
396
+ })());
397
+ group.command('list').description('List a seat’s active group subscriptions')
398
+ .requiredOption('--seat <seat>').option('--json')
399
+ .action((opts: { seat: string; json?: boolean }) => run(() => {
400
+ const groups = withStore(store => store.listGroups(opts.seat));
401
+ emit(groups, opts.json, () => { if (!groups.length) out.log('No groups.'); else for (const address of groups) out.log(address); });
402
+ })());
403
+
375
404
  msg.command('list').description('List messages for one recipient or one thread without acknowledging them')
376
405
  .option('--to <seat>').option('--thread <id>', 'request ID; list it and its replies, regardless of recipient')
377
406
  .option('--after <id>', 'exclusive message ID (default: acknowledged cursor for a recipient, 0 for a thread)')
package/src/cli/pr-cli.ts CHANGED
@@ -37,6 +37,7 @@ import {
37
37
  type CmdRunner,
38
38
  type PrManager,
39
39
  } from '../autopilot/pr-manager.js';
40
+ import { observePrLineage } from '../pr-tool/census.js';
40
41
  import {
41
42
  collectBaseLandingCommits,
42
43
  computeGranularityStats,
@@ -68,6 +69,7 @@ import { ensurePrLandHeavyRemote, type HeavyRemoteInput, type HeavyRemoteResult
68
69
  import { readPrBaseNameWithRetry } from './pr-land-base-read.js';
69
70
  import { runHeavyOnPodShadow } from './pr-land-pod-shadow.js';
70
71
  import type { LandingPodShadowInput, LandingPodShadowVerdict } from './pr-land-pod-shadow-job.js';
72
+ import { recordWarmReuseEvidence, warmReuseEvidencePath } from '../task-orchestrator/surfaces/warm-reuse-evidence.js';
71
73
  import { readTaskAgentState, taskAgentStatePath, type TaskCard } from '../task-agent/task-hand.js';
72
74
  import { INFLIGHT_REGISTRY_FILE, removeInflightForPr } from '../pr-tool/inflight-registry.js';
73
75
  import { PR_LABEL_NAMES } from '../github/pr-labels.js';
@@ -1899,10 +1901,19 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1899
1901
  local: { measured: verdict.rootPlan != null, ok: verdict.ok, rootPlan: verdict.rootPlan ?? null },
1900
1902
  runPod: async () => {
1901
1903
  const runPod = deps.runLandingPodShadow ?? (await import('./pr-land-pod-shadow-job.js')).runLandingPodShadowJob;
1902
- return runPod({ head: opts.expectedHead!, main });
1904
+ return runPod({ pr: Number(opts.pr), repo: cwd, host: verdict.host ?? '', head: opts.expectedHead!, main });
1903
1905
  },
1904
1906
  log: (category, event, data) => debug.log(category, event, { ...data, main, phase: 'initial' }),
1905
1907
  warn: (message) => out.error(`⚠ heavy-on-pod-shadow: ${message}`),
1908
+ onShadow: ({ pod, agree }) => {
1909
+ const shadow = pod && typeof pod === 'object' ? pod as LandingPodShadowVerdict : undefined;
1910
+ const warm = shadow?.warmEvidence;
1911
+ recordWarmReuseEvidence(warmReuseEvidencePath(), {
1912
+ schema: 1, consumer: 'land', pr: Number(opts.pr), head: opts.expectedHead!, main, recordedAt: new Date().toISOString(),
1913
+ ...(warm ? { ...warm, agree: warm.agree && agree } : {}),
1914
+ ...(!warm ? { reason: shadow?.warmReason ?? 'warm-shadow-unmeasured' } : {}),
1915
+ });
1916
+ },
1906
1917
  });
1907
1918
  }
1908
1919
  }
@@ -2536,6 +2547,15 @@ export function registerPrCommands(program: Command, deps: PrLandDeps = {}, queu
2536
2547
  try { await supersedeMerged(number, opts.cwd ?? process.cwd()); }
2537
2548
  catch (error) { prToolOut.error(`✗ supersede-drafts: ${String(error)}`); prToolExit(1); }
2538
2549
  });
2550
+ pr.command('lineage <pr>')
2551
+ .description('PR 계보의 관측 사실만 JSON으로 읽기 (첫 조각 · 닫기 판정 없음)')
2552
+ .requiredOption('--json', 'JSON 관측 결과 출력')
2553
+ .option('--cwd <path>', '저장소 경로')
2554
+ .action((rawPr: string, opts: { cwd?: string }) => {
2555
+ const result = observePrLineage({ pr: Number(rawPr), run: prToolRun, cwd: opts.cwd });
2556
+ prToolOut.log(JSON.stringify(result));
2557
+ if (result.status === 'unknown') prToolExit(1);
2558
+ });
2539
2559
  pr.command('census')
2540
2560
  .description('열린 PR 전체·골 문서만·2일 무커밋 draft·미닫힌 superseded 집계')
2541
2561
  .option('--cwd <path>', '저장소 경로')
@@ -8,6 +8,7 @@ import { debug, redactSecretText } from '../debug/log.js';
8
8
  import { gateRemoteHostCap, realGateRemoteRunner, resolveGateRemoteSettings, runOnRemote, type GateRemoteRunner, type RemoteRunOutcome } from '../self-implement/gate-remote.js';
9
9
  import { decideWarmReuse, type WarmReuseEvidenceByConsumer, type WarmReuseSwitchConfig } from '../task-orchestrator/surfaces/pod-warm-switch.js';
10
10
  import { buildLandWarmEvidence, type LandShadowSampleWindow } from './pr-land-pod-shadow-job.js';
11
+ import { readWarmReuseEvidence, warmReuseEvidencePath, type WarmReuseEvidenceRow } from '../task-orchestrator/surfaces/warm-reuse-evidence.js';
11
12
 
12
13
  const SHA = /^[0-9a-f]{40}$/i;
13
14
  // This is the stable fallback order when settings.host is unavailable; an explicitly configured allowlisted host
@@ -18,7 +19,7 @@ export type PrLandHeavyHost = typeof PR_LAND_HEAVY_HOSTS[number];
18
19
  const allowedHost = (host: string): host is PrLandHeavyHost => PR_LAND_HEAVY_HOSTS.some((candidate) => candidate === host);
19
20
 
20
21
  export interface HeavyRemoteEvidence {
21
- schema: 2;
22
+ schema: 3;
22
23
  pr: number;
23
24
  head: string;
24
25
  main: string;
@@ -72,6 +73,42 @@ export interface HeavyRemoteDeps {
72
73
  warmReuseConfig?: () => WarmReuseSwitchConfig | undefined;
73
74
  /** WARM-REUSE-LAND-CONSUMER-WIRE — land shadow Job 결과 창 seam(기본 없음 = 증거 없음 = off). */
74
75
  landShadowSamples?: () => LandShadowSampleWindow | undefined;
76
+ /** Durable shadow journal reader seam. */
77
+ readWarmEvidence?: (identity: { consumer: 'land' | 'gate-recheck'; pr: number; head: string; main: string }) => WarmReuseEvidenceRow[] | undefined;
78
+ warmEvidencePath?: () => string;
79
+ }
80
+
81
+ function journalLandShadowSamples(input: HeavyRemoteInput, deps: HeavyRemoteDeps): LandShadowSampleWindow | undefined {
82
+ const read = deps.readWarmEvidence ?? ((identity) => readWarmReuseEvidence(
83
+ (deps.warmEvidencePath ?? warmReuseEvidencePath)(), identity));
84
+ const rows = read({ consumer: 'land', pr: input.pr, head: input.head, main: input.main });
85
+ if (!rows?.length) return undefined;
86
+ const samples = rows.map((row) => ({ head: row.head, main: row.main,
87
+ lock: row.expectedLockHash ?? '', leaseValid: row.leaseValid === true && !!row.leaseId && !!row.workerId
88
+ && row.generation !== undefined && row.expectedLockHash === row.workerLockHash,
89
+ canaryPassed: row.canaryPassed === true, agree: row.agree === true }));
90
+ const latest = rows[rows.length - 1]!;
91
+ const gateRows = read({ consumer: 'gate-recheck', pr: input.pr, head: input.head, main: input.main });
92
+ let gateRecheck: LandShadowSampleWindow['gateRecheck'];
93
+ if (gateRows?.length) {
94
+ let consecutiveMatchSamples = 0;
95
+ for (let i = gateRows.length - 1; i >= 0; i--) {
96
+ const row = gateRows[i]!;
97
+ if (row.workerId !== latest.workerId || row.expectedLockHash !== latest.expectedLockHash
98
+ || row.workerLockHash !== row.expectedLockHash || row.leaseValid !== true
99
+ || !row.leaseId || row.generation === undefined
100
+ || row.canaryPassed !== true || row.agree !== true) break;
101
+ consecutiveMatchSamples++;
102
+ }
103
+ const latestGate = gateRows[gateRows.length - 1]!;
104
+ gateRecheck = { consecutiveMatchSamples, recentMismatchCount: gateRows.filter((row) => row.agree === false).length,
105
+ leaseValid: latestGate.leaseValid === true && !!latestGate.leaseId && !!latestGate.workerId && latestGate.generation !== undefined,
106
+ canaryPassed: latestGate.canaryPassed === true,
107
+ expected: { head: input.head, main: input.main, lock: latestGate.expectedLockHash },
108
+ worker: { head: input.head, main: input.main, lock: latestGate.workerLockHash } };
109
+ }
110
+ const lock = latest.expectedLockHash ?? '';
111
+ return { samples, lock, ...(gateRecheck ? { gateRecheck } : {}) };
75
112
  }
76
113
 
77
114
  function evidencePath(input: HeavyRemoteInput): string {
@@ -83,7 +120,7 @@ function validRootPlan(value: unknown): value is RootPlanSummary | null {
83
120
  if (!value || typeof value !== 'object') return false;
84
121
  const plan = value as Partial<RootPlanSummary>;
85
122
  return (plan.mode === 'affected' || plan.mode === 'full')
86
- && (plan.roots === null || (Number.isSafeInteger(plan.roots) && plan.roots >= 0))
123
+ && (plan.roots === null || (typeof plan.roots === 'number' && Number.isSafeInteger(plan.roots) && plan.roots >= 0))
87
124
  && typeof plan.promoted === 'boolean'
88
125
  && (plan.reason === null || typeof plan.reason === 'string');
89
126
  }
@@ -92,7 +129,7 @@ function matchingEvidence(path: string, input: HeavyRemoteInput): HeavyRemoteEvi
92
129
  if (!existsSync(path)) return null;
93
130
  try {
94
131
  const data: HeavyRemoteEvidence = JSON.parse(readFileSync(path, 'utf8'));
95
- return data.schema === 2 && data.pr === input.pr && data.head === input.head
132
+ return data.schema === 3 && data.pr === input.pr && data.head === input.head
96
133
  && data.main === input.main && allowedHost(data.host) && Number.isFinite(data.elapsedMs)
97
134
  && typeof data.interferenceMeasured === 'boolean' && validRootPlan(data.rootPlan) ? data : null;
98
135
  } catch { return null; }
@@ -232,7 +269,8 @@ export function ensurePrLandHeavyRemote(input: HeavyRemoteInput, deps: HeavyRemo
232
269
  }
233
270
  try {
234
271
  warmStage = 'evidence';
235
- warmEvidence = buildLandWarmEvidence(deps.landShadowSamples?.(), { head: input.head, main: input.main });
272
+ const samples = deps.landShadowSamples ? deps.landShadowSamples() : journalLandShadowSamples(input, deps);
273
+ warmEvidence = buildLandWarmEvidence(samples, { head: input.head, main: input.main });
236
274
  } catch (error) {
237
275
  debug.log('pod.warm', 'land-shadow-unavailable', {
238
276
  pr: input.pr, stage: warmStage, reason: 'warm-evidence-read-failed',
@@ -266,7 +304,7 @@ export function ensurePrLandHeavyRemote(input: HeavyRemoteInput, deps: HeavyRemo
266
304
  // then run typecheck and self gate (changed tests and PWA reach/build) at that exact pair.
267
305
  // The detached integration commit stays on the selected host and never changes the PR branch.
268
306
  argv: (sha) => ['sh', '-c',
269
- 'git -c user.name=elanous-gate -c user.email=gate@localhost -c commit.gpgsign=false merge --no-ff --no-edit "$1" && TSC_BASE_REF="$1" bun run scripts/ci-typecheck-changed.ts --local && bun bin/elanous.mjs self gate --changed --base "$1" --local --shards 4 && bun scripts/pr-land-extra-remote-gates.ts "$1"',
307
+ 'git -c user.name=elanous-gate -c user.email=gate@localhost -c commit.gpgsign=false merge --no-ff --no-edit "$1" && bash scripts/ci-typecheck-main-delta.sh "$1" && bun bin/elanous.mjs self gate --changed --base "$1" --local --shards 4 && bun scripts/pr-land-extra-remote-gates.ts "$1"',
270
308
  'sh', sha(input.main)],
271
309
  }, deps.runner ?? realGateRemoteRunner);
272
310
  } catch (error) {
@@ -309,7 +347,7 @@ export function ensurePrLandHeavyRemote(input: HeavyRemoteInput, deps: HeavyRemo
309
347
  return { ok: false, host: selectedHost, attemptedHost: selectedHost, source: 'unmeasured', reason, elapsedMs, evidencePath: path, ...(failureLogPath ? { failureLogPath } : {}) };
310
348
  }
311
349
  const evidence: HeavyRemoteEvidence = {
312
- schema: 2, pr: input.pr, head: input.head, main: input.main, host: selectedHost,
350
+ schema: 3, pr: input.pr, head: input.head, main: input.main, host: selectedHost,
313
351
  passedAt: new Date().toISOString(), elapsedMs: outcome.ms, rootPlan: rootPlanFromOutput(outcome.stdout),
314
352
  interferenceMeasured: extraGates.interferenceMeasured,
315
353
  };
@@ -14,6 +14,9 @@
14
14
  * ③ 리뷰 — 증거가 가리키는 `review-results/<card>-<pr>-<head접두 10~40>.json`(TA 가 받는 `self review --json` stdout)이
15
15
  * 파일명에서 같은 PR·머리 접두이고 내용에서 전체 PR·머리가 정확히 같으며 `reviewed:true` · `verdict ∈ {pass, warn}` · must-fix 가 «잰 수» 0 인가
16
16
  * (자동 병합 canAuto · TA-LAND-WARN-MUSTFIX0 과 같은 규칙 — must-fix 를 못 셌으면 거부).
17
+ * ③' 공급자(PRLAND-ACP-CLAUDE-ALLOW) — 백엔드가 `acp:claude`(또는 `acp:claude/…`, acp-fallback+`claude`)인 리뷰도
18
+ * ③ 을 만족하고 «같은 머리의 선택된 리뷰» 이면 착지 증거다. 같은 머리의 실패한 금지 리뷰는 후보에서
19
+ * superseded 로 제외되고(supersedes 장부), 유효한 같은-머리 리뷰가 없으면 종전처럼 거부한다(fail-closed).
17
20
  * ⓐ 이미 조상(TC #26019 실측) — 겹친 최근 착지 커밋이 «전부» 고정 머리의 조상이면 그 겹침은 이미 그 머리의 게이트·리뷰에
18
21
  * 반영됐다 ⇒ ①② 없이 ③ 만으로 통과(관측 reason `already-ancestor`). 하나라도 조상이 아니면 ①②③ 전부.
19
22
  * ⓐ' 증거 파일이 없을 때(`verifyAncestorAutoPass`) — 같은 ⓐ 를 표준 자리 `review-results/*-<pr>-<head접두 10~40>.json` 만으로 잰다
@@ -453,6 +456,7 @@ function checkReview(input: Pick<VerifyOverlapEvidenceInput, 'pr' | 'readFile'>
453
456
  if (!review.head || review.head.toLowerCase() !== reviewHead) return { ok: false, reason: 'review-head-mismatch', baseTip };
454
457
  // The capture parser projects away model provenance; inspect the same last result-shaped line here.
455
458
  const raw = lastReviewRecord(text);
459
+ let acpClaudeEvidence: { actualBackend: string; model: string; reviewRoute: string } | undefined;
456
460
  if (raw) {
457
461
  if (raw.reviewer === 'OP-waiver') {
458
462
  const waiver = validOpWaiver(raw, input.pr, head);
@@ -463,10 +467,15 @@ function checkReview(input: Pick<VerifyOverlapEvidenceInput, 'pr' | 'readFile'>
463
467
  const route = typeof raw.reviewRoute === 'string' ? raw.reviewRoute.trim().toLowerCase() : '';
464
468
  const respondedProvider = typeof raw.respondedProvider === 'string' ? raw.respondedProvider.trim().toLowerCase() : '';
465
469
  const respondedModel = typeof raw.respondedModel === 'string' ? raw.respondedModel.trim().toLowerCase() : '';
470
+ // PRLAND-ACP-CLAUDE-ALLOW — `acp:claude` is no longer refused outright. A review that satisfies
471
+ // the landing contract below (same PR/head, reviewed, pass|warn, counted must-fix 0) is evidence
472
+ // whatever backend produced it; a failed acp:claude attempt is excluded by the same-head
473
+ // supersedes ledger instead of blocking every landing. This note records the provenance only —
474
+ // the contract below still decides, so an invalid or other-head acp:claude review stays rejected.
466
475
  if (actualBackend === 'acp:claude' || actualBackend.startsWith('acp:claude/')
467
476
  || model === 'acp:claude' || model.startsWith('acp:claude/')
468
477
  || ((route === 'acp' || route === 'acp-fallback') && typeof raw.fallbackBackend === 'string' && raw.fallbackBackend.trim().toLowerCase() === 'claude')) {
469
- return { ok: false, reason: 'review-forbidden-acp-claude', baseTip };
478
+ acpClaudeEvidence = { actualBackend, model, reviewRoute: route };
470
479
  }
471
480
  const requested = typeof raw.requestedModel === 'string' ? raw.requestedModel.trim().toLowerCase() : '';
472
481
  if (requested) {
@@ -490,6 +499,9 @@ function checkReview(input: Pick<VerifyOverlapEvidenceInput, 'pr' | 'readFile'>
490
499
  if (review.reviewed !== true) return { ok: false, reason: 'review-not-reviewed', baseTip };
491
500
  if (review.verdict === null || !ACCEPTED_REVIEW_VERDICTS.has(review.verdict)) return { ok: false, reason: `review-verdict-${review.verdict ?? 'null'}`, baseTip };
492
501
  if (review.mustFix !== 0) return { ok: false, reason: review.mustFix === null ? 'review-must-fix-unknown' : `review-must-fix-${review.mustFix}`, baseTip };
502
+ if (acpClaudeEvidence) {
503
+ debug.log('pr.land', 'review-acp-claude-accepted', { pr: input.pr, head, reviewResult: e.reviewResult, ...acpClaudeEvidence });
504
+ }
493
505
  if (carry) {
494
506
  if (!input.cwd || !input.remote || !input.branch) return { ok: false, reason: 'carry-repo-unmeasured', baseTip };
495
507
  const digest = createHash('sha256').update(text).digest('hex');
@@ -3,8 +3,15 @@ import { readFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { runPodCommand, type RunPodCommandOptions, type PodCommandResult } from '../task-orchestrator/surfaces/pod-command-job.js';
5
5
  import { redactSecretText } from '../debug/log.js';
6
+ import { getUserConfig } from '../user-config.js';
6
7
  import type { RootPlanSummary } from './pr-land-heavy-remote.js';
7
- import type { WarmReuseEvidence, WarmReuseEvidenceByConsumer } from '../task-orchestrator/surfaces/pod-warm-switch.js';
8
+ import type { WarmReuseEvidence, WarmReuseEvidenceByConsumer, WarmReuseSwitchConfig } from '../task-orchestrator/surfaces/pod-warm-switch.js';
9
+ import { requestWarmPodReplay, finalizeWarmPodReplay, quarantineWarmPodReplay } from '../task-orchestrator/surfaces/pod-warm-worker-provider.js';
10
+ import { assessWarmWorkerShadow, type WarmWorkerFileResult } from '../task-orchestrator/surfaces/pod-warm-worker-protocol.js';
11
+ import { writeWarmJobManifest, warmReferenceFromJobArtifacts } from '../../scripts/release-loop/gate-warm-artifacts.js';
12
+ import type { ActualWarmLeaseEvidence } from '../task-orchestrator/surfaces/warm-reuse-evidence.js';
13
+ import { randomUUID } from 'node:crypto';
14
+ import { spawnSync } from 'node:child_process';
8
15
 
9
16
  const SHA = /^[0-9a-f]{40}$/i;
10
17
  const MARKER = 'ELANOUS_PRLAND_SHADOW';
@@ -12,7 +19,7 @@ const MARKER = 'ELANOUS_PRLAND_SHADOW';
12
19
  export const LANDING_POD_SHADOW_HOST_TIMEOUT_MS = 10 * 60_000;
13
20
  export const LANDING_POD_SHADOW_STATUS_UNREADABLE_MS = 60_000;
14
21
 
15
- export interface LandingPodShadowInput { head: string; main: string }
22
+ export interface LandingPodShadowInput { pr?: number; repo?: string; host?: string; head: string; main: string }
16
23
  export interface LandingPodShadowVerdict {
17
24
  measured: boolean;
18
25
  ok: boolean;
@@ -21,9 +28,26 @@ export interface LandingPodShadowVerdict {
21
28
  gateRc?: number;
22
29
  reason?: string;
23
30
  job?: string;
31
+ /** Warm evidence only exists after a real worker lease and exact per-file comparison. */
32
+ warmEvidence?: ActualWarmLeaseEvidence;
33
+ warmReason?: string;
34
+ warmTestFiles?: string[];
24
35
  }
25
36
 
26
- export function landingPodShadowScript(head: string, main: string): string {
37
+ const LAND_TEST_PATH = /^(?:[A-Za-z0-9_-][A-Za-z0-9_.-]*\/)*[A-Za-z0-9_-][A-Za-z0-9_.-]*\.test\.tsx?$/;
38
+ export const LAND_WARM_CANARY_TIMEOUT_MS = 5 * 60_000;
39
+
40
+ /** Changed test files are the bounded canary scope; no test file means no warm evidence. */
41
+ export function changedLandWarmTestFiles(repo: string, head: string, main: string): string[] {
42
+ if (!SHA.test(head) || !SHA.test(main)) return [];
43
+ const result = spawnSync('git', ['-C', repo, 'diff', '--name-only', '--diff-filter=ACMR', `${main}...${head}`], {
44
+ encoding: 'utf8', timeout: 15_000, maxBuffer: 2 * 1024 * 1024,
45
+ });
46
+ if (result.status !== 0) return [];
47
+ return [...new Set(result.stdout.split(/\r?\n/).filter((path) => LAND_TEST_PATH.test(path)))].sort();
48
+ }
49
+
50
+ export function landingPodShadowScript(head: string, main: string, afterGate = ''): string {
27
51
  if (!SHA.test(head) || !SHA.test(main)) throw new Error('pod shadow: invalid head/main');
28
52
  return [
29
53
  'set -u',
@@ -39,17 +63,117 @@ export function landingPodShadowScript(head: string, main: string): string {
39
63
  `printf '${MARKER}_TSC_PLAN %s\\n' "$(grep '^\\[tsc-gate\\] root-plan ' /tmp/prland-shadow-tsc.log | tail -n 1 | sed 's/^\\[tsc-gate\\] root-plan //')"`,
40
64
  "tail -n 8 /tmp/prland-shadow-tsc.log; tail -n 8 /tmp/prland-shadow-gate.log",
41
65
  `printf '${MARKER} head=%s main=%s tsc=%s gate=%s\\n' '${head}' '${main}' "$tsc_rc" "$gate_rc"`,
66
+ ...(afterGate ? [afterGate] : []),
42
67
  'exit 0',
43
68
  ].join('\n');
44
69
  }
45
70
 
71
+ function landWarmColdTestScript(files: readonly string[], head: string, attemptId: string): string {
72
+ if (files.some((file) => !LAND_TEST_PATH.test(file)) || !SHA.test(head) || !/^[0-9a-f-]{36}$/i.test(attemptId))
73
+ throw new Error('pod shadow: invalid warm test scope');
74
+ return files.map((file, index) => {
75
+ const prefix = `"$HOME/outbox/pr-land-warm/${index}"`;
76
+ const quotedFile = `'${file}'`;
77
+ return [
78
+ `mkdir -p "$HOME/outbox/pr-land-warm"`,
79
+ `bun test --reporter=junit --reporter-outfile=${prefix}.junit.xml ${quotedFile} >${prefix}.log 2>&1`,
80
+ 'test_rc=$?',
81
+ `printf '%s' "$test_rc" >${prefix}.rc`,
82
+ `printf '{"commit":"${head}","attemptId":"${attemptId}","files":["${file}"],"rc":%s,"jobFailed":false,"jobExitCode":0}\n' "$test_rc" >${prefix}.json`,
83
+ `printf '[warm-worker] file=%s\\n[warm-worker] cut=%s attempt=%s\\n' '${file}' '${head}' '${attemptId}' >${prefix}.log.stamped`,
84
+ `cat ${prefix}.log >>${prefix}.log.stamped`,
85
+ `printf '\\n[warm-worker] junit-sha256=%s\\n' "$(sha256sum ${prefix}.junit.xml 2>/dev/null | cut -d' ' -f1)" >>${prefix}.log.stamped`,
86
+ `mv ${prefix}.log.stamped ${prefix}.log`,
87
+ ].join('\n');
88
+ }).join('\n');
89
+ }
90
+
91
+ async function runWarmLandCanary(input: {
92
+ pr: number; head: string; main: string; host: string; repo: string;
93
+ job: PodCommandResult; files: readonly string[]; attemptId: string; coldGatePassed: boolean;
94
+ timeoutMs?: number;
95
+ readReference?: typeof warmReferenceFromJobArtifacts;
96
+ requestWarm?: typeof requestWarmPodReplay;
97
+ finalizeWarm?: typeof finalizeWarmPodReplay;
98
+ quarantineWarm?: typeof quarantineWarmPodReplay;
99
+ warmConfig?: () => WarmReuseSwitchConfig | undefined;
100
+ }): Promise<{ warmEvidence?: ActualWarmLeaseEvidence; reason: string }> {
101
+ let config: WarmReuseSwitchConfig | undefined;
102
+ try { config = input.warmConfig ? input.warmConfig() : getUserConfig().pod?.warmReuse; }
103
+ catch { return { reason: 'warm-config-unavailable' }; }
104
+ if (input.host !== 'node-b') return { reason: 'canary-host-mismatch' };
105
+ if (config?.land !== true) return { reason: 'land-canary-flag-off' };
106
+ if (!input.files.length) return { reason: 'changed-test-files-unmeasured' };
107
+ const coldFiles = input.files.map((file, index) => {
108
+ const prefix = join(input.job.artifactsDir, 'outbox', 'pr-land-warm', String(index));
109
+ const writeManifest = writeWarmJobManifest(prefix, file, input.head, input.attemptId);
110
+ return writeManifest ? (input.readReference ?? warmReferenceFromJobArtifacts)(prefix, file,
111
+ { cutSha: input.head, attemptId: input.attemptId }) : null;
112
+ });
113
+ if (coldFiles.some((row) => row === null)) return { reason: 'cold-reference-unmeasured' };
114
+ const requestWarm = input.requestWarm ?? requestWarmPodReplay;
115
+ let replay;
116
+ const timeoutMs = input.timeoutMs ?? LAND_WARM_CANARY_TIMEOUT_MS;
117
+ const request = requestWarm({ protocol: 1, runId: `land-${input.pr}-${input.head.slice(0, 8)}`,
118
+ attemptId: input.attemptId, cutSha: input.head, baselineSha: input.main,
119
+ deadlineAt: Date.now() + timeoutMs, files: [...input.files], envProfile: 'gate-v1' });
120
+ const timedOut = Symbol('warm-canary-timeout');
121
+ let timer: ReturnType<typeof setTimeout> | undefined;
122
+ try {
123
+ const raced = await Promise.race([request, new Promise<typeof timedOut>((resolve) => {
124
+ timer = setTimeout(() => resolve(timedOut), timeoutMs);
125
+ })]);
126
+ if (raced === timedOut) {
127
+ // The provider API has no AbortSignal yet. Fence any late lease as soon as it arrives.
128
+ void request.then(async (late) => {
129
+ if (late.command) await (input.quarantineWarm ?? quarantineWarmPodReplay)(late.command, 'land-shadow-late-after-timeout');
130
+ }).catch(() => {});
131
+ return { reason: 'warm-request-timeout' };
132
+ }
133
+ replay = raced;
134
+ } catch (error) { return { reason: `warm-request-failed:${error instanceof Error ? error.name : 'unknown'}` }; }
135
+ finally { if (timer) clearTimeout(timer); }
136
+ const command = replay.command;
137
+ if (!command) return { reason: replay.transport.reason ?? 'warm-lease-unmeasured' };
138
+ const decision = assessWarmWorkerShadow(command, coldFiles as WarmWorkerFileResult[], replay.transport.reply);
139
+ const matched = decision.reason === 'match';
140
+ let leaseValid = replay.transport.status === 'observed' && replay.transport.reason === 'complete';
141
+ try {
142
+ if (matched) await (input.finalizeWarm ?? finalizeWarmPodReplay)(command);
143
+ else { leaseValid = false; await (input.quarantineWarm ?? quarantineWarmPodReplay)(command, `land-shadow-${decision.reason}`); }
144
+ } catch { leaseValid = false; }
145
+ // The reply is the worker-side observation. Falling back to the host's requested key
146
+ // would turn a missing worker identity into a false positive comparison.
147
+ const workerLockHash = replay.transport.reply?.key?.lockHash;
148
+ if (!command.leaseId || !Number.isSafeInteger(command.generation) || command.generation < 1
149
+ || !command.key.lockHash || !workerLockHash) return { reason: 'warm-lease-identity-unmeasured' };
150
+ return { reason: decision.reason, warmEvidence: {
151
+ workerId: command.workerId,
152
+ leaseId: command.leaseId, generation: command.generation,
153
+ expectedLockHash: command.key.lockHash, workerLockHash,
154
+ leaseValid, canaryPassed: matched && leaseValid && input.coldGatePassed, agree: matched,
155
+ } };
156
+ }
157
+
46
158
  export async function runLandingPodShadowJob(input: LandingPodShadowInput, deps: {
47
159
  runPod?: (options: RunPodCommandOptions) => Promise<PodCommandResult>;
48
160
  readLog?: (path: string) => string;
49
161
  /** Deterministic timer seam for the host deadline. */
50
162
  armTimeout?: (onTimeout: () => void, ms: number) => () => void;
163
+ testFiles?: readonly string[];
164
+ warmReplay?: typeof requestWarmPodReplay;
165
+ finalizeWarm?: typeof finalizeWarmPodReplay;
166
+ quarantineWarm?: typeof quarantineWarmPodReplay;
167
+ readReference?: typeof warmReferenceFromJobArtifacts;
168
+ warmConfig?: () => WarmReuseSwitchConfig | undefined;
169
+ warmTimeoutMs?: number;
51
170
  } = {}): Promise<LandingPodShadowVerdict> {
52
- const script = landingPodShadowScript(input.head, input.main);
171
+ let warmConfig: WarmReuseSwitchConfig | undefined;
172
+ try { warmConfig = deps.warmConfig ? deps.warmConfig() : getUserConfig().pod?.warmReuse; } catch { /* no warm launch without readable config */ }
173
+ const canaryEnabled = input.host === 'node-b' && warmConfig?.land === true;
174
+ const files = canaryEnabled ? deps.testFiles ?? (input.repo ? changedLandWarmTestFiles(input.repo, input.head, input.main) : []) : [];
175
+ const attemptId = randomUUID();
176
+ const script = landingPodShadowScript(input.head, input.main, landWarmColdTestScript(files, input.head, attemptId));
53
177
  const controller = new AbortController();
54
178
  const armTimeout = deps.armTimeout ?? ((onTimeout: () => void, ms: number) => {
55
179
  const timer = setTimeout(onTimeout, ms);
@@ -106,7 +230,21 @@ export async function runLandingPodShadowJob(input: LandingPodShadowInput, deps:
106
230
  if (!rootPlan) return { measured: false, ok: false, rootPlan: null, reason: 'root-plan-missing', job: job.job };
107
231
  const tscRc = Number(match[1]);
108
232
  const gateRc = Number(match[2]);
109
- return { measured: true, ok: tscRc === 0 && gateRc === 0, rootPlan, tscRc, gateRc, job: job.job };
233
+ const verdict: LandingPodShadowVerdict = { measured: true, ok: tscRc === 0 && gateRc === 0, rootPlan, tscRc, gateRc, job: job.job,
234
+ ...(files.length ? { warmTestFiles: [...files] } : {}) };
235
+ if (input.pr && input.repo && input.host) {
236
+ const warm = await runWarmLandCanary({ pr: input.pr, head: input.head, main: input.main, host: input.host,
237
+ repo: input.repo, job, files, attemptId, coldGatePassed: verdict.ok,
238
+ ...(deps.warmTimeoutMs !== undefined ? { timeoutMs: deps.warmTimeoutMs } : {}),
239
+ ...(deps.readReference ? { readReference: deps.readReference } : {}),
240
+ ...(deps.warmReplay ? { requestWarm: deps.warmReplay } : {}),
241
+ ...(deps.finalizeWarm ? { finalizeWarm: deps.finalizeWarm } : {}),
242
+ ...(deps.quarantineWarm ? { quarantineWarm: deps.quarantineWarm } : {}),
243
+ warmConfig: () => warmConfig });
244
+ verdict.warmReason = warm.reason;
245
+ if (warm.warmEvidence) verdict.warmEvidence = warm.warmEvidence;
246
+ }
247
+ return verdict;
110
248
  }
111
249
 
112
250
  /** WARM-REUSE-LAND-CONSUMER-WIRE — land shadow Job 결과 표본(착지쌍·lock·lease·카나리아·그림자 일치). */
@@ -15,6 +15,8 @@ export interface HeavyOnPodShadowInput<T> {
15
15
  runPod: () => T | Promise<T>;
16
16
  log: (category: string, event: string, data: Record<string, unknown>) => void;
17
17
  warn: (message: string) => void;
18
+ /** Evidence persistence is best effort; it must never change the cold landing verdict. */
19
+ onShadow?: (observation: { pod: unknown; agree: boolean }) => void;
18
20
  }
19
21
 
20
22
  function agree(local: unknown, pod: unknown): boolean {
@@ -38,22 +40,25 @@ function elapsedMs(started: number): number {
38
40
  }
39
41
 
40
42
  export async function runHeavyOnPodShadow<T>(input: HeavyOnPodShadowInput<T>): Promise<T> {
41
- const { enabled, pr, head, local, runPod, log, warn } = input;
43
+ const { enabled, pr, head, local, runPod, log, warn, onShadow } = input;
42
44
  if (!enabled) return local;
43
45
 
44
46
  const localMs = 0;
45
47
  const started = performance.now();
46
48
  try {
47
49
  const pod = await runPod();
50
+ const agrees = agree(local, pod);
48
51
  log('pr.land', 'heavy-on-pod-shadow', {
49
52
  pr,
50
53
  head,
51
54
  local,
52
55
  pod,
53
- agree: agree(local, pod),
56
+ agree: agrees,
54
57
  podMs: elapsedMs(started),
55
58
  localMs,
56
59
  });
60
+ try { onShadow?.({ pod, agree: agrees }); }
61
+ catch (error) { warn(`shadow evidence write failed: ${error instanceof Error ? error.message : String(error)}`); }
57
62
  } catch (error) {
58
63
  warn(error instanceof Error ? error.message : String(error));
59
64
  log('pr.land', 'heavy-on-pod-shadow', {
@@ -62,6 +67,8 @@ export async function runHeavyOnPodShadow<T>(input: HeavyOnPodShadowInput<T>): P
62
67
  agree: false,
63
68
  podMs: elapsedMs(started), localMs,
64
69
  });
70
+ try { onShadow?.({ pod: { measured: false, ok: false, reason: `pod-exception:${error instanceof Error ? error.name : 'unknown'}` }, agree: false }); }
71
+ catch (writeError) { warn(`shadow evidence write failed: ${writeError instanceof Error ? writeError.message : String(writeError)}`); }
65
72
  }
66
73
  return local;
67
74
  }