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
@@ -5,8 +5,8 @@
5
5
  // ⛔ 읽기 전용 — 칸을 옮기지도, 동결을 바꾸지도, push 하지도 않는다. 옮길 것은 «명령»으로 제안만 한다.
6
6
  // ⛔ 게이트 규칙을 다시 쓰지 않는다 — checklist-gate 노드 · release run 진입 검사 · 예약 시작 준비 검사(releaseReadiness, #24557)가
7
7
  // 함께 쓰는 단 하나의 판정 cutChecklistGate 를 그대로 부르고, 예약 시작 경로는 releaseReadiness 를 CLI 와 같은 인자로 부른다.
8
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, mkdtempSync } from 'node:fs';
9
- import { join } from 'node:path';
8
+ import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, mkdtempSync } from 'node:fs';
9
+ import { dirname, join } from 'node:path';
10
10
  import { tmpdir } from 'node:os';
11
11
  import { spawnSync } from 'node:child_process';
12
12
  import { cutChecklistGate, listChecklist, type ChecklistItem } from '../../src/release-loop/checklist.js';
@@ -17,9 +17,10 @@ import { debug } from '../../src/debug/log.js';
17
17
  import { releaseReadiness } from './release-readiness.js';
18
18
  import { latestPublishedPreviousVersion, runUnattendedRelease, type UnattendedReleaseDeps } from './unattended-release.js';
19
19
  import { loadExportConfig, run as runPublicExport, selectExportFiles } from '../public-export.js';
20
+ import { SPAWN_SYNC_MAX_BUFFER } from '../../src/util/spawn-sync-output.js';
20
21
 
21
22
  export type PreflightLevel = 'ok' | 'warn' | 'block';
22
- export type PreflightCheck = 'checklist' | 'postpub' | 'run-input' | 'freeze' | 'schedule' | 'export';
23
+ export type PreflightCheck = 'checklist' | 'postpub' | 'run-input' | 'freeze' | 'schedule' | 'export' | 'notes' | 'cut-tree' | 'gate-slot' | 'release-notes';
23
24
  export interface PreflightFinding { level: PreflightLevel; check: PreflightCheck; id?: string; message: string; suggestion?: string }
24
25
  export interface GateMeasure { version: string; runId: string; gateSeconds: number; toPublishSeconds?: number }
25
26
  const compareStable = (a: string, b: string) => { const x = a.split('.').map(Number), y = b.split('.').map(Number); return x[0]! - y[0]! || x[1]! - y[1]! || x[2]! - y[2]!; };
@@ -32,6 +33,13 @@ export interface PreflightResult {
32
33
  findings: PreflightFinding[];
33
34
  schedule: { cutAt: string; landBy: string | null; publishAt: string | null; publishAtSource: 'option' | 'schedule' | 'cadence' | null; exportCheckAt: string } | null;
34
35
  exportCheck: { mainSha: string; files: number; leaks: number; codeLiterals: number } | null;
36
+ /** Read-only T−120 evidence. It describes checks only; it never means a release stage ran. */
37
+ countdownReadiness: {
38
+ status: 'green' | 'red' | 'unmeasured';
39
+ notes: { status: 'green' | 'red' | 'unmeasured'; addedLines: number | null };
40
+ export: { status: 'green' | 'red' | 'unmeasured'; leaks: number | null };
41
+ checklist: { status: 'green' | 'red' | 'unmeasured' };
42
+ };
35
43
  /** The immediately previous release (by version order) whose gate is compared. */
36
44
  previousVersion: string | null;
37
45
  gateMeasure: GateMeasure | null;
@@ -39,8 +47,76 @@ export interface PreflightResult {
39
47
  fallbackGateMeasure: GateMeasure | null;
40
48
  }
41
49
 
50
+ // ── RELEASE-COUNTDOWN-SEQUENCE — T−120 → T0 발사 시퀀스 ─────────────────────────────────────────
51
+ // 누리호 발사 체계의 사상: H0 전 자동 시퀀스 · 단계별 녹색/빨강 한 화면 · 범위 이탈(빨강)이면 자동 중지 ·
52
+ // 최후 수동 취소 구간 · 실패는 «부적합 보고»로 원장에 남겨 다음 판에 반영한다.
53
+ // 단계 → 검사 묶음은 기존 findings 의 check 분류를 «그대로» 재사용한다(게이트 규칙을 다시 쓰지 않는다).
54
+ export type CountdownStage = 'T-120' | 'T-60' | 'T-30' | 'T0';
55
+
56
+ /** What `scripts/release-loop/cutoff.ts` pins at T−60 (`<instance>/release/<version>/manifest.json`). */
57
+ export interface CountdownManifest {
58
+ cutoff?: { sha?: string };
59
+ fragments?: { byPr: number; byNextMd: number; unlinked: number; unknown: number };
60
+ escalate?: Array<{ kind?: string }>;
61
+ }
62
+
63
+ /** The «node-b» gate slot: the dispatcher is paused and the pod target lowered so the gate can take a Pod. */
64
+ export interface CountdownGateSlot { dispatcherPaused?: boolean; podTargetFrom?: number; podTargetTo?: number }
65
+
66
+ export interface CountdownStep {
67
+ stage: CountdownStage;
68
+ /** Minutes before the cut. */
69
+ offsetMinutes: number;
70
+ /** Cut − offset (ISO); null when the release has no stored schedule. */
71
+ at: string | null;
72
+ label: string;
73
+ level: PreflightLevel;
74
+ findings: PreflightFinding[];
75
+ /** Not judged — an earlier step went red and the sequence stopped. */
76
+ skipped: boolean;
77
+ }
78
+
79
+ export interface NonconformanceEntry {
80
+ version: string;
81
+ stage: CountdownStage;
82
+ /** 원인 */
83
+ cause: string;
84
+ /** 수리 */
85
+ repair: string;
86
+ /** 다음 판 반영 */
87
+ nextRelease: string;
88
+ at: string;
89
+ }
90
+
91
+ export interface CountdownResult {
92
+ version: string;
93
+ next: string;
94
+ cutAt: string | null;
95
+ verdict: PreflightLevel;
96
+ steps: CountdownStep[];
97
+ /** The stage that went red and stopped the sequence. */
98
+ haltedAt: CountdownStage | null;
99
+ /** 담당 자리 우편 — sent when the sequence stops. */
100
+ mail: { from: string; to: string; subject: string; body: string } | null;
101
+ /** 최후 수동 취소 구간 — the last seconds before T0 in which a human can still abort. */
102
+ manualCancel: { windowStartAt: string; windowEndAt: string; totalResponsibleSeconds: number; ldSeconds: number } | null;
103
+ nonconformance: NonconformanceEntry[];
104
+ /** The target «부적합 보고» ledger (JSON Lines); dry-run does not append. */
105
+ nonconformanceLedger: string;
106
+ sideEffectsEnabled: boolean;
107
+ preflight: PreflightResult;
108
+ }
109
+ export type ReleaseCountdownStep = {
110
+ id: 'notes-and-readiness' | 'pinned-main-preflight' | 'gate-window' | 'cut';
111
+ offsetMinutes: number;
112
+ at: string;
113
+ action: string;
114
+ observation: 'not-observed-by-countdown';
115
+ };
116
+
42
117
  export interface PreflightDeps {
43
118
  now?: Date;
119
+ countdown?: boolean;
44
120
  /** Planned publish time (ISO). Without it, the October cadence (07:00 · 18:00 KST) after the cut is assumed. */
45
121
  publishAt?: string;
46
122
  runInput?: (version: string) => Promise<{ input: unknown }>;
@@ -52,10 +128,22 @@ export interface PreflightDeps {
52
128
  previousVersion?: string;
53
129
  /** Injectable for deterministic preflight tests. Production pins origin/main and scans a disposable checkout. */
54
130
  exportCheck?: () => Promise<{ mainSha: string; files: number; leaks: number; codeLiterals: number }>;
131
+ /** Countdown T−120/T−60/T0: the cut manifest `cutoff.ts` pinned (default `<instance>/release/<v>/manifest.json`). */
132
+ manifest?: (version: string) => CountdownManifest | null;
133
+ /** Countdown T−60: the «node-b» gate-slot record (default `<instance>/release/<v>/gate-slot.json`). */
134
+ gateSlot?: (version: string) => CountdownGateSlot | null;
135
+ /** Countdown seat mail — default posts `eln msg post --from OP --to <담당 자리>`. */
136
+ postMail?: (mail: { from: string; to: string; subject: string; body: string }) => void;
137
+ /** Countdown «부적합 보고» ledger (JSON Lines) — default `<instance>/release/nonconformance.jsonl`. */
138
+ nonconformanceLog?: string;
139
+ /** Injectable read-only comparison of release/next.md against the previous published tag. */
140
+ releaseNotesCheck?: (previousVersion: string | undefined, mainSha: string | undefined) => Promise<number>;
141
+ /** Explicitly enable owner mail and nonconformance ledger append; defaults to dry-run. */
142
+ allowSideEffects?: boolean;
55
143
  }
56
144
 
57
145
  function runGit(cwd: string, args: string[]): string {
58
- const result = spawnSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 16 << 20 });
146
+ const result = spawnSync('git', args, { cwd, encoding: 'utf8', timeout: 60_000, maxBuffer: 16 << 20 });
59
147
  if (result.status !== 0) throw new Error(`git ${args.join(' ')} 실패 rc=${result.status}: ${(result.stderr ?? '').trim().slice(0, 300)}`);
60
148
  return (result.stdout ?? '').trim();
61
149
  }
