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
@@ -52,6 +52,7 @@ export interface GateArtifactRun {
52
52
  export interface GateArtifactShard {
53
53
  shardId: string;
54
54
  attempt: number;
55
+ elapsedMs?: number;
55
56
  files: string[];
56
57
  current: GateArtifactRun;
57
58
  baseline: GateArtifactRun;
@@ -210,7 +211,7 @@ export function writeGateArtifacts(input: GateArtifactInput): { summaryPath: str
210
211
  return run;
211
212
  };
212
213
  shardsDetail.push({
213
- shardId: attempt.shardId, attempt: attempt.attempt, files, current: side('current'), baseline: side('baseline'),
214
+ shardId: attempt.shardId, attempt: attempt.attempt, ...(attempt.elapsedMs !== undefined ? { elapsedMs: attempt.elapsedMs } : {}), files, current: side('current'), baseline: side('baseline'),
214
215
  ...(input.sharded?.unmeasuredByShard?.[attempt.shardId] !== undefined
215
216
  && attempt === input.sharded.attempts.filter((item) => item.shardId === attempt.shardId).at(-1)
216
217
  ? { unmeasuredReason: input.sharded.unmeasuredByShard[attempt.shardId] } : {}),
@@ -19,6 +19,7 @@ import {
19
19
  type GoalAuthorDeps,
20
20
  type GoalAuthorGradeSelection,
21
21
  resolveGoalAuthorGrade,
22
+ resolveGoalAuthorReviewerPrecheckEnabled,
22
23
  type GoalType,
23
24
  type GoalFileLintFinding,
24
25
  } from './goal-author.js';
@@ -292,9 +293,10 @@ export async function runGoalAuthorCli(
292
293
  ? { passed: false }
293
294
  : { passed: true, titleChars: proseTitle.length });
294
295
  const gradeDeps = authorGrade.grade === 'lite' || opts.authorGrade ? { authorGrade } : {};
296
+ const reviewerPrecheckDeps = { reviewerPrecheckEnabled: resolveGoalAuthorReviewerPrecheckEnabled() };
295
297
  const authorDeps: Partial<GoalAuthorDeps> = parentGoalFile && parentQuestionId
296
- ? { parent: { goalFile: parentGoalFile, questionId: parentQuestionId }, parentDocument, clarificationAnswers, ...(decomposeSteps ? { decomposeSteps } : {}), ...gradeDeps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps }
297
- : { ...(clarificationAnswers && { clarificationAnswers }), ...(decomposeSteps ? { decomposeSteps } : {}), ...gradeDeps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps };
298
+ ? { parent: { goalFile: parentGoalFile, questionId: parentQuestionId }, parentDocument, clarificationAnswers, ...(decomposeSteps ? { decomposeSteps } : {}), ...gradeDeps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...reviewerPrecheckDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps }
299
+ : { ...(clarificationAnswers && { clarificationAnswers }), ...(decomposeSteps ? { decomposeSteps } : {}), ...gradeDeps, ...selfResolutionDeps, ...progressDeps, ...launchPreflightDeps, ...reviewerPrecheckDeps, ...(opts.rootIntent !== undefined && { rootIntent: opts.rootIntent }), ...(goalType !== undefined && { goalType }), ...goalTitleDeps };
298
300
  const write = deps.write ?? writeAuthoredGoal;
299
301
  const result = opts.groundingCwd === undefined
300
302
  ? await write(ask, opts.cwd, authorDeps, superseded ? { supersedes: superseded } : undefined)
@@ -10,6 +10,7 @@ import type { LLMUsage } from '../prompt-cache/types.js';
10
10
  import { debug } from '../debug/log.js';
11
11
  import { ensureDeviceFirstSteps, inspectDeviceFirstGoal } from './device-first.js';
12
12
  import { COMPLETION_BOUNDARY_STEP_PREFIX, FOLDED_DEVICE_FIRST_ACTION_MARKER } from './goal-author-decompose.js';
13
+ import { loadMockScenarioCatalog, type MockScenarioDevice, type MockScenarioEntry } from '../ux-sim/mock-scenario-catalog.js';
13
14
 
14
15
  function observeGoalAuthor(
15
16
  category: 'goal-author' | 'goal-author.clarify',
@@ -20,6 +21,7 @@ function observeGoalAuthor(
20
21
  debug.log(category === 'goal-author' ? 'harness.author' : 'harness.author.clarify', event, data);
21
22
  }
22
23
  import { getUserConfig } from '../user-config.js';
24
+ import { getProviderForConfig, streamLLM, type LLMMessage } from '../llm.js';
23
25
 
24
26
  export type GoalAuthorGrade = 'full' | 'lite';
25
27
  export type GoalAuthorGradeSource = 'flag' | 'env' | 'config' | 'default';
@@ -79,6 +81,10 @@ export interface GoalAuthorDeps {
79
81
  ground: (ask: string, groundingDeps?: GoalAuthorGroundingDeps) => Promise<CodebaseGrounding>;
80
82
  persistentGrounding?: GoalAuthorGroundingDeps;
81
83
  authorGrade?: GoalAuthorGradeSelection;
84
+ /** Production Terra reviewer precheck; omitted is disabled unless the shared config switch is on. */
85
+ reviewerPrecheckEnabled?: boolean;
86
+ /** Optional seam for focused tests; production uses the pinned Terra medium reviewer. */
87
+ reviewerPrecheck?: (document: string, authorRunId: string) => Promise<GoalAuthorReviewerPrecheckResult>;
82
88
  enhance: (ask: string, opts?: EnhanceOpts) => Promise<GoalEnhancement>;
83
89
  /** Additive enhancer options supplied by the file-writing entrypoint. */
84
90
  enhanceOpts?: EnhanceOpts;
@@ -137,6 +143,209 @@ export interface GoalAuthorDeps {
137
143
  authoringLessons?: string;
138
144
  }
139
145
 
146
+ export interface GoalAuthorReviewerPrecheckResult {
147
+ readonly suggestions: readonly string[];
148
+ readonly fixes: readonly string[];
149
+ /** Exact, replayable edits in fixes order; together they must explain the entire document diff. */
150
+ readonly fixEvidence?: readonly { readonly fix: string; readonly originalText: string; readonly revisedText: string }[];
151
+ readonly remainingNeedsHuman: readonly string[];
152
+ readonly revisedDocument: string;
153
+ readonly appliedFixes: readonly string[];
154
+ readonly unappliedItems: readonly string[];
155
+ }
156
+
157
+ const GOAL_AUTHOR_REVIEWER_PRECHECK_MODEL = 'gpt-6.1-terra';
158
+
159
+ export function parseGoalAuthorReviewerPrecheck(raw: string): GoalAuthorReviewerPrecheckResult {
160
+ const text = raw.trim().replace(/^```(?:json)?\s*/iu, '').replace(/\s*```$/u, '');
161
+ const value: unknown = JSON.parse(text);
162
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('reviewer response must be an object');
163
+ const record = value as Record<string, unknown>;
164
+ const readList = (key: string): string[] => {
165
+ const candidate = record[key];
166
+ if (!Array.isArray(candidate) || candidate.some((item) => typeof item !== 'string')) {
167
+ throw new Error(`reviewer response ${key} must be a string array`);
168
+ }
169
+ return candidate;
170
+ };
171
+ const revisedDocument = record.revisedDocument;
172
+ if (typeof revisedDocument !== 'string' || !revisedDocument.trim()) throw new Error('reviewer response revisedDocument must be non-empty text');
173
+ return {
174
+ suggestions: readList('suggestions'),
175
+ fixes: readList('fixes'),
176
+ ...(record.fixEvidence === undefined ? {} : {
177
+ fixEvidence: (() => {
178
+ const candidate = record.fixEvidence;
179
+ if (!Array.isArray(candidate) || candidate.some((item) => !item || typeof item !== 'object'
180
+ || typeof (item as Record<string, unknown>).fix !== 'string'
181
+ || typeof (item as Record<string, unknown>).originalText !== 'string'
182
+ || typeof (item as Record<string, unknown>).revisedText !== 'string')) {
183
+ throw new Error('reviewer response fixEvidence must be an array of { fix, originalText, revisedText }');
184
+ }
185
+ return candidate as { fix: string; originalText: string; revisedText: string }[];
186
+ })(),
187
+ }),
188
+ remainingNeedsHuman: readList('remainingNeedsHuman'),
189
+ revisedDocument,
190
+ appliedFixes: [],
191
+ unappliedItems: [],
192
+ };
193
+ }
194
+
195
+ function reviewerRevisionIsValid(original: string, revised: string): boolean {
196
+ if (!revised.trim() || verbatimOriginalAsk(revised) !== verbatimOriginalAsk(original)) return false;
197
+ if (parseGoalId(revised) !== parseGoalId(original)
198
+ || parseRootIntent(revised) !== parseRootIntent(original)
199
+ || parseGoalType(revised) !== parseGoalType(original)) return false;
200
+ if (JSON.stringify(canonicalBlocks(revised)) !== JSON.stringify(canonicalBlocks(original))) return false;
201
+ return !lintGoalFile(revised, 'reviewer-precheck').some((finding) => finding.level === 'ERROR');
202
+ }
203
+
204
+ function reviewerEditIsGrounded(original: string, edit: { fix: string; originalText: string; revisedText: string }): boolean {
205
+ if (!edit.originalText || edit.revisedText === edit.originalText || !edit.revisedText.startsWith(edit.originalText)) return false;
206
+ const acceptanceStart = original.indexOf('## ACCEPTANCE CRITERIA');
207
+ const evidenceStart = original.indexOf('## REQUIRED EVIDENCE');
208
+ const nextHeading = (start: number): number => {
209
+ const next = original.indexOf('\n## ', start + 1);
210
+ return next < 0 ? original.length : next;
211
+ };
212
+ const editStart = original.indexOf(edit.originalText);
213
+ if (editStart < 0 || original.indexOf(edit.originalText, editStart + edit.originalText.length) >= 0) return false;
214
+ const sectionTexts = [
215
+ acceptanceStart >= 0 ? original.slice(acceptanceStart + '## ACCEPTANCE CRITERIA'.length, nextHeading(acceptanceStart)) : '',
216
+ evidenceStart >= 0 ? original.slice(evidenceStart + '## REQUIRED EVIDENCE'.length, nextHeading(evidenceStart)) : '',
217
+ ];
218
+ const isCompleteCriterion = sectionTexts.some((section) => section.split('\n').some((line) =>
219
+ /^\s*[-*]\s+\S/u.test(line) && line.trim() === edit.originalText.trim()));
220
+ if (!isCompleteCriterion) return false;
221
+ const appended = edit.revisedText.slice(edit.originalText.length);
222
+ if (!/^\r?\n[ \t]*[-*][ \t]+\S/u.test(appended)) return false;
223
+ const added = appended
224
+ .replace(/^\r?\n[ \t]*[-*][ \t]*/u, '')
225
+ .replace(/^\[[a-z-]+\][ \t]*/iu, '')
226
+ .trim();
227
+ if (edit.fix !== added) return false;
228
+ const ask = verbatimOriginalAsk(original);
229
+ if (!added || !ask) return false;
230
+ const sentences = ask
231
+ .split(/(?<=[.!?])(?:[ \t]+|$)|\r?\n/u)
232
+ .map((sentence) => sentence.trim())
233
+ .filter(Boolean);
234
+ return sentences.includes(added);
235
+ }
236
+
237
+ export function resolveGoalAuthorReviewerPrecheckEnabled(config = getUserConfig()): boolean {
238
+ return config.tools.selfImplement.goalAuthorReviewerPrecheck === true;
239
+ }
240
+
241
+ export async function runGoalAuthorReviewerPrecheck(
242
+ document: string,
243
+ deps: { config?: ReturnType<typeof getUserConfig>; stream?: typeof streamLLM } = {},
244
+ ): Promise<GoalAuthorReviewerPrecheckResult> {
245
+ const config = deps.config ?? getUserConfig();
246
+ const pinnedConfig = {
247
+ ...config,
248
+ llm: { ...config.llm, provider: 'openai-codex' as const, model: GOAL_AUTHOR_REVIEWER_PRECHECK_MODEL },
249
+ };
250
+ const provider = getProviderForConfig(pinnedConfig, GOAL_AUTHOR_REVIEWER_PRECHECK_MODEL);
251
+ const prompt = [
252
+ 'Review this completed goal document before it is written. Return only JSON with string-array fields suggestions, fixes, remainingNeedsHuman, a fixEvidence array of { fix, originalText, revisedText }, and a revisedDocument string.',
253
+ 'Apply each necessary fix to revisedDocument exactly once while preserving the original ask, GoalId, RootIntent, GoalType, every existing criterion and scope boundary, and canonical section structure. Be strictly conservative: only append one complete sentence copied verbatim from the original ask to an existing acceptance-criteria or required-evidence line; never append a partial substring or clause, especially one inside a negation or condition, and do not delete or reword existing text, add new scope, or edit other sections. For every fixes item, include one fixEvidence object in the same order: fixes item and fix must both equal the exact complete sentence appended from the original ask; originalText and revisedText must be exact spans where revisedText starts with originalText and appends that sentence, and replaying every single replacement reproduces the complete revisedDocument with no other edits. If you cannot explain and ground every change this way, return no fixes and leave revisedDocument byte-for-byte unchanged. Keep optional suggestions separate; list unresolved decisions or evidence as remainingNeedsHuman.',
254
+ document,
255
+ ].join('\n\n');
256
+ const messages: LLMMessage[] = [{ role: 'user', content: prompt }];
257
+ let actualProvider = provider.name;
258
+ let actualModel = GOAL_AUTHOR_REVIEWER_PRECHECK_MODEL;
259
+ const raw = await (deps.stream ?? streamLLM)(messages, () => undefined, {
260
+ provider,
261
+ model: GOAL_AUTHOR_REVIEWER_PRECHECK_MODEL,
262
+ reasoningEffort: 'medium',
263
+ maxTokens: 3000,
264
+ usageRole: 'review',
265
+ usagePhase: 'author-reviewer-precheck',
266
+ usageSite: 'author-reviewer-precheck',
267
+ onResolvedProvider: (resolvedProvider, resolvedModel) => { actualProvider = resolvedProvider; actualModel = resolvedModel; },
268
+ });
269
+ debug.log('author.reviewer-precheck', 'response', { provider: actualProvider, model: actualModel, responseChars: raw.length });
270
+ return parseGoalAuthorReviewerPrecheck(raw);
271
+ }
272
+
273
+ export async function executeGoalAuthorReviewerPrecheck(
274
+ enabled: boolean,
275
+ document: string,
276
+ authorRunId: string,
277
+ run: (document: string) => Promise<GoalAuthorReviewerPrecheckResult> = (value) => runGoalAuthorReviewerPrecheck(value),
278
+ observe: (event: string, data: Record<string, unknown>) => void = (event, data) => debug.log('author.reviewer-precheck', event, data),
279
+ ): Promise<{ status: 'skipped' | 'completed' | 'rejected-soft' | 'failed-soft'; result?: GoalAuthorReviewerPrecheckResult }> {
280
+ if (!enabled) {
281
+ observe('precheck-skipped', { authorRunId, reason: 'disabled', providerCalls: 0 });
282
+ return { status: 'skipped' };
283
+ }
284
+ try {
285
+ const proposed = await run(document);
286
+ const evidence = proposed.fixEvidence ?? [];
287
+ let replayed = document;
288
+ let fixesSupported = proposed.fixes.length === 0
289
+ ? proposed.revisedDocument === document && evidence.length === 0
290
+ : evidence.length === proposed.fixes.length;
291
+ if (fixesSupported) {
292
+ for (let index = 0; index < proposed.fixes.length; index += 1) {
293
+ const edit = evidence[index];
294
+ if (!edit || edit.fix !== proposed.fixes[index] || !reviewerEditIsGrounded(document, edit) || !replayed.includes(edit.originalText)) {
295
+ fixesSupported = false;
296
+ break;
297
+ }
298
+ const at = replayed.indexOf(edit.originalText);
299
+ if (replayed.indexOf(edit.originalText, at + edit.originalText.length) !== -1) {
300
+ fixesSupported = false;
301
+ break;
302
+ }
303
+ replayed = replayed.slice(0, at) + edit.revisedText + replayed.slice(at + edit.originalText.length);
304
+ }
305
+ fixesSupported = fixesSupported && replayed === proposed.revisedDocument;
306
+ }
307
+ const valid = reviewerRevisionIsValid(document, proposed.revisedDocument)
308
+ && fixesSupported
309
+ && (proposed.fixes.length === 0 || proposed.revisedDocument !== document);
310
+ const result: GoalAuthorReviewerPrecheckResult = valid
311
+ ? { ...proposed, appliedFixes: proposed.fixes, unappliedItems: [] }
312
+ : {
313
+ ...proposed,
314
+ revisedDocument: document,
315
+ appliedFixes: [],
316
+ unappliedItems: proposed.fixes,
317
+ remainingNeedsHuman: [...new Set([...proposed.remainingNeedsHuman, ...proposed.fixes])],
318
+ };
319
+ const status = valid ? 'completed' : 'rejected-soft';
320
+ observe(valid ? 'completed' : 'revision-rejected', {
321
+ authorRunId,
322
+ provider: 'openai-codex',
323
+ model: GOAL_AUTHOR_REVIEWER_PRECHECK_MODEL,
324
+ status,
325
+ proposedSuggestionCount: result.suggestions.length,
326
+ proposedFixCount: result.fixes.length,
327
+ appliedFixCount: result.appliedFixes.length,
328
+ appliedFixes: result.appliedFixes,
329
+ fixEvidence: result.fixEvidence ?? [],
330
+ correctedItems: result.appliedFixes.length,
331
+ unappliedItemCount: result.unappliedItems.length,
332
+ unappliedItems: result.unappliedItems,
333
+ remainingNeedsHuman: result.remainingNeedsHuman,
334
+ suggestionsResult: result.suggestions,
335
+ fixesResult: result.fixes,
336
+ remainingNeedsHumanResult: result.remainingNeedsHuman,
337
+ });
338
+ return { status, result };
339
+ } catch (error) {
340
+ observe('failed-soft', {
341
+ authorRunId,
342
+ reason: error instanceof Error ? error.message : String(error),
343
+ correctedItems: 0,
344
+ });
345
+ return { status: 'failed-soft' };
346
+ }
347
+ }
348
+
140
349
  export type GoalAuthorGroundingPath = 'groundMissionInCodebase';
141
350
 
142
351
  export interface GoalAuthorGroundingDeps {
@@ -663,9 +872,139 @@ export function inspectGoalDoneBoundary(document: string): { values: Partial<Rec
663
872
  return { values, missing: GOAL_DONE_BOUNDARY_LABELS.filter((label) => !values[label]) };
664
873
  }
665
874
 
666
- export function explicitGoalDoneBoundaryLines(ask: string): string[] {
875
+ function goalDoneTestPaths(targetPath: string): string[] {
876
+ if (/\.(?:test|spec)\.[cm]?[jt]sx?$/i.test(targetPath)) return [targetPath];
877
+ const source = /^(.*)\.([cm]?[jt]sx?)$/i.exec(targetPath);
878
+ if (!source) return [`${targetPath}.test.ts`, `${targetPath}.spec.ts`];
879
+ const extension = source[2]!.toLowerCase();
880
+ const siblingExtensions = extension === 'tsx' ? ['tsx', 'ts'] : extension === 'jsx' ? ['jsx', 'js'] : extension === 'ts' ? ['ts', 'tsx'] : extension === 'js' ? ['js', 'jsx'] : [extension];
881
+ return siblingExtensions.flatMap((testExtension) => [`${source[1]}.test.${testExtension}`, `${source[1]}.spec.${testExtension}`]);
882
+ }
883
+
884
+ function bunTestEvidencePath(command: string | undefined): string | undefined {
885
+ if (command === undefined) return undefined;
886
+ return /^bun\s+test\s+(?:(?:--\s+)?)(\S+\.(?:test|spec)\.[cm]?[jt]sx?)(?:\s|$)/u.exec(unwrapGoalDoneValue(command))?.[1];
887
+ }
888
+
889
+ function goalPathTokens(paths: readonly string[]): Set<string> {
890
+ return new Set(paths.map((path) => path.split(/[\\/]/u).at(-1) ?? path)
891
+ .flatMap((path) => path.toLowerCase().split(/[._-]+/u))
892
+ .filter((token) => token.length > 2 && !['src', 'test', 'tests', 'spec', 'tsx', 'ts', 'jsx', 'js'].includes(token)));
893
+ }
894
+
895
+ function goalPathStems(paths: readonly string[]): Set<string> {
896
+ return new Set(paths.map((path) => (path.split(/[\\/]/u).at(-1) ?? path).toLowerCase()
897
+ .replace(/\.(?:test|spec)\.[^.]+$/u, '')
898
+ .replace(/\.[^.]+$/u, '')));
899
+ }
900
+
901
+ function matchingPathCount(paths: readonly string[], targetPaths: readonly string[]): number {
902
+ const targetStems = goalPathStems(targetPaths);
903
+ if ([...goalPathStems(paths)].some((stem) => targetStems.has(stem))) return 10;
904
+ const targetTokens = goalPathTokens(targetPaths);
905
+ return [...goalPathTokens(paths)].filter((token) => targetTokens.has(token)).length;
906
+ }
907
+
908
+ function behaviorTokens(value: string): Set<string> {
909
+ const stop = new Set(['the', 'and', 'with', 'from', 'this', 'that', 'when', 'then', 'into', 'only', 'are', 'is', 'for', 'bun', 'test', 'code', 'boundary', 'request', 'expected', 'target', 'file', '완료', '경계', '증거', '명령', '대상', '요청', '기대', '시험', '확인', '시나리오']);
910
+ return new Set((value.toLowerCase().match(/[\p{L}\p{N}]{2,}/gu) ?? []).filter((token) => !stop.has(token)));
911
+ }
912
+
913
+ function matchingScenarioBehaviorCount(scenario: MockScenarioEntry, ask: string): number {
914
+ const { values } = inspectGoalDoneBoundary(ask);
915
+ const requestedText = `${values['완료 경계 코드'] ?? ''} ${values['완료 경계 실물'] ?? ''}`;
916
+ const describedText = `${scenario.name} ${scenario.kind} ${scenario.trigger} ${scenario.observe.join(' ')} ${scenario.expected}`;
917
+ const requested = behaviorTokens(requestedText);
918
+ const described = behaviorTokens(describedText);
919
+ const polarity = (text: string, token: string): boolean => {
920
+ const words = text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
921
+ return words.some((word, index) => word === token && words.slice(Math.max(0, index - 3), index).some((nearby) => /^(?:not|never|no|without|isn't|doesn't|않|못|아니)/u.test(nearby)));
922
+ };
923
+ const oppositePairs = [
924
+ ['distinct', 'indistinguishable'], ['preserved', 'lost'], ['visible', 'hidden'], ['visible', 'invisible'],
925
+ ['harvestable', 'unharvestable'], ['independent', 'dependent'], ['succeeds', 'fails'], ['accepted', 'rejected'],
926
+ ];
927
+ const shared = [...described].filter((token) => requested.has(token));
928
+ if (shared.some((token) => polarity(requestedText, token) !== polarity(describedText, token))
929
+ || oppositePairs.some(([left, right]) => (requested.has(left) && described.has(right)) || (requested.has(right) && described.has(left)))) return 0;
930
+ return shared.length;
931
+ }
932
+
933
+ function nextGoalScenarioId(catalogIds: readonly string[], targets: readonly string[]): string {
934
+ const targetName = targets.map((path) => path.split(/[\\/]/u).at(-1) ?? '')
935
+ .map((name) => name.replace(/\.[^.]+$/u, '').replace(/\.(?:test|spec)$/u, ''))
936
+ .find(Boolean) ?? 'TARGET';
937
+ const slug = targetName.toUpperCase().replace(/[^A-Z0-9]+/gu, '-').replace(/^-|-$/gu, '').slice(0, 32) || 'TARGET';
938
+ const prefix = `MK-${slug}-TDD-EVIDENCE`;
939
+ const existing = new Set(catalogIds);
940
+ for (let sequence = 1; sequence <= 99; sequence++) {
941
+ const candidate = `${prefix}-${String(sequence).padStart(2, '0')}`;
942
+ if (!existing.has(candidate)) return candidate;
943
+ }
944
+ return `${prefix}-${Date.now().toString(36).toUpperCase()}`;
945
+ }
946
+
947
+ function selectGoalMockStage(ask: string, targets: readonly string[]): { device: MockScenarioDevice; scenario?: MockScenarioEntry } | undefined {
948
+ const catalog = loadMockScenarioCatalog();
949
+ const device = catalog.devices
950
+ .map((candidate) => ({ candidate, score: matchingPathCount([...candidate.implementation, ...candidate.tests], targets) }))
951
+ .filter((entry) => entry.score >= 2)
952
+ .sort((left, right) => right.score - left.score)[0]?.candidate
953
+ ?? (/(?:author|goal|mission|저작|골|미션)/iu.test(`${targets.join(' ')}\n${ask}`)
954
+ ? catalog.devices.find((candidate) => candidate.id === 'product-devices')
955
+ : catalog.devices.find((candidate) => candidate.id === 'scenario-runner'));
956
+ if (!device) return undefined;
957
+ const scenario = catalog.scenarios
958
+ .filter((candidate) => candidate.device === device.id)
959
+ .map((candidate) => ({ candidate, pathScore: matchingPathCount([...candidate.implementation, ...candidate.tests], targets), behaviorScore: matchingScenarioBehaviorCount(candidate, ask) }))
960
+ .filter((entry) => entry.pathScore >= 2 && entry.behaviorScore >= 2)
961
+ .sort((left, right) => right.behaviorScore - left.behaviorScore || right.pathScore - left.pathScore)[0]?.candidate;
962
+ return { device, ...(scenario ? { scenario } : {}) };
963
+ }
964
+
965
+ export function explicitGoalDoneBoundaryLines(ask: string, repositoryRoot?: string): string[] {
667
966
  const { values } = inspectGoalDoneBoundary(ask);
668
- return GOAL_DONE_BOUNDARY_LABELS.flatMap((label) => values[label] ? [`- ${label}: ${values[label]}`] : []);
967
+ const explicitLines = GOAL_DONE_BOUNDARY_LABELS.flatMap((label) => values[label] ? [`- ${label}: ${values[label]}`] : []);
968
+ // Keep the exported extractor's original contract for callers that only ask
969
+ // for verbatim values. Goal authoring opts into catalog planning by supplying
970
+ // its repository root at the production call sites below.
971
+ if (repositoryRoot === undefined) return explicitLines;
972
+ const unquotedAsk = ask.replace(/```[\s\S]*?```/gu, '');
973
+ const targets = declaredTargetPaths(unquotedAsk);
974
+ const existingEvidence = values['완료 경계 증거 명령'];
975
+ const targetTestPaths = targets.flatMap(goalDoneTestPaths);
976
+ const existingBunTestPath = bunTestEvidencePath(existingEvidence);
977
+ const testPath = targetTestPaths.find((path) => existsSync(resolve(repositoryRoot, path)))
978
+ ?? (existingBunTestPath && targetTestPaths.includes(existingBunTestPath) ? existingBunTestPath : undefined)
979
+ ?? targetTestPaths[0]
980
+ ?? existingBunTestPath;
981
+ const shouldReplaceEvidence = existingBunTestPath === undefined;
982
+ const plannedTestPath = !shouldReplaceEvidence && existingBunTestPath ? existingBunTestPath : testPath;
983
+ const evidenceCommand = shouldReplaceEvidence && testPath ? `bun test ${testPath}` : existingEvidence;
984
+ const needsNewTest = plannedTestPath !== undefined && !existsSync(resolve(repositoryRoot, plannedTestPath));
985
+ const mockStage = targets.length ? selectGoalMockStage(ask, targets) : undefined;
986
+ const lines = GOAL_DONE_BOUNDARY_LABELS.flatMap((label) => {
987
+ if (label === '완료 경계 증거 명령' && evidenceCommand !== undefined) return [`- ${label}: ${evidenceCommand}`];
988
+ return values[label] ? [`- ${label}: ${values[label]}`] : [];
989
+ });
990
+ if (needsNewTest && plannedTestPath) lines.push(`- 신설: ${plannedTestPath}`);
991
+ if (shouldReplaceEvidence && existingEvidence && /type-?check|tsc|typescript/iu.test(existingEvidence)) {
992
+ lines.push(`- 증거 보충: ${existingEvidence} (타입검사는 보조 검증)`);
993
+ }
994
+ if (mockStage) {
995
+ lines.push(`- 장치: ${mockStage.device.id} — ${mockStage.device.name} (카탈로그 경로 일치: ${[...mockStage.device.implementation, ...mockStage.device.tests].filter((path) => matchingPathCount([path], targets) > 0).join(' · ') || mockStage.device.target})`);
996
+ if (mockStage.scenario) {
997
+ lines.push(`- 시나리오: ${mockStage.scenario.id} — ${mockStage.scenario.name}`);
998
+ } else {
999
+ const id = nextGoalScenarioId(loadMockScenarioCatalog().scenarios.map((scenario) => scenario.id), targets);
1000
+ const requestedCode = values['완료 경계 코드'] ?? '요청 대상의 완료 경계';
1001
+ const requestedObservation = values['완료 경계 실물'] ?? '격리 시험에서 요청된 생산 동작과 결과를 관측한다';
1002
+ lines.push(`- 시나리오: 신설 초안 (MS-id 후보: ${id})`);
1003
+ lines.push(`- 시나리오 초안: 사건은 ${targets.join(' · ') || '요청 대상'}에 «${requestedCode}» 경계를 적용한 입력; 기대는 생산 경로에서 «${requestedObservation}»을 관측하고 bun test ${plannedTestPath ?? '<대상 시험 파일>'}로 GREEN을 확인하는 것이다. 자식은 기존 카탈로그 API·ScenarioV0 형식에 맞춰 요청 대상의 사건·기대를 구체화해 등록한다.`);
1004
+ }
1005
+ }
1006
+ if (plannedTestPath) lines.push(`- 검증 계획(TDD): 장치 ${mockStage?.device.id ?? '미선정'} · 시나리오 ${mockStage?.scenario?.id ?? '신설 초안'} · ${needsNewTest ? '신설 시험' : '기존 시험에 요청 동작 회귀 사례 추가'} ${plannedTestPath} · 피처 시험 bun test ${plannedTestPath}를 구현 전에 RED로 확인한다.`);
1007
+ return lines;
669
1008
  }
670
1009
 
671
1010
  /**
@@ -2535,6 +2874,8 @@ export interface AuthoredGoal {
2535
2874
  authorRunId: string;
2536
2875
  /** AUTHOR-TIMEBOX: present only when the `ground` phase was short-circuited for exceeding its budget. */
2537
2876
  groundingTimebox?: GoalAuthorGroundingTimebox;
2877
+ /** Raw structured reviewer output is preserved for the caller and run observability. */
2878
+ reviewerPrecheck?: GoalAuthorReviewerPrecheckResult;
2538
2879
  }
2539
2880
 
2540
2881
  /** AUTHOR-TIMEBOX 산출 — 예산과 실제 경과. 둘 다 «잰 값»이고 지어낸 값이 아니다. */
@@ -6236,7 +6577,7 @@ async function authorGoalWithSupersededRootIntent(
6236
6577
  '',
6237
6578
  '## ACCEPTANCE CRITERIA',
6238
6579
  ...enhancement.checklist.map(requestedCriterionLine),
6239
- ...explicitGoalDoneBoundaryLines(ask),
6580
+ ...explicitGoalDoneBoundaryLines(ask, deps.repositoryRoot ?? process.cwd()),
6240
6581
  '',
6241
6582
  '## REQUIRED EVIDENCE',
6242
6583
  '- [requested] Verify the decision signal and the verbatim ask.',
@@ -6721,7 +7062,7 @@ async function authorGoalWithSupersededRootIntent(
6721
7062
  : ['## STEPS', ...(resolvedSteps.length ? resolvedSteps.map((step) => `- ${step}`) : ['- No externally injected steps.']), '']),
6722
7063
  '## ACCEPTANCE CRITERIA',
6723
7064
  ...acceptanceSection,
6724
- ...explicitGoalDoneBoundaryLines(ask),
7065
+ ...explicitGoalDoneBoundaryLines(ask, deps.repositoryRoot ?? process.cwd()),
6725
7066
  ...preservationAmbiguityCriteria(ambiguities, clarificationAnswers),
6726
7067
  ...preservationAmbiguityNotice(ambiguities),
6727
7068
  ...preservationAmbiguityClarification(clarificationQuestions, clarificationResponses),
@@ -7067,6 +7408,19 @@ export async function writeAuthoredGoal(
7067
7408
  ...(supersededGoalId && { goalId: supersededGoalId }),
7068
7409
  ...(supersededRootIntent !== null && { supersessionRootIntent: supersededRootIntent }),
7069
7410
  });
7411
+ const reviewerPrecheckEnabled = resolvedDeps.reviewerPrecheckEnabled ?? resolveGoalAuthorReviewerPrecheckEnabled();
7412
+ const precheck = await executeGoalAuthorReviewerPrecheck(
7413
+ reviewerPrecheckEnabled,
7414
+ authored.document,
7415
+ authored.authorRunId,
7416
+ (document) => (resolvedDeps.reviewerPrecheck
7417
+ ? resolvedDeps.reviewerPrecheck(document, authored.authorRunId)
7418
+ : runGoalAuthorReviewerPrecheck(document)),
7419
+ );
7420
+ if (precheck.result) {
7421
+ authored.reviewerPrecheck = precheck.result;
7422
+ if (precheck.status === 'completed') authored.document = precheck.result.revisedDocument;
7423
+ }
7070
7424
  const stampedAt = fileDeps.now?.() ?? new Date();
7071
7425
  const identity = identityLines(ask, cwd, fileDeps.env ?? process.env, stampedAt);
7072
7426
  if (identity.length) {
@@ -167,8 +167,10 @@ export function applyGraphOverlays(
167
167
  rejections.push({ kind: 'unknown-target', overlayId: overlay.overlayId, target: overlay.target });
168
168
  continue;
169
169
  }
170
+ const beforeNodes = new Map(next.nodes.map((node) => [node.nodeId, node]));
170
171
  const beforeVisits = new Map(next.nodes.map((node) => [node.nodeId, node.maxVisits]));
171
- const beforeRoutes = edgeMapOf(next);
172
+ const beforeRoutes = graphRouteMap(next);
173
+ const beforeEdgeMap = edgeMapOf(next);
172
174
  for (const op of overlay.patch) {
173
175
  const resolved = resolvePointer(next, op.path);
174
176
  if (!resolved) { rejections.push({ kind: 'bad-pointer', overlayId: overlay.overlayId, path: op.path }); continue; }
@@ -190,15 +192,27 @@ export function applyGraphOverlays(
190
192
  if (op.op === 'remove') delete bag[key]; else bag[key] = op.value;
191
193
  } else rejections.push({ kind: 'bad-pointer', overlayId: overlay.overlayId, path: op.path });
192
194
  }
195
+ for (const node of next.nodes) {
196
+ if (beforeNodes.has(node.nodeId)) continue;
197
+ patches.push({ overlayId: overlay.overlayId, field: 'node-added', node: node.nodeId, kind: node.kind, maxVisits: node.maxVisits });
198
+ }
199
+ const afterRoutes = graphRouteMap(next);
200
+ for (const [key, route] of afterRoutes) {
201
+ const before = beforeRoutes.get(key);
202
+ if (before && before.to !== route.to) {
203
+ patches.push({ overlayId: overlay.overlayId, field: 'edge-rerouted', from: route.from, outcome: route.outcome, was: before.to, to: route.to });
204
+ }
205
+ }
193
206
  for (const node of next.nodes) {
194
207
  const before = beforeVisits.get(node.nodeId);
195
208
  if (before !== undefined && before !== node.maxVisits) {
196
209
  patches.push({ overlayId: overlay.overlayId, field: 'maxVisits', node: node.nodeId, before, after: node.maxVisits });
197
210
  }
198
211
  }
199
- const afterRoutes = edgeMapOf(next);
200
- for (const [node, before] of Object.entries(beforeRoutes)) {
201
- const after = afterRoutes[node] ?? [];
212
+ const afterEdgeMap = edgeMapOf(next);
213
+ for (const node of Object.keys(beforeEdgeMap)) {
214
+ const before = beforeEdgeMap[node] ?? [];
215
+ const after = afterEdgeMap[node] ?? [];
202
216
  if (before.length !== after.length || before.some((destination, index) => destination !== after[index])) {
203
217
  patches.push({ overlayId: overlay.overlayId, field: 'routes', node, before, after });
204
218
  }
@@ -246,6 +260,18 @@ export function applyGraphOverlays(
246
260
  return { ok: true, template: next, overlayIds: applied, patches };
247
261
  }
248
262
 
263
+ /** Keep outcome names while comparing route changes; the compiled edge map deliberately drops them. */
264
+ function graphRouteMap(template: GraphTemplateSpec): Map<string, { from: string; outcome: string; to: string }> {
265
+ const routes = new Map<string, { from: string; outcome: string; to: string }>();
266
+ for (const [index, edge] of template.edges.entries()) {
267
+ if (edge.to) routes.set(`${edge.from}\u0000direct\u0000${index}`, { from: edge.from, outcome: '', to: edge.to });
268
+ for (const [outcome, to] of Object.entries(edge.map ?? {})) {
269
+ routes.set(`${edge.from}\u0000${edge.on ?? 'outcome'}\u0000${outcome}`, { from: edge.from, outcome, to });
270
+ }
271
+ }
272
+ return routes;
273
+ }
274
+
249
275
  export interface OverlayLoadResult {
250
276
  readonly overlays: readonly GraphOverlaySpec[];
251
277
  readonly errors: readonly GraphParseIssue[];
@@ -26,7 +26,9 @@ export type OverlayRejection =
26
26
 
27
27
  export type OverlayPatch =
28
28
  | { readonly overlayId: string; readonly field: 'maxVisits'; readonly node: string; readonly before: number; readonly after: number }
29
- | { readonly overlayId: string; readonly field: 'routes'; readonly node: string; readonly before: readonly string[]; readonly after: readonly string[] };
29
+ | { readonly overlayId: string; readonly field: 'routes'; readonly node: string; readonly before: readonly string[]; readonly after: readonly string[] }
30
+ | { readonly overlayId: string; readonly field: 'node-added'; readonly node: string; readonly kind: string; readonly maxVisits: number }
31
+ | { readonly overlayId: string; readonly field: 'edge-rerouted'; readonly from: string; readonly outcome: string; readonly was: string; readonly to: string };
30
32
 
31
33
  export type OverlayResult =
32
34
  | { ok: true; template: GraphTemplate; patches: readonly OverlayPatch[] }
@@ -0,0 +1,107 @@
1
+ import { readFileSync, readdirSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { parse as parseYaml } from 'yaml';
5
+ import { evaluateOverlayCondition, parseOverlayCondition } from './graph-overlay-condition.js';
6
+ import type { GraphParseIssue } from './graph-yaml.js';
7
+
8
+ /** L1 profile: a deterministic state bundle and references to already-declared overlays. */
9
+ export interface GraphProfileSpec {
10
+ readonly profileId: string;
11
+ readonly appliesWhen: string;
12
+ readonly state: Readonly<Record<string, string | number | boolean>>;
13
+ readonly overlays: readonly string[];
14
+ }
15
+
16
+ export interface GraphProfileParseResult {
17
+ readonly profile?: GraphProfileSpec;
18
+ readonly errors: readonly GraphParseIssue[];
19
+ }
20
+
21
+ export function parseGraphProfileYaml(source: string, label = '<inline>'): GraphProfileParseResult {
22
+ let raw: unknown;
23
+ try { raw = parseYaml(source); }
24
+ catch (error) {
25
+ return { errors: [{ path: label, message: `YAML 파싱 실패: ${error instanceof Error ? error.message : String(error)}` }] };
26
+ }
27
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
28
+ return { errors: [{ path: label, message: 'YAML 최상위가 맵이 아니다' }] };
29
+ const doc = raw as Record<string, unknown>;
30
+ const errors: GraphParseIssue[] = [];
31
+ const profileId = typeof doc.profile_id === 'string' && /^[a-z][a-z0-9-]*$/.test(doc.profile_id) ? doc.profile_id : undefined;
32
+ if (!profileId) errors.push({ path: `${label}/profile_id`, message: 'profile_id는 소문자·숫자·하이픈 식별자여야 한다' });
33
+ const appliesWhen = typeof doc.applies_when === 'string' ? doc.applies_when : undefined;
34
+ if (!appliesWhen || !parseOverlayCondition(appliesWhen).ok)
35
+ errors.push({ path: `${label}/applies_when`, message: 'applies_when은 오버레이 조건 한 개(key op literal)여야 한다' });
36
+ const stateRaw = doc.state;
37
+ const state: Record<string, string | number | boolean> = {};
38
+ if (!stateRaw || typeof stateRaw !== 'object' || Array.isArray(stateRaw)) {
39
+ errors.push({ path: `${label}/state`, message: 'state는 스칼라 값만 담는 맵이어야 한다' });
40
+ } else {
41
+ for (const [key, value] of Object.entries(stateRaw as Record<string, unknown>)) {
42
+ if (!/^[a-z_][a-z0-9_]*$/i.test(key) || !['string', 'number', 'boolean'].includes(typeof value)
43
+ || (typeof value === 'number' && !Number.isFinite(value))) {
44
+ errors.push({ path: `${label}/state/${key}`, message: 'state 키와 값은 조건 파서가 다루는 키·문자열·유한수·불리언이어야 한다' });
45
+ } else state[key] = value as string | number | boolean;
46
+ }
47
+ }
48
+ const overlaysRaw = doc.overlays;
49
+ const overlays = Array.isArray(overlaysRaw) ? overlaysRaw.filter((value): value is string => typeof value === 'string') : undefined;
50
+ if (!Array.isArray(overlaysRaw) || !overlays || overlays.length !== overlaysRaw.length || new Set(overlays).size !== overlays.length)
51
+ errors.push({ path: `${label}/overlays`, message: 'overlays는 중복 없는 문자열 목록이어야 한다' });
52
+ if (errors.length > 0) return { errors };
53
+ return { profile: { profileId: profileId!, appliesWhen: appliesWhen!, state, overlays: overlays! }, errors };
54
+ }
55
+
56
+ export interface GraphProfileLoadResult {
57
+ readonly profiles: readonly GraphProfileSpec[];
58
+ readonly errors: readonly GraphParseIssue[];
59
+ readonly scannedFiles: number;
60
+ }
61
+
62
+ export function loadGraphProfiles(dir: string): GraphProfileLoadResult {
63
+ let files: string[];
64
+ try { files = readdirSync(dir).filter((file) => file.endsWith('.yaml') || file.endsWith('.yml')).sort(); }
65
+ catch (error) { return { profiles: [], errors: [{ path: dir, message: `프로필 디렉토리를 못 읽었다: ${error instanceof Error ? error.message : String(error)}` }], scannedFiles: 0 }; }
66
+ const errors: GraphParseIssue[] = [];
67
+ const profiles: GraphProfileSpec[] = [];
68
+ for (const file of files) {
69
+ try {
70
+ const parsed = parseGraphProfileYaml(readFileSync(join(dir, file), 'utf8'), file);
71
+ errors.push(...parsed.errors);
72
+ if (parsed.profile) profiles.push(parsed.profile);
73
+ } catch (error) { errors.push({ path: file, message: `읽기 실패: ${error instanceof Error ? error.message : String(error)}` }); }
74
+ }
75
+ const seen = new Set<string>();
76
+ for (const profile of profiles) {
77
+ if (seen.has(profile.profileId)) errors.push({ path: `${dir}/${profile.profileId}`, message: `profile_id '${profile.profileId}'가 중복이다` });
78
+ seen.add(profile.profileId);
79
+ }
80
+ return errors.length ? { profiles: [], errors, scannedFiles: files.length } : { profiles, errors, scannedFiles: files.length };
81
+ }
82
+
83
+ export function defaultProfilesDir(): string {
84
+ return join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'graphs', 'profiles');
85
+ }
86
+
87
+ export interface GraphProfileSelection {
88
+ readonly applied: readonly GraphProfileSpec[];
89
+ readonly errors: readonly string[];
90
+ readonly state: Readonly<Record<string, unknown>>;
91
+ }
92
+
93
+ /** Match all profiles deterministically; conflicting owned state rejects the whole profile set. */
94
+ export function selectGraphProfiles(
95
+ profiles: readonly GraphProfileSpec[],
96
+ state: Readonly<Record<string, unknown>>,
97
+ ): GraphProfileSelection {
98
+ const applied = profiles.filter((profile) => evaluateOverlayCondition(profile.appliesWhen, state).kind === 'applies');
99
+ const owned = new Map<string, string | number | boolean>();
100
+ const errors: string[] = [];
101
+ for (const profile of applied) for (const [key, value] of Object.entries(profile.state)) {
102
+ if (owned.has(key) && owned.get(key) !== value) errors.push(`profile state conflict: ${key} (${String(owned.get(key))} vs ${String(value)})`);
103
+ else owned.set(key, value);
104
+ }
105
+ if (errors.length) return { applied: [], errors, state };
106
+ return { applied, errors, state: { ...state, ...Object.fromEntries(owned) } };
107
+ }