elanous 0.2.29 → 0.2.31
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.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{058a98ba.7eb28d5e6dc03565.js → 0bb0ff36.b8d418980951e5ba.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +27 -0
- package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +287 -0
- package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +62 -0
- package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6013-2f769370d8b4c2c6.js → 1335-6731f392c35216eb.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8332.6f0f49df772e163b.js → 1654.32de4b324981a188.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +149 -0
- package/apps/pwa/out/_next/static/chunks/{8795.32573a185af18c7b.js → 1913.7cc6fb6055b1ed3f.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{419.736c0d6f426249a7.js → 2001.6c7e0fd02190886c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.1fcfc9b8be83975f.js → 2213.2ccbada92c33ea0f.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4759.1f76713aefb87db5.js → 2871.0bca6137343b3f76.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6776.06ff1e3b464cc607.js → 2898.fd781bc7cf01a7b7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1782-59db1b5aa06df38a.js → 2940-619bfd8ef337c611.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8471.8d2a8c74f09c36ff.js → 2985.39ccdecd36848b12.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +115 -0
- package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +64 -0
- package/apps/pwa/out/_next/static/chunks/{bc324b7c.02a09dd93f6a399b.js → 3267c0e6.d34854e7b3984a6e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3278.2e5d15b53a4091c8.js +2 -0
- package/apps/pwa/out/_next/static/chunks/{7725-4f83d5541fbdb81b.js → 3541-ce3a5424ed5ad7f1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +34 -0
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{46bd8bea.2f4b4099172fcdb7.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1142.65d002789ab3af7d.js → 4174.92ed04922709ac9e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +36 -0
- package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +77 -0
- package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +226 -0
- package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +79 -0
- package/apps/pwa/out/_next/static/chunks/5173-233188df2f42c626.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +148 -0
- package/apps/pwa/out/_next/static/chunks/5307.60f2209e809bd627.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3396-97b97928c49190c9.js → 5458-16cd7a2b51b74c8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3403.7199205e65124486.js → 5525.86debf231e181813.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9143.ff14585db1d275ff.js → 5543.a438b8ab5a13ea47.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +74 -0
- package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +94 -0
- package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8398.73a19b39715eda04.js → 6092.a7f99e68b188ca66.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5591.a35e7a217734a8b9.js → 6157.0c9af021de4fb31b.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7375.050ea0d72968e49f.js → 6433.fc573af22bbc9ab7.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +90 -0
- package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +104 -0
- package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +93 -0
- package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
- package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
- package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-a5635eba0d73b84e.js → page-2ebb8fd59b9461f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0a07363b130182a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-521ee23ac8c0abfa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-9f92737b8766009a.js → page-149dc1caba411bb9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
- package/apps/pwa/out/_next/static/css/{72becfd42807b50d.css → 3f5fc6f96e2cf7b2.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/bin/elanous.mjs +7 -3
- package/graphs/context/nightly-condense.yaml +1 -0
- package/graphs/intake/intake-daily.yaml +8 -1
- package/graphs/intake/recipes.yaml +5 -0
- package/graphs/lecture/lecture-note.yaml +2 -2
- package/graphs/ops/harness-gc.yaml +1 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +9 -5
- package/graphs/units/recipes.yaml +3 -0
- package/graphs/units/release-gate-recheck.yaml +15 -0
- package/package.json +2 -1
- package/scripts/check-native-tool-wiring.ts +3 -2
- package/scripts/ci-android-unit-tests.ts +16 -0
- package/scripts/ci-typecheck-changed.ts +37 -9
- package/scripts/coord-channel-watch.sh +22 -16
- package/scripts/coord-role-pack.ts +81 -2
- package/scripts/cron-run.ts +96 -3
- package/scripts/detect-test-interference.ts +38 -5
- package/scripts/gate-pr-cache.ts +65 -0
- package/scripts/gh-surface/capture.ts +126 -0
- package/scripts/gh-surface/gh +40 -0
- package/scripts/import-graph-scc.ts +38 -0
- package/scripts/install.ps1 +19 -0
- package/scripts/intake-social.ts +181 -0
- package/scripts/lecture-note/node.ts +71 -4
- package/scripts/lib/android-toolchain.ts +32 -0
- package/scripts/lib/deterministic-env.ts +62 -0
- package/scripts/lib/gate-test-env.ts +19 -0
- package/scripts/measure-goal-grounding-corpus.ts +2 -1
- package/scripts/ratchets/test-interference-patterns.allowlist.txt +257 -0
- package/scripts/ratchets/test-interference-patterns.ts +367 -0
- package/scripts/release-loop/cut-branch.ts +4 -3
- package/scripts/release-loop/export-check-node.ts +0 -1
- package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
- package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
- package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
- package/scripts/release-loop/gate-closure.ts +12 -8
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-host-mirror.ts +66 -0
- package/scripts/release-loop/gate-node.ts +523 -75
- package/scripts/release-loop/gate-partial.ts +106 -9
- package/scripts/release-loop/gate-pr-cache.ts +66 -0
- package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
- package/scripts/release-loop/gate-r2-verdict.ts +189 -0
- package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
- package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
- package/scripts/release-loop/import-graph-scc-run.ts +54 -0
- package/scripts/release-loop/import-graph-scc.ts +215 -0
- package/scripts/release-loop/node-verdict.ts +2 -0
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
- package/scripts/release-loop/resume-release.ts +33 -4
- package/scripts/release-loop/resume.ts +13 -5
- package/scripts/release-loop/spawn-lane.ts +2 -19
- package/scripts/release-loop/tui-sim-node.ts +3 -2
- package/scripts/release-loop/unattended-release.ts +16 -0
- package/scripts/test-deterministic.ts +5 -61
- package/scripts/train-reach-grouping.ts +48 -0
- package/scripts/tsc-incremental-cache.ts +86 -0
- package/scripts/tsc-incremental-diagnostics.ts +76 -0
- package/scripts/tsc-main-safety-net.ts +2 -2
- package/src/acp/client.ts +4 -1
- package/src/acp/core-turn-bridge.ts +50 -5
- package/src/ad-pipeline/run.ts +4 -2
- package/src/agent/runner.ts +169 -3
- package/src/agent/subagent-callable.ts +3 -2
- package/src/agent-mission/review-loop.ts +6 -3
- package/src/agent-substrate/acp-implementer.ts +14 -2
- package/src/agent-substrate/pr-reviewer.ts +12 -0
- package/src/agent-substrate/self-review-cli.ts +30 -4
- package/src/autopilot/pr-manager.ts +62 -7
- package/src/briefing/brief-items.ts +24 -22
- package/src/capture/tui-self-report.ts +15 -0
- package/src/chat/chat-cli.ts +10 -2
- package/src/chat/index.ts +77 -11
- package/src/chat/input-control-key.ts +5 -3
- package/src/chat/tool-interrupt-behavior.ts +38 -0
- package/src/chat/tool-render/dispatch.ts +5 -1
- package/src/chat/turn-typeahead.ts +75 -20
- package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
- package/src/cli/agent-cli.ts +41 -13
- package/src/cli/config-audit.ts +123 -0
- package/src/cli/decisions-cli.ts +80 -6
- package/src/cli/log-event-names.ts +7 -0
- package/src/cli/mcp-login.ts +21 -5
- package/src/cli/msg-cli.ts +88 -0
- package/src/cli/pr-cli.ts +214 -57
- package/src/cli/pr-land-heavy-remote.ts +2 -2
- package/src/cli/pr-land-overlap-evidence.ts +63 -9
- package/src/cli/pr-land-pod-shadow-job.ts +83 -0
- package/src/cli/pr-land-pod-shadow.ts +16 -3
- package/src/cli/pr-land-virtual-rebase.ts +108 -0
- package/src/cli/release-cli.ts +80 -14
- package/src/cli/seat-cli.ts +138 -3
- package/src/cli/self-update.ts +5 -2
- package/src/cli/tasks-cli.ts +97 -19
- package/src/context-bus/context-first.ts +13 -0
- package/src/context-bus/context-now.ts +13 -2
- package/src/context-bus/ops-events.ts +75 -0
- package/src/control-plane/lease-holder.ts +12 -8
- package/src/control-plane/ledger.ts +163 -4
- package/src/control-plane/server.ts +91 -11
- package/src/core-turn/run-core-turn.ts +1 -0
- package/src/core-turn/run-goal-loop.ts +222 -3
- package/src/core-turn/seat-turn-cap.ts +79 -0
- package/src/core-turn/short-question.ts +38 -6
- package/src/core-turn/types.ts +3 -0
- package/src/dashboard/acp-boot.ts +3 -0
- package/src/dashboard/index.ts +224 -615
- package/src/dashboard/input/chat-main-entry-runtime.ts +1 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
- package/src/dashboard/input/chat-main-session.ts +8 -1
- package/src/dashboard/input/chat-main-turn.ts +12 -3
- package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
- package/src/dashboard/input/external-input-host.ts +26 -0
- package/src/dashboard/input/internal-turn.ts +261 -0
- package/src/dashboard/input/seat-autowake.ts +318 -0
- package/src/dashboard/input/turn-steer-bridge.ts +70 -0
- package/src/dashboard/loop-scheduler.ts +72 -0
- package/src/dashboard/seat-boot-preamble.ts +18 -0
- package/src/dashboard/skill-runtime.ts +2 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
- package/src/dashboard/slash-runtime/index.ts +13 -0
- package/src/dashboard/turn-busy-teardown.ts +50 -0
- package/src/decisions/decision-ledger.ts +45 -4
- package/src/discord-self-message.ts +4 -4
- package/src/domains/release-tool.ts +18 -1
- package/src/field-note/transcribe.ts +17 -0
- package/src/github/remote-call.ts +81 -0
- package/src/goals/registry.ts +46 -6
- package/src/goals/types.ts +7 -1
- package/src/graph-runner/runner.ts +1 -0
- package/src/grok/credential.ts +26 -0
- package/src/harness/harness-clean.ts +2 -1
- package/src/harness/harness-cli-command.ts +52 -5
- package/src/harness/harness-gc.ts +2 -1
- package/src/harness/harness-incidents.ts +57 -20
- package/src/harness/harness-pod-dispatch.ts +87 -10
- package/src/harness/harness-queue.ts +53 -4
- package/src/harness/harness-stop.ts +4 -3
- package/src/harness/harness-substrate-default.ts +78 -7
- package/src/harness/harness-worktree-auto.ts +2 -1
- package/src/harness/harness-worktrees.ts +3 -2
- package/src/hooks/dispatch.ts +2 -1
- package/src/index.ts +152 -25
- package/src/input/external-input-queue.ts +33 -1
- package/src/intake-plane/slash.ts +14 -3
- package/src/keybindings.ts +4 -1
- package/src/llm/tool-loop-steered-rejection.ts +33 -0
- package/src/llm.ts +138 -19
- package/src/loops/consensus.ts +348 -0
- package/src/loops/msg-wake.ts +206 -4
- package/src/loops/observe.ts +19 -3
- package/src/loops/orchestrator/tick.ts +64 -10
- package/src/loops/orchestrator/traffic.ts +64 -1
- package/src/loops/registry.ts +30 -0
- package/src/market/signed-index.ts +14 -0
- package/src/mcp/mcp-oauth.ts +54 -5
- package/src/models/prompts.ts +28 -0
- package/src/msg/msg-sse-client.ts +223 -0
- package/src/msg/msg-store.ts +86 -2
- package/src/mss/logging/log-store.ts +225 -1
- package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
- package/src/nexus/api/http-server.ts +54 -15
- package/src/nexus/api/loop-resources.ts +19 -3
- package/src/nexus/api/ops-api.ts +11 -0
- package/src/nexus/daemon-thin-inventory.md +37 -0
- package/src/nexus/index.ts +70 -0
- package/src/nexus/state/state.ts +1 -0
- package/src/oauth/store.ts +32 -7
- package/src/onboarding/first-run.ts +28 -3
- package/src/ops/overview-cache.ts +16 -4
- package/src/ops/resources.ts +82 -0
- package/src/plugins/maker/connector-maker.ts +41 -0
- package/src/plugins/maker/skill-maker.ts +42 -0
- package/src/pr-tool/census.ts +288 -0
- package/src/prompt-library/chat-conciseness.ts +13 -0
- package/src/prompt-library/universal-preamble.ts +10 -5
- package/src/release-loop/gate-host-reservation.ts +97 -0
- package/src/release-loop/landing-freeze.ts +5 -0
- package/src/release-loop/light-rc.ts +5 -2
- package/src/release-loop/placement.ts +92 -1
- package/src/release-loop/rehearsal-shard-plan.ts +149 -0
- package/src/release-loop/rehearsal.ts +73 -17
- package/src/repl/index.ts +20 -2
- package/src/seat-loop/seat-knowhow.ts +282 -0
- package/src/seat-loop/seat-loop.ts +41 -2
- package/src/seat-loop/traffic-signal.ts +3 -0
- package/src/self-dev/ask-launch-flow.ts +24 -3
- package/src/self-dev/decompose-compose-graph.ts +28 -27
- package/src/self-dev/decompose-proposal.ts +53 -38
- package/src/self-dev/decompose.ts +17 -0
- package/src/self-dev/dev-pipeline.ts +31 -2
- package/src/self-dev/draft-residue.ts +24 -9
- package/src/self-dev/draft-sweep.ts +59 -4
- package/src/self-dev/external-call-zero.ts +77 -0
- package/src/self-dev/launch-preflight-text.ts +6 -0
- package/src/self-dev/launch-preflight.ts +25 -3
- package/src/self-dev/local-supervisor-judge.ts +185 -0
- package/src/self-dev/run-supervisor.ts +229 -19
- package/src/self-dev/run-types.ts +20 -0
- package/src/self-dev/shard-aggregate.ts +13 -2
- package/src/self-dev/shard-plan.ts +47 -0
- package/src/self-dev/shard-run.ts +112 -10
- package/src/self-dev/spawn-lane-files.ts +19 -0
- package/src/self-implement/app-api-budget.ts +51 -11
- package/src/self-implement/config-gate.ts +2 -1
- package/src/self-implement/expose-gate.ts +2 -1
- package/src/self-implement/gate-artifacts.ts +405 -0
- package/src/self-implement/gate-cli.ts +201 -16
- package/src/self-implement/gate-remote.ts +110 -25
- package/src/self-implement/gate-scenario.ts +85 -0
- package/src/self-implement/goal-author.ts +160 -8
- package/src/self-implement/graph-authority.ts +38 -6
- package/src/self-implement/graph-overlay-condition.ts +92 -1
- package/src/self-implement/heal-triage.ts +79 -0
- package/src/self-implement/host-regate.ts +61 -3
- package/src/self-implement/orchestrator.ts +14 -123
- package/src/self-implement/pr-title.ts +123 -0
- package/src/self-implement/run-checkpoint.ts +235 -0
- package/src/self-implement/run-ledger.ts +155 -10
- package/src/self-implement/run-stop.ts +4 -3
- package/src/self-implement/run-ttl.ts +28 -4
- package/src/self-implement/seams.ts +2 -0
- package/src/self-implement/shadow-stage.ts +7 -6
- package/src/self-implement/stop-autoheal.ts +2 -1
- package/src/self-implement/train-gate-remote.ts +37 -8
- package/src/self-implement/train-reach-grouping.ts +157 -0
- package/src/self-implement/train-scenario-layers.ts +133 -0
- package/src/self-implement/uncommitted-work.ts +2 -0
- package/src/session/pending-input.ts +19 -0
- package/src/session/session-start.ts +224 -0
- package/src/session-runtime/parallel-dispatch.ts +22 -5
- package/src/skills/tools/dev-harness.ts +6 -4
- package/src/skills/tools/shell.ts +1 -1
- package/src/steward/resync-tick.ts +114 -23
- package/src/steward/ta-repair-event-collect.ts +158 -0
- package/src/task-agent/card-evidence.ts +25 -1
- package/src/task-agent/green-sweep.ts +8 -3
- package/src/task-agent/judge.ts +76 -0
- package/src/task-agent/land-queue.ts +79 -0
- package/src/task-agent/live-moves.ts +30 -9
- package/src/task-agent/postland-card.ts +5 -0
- package/src/task-agent/prelaunch-already-done.ts +98 -0
- package/src/task-agent/real-launch-guard.ts +37 -0
- package/src/task-agent/rejudge-on-head.ts +89 -12
- package/src/task-agent/remote-rejudge-bind.ts +28 -8
- package/src/task-agent/repair-cycle.ts +45 -7
- package/src/task-agent/repair-worker.ts +7 -0
- package/src/task-agent/run-identity.ts +200 -0
- package/src/task-agent/shadow.ts +50 -3
- package/src/task-agent/task-hand.ts +158 -5
- package/src/task-agent/train-landing.ts +77 -0
- package/src/task-agent/work-order.ts +104 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +88 -28
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
- package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
- package/src/task-orchestrator/surfaces/pod-lease.ts +20 -6
- package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
- package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
- package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +63 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
- package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
- package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +208 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +132 -15
- package/src/telegram.ts +2 -4
- package/src/tui/input/pickers.ts +732 -0
- package/src/tui/slash/mission.ts +492 -0
- package/src/tui/slash/term.ts +877 -0
- package/src/tui-client/dashboard-session.ts +9 -0
- package/src/tui.ts +48 -0
- package/src/user-config/gemini-server-tools.ts +9 -0
- package/src/user-config.ts +53 -16
- package/src/util/spawn-sync-output.ts +7 -0
- package/src/ux-sim/fake-bin.ts +154 -0
- package/src/ux-sim/fake-clock.ts +36 -0
- package/src/ux-sim/headless-tui.ts +72 -0
- package/src/ux-sim/in-process-cli.ts +2 -1
- package/src/ux-sim/temp-git-remote.ts +82 -0
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/vlog.ts +25 -7
- package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
- package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
- package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
- package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
- package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
- package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
- package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
- package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
- package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
- package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
- package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
- package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
- package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
- package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
- package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
- package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
- package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
- package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
- package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
- package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
- package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
- package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
- package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
- /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RES-FLOOR-API — «자원 지도» 접기(순수 층). I/O 0 · kubectl/ssh 0 · 새 수집 0.
|
|
3
|
+
* 이미 도는 overview 캐시의 메모 스냅숏과 응답 때 얹는 Pod 점유를 PWA 자원 지도 꼴로 접는다.
|
|
4
|
+
* 설계: 칸 RES-FLOOR-API(0.2.28) — 호스트별 load·mem · Pod 슬롯 · 칸마다 observedAt · 빠진 칸은 missing 사유.
|
|
5
|
+
*/
|
|
6
|
+
import type { Cell, MachineLoad, OverviewSnapshot, PodMemberRow } from './overview.js';
|
|
7
|
+
|
|
8
|
+
export interface ResourceCell<T> {
|
|
9
|
+
value: T | null;
|
|
10
|
+
observedAt: string | null;
|
|
11
|
+
/** value 가 없는 칸의 사유 — 측정됐으면 null */
|
|
12
|
+
missing: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface HostResourcesRow {
|
|
16
|
+
name: string;
|
|
17
|
+
load1: ResourceCell<number>;
|
|
18
|
+
load5: ResourceCell<number>;
|
|
19
|
+
load15: ResourceCell<number>;
|
|
20
|
+
cpuCount: ResourceCell<number>;
|
|
21
|
+
memFreeGb: ResourceCell<number>;
|
|
22
|
+
memTotalGb: ResourceCell<number>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PodSlotRow {
|
|
26
|
+
context: string;
|
|
27
|
+
capacity: number;
|
|
28
|
+
occupied: ResourceCell<number>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ResourcesMap {
|
|
32
|
+
/** 접은 스냅숏의 시각(overview generatedAt) */
|
|
33
|
+
generatedAt: string;
|
|
34
|
+
/** 이 읽기 시각 */
|
|
35
|
+
readAt: string;
|
|
36
|
+
hosts: HostResourcesRow[];
|
|
37
|
+
pods: PodSlotRow[];
|
|
38
|
+
/** 구조적으로 통째로 빈 칸의 사유(호스트 원장 비어 있음 · 풀 설정 없음) */
|
|
39
|
+
missing: string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const NO_REASON = '사유 없음';
|
|
43
|
+
|
|
44
|
+
function fold<T>(source: Cell<T>): ResourceCell<T> {
|
|
45
|
+
const measured = source.status !== 'unmeasured' && source.value !== null;
|
|
46
|
+
return { value: measured ? source.value : null, observedAt: source.observedAt, missing: measured ? null : source.reason ?? NO_REASON };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 호스트의 모든 숫자 칸은 같은 하트비트 cell 에서 나오니 observedAt·missing 도 함께 접힌다. */
|
|
50
|
+
function hostRow(host: OverviewSnapshot['machines']['hosts'][number]): HostResourcesRow {
|
|
51
|
+
const load = fold(host.load);
|
|
52
|
+
const num = (pick: (l: MachineLoad) => number): ResourceCell<number> => load.value !== null
|
|
53
|
+
? { value: pick(load.value), observedAt: load.observedAt, missing: null }
|
|
54
|
+
: { value: null, observedAt: load.observedAt, missing: load.missing };
|
|
55
|
+
return {
|
|
56
|
+
name: host.name,
|
|
57
|
+
load1: num((l) => l.load1),
|
|
58
|
+
load5: num((l) => l.load5),
|
|
59
|
+
load15: num((l) => l.load15),
|
|
60
|
+
cpuCount: num((l) => l.cpuCount),
|
|
61
|
+
memFreeGb: num((l) => l.freeGb),
|
|
62
|
+
memTotalGb: num((l) => l.totalGb),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function resourcesFromOverview(snapshot: OverviewSnapshot, pods: readonly PodMemberRow[], now: number): ResourcesMap {
|
|
67
|
+
const byContext = new Map(pods.map((pod) => [pod.context, pod]));
|
|
68
|
+
const missing: string[] = [];
|
|
69
|
+
if (snapshot.machines.hosts.length === 0) missing.push('hosts: 하트비트 원장 비어 있음');
|
|
70
|
+
if (snapshot.machines.pods.length === 0) missing.push('pods: 풀 설정 없음');
|
|
71
|
+
return {
|
|
72
|
+
generatedAt: snapshot.generatedAt,
|
|
73
|
+
readAt: new Date(now).toISOString(),
|
|
74
|
+
hosts: snapshot.machines.hosts.map(hostRow),
|
|
75
|
+
pods: snapshot.machines.pods.map((pod): PodSlotRow => ({
|
|
76
|
+
context: pod.context,
|
|
77
|
+
capacity: pod.capacity,
|
|
78
|
+
occupied: fold((byContext.get(pod.context) ?? pod).occupied),
|
|
79
|
+
})),
|
|
80
|
+
missing,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { lstatSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { loadPluginManifestFromDir } from '../core/manifest.js';
|
|
4
|
+
import type { PluginDraft } from './plugin-maker.js';
|
|
5
|
+
|
|
6
|
+
export interface MakeConnectorOptions {
|
|
7
|
+
dir: string;
|
|
8
|
+
gap: PluginDraft['connectors'][number];
|
|
9
|
+
id: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Add one connector's credential-name-only draft to the existing extension manifest. */
|
|
13
|
+
export function makeConnector({ dir: inputDir, gap, id }: MakeConnectorOptions): string {
|
|
14
|
+
if (!/^[a-z0-9][a-z0-9-]{1,31}$/.test(id) || !gap || !gap.name.trim() || gap.name === '미확인'
|
|
15
|
+
|| !gap.use.trim() || !Array.isArray(gap.evidence) || !gap.evidence.every(source => typeof source === 'string')
|
|
16
|
+
|| !Array.isArray(gap.missingCredentials)) throw new Error('invalid connector gap or id');
|
|
17
|
+
const dir = resolve(inputDir);
|
|
18
|
+
const path = join(dir, 'plugin.json');
|
|
19
|
+
const stat = lstatSync(path, { throwIfNoEntry: false });
|
|
20
|
+
if (!stat?.isFile() || stat.isSymbolicLink() || lstatSync(dir).isSymbolicLink()
|
|
21
|
+
|| realpathSync(dir) !== join(realpathSync(dirname(dir)), basename(dir))) {
|
|
22
|
+
throw new Error('plugin.json missing or unsafe');
|
|
23
|
+
}
|
|
24
|
+
const raw: unknown = JSON.parse(readFileSync(path, 'utf8'));
|
|
25
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('invalid plugin.json');
|
|
26
|
+
const data = raw as Record<string, unknown>;
|
|
27
|
+
const extensions = data.extensions as Record<string, unknown> | undefined;
|
|
28
|
+
const extension = extensions?.['ai.elanous'];
|
|
29
|
+
if (!extension || typeof extension !== 'object' || Array.isArray(extension)) throw new Error('missing ai.elanous extension');
|
|
30
|
+
const entry = extension as Record<string, unknown>;
|
|
31
|
+
if (entry.connectors !== undefined && !Array.isArray(entry.connectors)) throw new Error('invalid connectors');
|
|
32
|
+
const manifest = loadPluginManifestFromDir(dir, { id: 'local-plugin' }).manifest;
|
|
33
|
+
if (manifest.contributes.connectors?.some(connector => connector.id === id)) throw new Error(`connector already exists: ${id}`);
|
|
34
|
+
const credentials = gap.missingCredentials.filter(name => /^[A-Za-z_][A-Za-z0-9_-]*$/.test(name));
|
|
35
|
+
if (new Set(credentials).size !== credentials.length) throw new Error('duplicate connector credential name');
|
|
36
|
+
entry.connectors = [...(entry.connectors as unknown[] | undefined ?? []), {
|
|
37
|
+
id, fields: credentials.map(name => ({ name, secret: true })),
|
|
38
|
+
}];
|
|
39
|
+
writeFileSync(path, JSON.stringify(data, null, 2) + '\n');
|
|
40
|
+
return path;
|
|
41
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { lstatSync, mkdirSync, realpathSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { stringify as stringifyYaml } from 'yaml';
|
|
4
|
+
import { loadPluginManifestFromDir } from '../core/manifest.js';
|
|
5
|
+
import type { PluginDraft } from './plugin-maker.js';
|
|
6
|
+
|
|
7
|
+
export interface MakeSkillOptions {
|
|
8
|
+
dir: string;
|
|
9
|
+
gap: PluginDraft['skills'][number];
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Write one researched skill as the wizard's SKILL.md draft, without altering the plugin manifest. */
|
|
14
|
+
export function makeSkill({ dir: inputDir, gap, id }: MakeSkillOptions): string {
|
|
15
|
+
if (!/^[a-z0-9][a-z0-9-]{1,31}$/.test(id) || !gap || !gap.name.trim() || gap.name === '미확인'
|
|
16
|
+
|| !gap.use.trim() || !Array.isArray(gap.evidence) || !gap.evidence.every(source => typeof source === 'string')) {
|
|
17
|
+
throw new Error('invalid skill gap or id');
|
|
18
|
+
}
|
|
19
|
+
const dir = resolve(inputDir);
|
|
20
|
+
const manifestPath = join(dir, 'plugin.json');
|
|
21
|
+
const manifestEntry = lstatSync(manifestPath, { throwIfNoEntry: false });
|
|
22
|
+
if (!manifestEntry?.isFile() || manifestEntry.isSymbolicLink()) {
|
|
23
|
+
throw new Error('plugin.json missing or unsafe');
|
|
24
|
+
}
|
|
25
|
+
loadPluginManifestFromDir(dir, { id: 'local-plugin' });
|
|
26
|
+
const skillsDir = join(dir, 'skills');
|
|
27
|
+
const skillDir = join(skillsDir, id);
|
|
28
|
+
const path = join(skillDir, 'SKILL.md');
|
|
29
|
+
// An ancestor can be a platform alias (macOS /var -> /private/var); the plugin directory itself cannot be a link.
|
|
30
|
+
if (lstatSync(dir).isSymbolicLink()
|
|
31
|
+
|| realpathSync(dir) !== join(realpathSync(dirname(dir)), basename(dir))) {
|
|
32
|
+
throw new Error('unsafe plugin directory');
|
|
33
|
+
}
|
|
34
|
+
const skillsEntry = lstatSync(skillsDir, { throwIfNoEntry: false });
|
|
35
|
+
if (skillsEntry && !skillsEntry.isDirectory()) throw new Error('unsafe skills directory');
|
|
36
|
+
if (lstatSync(skillDir, { throwIfNoEntry: false })) throw new Error(`skill already exists: ${id}`);
|
|
37
|
+
const instructions = gap.use + (gap.evidence.length ? `\n\nResearch sources:\n${gap.evidence.join(', ')}` : '');
|
|
38
|
+
const content = `---\n${stringifyYaml({ name: id, description: gap.use, requires: [] })}---\n\n${instructions}\n`;
|
|
39
|
+
mkdirSync(skillDir, { recursive: true });
|
|
40
|
+
writeFileSync(path, content, { flag: 'wx' });
|
|
41
|
+
return path;
|
|
42
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/** Shared PR inventory and creation guard for the CLI and harness. All incomplete reads stay unknown. */
|
|
2
|
+
import { debug } from '../debug/log.js';
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
6
|
+
import { withFileLockSync } from '../storage/file-lock.js';
|
|
7
|
+
import { resolveHostId } from '../platform/host-id.js';
|
|
8
|
+
|
|
9
|
+
export interface PrToolCommandResult { ok: boolean; out: string; err?: string }
|
|
10
|
+
export type PrToolCommand = (command: string, args: readonly string[], opts?: { cwd?: string }) => PrToolCommandResult;
|
|
11
|
+
export type Seat = 'OP' | 'TC' | 'MK' | 'UX';
|
|
12
|
+
export interface OpenPr {
|
|
13
|
+
number: number;
|
|
14
|
+
title: string;
|
|
15
|
+
draft: boolean;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
headSha: string;
|
|
18
|
+
labels: readonly string[];
|
|
19
|
+
files: readonly string[];
|
|
20
|
+
seat: Seat | null;
|
|
21
|
+
lastCommitAt?: string;
|
|
22
|
+
cellId: string | null;
|
|
23
|
+
hunks?: readonly DiffHunk[];
|
|
24
|
+
}
|
|
25
|
+
export type Inventory = { status: 'checked'; prs: readonly OpenPr[] } | { status: 'unknown'; reason: string };
|
|
26
|
+
export interface CensusRow { seat: Seat | 'unknown'; open: number; goalOnly: number; staleDraft: number; supersededOpen: number }
|
|
27
|
+
export type Census = { status: 'checked'; total: number; rows: readonly CensusRow[]; closeCandidates: readonly { number: number; reason: 'goal-only' | 'stale-draft' | 'superseded-open' }[] }
|
|
28
|
+
| { status: 'unknown'; reason: string };
|
|
29
|
+
export interface DiffHunk { path: string; start: number; end: number }
|
|
30
|
+
export type GuardCode = 'inventory-unknown' | 'candidate-unknown' | 'goal-only' | 'file-overlap' | 'hunk-overlap' | 'same-cell' | 'seat-cap' | 'seat-unattributed';
|
|
31
|
+
export interface GuardReason { code: GuardCode; detail: string; prs?: readonly number[] }
|
|
32
|
+
export interface GuardVerdict { status: 'allow' | 'refuse' | 'unknown'; reasons: readonly GuardReason[]; warnings: readonly GuardReason[] }
|
|
33
|
+
|
|
34
|
+
const SEATS = ['OP', 'TC', 'MK', 'UX'] as const;
|
|
35
|
+
const DEFAULT_SEAT_CAP = 30;
|
|
36
|
+
const DRAFT_STALE_MS = 2 * 24 * 60 * 60 * 1000;
|
|
37
|
+
const MAX_PAGES = 100;
|
|
38
|
+
const MAX_FILES = 3000; // GitHub does not expose more than 3000 PR files.
|
|
39
|
+
const UNMEASURED_WINDOW_MS = 60 * 60 * 1000;
|
|
40
|
+
const UNMEASURED_ALLOW_COUNT = 3;
|
|
41
|
+
|
|
42
|
+
function unknown(reason: string): Inventory { return { status: 'unknown', reason }; }
|
|
43
|
+
function seatValue(value: unknown): Seat | null { return SEATS.find(seat => seat === value) ?? null; }
|
|
44
|
+
function seatFromLabels(labels: readonly string[]): Seat | null {
|
|
45
|
+
return SEATS.find(seat => labels.includes(`seat:${seat}`)) ?? null;
|
|
46
|
+
}
|
|
47
|
+
export function cellIdFromBody(body: string): string | null {
|
|
48
|
+
return /^\s*(?:[-*]\s*)?칸\s*:\s*([A-Z][A-Z0-9-]{2,})\s*$/m.exec(body)?.[1] ?? null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function parseDiffHunks(patch: string): DiffHunk[] {
|
|
52
|
+
const hunks: DiffHunk[] = [];
|
|
53
|
+
let path: string | null = null;
|
|
54
|
+
let fileHeaderPending = false;
|
|
55
|
+
for (const line of patch.split('\n')) {
|
|
56
|
+
if (line.startsWith('diff --git ')) { path = null; fileHeaderPending = true; continue; }
|
|
57
|
+
if (fileHeaderPending && line.startsWith('--- ')) {
|
|
58
|
+
if (line.startsWith('--- a/')) path = line.slice('--- a/'.length);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (fileHeaderPending && line.startsWith('+++ ')) {
|
|
62
|
+
if (line.startsWith('+++ b/')) path = line.slice('+++ b/'.length);
|
|
63
|
+
fileHeaderPending = false;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const match = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(line);
|
|
67
|
+
if (path && match) {
|
|
68
|
+
// This is an approximate comparison of old-side lines; PRs with different
|
|
69
|
+
// base trees can shift line numbers. The full merge gate remains authoritative.
|
|
70
|
+
// An insertion or new file has no old-side lines: use its insertion anchor.
|
|
71
|
+
const oldStart = Number(match[1]);
|
|
72
|
+
const oldCount = match[2] === undefined ? 1 : Number(match[2]);
|
|
73
|
+
const start = oldCount === 0 && oldStart === 0 ? Number(match[3]) : oldStart;
|
|
74
|
+
const count = oldCount === 0 ? 1 : oldCount;
|
|
75
|
+
hunks.push({ path, start, end: start + Math.max(1, count) - 1 });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return hunks;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** `gh api --paginate --slurp` must return every REST page, including the last page. */
|
|
82
|
+
function pages(run: PrToolCommand, endpoint: string, cwd?: string): readonly unknown[] {
|
|
83
|
+
const result = run('gh', ['api', '--paginate', '--slurp', endpoint], cwd ? { cwd } : undefined);
|
|
84
|
+
if (!result.ok) throw new Error(`gh api ${endpoint}: ${result.err || result.out || '조회 실패'}`);
|
|
85
|
+
let parsed: unknown;
|
|
86
|
+
try { parsed = JSON.parse(result.out); } catch { throw new Error(`gh api ${endpoint}: JSON 오류`); }
|
|
87
|
+
if (!Array.isArray(parsed) || parsed.length >= MAX_PAGES || !parsed.every(page => Array.isArray(page) && page.length <= 100)) {
|
|
88
|
+
throw new Error(`gh api ${endpoint}: 페이지 형식·상한 판정 불가`);
|
|
89
|
+
}
|
|
90
|
+
return parsed.flat();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function object(value: unknown): Record<string, unknown> {
|
|
94
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) throw new Error('PR 응답 행 형식 오류');
|
|
95
|
+
return value as Record<string, unknown>;
|
|
96
|
+
}
|
|
97
|
+
function text(value: unknown, name: string): string {
|
|
98
|
+
if (typeof value !== 'string' || !value.trim()) throw new Error(`${name} 누락`);
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
function date(value: unknown, name: string): string {
|
|
102
|
+
const raw = text(value, name);
|
|
103
|
+
if (!Number.isFinite(Date.parse(raw))) throw new Error(`${name} 날짜 오류`);
|
|
104
|
+
return raw;
|
|
105
|
+
}
|
|
106
|
+
function pathsForPr(run: PrToolCommand, number: number, cwd?: string): string[] {
|
|
107
|
+
const rows = pages(run, `repos/{owner}/{repo}/pulls/${number}/files?per_page=100`, cwd);
|
|
108
|
+
if (rows.length >= MAX_FILES) throw new Error(`PR #${number}: 파일 ${MAX_FILES}개 GitHub 상한에 닿음`);
|
|
109
|
+
return rows.map(row => text(object(row).filename, `PR #${number} 파일명`));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Fast file projection; the REST page census below remains the authority for which PRs exist. */
|
|
113
|
+
function projectedFiles(run: PrToolCommand, count: number, cwd?: string): Map<number, string[]> {
|
|
114
|
+
const result = run('gh', ['pr', 'list', '--state', 'open', '--limit', String(Math.max(count, 1)), '--json', 'number,changedFiles,files'], cwd ? { cwd } : undefined);
|
|
115
|
+
if (!result.ok) return new Map();
|
|
116
|
+
let rows: unknown;
|
|
117
|
+
try { rows = JSON.parse(result.out); } catch { return new Map(); }
|
|
118
|
+
if (!Array.isArray(rows)) return new Map();
|
|
119
|
+
const projection = new Map<number, string[]>();
|
|
120
|
+
for (const value of rows) {
|
|
121
|
+
try {
|
|
122
|
+
const row = object(value);
|
|
123
|
+
if (!Number.isSafeInteger(row.number) || (row.number as number) <= 0 || !Number.isSafeInteger(row.changedFiles) || (row.changedFiles as number) < 0 || !Array.isArray(row.files)) continue;
|
|
124
|
+
const paths = row.files.map(file => text(object(file).path, 'PR 파일명'));
|
|
125
|
+
if (paths.length === row.changedFiles && paths.length < MAX_FILES && !projection.has(row.number as number)) projection.set(row.number as number, paths);
|
|
126
|
+
} catch { /* malformed projection: REST file endpoint below decides this PR */ }
|
|
127
|
+
}
|
|
128
|
+
return projection;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function readOpenPrs(run: PrToolCommand, options: {
|
|
132
|
+
cwd?: string;
|
|
133
|
+
seatOfPr?: (pr: { number: number; headRefName: string; body: string; labels: readonly string[] }) => Seat | null;
|
|
134
|
+
includeDraftCommitDates?: boolean;
|
|
135
|
+
candidateFiles?: readonly string[];
|
|
136
|
+
} = {}): Inventory {
|
|
137
|
+
try {
|
|
138
|
+
const rows = pages(run, 'repos/{owner}/{repo}/pulls?state=open&per_page=100', options.cwd);
|
|
139
|
+
const projected = projectedFiles(run, rows.length, options.cwd);
|
|
140
|
+
const prs: OpenPr[] = [];
|
|
141
|
+
const seen = new Set<number>();
|
|
142
|
+
for (const value of rows) {
|
|
143
|
+
const row = object(value);
|
|
144
|
+
const number = row.number;
|
|
145
|
+
if (!Number.isSafeInteger(number) || (number as number) <= 0 || seen.has(number as number)) throw new Error('PR 번호 누락·중복');
|
|
146
|
+
seen.add(number as number);
|
|
147
|
+
if (row.state !== 'open' || typeof row.draft !== 'boolean') throw new Error(`PR #${number}: OPEN 상태·draft 판정 불가`);
|
|
148
|
+
const head = object(row.head);
|
|
149
|
+
const labels = row.labels;
|
|
150
|
+
if (!Array.isArray(labels)) throw new Error(`PR #${number}: 라벨 판정 불가`);
|
|
151
|
+
const labelNames = labels.map(label => text(object(label).name, `PR #${number} 라벨`));
|
|
152
|
+
const headRefName = text(head.ref, `PR #${number} head ref`);
|
|
153
|
+
const headSha = text(head.sha, `PR #${number} head sha`);
|
|
154
|
+
const body = typeof row.body === 'string' ? row.body : '';
|
|
155
|
+
const seat = seatValue(options.seatOfPr?.({ number: number as number, headRefName, body, labels: labelNames })) ?? seatFromLabels(labelNames);
|
|
156
|
+
const pr: OpenPr = {
|
|
157
|
+
number: number as number, title: text(row.title, `PR #${number} title`), draft: row.draft,
|
|
158
|
+
updatedAt: date(row.updated_at, `PR #${number} updated_at`), headSha, labels: labelNames,
|
|
159
|
+
files: projected.get(number as number) ?? pathsForPr(run, number as number, options.cwd), seat,
|
|
160
|
+
cellId: cellIdFromBody(body),
|
|
161
|
+
};
|
|
162
|
+
if (options.candidateFiles?.some(file => pr.files.includes(file))) {
|
|
163
|
+
const patch = run('gh', ['pr', 'diff', String(number), '--patch'], options.cwd ? { cwd: options.cwd } : undefined);
|
|
164
|
+
if (!patch.ok) throw new Error(`PR #${number}: 수정 줄 조회 실패: ${patch.err || patch.out}`);
|
|
165
|
+
pr.hunks = parseDiffHunks(patch.out);
|
|
166
|
+
}
|
|
167
|
+
if (pr.draft && options.includeDraftCommitDates) {
|
|
168
|
+
const commit = run('gh', ['api', `repos/{owner}/{repo}/commits/${headSha}`, '--jq', '.commit.committer.date'], options.cwd ? { cwd: options.cwd } : undefined);
|
|
169
|
+
if (!commit.ok) throw new Error(`PR #${number}: 마지막 커밋 날짜 조회 실패: ${commit.err || commit.out}`);
|
|
170
|
+
pr.lastCommitAt = date(commit.out.trim(), `PR #${number} 마지막 커밋`);
|
|
171
|
+
}
|
|
172
|
+
prs.push(pr);
|
|
173
|
+
}
|
|
174
|
+
return { status: 'checked', prs };
|
|
175
|
+
} catch (error) {
|
|
176
|
+
return unknown(error instanceof Error ? error.message : String(error));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function isGoalOnly(files: readonly string[]): boolean {
|
|
181
|
+
return files.length > 0 && files.every(path => path.startsWith('docs/goals/') && path.length > 'docs/goals/'.length);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function censusOpenPrs(inventory: Inventory, now = Date.now()): Census {
|
|
185
|
+
if (inventory.status === 'unknown') {
|
|
186
|
+
debug.log('pr.tool', 'census', { status: 'unknown', reason: inventory.reason });
|
|
187
|
+
return inventory;
|
|
188
|
+
}
|
|
189
|
+
const rows = new Map<Seat | 'unknown', CensusRow>();
|
|
190
|
+
const closeCandidates: Array<{ number: number; reason: 'goal-only' | 'stale-draft' | 'superseded-open' }> = [];
|
|
191
|
+
for (const pr of inventory.prs) {
|
|
192
|
+
const key = pr.seat ?? 'unknown';
|
|
193
|
+
const row = rows.get(key) ?? { seat: key, open: 0, goalOnly: 0, staleDraft: 0, supersededOpen: 0 };
|
|
194
|
+
row.open += 1;
|
|
195
|
+
if (isGoalOnly(pr.files)) { row.goalOnly += 1; closeCandidates.push({ number: pr.number, reason: 'goal-only' }); }
|
|
196
|
+
if (pr.draft) {
|
|
197
|
+
if (!pr.lastCommitAt) {
|
|
198
|
+
const reason = `PR #${pr.number}: draft 마지막 커밋 날짜 없음`;
|
|
199
|
+
debug.log('pr.tool', 'census', { status: 'unknown', reason });
|
|
200
|
+
return { status: 'unknown', reason };
|
|
201
|
+
}
|
|
202
|
+
if (now - Date.parse(pr.lastCommitAt) >= DRAFT_STALE_MS) { row.staleDraft += 1; closeCandidates.push({ number: pr.number, reason: 'stale-draft' }); }
|
|
203
|
+
}
|
|
204
|
+
if (pr.labels.includes('elanous:superseded')) { row.supersededOpen += 1; closeCandidates.push({ number: pr.number, reason: 'superseded-open' }); }
|
|
205
|
+
rows.set(key, row);
|
|
206
|
+
}
|
|
207
|
+
const result: Census = { status: 'checked', total: inventory.prs.length, rows: [...rows.values()], closeCandidates };
|
|
208
|
+
debug.log('pr.tool', 'census', { status: 'checked', total: result.total, candidates: closeCandidates.length });
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function guardNewPr(input: { files: readonly string[] | null; seat?: Seat | null; seatCap?: number; cellId?: string | null; hunks?: readonly DiffHunk[] }, inventory: Inventory): GuardVerdict {
|
|
213
|
+
if (!input.files || input.files.length === 0 || input.files.some(file => !file || file.startsWith('/') || file.includes('..'))) {
|
|
214
|
+
const reasons: GuardReason[] = [{ code: 'candidate-unknown', detail: '새 PR 변경 파일을 확인할 수 없음' }];
|
|
215
|
+
debug.log('pr.tool', 'guard-refuse', { status: 'unknown', reasons });
|
|
216
|
+
return { status: 'unknown', reasons, warnings: [] };
|
|
217
|
+
}
|
|
218
|
+
if (inventory.status === 'unknown') {
|
|
219
|
+
const reasons: GuardReason[] = [{ code: 'inventory-unknown', detail: inventory.reason }];
|
|
220
|
+
return { status: 'unknown', reasons, warnings: [] };
|
|
221
|
+
}
|
|
222
|
+
const reasons: GuardReason[] = [];
|
|
223
|
+
const warnings: GuardReason[] = [];
|
|
224
|
+
if (isGoalOnly(input.files)) reasons.push({ code: 'goal-only', detail: '골 문서만 변경 · 구현 0' });
|
|
225
|
+
const candidate = new Set(input.files);
|
|
226
|
+
const sameCell = input.cellId ? inventory.prs.filter(pr => pr.cellId === input.cellId) : [];
|
|
227
|
+
if (sameCell.length) reasons.push({ code: 'same-cell', detail: `같은 칸 ${input.cellId} OPEN PR이 있음`, prs: sameCell.map(pr => pr.number) });
|
|
228
|
+
const overlaps = inventory.prs.filter(pr => pr.files.some(file => candidate.has(file)));
|
|
229
|
+
const sameHunk = overlaps.filter(pr => pr.hunks?.some(other => input.hunks?.some(own => own.path === other.path && own.start <= other.end && other.start <= own.end)));
|
|
230
|
+
if (sameHunk.length) reasons.push({ code: 'hunk-overlap', detail: '같은 파일의 수정 줄 범위가 겹침', prs: sameHunk.map(pr => pr.number) });
|
|
231
|
+
if (overlaps.length) warnings.push({ code: 'file-overlap', detail: '같은 파일의 OPEN PR이 있음 · 줄 겹침은 별도 판정', prs: overlaps.map(pr => pr.number) });
|
|
232
|
+
const seat = seatValue(input.seat);
|
|
233
|
+
if (input.seat !== undefined && input.seat !== null && !seat) reasons.push({ code: 'candidate-unknown', detail: '호출자 자리 값 오류' });
|
|
234
|
+
const cap = input.seatCap ?? DEFAULT_SEAT_CAP;
|
|
235
|
+
if (!Number.isSafeInteger(cap) || cap < 1) {
|
|
236
|
+
reasons.push({ code: 'candidate-unknown', detail: '자리별 PR 상한 설정 오류' });
|
|
237
|
+
} else if (!seat) {
|
|
238
|
+
warnings.push({ code: 'seat-unattributed', detail: `호출자 자리 미상 · 전체 OPEN PR ${inventory.prs.length}건` });
|
|
239
|
+
} else {
|
|
240
|
+
const count = inventory.prs.filter(pr => pr.seat === seat).length;
|
|
241
|
+
if (count >= cap) warnings.push({ code: 'seat-cap', detail: `${seat} OPEN PR ${count}건 · 상한 ${cap}` });
|
|
242
|
+
const unattributed = inventory.prs.filter(pr => pr.seat === null).length;
|
|
243
|
+
if (unattributed) warnings.push({ code: 'seat-unattributed', detail: `귀속 미상 ${unattributed}건 · 전체 OPEN PR ${inventory.prs.length}건` });
|
|
244
|
+
}
|
|
245
|
+
const status = reasons.some(reason => reason.code === 'candidate-unknown') ? 'unknown' : reasons.length ? 'refuse' : 'allow';
|
|
246
|
+
if (status !== 'allow') debug.log('pr.tool', 'guard-refuse', { status, reasons, warnings });
|
|
247
|
+
else if (warnings.length) debug.log('pr.tool', 'guard-warn', { warnings });
|
|
248
|
+
return { status, reasons, warnings };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Persist the unknown-read budget across harness processes sharing one instance state root. */
|
|
252
|
+
export function recordGuardUnmeasured(input: { seat: Seat | null; reason: string; stateRoot?: string; host?: string; now?: number }): { count: number; blocked: boolean; reason?: string } {
|
|
253
|
+
const now = input.now ?? Date.now();
|
|
254
|
+
const seat = input.seat ?? 'unknown';
|
|
255
|
+
const host = input.host ?? resolveHostId();
|
|
256
|
+
try {
|
|
257
|
+
const dir = join(input.stateRoot ?? effectiveInstanceRoot(), 'pr-tool');
|
|
258
|
+
mkdirSync(dir, { recursive: true });
|
|
259
|
+
const file = join(dir, 'guard-unmeasured.jsonl');
|
|
260
|
+
return withFileLockSync(`${file}.lock`, () => {
|
|
261
|
+
const rows = existsSync(file) ? readFileSync(file, 'utf8').split('\n').filter(Boolean) : [];
|
|
262
|
+
const retained: Array<{ at: number; seat: string; host: string }> = [];
|
|
263
|
+
let count = 0;
|
|
264
|
+
for (const line of rows) {
|
|
265
|
+
let value: unknown;
|
|
266
|
+
try { value = JSON.parse(line); } catch { return { count: 0, blocked: true, reason: '판정 불가 원장 JSON 오류' }; }
|
|
267
|
+
if (value && typeof value === 'object') {
|
|
268
|
+
const row = value as { at?: unknown; seat?: unknown; host?: unknown };
|
|
269
|
+
if (typeof row.at !== 'number' || typeof row.seat !== 'string' || typeof row.host !== 'string') return { count: 0, blocked: true, reason: '판정 불가 원장 행 형식 오류' };
|
|
270
|
+
if (row.at > now - UNMEASURED_WINDOW_MS && row.at <= now) {
|
|
271
|
+
retained.push({ at: row.at, seat: row.seat, host: row.host });
|
|
272
|
+
if (row.seat === seat && row.host === host) count += 1;
|
|
273
|
+
}
|
|
274
|
+
} else return { count: 0, blocked: true, reason: '판정 불가 원장 행 형식 오류' };
|
|
275
|
+
}
|
|
276
|
+
retained.push({ at: now, seat, host });
|
|
277
|
+
count += 1;
|
|
278
|
+
writeFileSync(file, `${retained.map(row => JSON.stringify(row)).join('\n')}\n`);
|
|
279
|
+
const blocked = count > UNMEASURED_ALLOW_COUNT;
|
|
280
|
+
debug.log('pr-tool.open-guard', 'guard-unmeasured', { seat, host, count, blocked, reason: input.reason });
|
|
281
|
+
return { count, blocked };
|
|
282
|
+
});
|
|
283
|
+
} catch (error) {
|
|
284
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
285
|
+
debug.log('pr-tool.open-guard', 'guard-unmeasured', { seat, host, blocked: true, reason: `원장 오류: ${reason}` });
|
|
286
|
+
return { count: 0, blocked: true, reason };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
@@ -39,6 +39,19 @@ useful answers instead of narrated progress.
|
|
|
39
39
|
- Group related actions into one short preamble instead of emitting
|
|
40
40
|
a new status line before every command.
|
|
41
41
|
|
|
42
|
+
## Initiative
|
|
43
|
+
|
|
44
|
+
- Act first: when looking (repo, logs, tools) can answer or advance the
|
|
45
|
+
request, do that before asking, and answer with what you found or did.
|
|
46
|
+
- Ambiguous request: take the most plausible reading, proceed, and state
|
|
47
|
+
the assumption in one line. Ask first only when a wrong guess would be
|
|
48
|
+
costly or hard to undo.
|
|
49
|
+
- Finish forward: end with up to 3 concrete next steps. When one is
|
|
50
|
+
obvious, cheap and inside the request, continue and do it instead of
|
|
51
|
+
offering it.
|
|
52
|
+
- A stop always comes with a path: when you decline or cannot finish, say
|
|
53
|
+
what you will do instead or what would unblock it.
|
|
54
|
+
|
|
42
55
|
## Terminal formatting
|
|
43
56
|
|
|
44
57
|
- Use monospace CommonMark for commands, paths, env vars, and code ids.
|
|
@@ -104,10 +104,13 @@ execute the next stage; your tool calls are the audit trail.
|
|
|
104
104
|
|
|
105
105
|
## Analysis (분석) — find → read → organize
|
|
106
106
|
When a user's analysis question identifies a concrete, user-fixable code or
|
|
107
|
-
configuration defect
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
configuration defect: if the fix is small, low-risk and inside what the user
|
|
108
|
+
asked about, make it — switch to the Implementation pipeline, verify it, then
|
|
109
|
+
report what changed. Otherwise end the organized answer with 1-3 concrete
|
|
110
|
+
next actions and ask only the one decision that is really the user's (for
|
|
111
|
+
example, \`이 세 곳을 고칠까요?\` / \`수정할까요?\`). Do not ask when no actionable
|
|
112
|
+
defect was found, and do not claim a change was made before it is implemented
|
|
113
|
+
and verified.
|
|
111
114
|
1. **find**: ONE batch of search tools (Grep / Glob / ListDir / AstGrep
|
|
112
115
|
in parallel) to locate candidate files. Do not run a second \`find\`
|
|
113
116
|
batch unless the first returned ZERO useful candidates — if it
|
|
@@ -144,7 +147,9 @@ not claim a change was made before it is implemented and verified.
|
|
|
144
147
|
produces candidate paths. Do not issue a second \`find\` batch
|
|
145
148
|
searching the SAME paths/globs with different keywords — the
|
|
146
149
|
candidates are already on the table; advance to \`read\`.
|
|
147
|
-
- For Analysis:
|
|
150
|
+
- For Analysis: end at \`organize\` unless a small, low-risk fix inside the
|
|
151
|
+
request is ready — then switch to Implementation (edit → verify). Larger or
|
|
152
|
+
out-of-scope changes stay a proposal.
|
|
148
153
|
- For Implementation/Debugging: \`verify\` is mandatory. "I made the
|
|
149
154
|
change" without verification is incomplete output.
|
|
150
155
|
- Pick a pipeline ONLY when you actually need to use it. Pure conversational
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { psProcessStartMs } from '../harness/harness-stop.js';
|
|
5
|
+
import { debug } from '../debug/log.js';
|
|
6
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
7
|
+
|
|
8
|
+
interface GateHostClaim {
|
|
9
|
+
token: string;
|
|
10
|
+
runId: string;
|
|
11
|
+
hosts: string[];
|
|
12
|
+
pid: number;
|
|
13
|
+
pidStartedAt: number | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type GateHostReservation =
|
|
17
|
+
| { status: 'free' }
|
|
18
|
+
| { status: 'reserved' | 'unknown'; reason: string; runId?: string };
|
|
19
|
+
|
|
20
|
+
const hostName = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
21
|
+
const claimsDir = (root: string) => join(root, 'release', 'gate-host-reservations');
|
|
22
|
+
|
|
23
|
+
/** The release graph's pinned child state and the self gate CLI's selected universe resolve through this same entry. */
|
|
24
|
+
export function gateHostReservationRoot(): string { return effectiveInstanceRoot(); }
|
|
25
|
+
|
|
26
|
+
function claimAlive(claim: GateHostClaim): 'alive' | 'dead' | 'unknown' {
|
|
27
|
+
try { process.kill(claim.pid, 0); }
|
|
28
|
+
catch (error) {
|
|
29
|
+
return (error as NodeJS.ErrnoException).code === 'ESRCH' ? 'dead' : 'unknown';
|
|
30
|
+
}
|
|
31
|
+
if (claim.pidStartedAt === null) return 'unknown';
|
|
32
|
+
const current = psProcessStartMs(claim.pid);
|
|
33
|
+
if (current === null) return 'unknown';
|
|
34
|
+
return Math.abs(current - claim.pidStartedAt) <= 2_000 ? 'alive' : 'dead';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A gate owns its host until its node exits. A crashed owner's claim is removed on the next read. */
|
|
38
|
+
export function reserveReleaseGateHosts(root: string, runId: string, hosts: readonly string[]): () => void {
|
|
39
|
+
const unique = [...new Set(hosts)];
|
|
40
|
+
if (!runId || unique.some(host => host !== '*' && !hostName.test(host))) throw new Error('invalid release gate reservation');
|
|
41
|
+
if (!unique.length) return () => undefined;
|
|
42
|
+
const dir = claimsDir(root);
|
|
43
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
44
|
+
const token = randomUUID();
|
|
45
|
+
const pidStartedAt = psProcessStartMs(process.pid);
|
|
46
|
+
if (pidStartedAt === null) throw new Error('release gate owner start time unmeasured');
|
|
47
|
+
const claim: GateHostClaim = { token, runId, hosts: unique, pid: process.pid, pidStartedAt };
|
|
48
|
+
const path = join(dir, `${token}.json`);
|
|
49
|
+
const temp = join(dir, `.${token}.tmp`);
|
|
50
|
+
try {
|
|
51
|
+
writeFileSync(temp, JSON.stringify(claim) + '\n', { mode: 0o600, flag: 'wx' });
|
|
52
|
+
renameSync(temp, path);
|
|
53
|
+
} finally { if (existsSync(temp)) rmSync(temp); }
|
|
54
|
+
debug.log('release-loop.gate', 'host-reserved', { runId, hosts: unique, pid: process.pid, path });
|
|
55
|
+
return () => {
|
|
56
|
+
try {
|
|
57
|
+
const current = JSON.parse(readFileSync(path, 'utf8')) as Partial<GateHostClaim>;
|
|
58
|
+
if (current.token === token) rmSync(path);
|
|
59
|
+
debug.log('release-loop.gate', 'host-released', { runId, hosts: unique, path });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT')
|
|
62
|
+
debug.log('release-loop.gate', 'host-release-unmeasured', { runId, path, error: String(error) });
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** An unreadable claim is a reservation, never permission to enter a gate host. */
|
|
68
|
+
export function inspectReleaseGateHost(root: string, host: string): GateHostReservation {
|
|
69
|
+
const dir = claimsDir(root);
|
|
70
|
+
let names: string[];
|
|
71
|
+
try { names = readdirSync(dir).filter(name => name.endsWith('.json')); }
|
|
72
|
+
catch (error) {
|
|
73
|
+
return { status: 'unknown', reason: `reservation directory unreadable: ${String(error)}` };
|
|
74
|
+
}
|
|
75
|
+
for (const name of names) {
|
|
76
|
+
const path = join(dir, name);
|
|
77
|
+
let claim: GateHostClaim;
|
|
78
|
+
try {
|
|
79
|
+
claim = JSON.parse(readFileSync(path, 'utf8')) as GateHostClaim;
|
|
80
|
+
if (!claim || !Array.isArray(claim.hosts) || claim.hosts.length === 0
|
|
81
|
+
|| !claim.hosts.every(item => typeof item === 'string' && (item === '*' || hostName.test(item)))
|
|
82
|
+
|| !Number.isSafeInteger(claim.pid) || claim.pid <= 0 || typeof claim.token !== 'string'
|
|
83
|
+
|| typeof claim.runId !== 'string' || !claim.runId
|
|
84
|
+
|| (claim.pidStartedAt !== null && (!Number.isSafeInteger(claim.pidStartedAt)
|
|
85
|
+
|| claim.pidStartedAt <= 0 || claim.pidStartedAt > Date.now()))) throw new Error('invalid claim');
|
|
86
|
+
} catch (error) { return { status: 'unknown', reason: `reservation unreadable: ${name}: ${String(error)}` }; }
|
|
87
|
+
const live = claimAlive(claim);
|
|
88
|
+
if (live === 'dead') {
|
|
89
|
+
try { rmSync(path); } catch { /* a confirmed dead process cannot still own the host */ }
|
|
90
|
+
debug.log('release-loop.gate', 'host-claim-reclaimed', { runId: claim.runId, hosts: claim.hosts, path });
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (!claim.hosts.includes(host) && !claim.hosts.includes('*')) continue;
|
|
94
|
+
return { status: live === 'unknown' ? 'unknown' : 'reserved', reason: `release gate ${claim.runId} holds ${host}`, runId: claim.runId };
|
|
95
|
+
}
|
|
96
|
+
return { status: 'free' };
|
|
97
|
+
}
|
|
@@ -36,6 +36,11 @@ export function readLandingFreeze(root = effectiveInstanceRoot(), now = new Date
|
|
|
36
36
|
return { ...freeze, holdLaunches: freeze.holdLaunches ?? false } as LandingFreeze;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/** Interpret a validated, expiry-aware read without reading the freeze file twice. */
|
|
40
|
+
export function landingFreezeState(freeze: LandingFreeze | null): 'on' | 'off' {
|
|
41
|
+
return freeze === null ? 'off' : 'on';
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
export function enableLandingFreeze(opts: { reason?: string; until?: string; by?: string; holdLaunches?: boolean }, root = effectiveInstanceRoot(), now = new Date()): LandingFreeze {
|
|
40
45
|
const until = opts.until === undefined ? null : opts.until;
|
|
41
46
|
if (until !== null && (!/^\d{4}-\d\d-\d\dT\d\d:\d\d(?::\d\d(?:\.\d+)?)?(?:Z|[+-]\d\d:\d\d)$/.test(until) || !Number.isFinite(Date.parse(until)) || Date.parse(until) <= now.getTime())) {
|
|
@@ -29,6 +29,9 @@ export interface LightRcOptions {
|
|
|
29
29
|
/** Run on this machine (the remote child is re-invoked with it). */
|
|
30
30
|
local?: boolean;
|
|
31
31
|
shards?: number;
|
|
32
|
+
/** OP FU — pass `--fixed-shard-distribution` to self gate (sorted round-robin into `shards`, no RSS pre-measurement).
|
|
33
|
+
* Opt-in; absent = the measured planner, unchanged. Also carried to the remote child. */
|
|
34
|
+
fixedShardDistribution?: boolean;
|
|
32
35
|
/** Release ledger root for the previous-version lookup (release run's deps.ledgerRoot). */
|
|
33
36
|
ledgerRoot?: string;
|
|
34
37
|
log?: (line: string) => void;
|
|
@@ -192,7 +195,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
|
|
|
192
195
|
try {
|
|
193
196
|
const dir = checkout?.dir ?? cwd;
|
|
194
197
|
if (checkout) alwaysInclude = readList(dir);
|
|
195
|
-
local = (deps.runGate ?? runSelfGateCli)(dir, { base, shards, alwaysInclude, includeImporterTests: true });
|
|
198
|
+
local = (deps.runGate ?? runSelfGateCli)(dir, { base, shards, ...(opts.fixedShardDistribution ? { fixedShardDistribution: true } : {}), alwaysInclude, includeImporterTests: true });
|
|
196
199
|
if (opts.rehearsalTui) {
|
|
197
200
|
const command = async (cmd: string, args: string[], tree: string, limitMs?: number) => {
|
|
198
201
|
const run = spawnSync(cmd, args, { cwd: tree, encoding: 'utf8', timeout: limitMs });
|
|
@@ -208,7 +211,7 @@ export async function runLightRc(version: string, opts: LightRcOptions = {}, dep
|
|
|
208
211
|
const rc = await (deps.dispatch ?? dispatchHeavyCheck)({
|
|
209
212
|
tool: 'self-gate', repo: cwd, installPwa: true, refs: [base], json: true, commit: measuredCommit,
|
|
210
213
|
// The host re-runs this command with --local (and ELANOUS_GATE_REMOTE_CHILD=1), so it never recurses.
|
|
211
|
-
remoteArgv: (sha) => ['bun', 'bin/elanous.mjs', 'release', 'light-rc', '--version', version, '--base', sha(base), '--head', measuredCommit, '--shards', String(shards), '--local', '--json', ...(opts.rehearsalTui ? ['--rehearsal-tui'] : [])],
|
|
214
|
+
remoteArgv: (sha) => ['bun', 'bin/elanous.mjs', 'release', 'light-rc', '--version', version, '--base', sha(base), '--head', measuredCommit, '--shards', String(shards), ...(opts.fixedShardDistribution ? ['--fixed-shard-distribution'] : []), '--local', '--json', ...(opts.rehearsalTui ? ['--rehearsal-tui'] : [])],
|
|
212
215
|
flags: { remote: opts.local ? undefined : opts.remote ?? true, local: !!opts.local },
|
|
213
216
|
runLocal,
|
|
214
217
|
}, {
|