@@ -76,7 +164,7 @@ export async function scanOriginMainExport(): Promise<{ mainSha: string; files:
76
164
  needed.add('release/public-export.yaml');
77
165
  // Read only the paths the pinned manifest can inspect; the full tracked-path index stays at mainSha.
78
166
  const manifestPath = join(snapshot, 'release/public-export.yaml');
79
- const manifest = spawnSync('git', ['-C', snapshot, 'show', `${mainSha}:release/public-export.yaml`], { encoding: 'utf8', maxBuffer: 4 << 20 });
167
+ const manifest = spawnSync('git', ['-C', snapshot, 'show', `${mainSha}:release/public-export.yaml`], { encoding: 'utf8', timeout: 60_000, maxBuffer: 4 << 20 });
80
168
  if (manifest.status !== 0) throw new Error(`origin/main public export manifest 읽기 실패: ${(manifest.stderr ?? '').trim()}`);
81
169
  mkdirSync(join(snapshot, 'release'), { recursive: true });
82
170
  writeFileSync(manifestPath, manifest.stdout ?? '');
@@ -94,7 +182,7 @@ export async function scanOriginMainExport(): Promise<{ mainSha: string; files:
94
182
  }
95
183
  }
96
184
  const checkout = spawnSync('git', ['-C', snapshot, 'checkout-index', '--stdin', '-z', '-f'], {
97
- input: `${[...needed].filter((file) => trackedSet.has(file)).join('\0')}\0`, encoding: 'utf8', maxBuffer: 16 << 20,
185
+ input: `${[...needed].filter((file) => trackedSet.has(file)).join('\0')}\0`, encoding: 'utf8', timeout: 60_000, maxBuffer: 16 << 20,
98
186
  });
99
187
  if (checkout.status !== 0) throw new Error(`origin/main export 입력 파일 준비 실패 rc=${checkout.status}: ${(checkout.stderr ?? '').trim().slice(0, 300)}`);
100
188
  let output = '';
@@ -116,12 +204,27 @@ export async function scanOriginMainExport(): Promise<{ mainSha: string; files:
116
204
  }
117
205
  if (typeof report.files !== 'number' || typeof report.leaks !== 'number') throw new Error('public-export 검사 결과가 완전하지 않다');
118
206
  if (code !== (report.leaks > 0 ? 1 : 0)) throw new Error(`public-export 종료 코드와 누수 결과 불일치: rc=${code} leaks=${report.leaks}`);
119
- return { mainSha, files: report.files, leaks: report.leaks, codeLiterals: report.codeLiterals?.hits ?? 0 };
207
+ const codeLiterals = report.codeLiterals?.hits ?? 0;
208
+ return { mainSha, files: report.files, leaks: Math.max(0, report.leaks - codeLiterals), codeLiterals };
120
209
  } finally {
121
210
  rmSync(temp, { recursive: true, force: true });
122
211
  }
123
212
  }
124
213
 
214
+ /** Count added release-note lines from the last published tag to the exact pinned main commit. */
215
+ export async function scanReleaseNotesAddedLines(previousVersion: string | undefined, mainSha: string | undefined): Promise<number> {
216
+ if (!previousVersion || !STABLE.test(previousVersion)) throw new Error('직전 발행 판 버전이 없어 release/next.md 변경을 비교할 수 없다');
217
+ const repoRoot = runGit(process.cwd(), ['rev-parse', '--show-toplevel']);
218
+ const pinnedMainSha = mainSha && /^[0-9a-f]{40}$/u.test(mainSha)
219
+ ? mainSha : runGit(repoRoot, ['rev-parse', '--verify', 'origin/main^{commit}']);
220
+ const previousTag = runGit(repoRoot, ['rev-parse', '--verify', `v${previousVersion}^{commit}`]);
221
+ const numstat = runGit(repoRoot, ['diff', '--numstat', `${previousTag}...${pinnedMainSha}`, '--', 'release/next.md']);
222
+ if (!numstat) return 0;
223
+ const added = Number(numstat.split('\t', 1)[0]);
224
+ if (!Number.isSafeInteger(added) || added < 0) throw new Error(`release/next.md diff 결과를 읽을 수 없다: ${numstat}`);
225
+ return added;
226
+ }
227
+
125
228
  const POSTPUB_ID = /^POSTPUB-/i;
126
229
  // Only a title that «starts» with the marker: a pre-publish cell often mentions «발행 뒤» in its body (a slot, a plan).
127
230
  const POSTPUB_TITLE = /^[«"'(]?\s*(발행\s*(뒤|후)|post-?publish)/i;
@@ -149,6 +252,37 @@ export function cadencePublishAt(cutAt: string): string {
149
252
  return new Date(cut).toISOString();
150
253
  }
151
254
 
255
+ /** A read-only timeline; timestamps never imply that a human or automation completed a step. */
256
+ export function releaseCountdown(cutAt: string): ReleaseCountdownStep[] {
257
+ const cut = Date.parse(cutAt);
258
+ if (!Number.isFinite(cut)) throw new Error(`invalid release cut time: ${cutAt}`);
259
+ const phases = [
260
+ { id: 'notes-and-readiness', offsetMinutes: -120, action: 'release/next.md 새 줄 ≥1 · 공개 export 누수 0 · 체크리스트 게이트 모의' },
261
+ { id: 'pinned-main-preflight', offsetMinutes: -60, action: '컷 트리를 고정하고 origin/main export 및 release preflight 실행' },
262
+ { id: 'gate-window', offsetMinutes: -30, action: 'gate 모드 · node-b 자리 확보 · 디스패처 정지 · podTarget 감축 확인' },
263
+ { id: 'cut', offsetMinutes: 0, action: 'release 컷 실행' },
264
+ ] as const;
265
+ return phases.map((phase) => ({
266
+ ...phase,
267
+ at: new Date(cut + phase.offsetMinutes * 60_000).toISOString(),
268
+ observation: 'not-observed-by-countdown',
269
+ }));
270
+ }
271
+
272
+ export function formatReleaseCountdown(cutAt: string, now = new Date(), readiness?: PreflightResult['countdownReadiness']): string[] {
273
+ return [
274
+ `발행 카운트다운 · 컷 ${formatKst(cutAt)} · 이 명령은 단계 완료를 관측하거나 실행하지 않는다`,
275
+ ...releaseCountdown(cutAt).map((step) => {
276
+ const label = step.offsetMinutes === 0 ? 'T0' : `T${step.offsetMinutes}`;
277
+ const timing = now.getTime() < Date.parse(step.at) ? '예정' : '시각 도달 · 완료 미관측';
278
+ const t120 = readiness && step.id === 'notes-and-readiness'
279
+ ? ` · read-only 판정 ${readiness.status} (notes +${readiness.notes.addedLines ?? '?'} · export 누수 ${readiness.export.leaks ?? '?'} · checklist ${readiness.checklist.status})`
280
+ : '';
281
+ return `· ${label} ${formatKst(step.at)} · ${timing} · ${step.action}${t120}`;
282
+ }),
283
+ ];
284
+ }
285
+
152
286
  /**
153
287
  * A release's measured gate: the newest finished release-loop run of «that» version (`{ version }`) or, with
154
288
  * `{ below }`, the most recently measured run of any version under it. Node timings are not stored in the run state, so the gate time is the start of the gate node's context file to
@@ -273,6 +407,18 @@ export async function releasePreflight(version: string, deps: PreflightDeps = {}
273
407
  findings.push({ level: 'block', check: 'run-input', message: `release run --dry-run 입력 오류 — ${error instanceof Error ? error.message : String(error)}` });
274
408
  }
275
409
 
410
+ let notesAddedLines: number | null = null;
411
+ if (deps.countdown) {
412
+ try {
413
+ notesAddedLines = await (deps.releaseNotesCheck ?? scanReleaseNotesAddedLines)(runPrevious, exportCheck?.mainSha);
414
+ findings.push(notesAddedLines > 0
415
+ ? { level: 'ok', check: 'release-notes', message: `직전 발행 ${runPrevious} 이후 고정 main의 release/next.md 추가 ${notesAddedLines}줄` }
416
+ : { level: 'block', check: 'release-notes', message: `직전 발행 ${runPrevious ?? '-'} 이후 고정 main의 release/next.md 추가 줄이 없다` });
417
+ } catch (error) {
418
+ findings.push({ level: 'warn', check: 'release-notes', message: `release/next.md 변경을 측정하지 못했다 — ${error instanceof Error ? error.message : String(error)}` });
419
+ }
420
+ }
421
+
276
422
  // 4. Landing freeze (emergency switch since RELEASE-BRANCH): when on, `release run` refuses.
277
423
  try {
278
424
  const frozen = (deps.freeze ?? (() => readLandingFreeze(deps.releaseRunDeps?.freezeRoot)))();
@@ -320,10 +466,29 @@ export async function releasePreflight(version: string, deps: PreflightDeps = {}
320
466
  }
321
467
  }
322
468
 
469
+ const checklistHasResult = findings.some((f) => f.check === 'checklist' && f.level === 'ok');
470
+ const countdownReadiness: PreflightResult['countdownReadiness'] = !deps.countdown ? {
471
+ status: 'unmeasured', notes: { status: 'unmeasured', addedLines: null },
472
+ export: { status: 'unmeasured', leaks: null }, checklist: { status: 'unmeasured' },
473
+ } : (() => {
474
+ const notesFinding = findings.find((f) => f.check === 'release-notes');
475
+ const exportFinding = findings.find((f) => f.check === 'export');
476
+ const checklistBlocked = findings.some((f) => f.check === 'checklist' && f.level === 'block');
477
+ const notesStatus = notesFinding?.level === 'ok' ? 'green' : notesFinding?.level === 'block' ? 'red' : 'unmeasured';
478
+ const exportStatus = exportFinding?.level === 'ok' ? 'green' : exportFinding?.level === 'block' ? 'red' : 'unmeasured';
479
+ const checklistStatus = checklistBlocked ? 'red' : checklistHasResult ? 'green' : 'unmeasured';
480
+ const statuses = [notesStatus, exportStatus, checklistStatus];
481
+ return {
482
+ status: statuses.includes('red') ? 'red' : statuses.every((status) => status === 'green') ? 'green' : 'unmeasured',
483
+ notes: { status: notesStatus, addedLines: notesAddedLines },
484
+ export: { status: exportStatus, leaks: exportCheck?.leaks ?? null },
485
+ checklist: { status: checklistStatus },
486
+ };
487
+ })();
323
488
  const blockers = findings.filter((f) => f.level === 'block').length;
324
489
  const warnings = findings.filter((f) => f.level === 'warn').length;
325
490
  debug.log('release.preflight', 'checked', { version, blockers, warnings });
326
- return { version, next, verdict: blockers ? 'block' : warnings ? 'warn' : 'ok', blockers, warnings, findings, schedule: scheduleOut, exportCheck, previousVersion, gateMeasure, fallbackGateMeasure };
491
+ return { version, next, verdict: blockers ? 'block' : warnings ? 'warn' : 'ok', blockers, warnings, findings, schedule: scheduleOut, exportCheck, countdownReadiness, previousVersion, gateMeasure, fallbackGateMeasure };
327
492
  }
328
493
 
329
494
  const ICON: Record<PreflightLevel, string> = { ok: '✅', warn: '⚠️', block: '⛔' };
@@ -336,3 +501,192 @@ export function formatPreflight(result: PreflightResult): string[] {
336
501
  : result.verdict === 'warn' ? `⚠️ 판정: 통과(경고 ${result.warnings})` : '✅ 판정: 통과';
337
502
  return [`release preflight ${result.version} (다음 판 ${result.next})`, ...lines, verdict];
338
503
  }
504
+
505
+ const COUNTDOWN_ORDER: CountdownStage[] = ['T-120', 'T-60', 'T-30', 'T0'];
506
+ const COUNTDOWN_OFFSET_MINUTES: Record<CountdownStage, number> = { 'T-120': 120, 'T-60': 60, 'T-30': 30, T0: 0 };
507
+ /** Which existing finding group each stage judges — the check vocabulary of `releasePreflight`, not a new rule set. */
508
+ const COUNTDOWN_CHECKS: Record<CountdownStage, PreflightCheck[]> = {
509
+ 'T-120': ['checklist', 'postpub', 'notes', 'release-notes', 'export'],
510
+ 'T-60': ['run-input', 'freeze', 'cut-tree', 'gate-slot'],
511
+ 'T-30': ['schedule'],
512
+ T0: [],
513
+ };
514
+ const COUNTDOWN_LABELS: Record<CountdownStage, string> = {
515
+ 'T-120': '노트(next.md 새 줄) · 공개 export 누수 · 체크리스트 게이트 모의',
516
+ 'T-60': 'preflight(컷 트리 고정) ⊕ node-b 게이트 자리(디스패처 정지 · podTarget 감축)',
517
+ 'T-30': 'gate window 준비(컷→발행 창 ≥ 직전 실측 게이트)',
518
+ T0: '컷 트리 확인(실제 컷 실행은 별도)',
519
+ };
520
+ /** 담당 자리 — who is mailed when that stage goes red. */
521
+ const COUNTDOWN_OWNER: Record<CountdownStage, string> = { 'T-120': 'TC', 'T-60': 'OP', 'T-30': 'OP', T0: 'OP' };
522
+ /** 최후 수동 취소 구간(누리호 사상): 총책임자 8초 · LD 5초. */
523
+ const MANUAL_CANCEL_SECONDS = { totalResponsibleSeconds: 8, ldSeconds: 5 };
524
+
525
+ const worstLevel = (findings: PreflightFinding[]): PreflightLevel =>
526
+ findings.some((finding) => finding.level === 'block') ? 'block' : findings.some((finding) => finding.level === 'warn') ? 'warn' : 'ok';
527
+
528
+ function readReleaseJson<T>(version: string, file: string): T | null {
529
+ try { return JSON.parse(readFileSync(join(effectiveInstanceRoot(), 'release', version, file), 'utf8')) as T; } catch { return null; }
530
+ }
531
+
532
+ /** T−120 — `next.md` got at least one new line for this release (0.2.39 found notes-empty only after the cut). */
533
+ function countdownNotes(manifest: CountdownManifest | null): PreflightFinding {
534
+ if (!manifest) return { level: 'warn', check: 'notes', message: 'next.md 새 줄 판정 없음 — 컷 manifest 없음(T−60 의 cutoff.ts 가 만든다)' };
535
+ const lines = (manifest.fragments?.byNextMd ?? 0) + (manifest.fragments?.unlinked ?? 0);
536
+ if ((manifest.escalate ?? []).some((item) => item.kind === 'notes-empty') || lines < 1) {
537
+ return {
538
+ level: 'block', check: 'notes', message: 'next.md 새 줄 0 — notes-empty(이 판 공개 노트가 비어 있다 · 컷 뒤에 드러나면 발행이 늦어진다)',
539
+ suggestion: 'release/next.md 에 이 판 feat/fix 줄을 더하고 cutoff.ts 로 manifest 를 다시 만든다',
540
+ };
541
+ }
542
+ return { level: 'ok', check: 'notes', message: `next.md 새 줄 ${lines}줄` };
543
+ }
544
+
545
+ /** T−60 — the cut tree is pinned: the manifest names one cutoff sha (cutoff.ts output, its format unchanged). */
546
+ function countdownCutTree(manifest: CountdownManifest | null): PreflightFinding {
547
+ const sha = manifest?.cutoff?.sha;
548
+ return sha
549
+ ? { level: 'ok', check: 'cut-tree', message: `컷 트리 고정 ${sha.slice(0, 12)}` }
550
+ : { level: 'warn', check: 'cut-tree', message: '컷 트리 고정 없음 — T−60 에 `bun scripts/release-loop/cutoff.ts --version <v>` 로 manifest 를 만든다' };
551
+ }
552
+
553
+ /** T−60 — the «node-b» gate slot: dispatcher stopped and the pod target lowered so the gate can take a Pod. */
554
+ function countdownGateSlot(slot: CountdownGateSlot | null): PreflightFinding[] {
555
+ if (!slot) return [{ level: 'warn', check: 'gate-slot', message: 'node-b 게이트 자리 기록 없음 — release/<v>/gate-slot.json(디스패처 정지 · podTarget 감축)' }];
556
+ const findings: PreflightFinding[] = [];
557
+ if (slot.dispatcherPaused !== true) {
558
+ findings.push({
559
+ level: 'block', check: 'gate-slot', message: 'node-b 게이트 자리 — 디스패처가 멈추지 않았다(게이트가 Pod 를 잡지 못한다)',
560
+ suggestion: '디스패처를 정지하고 release/<v>/gate-slot.json 에 dispatcherPaused: true 를 남긴다',
561
+ });
562
+ }
563
+ if (slot.podTargetFrom !== undefined && slot.podTargetTo !== undefined && slot.podTargetTo >= slot.podTargetFrom) {
564
+ findings.push({
565
+ level: 'block', check: 'gate-slot', message: `node-b 게이트 자리 — podTarget 감축 없음(${slot.podTargetFrom}→${slot.podTargetTo})`,
566
+ suggestion: 'podTarget 을 게이트 몫만큼 줄이고 gate-slot.json 에 from/to 를 기록한다',
567
+ });
568
+ }
569
+ if (!findings.length) {
570
+ const target = slot.podTargetFrom !== undefined ? ` · podTarget ${slot.podTargetFrom}→${slot.podTargetTo ?? slot.podTargetFrom}` : '';
571
+ findings.push({ level: 'ok', check: 'gate-slot', message: `node-b 게이트 자리 확보 — 디스패처 정지${target}` });
572
+ }
573
+ return findings;
574
+ }
575
+
576
+ /** T0 — model readiness only: this command never executes the cut. */
577
+ function countdownCut(manifest: CountdownManifest | null): PreflightFinding {
578
+ const sha = manifest?.cutoff?.sha;
579
+ return sha
580
+ ? { level: 'ok', check: 'cut-tree', message: `T0 컷 준비 — 고정 트리 ${sha.slice(0, 12)}(실제 컷 실행은 별도 명령)` }
581
+ : { level: 'block', check: 'cut-tree', message: 'T0 컷 불가 — 컷 트리 고정(manifest cutoff.sha)이 없다', suggestion: 'T−60 에 cutoff.ts 로 컷 트리를 고정한다' };
582
+ }
583
+
584
+ function postSeatMail(mail: { from: string; to: string; subject: string; body: string }): void {
585
+ const result = spawnSync('eln', ['msg', 'post', '--from', mail.from, '--to', mail.to, '--kind', 'report', '--body', `${mail.subject}\n${mail.body}`], {
586
+ encoding: 'utf8', timeout: 60_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER,
587
+ });
588
+ if (result.status !== 0 || result.error) process.stderr.write(`release countdown 좌석 우편 실패: ${(result.stderr || String(result.error ?? result.status)).trim()}\n`);
589
+ }
590
+
591
+ /**
592
+ * `release preflight --countdown` — the launch sequence from T−120 to T0 over the same `releasePreflight` findings.
593
+ * A red stage stops every later stage, mails the owning seat and appends one «부적합 보고» per failure to the ledger.
594
+ * Read-only apart from that ledger append and the seat mail — the cut and the checklist are never changed.
595
+ */
596
+ export async function runReleaseCountdown(version: string, deps: PreflightDeps = {}): Promise<CountdownResult> {
597
+ const preflight = await releasePreflight(version, { ...deps, countdown: true });
598
+ const now = deps.now ?? new Date();
599
+ const manifest = (deps.manifest ?? ((v: string) => readReleaseJson<CountdownManifest>(v, 'manifest.json')))(version);
600
+ const slot = (deps.gateSlot ?? ((v: string) => readReleaseJson<CountdownGateSlot>(v, 'gate-slot.json')))(version);
601
+ const cutAt = preflight.schedule?.cutAt ?? null;
602
+
603
+ const grouped = new Map<PreflightCheck, PreflightFinding[]>();
604
+ for (const finding of preflight.findings) grouped.set(finding.check, [...(grouped.get(finding.check) ?? []), finding]);
605
+ const own: Record<CountdownStage, PreflightFinding[]> = {
606
+ 'T-120': [countdownNotes(manifest)],
607
+ 'T-60': [countdownCutTree(manifest), ...countdownGateSlot(slot)],
608
+ 'T-30': [],
609
+ T0: [countdownCut(manifest)],
610
+ };
611
+
612
+ const steps: CountdownStep[] = [];
613
+ let haltedAt: CountdownStage | null = null;
614
+ for (const stage of COUNTDOWN_ORDER) {
615
+ const offsetMinutes = COUNTDOWN_OFFSET_MINUTES[stage];
616
+ const at = cutAt ? new Date(Date.parse(cutAt) - offsetMinutes * 60_000).toISOString() : null;
617
+ if (haltedAt) {
618
+ steps.push({ stage, offsetMinutes, at, label: COUNTDOWN_LABELS[stage], level: 'ok', findings: [], skipped: true });
619
+ continue;
620
+ }
621
+ const findings = [...COUNTDOWN_CHECKS[stage].flatMap((check) => grouped.get(check) ?? []), ...own[stage]];
622
+ const level = worstLevel(findings);
623
+ steps.push({ stage, offsetMinutes, at, label: COUNTDOWN_LABELS[stage], level, findings, skipped: false });
624
+ if (level === 'block') haltedAt = stage;
625
+ }
626
+
627
+ const nonconformance: NonconformanceEntry[] = steps.flatMap((step) => step.findings
628
+ .filter((finding) => finding.level === 'block')
629
+ .map((finding) => ({
630
+ version, stage: step.stage, cause: finding.message,
631
+ repair: finding.suggestion ?? `${step.stage} 담당 자리가 원인을 확인해 고친다`,
632
+ nextRelease: preflight.next, at: now.toISOString(),
633
+ })));
634
+ const nonconformanceLedger = deps.nonconformanceLog ?? join(effectiveInstanceRoot(), 'release', 'nonconformance.jsonl');
635
+ if (deps.allowSideEffects && nonconformance.length) {
636
+ mkdirSync(dirname(nonconformanceLedger), { recursive: true });
637
+ appendFileSync(nonconformanceLedger, `${nonconformance.map((entry) => JSON.stringify(entry)).join('\n')}\n`);
638
+ }
639
+
640
+ const mail = haltedAt ? countdownMail(version, haltedAt, steps, nonconformance.length) : null;
641
+ if (deps.allowSideEffects && mail) (deps.postMail ?? postSeatMail)(mail);
642
+
643
+ const cancelSeconds = MANUAL_CANCEL_SECONDS.totalResponsibleSeconds + MANUAL_CANCEL_SECONDS.ldSeconds;
644
+ const manualCancel = cutAt ? {
645
+ windowStartAt: new Date(Date.parse(cutAt) - cancelSeconds * 1000).toISOString(),
646
+ windowEndAt: cutAt, ...MANUAL_CANCEL_SECONDS,
647
+ } : null;
648
+ const verdict = haltedAt ? 'block' : steps.some((step) => step.level === 'warn') ? 'warn' : 'ok';
649
+ debug.log('release.preflight', 'countdown', { version, haltedAt, verdict, nonconformance: nonconformance.length });
650
+ return {
651
+ version, next: preflight.next, cutAt, verdict, steps, haltedAt, mail, manualCancel, nonconformance, nonconformanceLedger,
652
+ sideEffectsEnabled: deps.allowSideEffects === true, preflight,
653
+ };
654
+ }
655
+
656
+ function countdownMail(version: string, stage: CountdownStage, steps: CountdownStep[], failures: number): CountdownResult['mail'] {
657
+ const step = steps.find((entry) => entry.stage === stage)!;
658
+ const reasons = step.findings.filter((finding) => finding.level === 'block');
659
+ const repairs = reasons.filter((finding) => finding.suggestion).map((finding) => `· ${finding.message} → ${finding.suggestion}`);
660
+ return {
661
+ from: 'OP', to: COUNTDOWN_OWNER[stage], subject: `RELEASE-COUNTDOWN ${version} ${stage}`,
662
+ body: [
663
+ `RELEASE-COUNTDOWN ${version} ${stage} 빨강 — 발사 시퀀스를 자동 중지했다.`,
664
+ ...reasons.map((finding) => `· ${finding.message}`),
665
+ ...(repairs.length ? ['수리:', ...repairs] : []),
666
+ `«부적합 보고» ${failures}건을 원장에 넣었다(원인·수리·다음 판 ${nextPatch(version)} 반영).`,
667
+ ].join('\n'),
668
+ };
669
+ }
670
+
671
+ /** The one screen of the launch sequence: every stage green/red, the manual-cancel window and one «판정:» line. */
672
+ export function formatCountdown(result: CountdownResult): string[] {
673
+ const lines = [`release countdown ${result.version} (다음 판 ${result.next})${result.cutAt ? ` · 컷 ${formatKst(result.cutAt)}` : ''} · 검사 상태만 표시(단계 실행은 미관측)`];
674
+ for (const step of result.steps) {
675
+ const when = step.at ? ` · ${formatKst(step.at)}` : '';
676
+ if (step.skipped) { lines.push(`⏸ ${step.stage} — 미진행(${result.haltedAt} 빨강 — 자동 중지)${when}`); continue; }
677
+ lines.push(`${ICON[step.level]} ${step.stage} ${step.label}${when}`);
678
+ for (const finding of step.findings) {
679
+ lines.push(` ${ICON[finding.level]} ${finding.message}`);
680
+ if (finding.suggestion) lines.push(` → ${finding.suggestion}`);
681
+ }
682
+ }
683
+ if (result.manualCancel) {
684
+ const seconds = Math.round((Date.parse(result.manualCancel.windowEndAt) - Date.parse(result.manualCancel.windowStartAt)) / 1000);
685
+ lines.push(`⏱ 최후 수동 취소 구간 T0−${seconds}초 ~ T0 (${formatKst(result.manualCancel.windowEndAt)}) — 총책임자 ${result.manualCancel.totalResponsibleSeconds}초 · LD ${result.manualCancel.ldSeconds}초`);
686
+ }
687
+ if (result.mail) lines.push(`${result.sideEffectsEnabled ? '📮 담당 자리 우편' : '📮 담당 자리 우편 계획(미발송 · 기본 dry-run)'} → ${result.mail.to} · ${result.mail.subject}`);
688
+ lines.push(result.verdict === 'block'
689
+ ? `⛔ 판정: 평가 중지 — ${result.haltedAt} 빨강 · 부적합 보고 ${result.nonconformance.length}건 ${result.sideEffectsEnabled ? `원장 기록(${result.nonconformanceLedger})` : `원장 기록 계획(미기록 · 기본 dry-run: ${result.nonconformanceLedger})`}`
690
+ : result.verdict === 'warn' ? '⚠️ 판정: 통과(경고) — 경고 단계는 기록만 한다' : '✅ 판정: 통과');
691
+ return lines;
692
+ }
@@ -15,6 +15,7 @@ import { releaseRunUniverse } from './release-universe.js';
15
15
  import { baseVersion, isStableVersion, nextPrereleaseVersion, type PrereleaseKind } from './release-version.js';
16
16
  import { publishAtError } from './publish-at.js';
17
17
  import { checkGateExecutorChoice, type GateExecutor } from './gate-executor.js';
18
+ import { readReleaseGateRehearsal, readReleaseOpsPolicy, selectReleaseGateMethod } from './gate-method.js';
18
19
 
19
20
  const VERSION = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
20
21
  const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
@@ -55,6 +56,8 @@ export interface ReleaseRunInput extends ReleaseLoopConfig {
55
56
  gatePodPool?: string;
56
57
  /** GATE-HOST-EXECUTOR — absent = pod (today's input, byte-identical); `host` sweeps on `gateRemote`. */
57
58
  gateExecutor?: GateExecutor;
59
+ /** RELEASE-POLICY-PACK — gate source/image identity follows the selected cut commit. */
60
+ gateImagePin?: 'cut-commit';
58
61
  forceFreeze?: boolean;
59
62
  publishAt?: string;
60
63
  /** RELEASE-BRANCH: version-release cuts release/<v> from main HEAD and bumps only the branch. */
@@ -65,6 +68,7 @@ export interface UnattendedReleaseDeps {
65
68
  ledgerRoot?: string;
66
69
  config?: ReleaseLoopConfig;
67
70
  configPath?: string;
71
+ policyPath?: string;
68
72
  graph?: (path: string, options: { input: ReleaseRunInput; pinChildUniverse?: boolean; deps?: { root?: string } }) => Promise<GraphRunState>;
69
73
  checklist?: (version: string) => Pick<ReturnType<typeof cutChecklistGate>, 'ok' | 'red' | 'undecided' | 'blocked'>;
70
74
  freezeRoot?: string;
@@ -125,20 +129,27 @@ export interface GateExecutorRequest { executor?: string; host?: string }
125
129
  export function buildReleaseRunInput(version: string, deps: UnattendedReleaseDeps = {}, cutCommit?: string, gate: GateExecutorRequest = {}): ReleaseRunInput {
126
130
  const config = deps.config ?? releaseLoopConfig(deps.configPath);
127
131
  if (gate.executor === undefined && gate.host !== undefined) throw new Error('--gate-host requires --gate-executor host');
128
- const choice = gate.executor === undefined ? undefined
129
- : checkGateExecutorChoice(gate.executor, gate.executor === 'host' ? gate.host ?? config.gateRemote : gate.host);
130
- const pool = config.gatePodPool;
131
- const hasPool = typeof pool === 'string' && !!pool.trim();
132
- // The pod executor (the default) stays fail-closed on a missing pool; an explicit host executor does not need one.
133
- if (choice?.executor !== 'host' && !hasPool) throw new Error('release.loop.gatePodPool is required before graph execution');
134
132
  const previousVersion = latestPublishedPreviousVersion(baseVersion(version), deps.ledgerRoot);
133
+ const rehearsal = readReleaseGateRehearsal(deps.ledgerRoot ?? releaseLedgerRoot(), previousVersion);
134
+ const method = selectReleaseGateMethod({ policy: readReleaseOpsPolicy(deps.policyPath), targetVersion: baseVersion(version),
135
+ configuredPool: config.gatePodPool, rehearsal });
136
+ debug.log('release.run', 'gate-method-selected', { version, previousVersion, ...method });
137
+ const requested = gate.executor === undefined ? undefined
138
+ : checkGateExecutorChoice(gate.executor, gate.executor === 'host' ? gate.host ?? config.gateRemote : gate.host);
139
+ if (requested && requested.executor !== method.executor) {
140
+ debug.log('release.run', 'gate-method-override-rejected', { version, requested: requested.executor, selected: method.executor, decision: method.decision });
141
+ throw new Error(`gate executor ${requested.executor} conflicts with release policy ${method.executor}`);
142
+ }
143
+ if (method.executor === 'pod' && !method.pool) throw new Error('release.loop.gatePodPool is required by release ops policy');
135
144
  return {
136
145
  ...config,
137
146
  version, previousVersion,
138
147
  ...(cutCommit !== undefined ? { cutCommit } : {}),
139
- ...(hasPool ? { gatePodPool: pool.trim() } : {}),
140
- ...(choice ? { gateExecutor: choice.executor } : {}),
141
- ...(choice?.host ? { gateRemote: choice.host } : {}),
148
+ ...(method.executor === 'pod' ? { gatePodPool: method.pool } : {}),
149
+ gateExecutor: method.executor,
150
+ gateImagePin: method.imagePin,
151
+ // A future policy may select host; only then can its validated host request reach this input.
152
+ ...(requested?.host ? { gateRemote: requested.host } : {}),
142
153
  };
143
154
  }
144
155
 
@@ -5,7 +5,7 @@ import { Database } from 'bun:sqlite';
5
5
  import { dirname, join } from 'node:path';
6
6
  import { effectiveInstanceRoot, prodInstanceRoot } from '../../src/instance/resolve.js';
7
7
  import { listSchedules } from '../../src/release-loop/release-schedule.js';
8
- import { devVersion, listChecklist } from '../../src/release-loop/checklist.js';
8
+ import { checklistDevVersion, devVersion, listChecklist } from '../../src/release-loop/checklist.js';
9
9
  import { DecisionLedger } from '../../src/decisions/decision-ledger.js';
10
10
  import { selectProact1Lite, type ProactSignals } from '../../src/decisions/proact1-lite.js';
11
11
  import { trafficTick, seatOfTree } from '../../src/loops/orchestrator/traffic.js';
@@ -21,6 +21,7 @@ import { BriefItemsLedger } from '../../src/briefing/brief-items.js';
21
21
  import { debug } from '../../src/debug/log.js';
22
22
  import { retroBriefingLines } from '../../src/retro/daily.js';
23
23
  import { dispatchCooAdmin } from '../../src/domains/coo-admin-tool.js';
24
+ import { runLinearProgressSync, type ProgressSyncResult } from './linear-progress-sync.js';
24
25
 
25
26
  export type Section<T> = { status: 'ok'; value: T } | { status: 'unreadable'; reason: string };
26
27
  export type Landing = { title: string; seat: string; mergedAt: string; prNumber?: number };
@@ -542,6 +543,7 @@ export type DailyDeps = { now?: () => Date; root?: string; vaultRoot?: string |
542
543
  target?: { chatId: number; botToken: string };
543
544
  send?: (request: DailySendRequest) => DailySendConfirmation | null; receipt?: (key: string) => DeliveryReceipt;
544
545
  recordDelivery?: (text: string, kind: 'ops-report') => void;
546
+ linearProgressSync?: typeof runLinearProgressSync;
545
547
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
546
548
  proactSignals?: () => Promise<ProactSignals>;
547
549
  proactPreviouslySuggested?: ReadonlySet<string>;
@@ -593,6 +595,8 @@ export async function runDaily(options: { dryRun?: boolean; noNews?: boolean; st
593
595
  let sendError: string | null = null;
594
596
  let recordError: string | null = null;
595
597
  let newsState: string | null = null;
598
+ let linearProgress: ProgressSyncResult | undefined;
599
+ let linearProgressError: string | null = null;
596
600
  let enabled = deps.sendEnabled === true;
597
601
  if (deps.sendEnabled === undefined && options.stage === 'deliver' && !options.dryRun) {
598
602
  try { enabled = record(record(record(getUserConfig().raw.loops).rhythm).daily).send === true; }
@@ -613,11 +617,39 @@ export async function runDaily(options: { dryRun?: boolean; noNews?: boolean; st
613
617
  deliveryState = delivery.deliveryState;
614
618
  if (resolved) newsState = sendNewsAfterReview(delivery, file, markdown, resolved, deps);
615
619
  }
620
+ if (options.stage === 'deliver' && !options.dryRun) {
621
+ try {
622
+ const dailyConfig = record(record(record(getUserConfig().raw.loops).rhythm).daily);
623
+ if (dailyConfig.linearProgressSync === true) {
624
+ const allowIssueIdentifiers = Array.isArray(dailyConfig.linearProgressIssueAllowlist)
625
+ ? dailyConfig.linearProgressIssueAllowlist.filter((value): value is string => typeof value === 'string') : [];
626
+ if (!allowIssueIdentifiers.length) {
627
+ linearProgressError = 'issue allowlist missing; no Linear comments sent';
628
+ if (deps.log) deps.log('loop.rhythm-daily', 'linear-progress-config-blocked', { reason: 'issue-allowlist-missing' });
629
+ else loopEvent('rhythm-daily', 'linear-progress-config-blocked', { reason: 'issue-allowlist-missing' });
630
+ } else {
631
+ linearProgress = await (deps.linearProgressSync ?? runLinearProgressSync)({ version: checklistDevVersion(devVersion()), now, root: deps.root,
632
+ apply: true, allowIssueIdentifiers,
633
+ log: (event, data) => deps.log ? deps.log('loop.rhythm-daily.linear-progress', event, data)
634
+ : loopEvent('rhythm-daily.linear-progress', event, data) });
635
+ if (linearProgress.failures.length) {
636
+ linearProgressError = `${linearProgress.failures.length} Linear summary failure(s); see loop.rhythm-daily.linear-progress logs`;
637
+ }
638
+ }
639
+ }
640
+ } catch (error) {
641
+ linearProgressError = shortReason(reasonOf(error));
642
+ if (deps.log) deps.log('loop.rhythm-daily', 'linear-progress-failed', { reason: linearProgressError });
643
+ else loopEvent('rhythm-daily', 'linear-progress-failed', { reason: linearProgressError });
644
+ }
645
+ }
616
646
  tick.sent = sent;
617
- const status = vault.vaultFatal || Object.values(sections).includes('unreadable') ? 'degraded'
647
+ if (linearProgress) tick.linearProgress = linearProgress;
648
+ if (linearProgressError) tick.linearProgressError = linearProgressError;
649
+ const status = vault.vaultFatal || Object.values(sections).includes('unreadable') || !!linearProgressError ? 'degraded'
618
650
  : deliveryState === 'pending' ? 'pending'
619
651
  : ['sent', 'already-sent', 'receipt-sent'].includes(deliveryState) ? 'ok' : 'degraded';
620
- const deliveryLine = `${options.stage} ${status} · target=${target} · ${deliveryState} · sent=${sent} · chars=${chars} · receipt=${receiptKey}${recordError ? ` · ${recordError}` : ''}${newsState ? ` · news=${newsState}` : ''}`;
652
+ const deliveryLine = `${options.stage} ${status} · target=${target} · ${deliveryState} · sent=${sent} · chars=${chars} · receipt=${receiptKey}${recordError ? ` · ${recordError}` : ''}${newsState ? ` · news=${newsState}` : ''}${linearProgressError ? ` · linear=${linearProgressError}` : ''}`;
621
653
  if (options.stage === 'deliver') {
622
654
  Object.assign(tick, { status, deliveryState, target, chars, receiptKey, deliveryLine, recordError });
623
655
  if (!options.dryRun) {
@@ -625,7 +657,7 @@ export async function runDaily(options: { dryRun?: boolean; noNews?: boolean; st
625
657
  else loopEvent('rhythm-daily', 'tick', tick);
626
658
  }
627
659
  }
628
- return { file, markdown, header, risks, sections, sent, ...vault, sendError, recordError, status, deliveryState, deliveryLine,
660
+ return { file, markdown, header, risks, sections, sent, ...vault, sendError, recordError, status, deliveryState, deliveryLine, linearProgress, linearProgressError,
629
661
  draftCloseSummary: undefined };
630
662
  }
631
663
  const safe = async <T>(fetch: () => Promise<T>): Promise<Section<T>> => {