elanous 0.2.28 → 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/{y1ltt7oCZxVpC6zVPhZ2O → LSXfY0u9QtfDbejY0Ukf_}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{ab4d57c2.e90bc2cb31949045.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/{5492-e05e26a033ba80d2.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/1654.32de4b324981a188.js +23 -0
- 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/1913.7cc6fb6055b1ed3f.js +41 -0
- package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +1 -0
- 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/{8578.dff22d988cc2b106.js → 2213.2ccbada92c33ea0f.js} +3 -3
- 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/{5081.a240b63fad28663a.js → 2871.0bca6137343b3f76.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2940-619bfd8ef337c611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2846.d6a433b8663819a5.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/{f4dfbfc0.a69fb12f854882aa.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/3541-ce3a5424ed5ad7f1.js +1 -0
- 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/{3143.257997a5f1ed79df.js → 3902.e1e71aaac850a045.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{16e57f67.3ea19e893461e611.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1146.80d15ea7c6e6ee95.js → 4111.2bfedbb233ad206b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1516.83dd2c1b86b4e507.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/{9938.b23e4d4dfa0114cd.js → 4999.c064a4000c2a9e94.js} +2 -2
- 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/{1157.f08bf2b70915e176.js → 5304.04d24756f242a094.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{7752.5cbdd0b433c54af9.js → 5307.60f2209e809bd627.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9917-9e26abc5f7772735.js → 5458-16cd7a2b51b74c8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6196.34d6b229079e9e28.js → 5525.86debf231e181813.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4593.10f5b9bd702d4a6c.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/{7483.ba01c6c209b81bba.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/{9974.e77b4ff4884557b3.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/{3309.364573ceedbdfd5f.js → 6323.8672b4817a306928.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{94.4cfed21c0b781a06.js → 6433.fc573af22bbc9ab7.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{949.1e7d45ccb71580aa.js → 6517.4147878ac06d584d.js} +2 -2
- 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/{2528.3868070ef1be69f9.js → 6767.ea607cf0c20a25af.js} +2 -2
- 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/{1743.563d3168e95825ef.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/{5408.377c8c543635b81f.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/{65ebff95.081daeff622d238e.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2697.76ca2ac3efef6f3b.js → 8018.a32663f04a6fc5f9.js} +1 -1
- 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/9138.b6e80031afb1d973.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4204.a409ab6250c0f6a8.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/{5785-ea8d2c633b6688e3.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/9398-6aed28f0a96d0d6f.js +1 -0
- 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/997ce8a5-2ad501927003b41b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9311.24c8f5ea793253dd.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-fa46d4588e8442c2.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-ced0bcfc6542b3fc.js → page-349f2752d8cd37ad.js} +1 -1
- 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-cb249e81ed339318.js → page-0a07363b130182a1.js} +1 -1
- 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-521ee23ac8c0abfa.js +1 -0
- 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-149dc1caba411bb9.js +1 -0
- 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/{6def8a8e.c81f9ca41028eccf.js → b313b242.cb1265eea908db61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{e87d89b9.2e71c0ae475d28a1.js → e5012ffe.f727e23c231f4342.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{e117f801.e92bf10242653497.js → ebc7d829.264a0bcb6c750b50.js} +1 -1
- 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 +15 -7
- package/graphs/units/recipes.yaml +3 -0
- package/graphs/units/release-gate-recheck.yaml +15 -0
- package/package.json +2 -1
- package/plugins/agent-team/agents/research.md +1 -0
- package/scripts/check-native-tool-wiring.ts +3 -2
- package/scripts/ci-android-unit-tests.ts +16 -0
- package/scripts/ci-typecheck-changed.ts +40 -11
- package/scripts/coord-channel-watch.sh +45 -19
- package/scripts/coord-role-pack.ts +222 -0
- 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/lib/morning-report-options.ts +41 -0
- package/scripts/measure-goal-grounding-corpus.ts +2 -1
- package/scripts/pr-land-extra-remote-gates.ts +49 -0
- 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-batch-safe.ts +23 -0
- package/scripts/release-loop/gate-closure.ts +12 -8
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-history.ts +422 -0
- package/scripts/release-loop/gate-host-mirror.ts +66 -0
- package/scripts/release-loop/gate-node.ts +806 -94
- 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-triage-node.ts +190 -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 +51 -0
- package/scripts/release-loop/tui-node-checks.ts +23 -0
- package/scripts/release-loop/tui-sim-node.ts +3 -2
- package/scripts/release-loop/unattended-release.ts +16 -0
- package/scripts/release-loop/version-node.ts +62 -4
- package/scripts/test-deterministic.ts +46 -73
- 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/scripts/usage-rollup.ts +11 -3
- package/src/acp/client.ts +4 -1
- package/src/acp/core-turn-bridge.ts +145 -24
- package/src/acp/elanous-extensions.ts +2 -0
- package/src/acp/server.ts +2 -0
- package/src/ad-pipeline/run.ts +4 -2
- package/src/agent/ref-grounding.ts +18 -0
- 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 +41 -21
- 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/budget/pty-usage-reemit.ts +7 -0
- package/src/budget/run-usage-rollup.ts +9 -0
- package/src/budget/usage-daily-store.ts +98 -0
- package/src/capture/tui-self-report.ts +37 -4
- package/src/chat/chat-cli.ts +10 -2
- package/src/chat/index.ts +107 -20
- package/src/chat/input-control-key.ts +5 -3
- package/src/chat/pickers/modal-runtime.ts +1 -0
- package/src/chat/pickers/modals.ts +3 -1
- package/src/chat/tool-interrupt-behavior.ts +38 -0
- package/src/chat/tool-render/dispatch.ts +5 -1
- package/src/chat/turn-typeahead.ts +191 -29
- 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/dashboard-name-flag.ts +48 -0
- package/src/cli/decisions-cli.ts +80 -6
- package/src/cli/doctor-cli.ts +80 -0
- package/src/cli/log-event-names.ts +19 -0
- package/src/cli/mcp-login.ts +21 -5
- package/src/cli/msg-cli.ts +133 -2
- package/src/cli/pr-cli.ts +546 -112
- package/src/cli/pr-land-heavy-remote.ts +233 -0
- package/src/cli/pr-land-overlap-evidence.ts +167 -14
- 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/pty-takeover-cli.ts +125 -16
- package/src/cli/release-cli.ts +122 -14
- package/src/cli/remote-resolve.ts +2 -1
- package/src/cli/seat-cli.ts +164 -19
- package/src/cli/self-update.ts +5 -2
- package/src/cli/tasks-cli.ts +105 -21
- package/src/cli/usage-cli.ts +146 -12
- package/src/cli/usage-daily-cli.ts +84 -0
- package/src/context-bus/context-first.ts +13 -0
- package/src/context-bus/context-now.ts +95 -7
- 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/auth-rejected-notice.ts +41 -0
- package/src/core-turn/run-core-turn.ts +14 -2
- package/src/core-turn/run-goal-loop.ts +239 -4
- package/src/core-turn/seat-turn-cap.ts +79 -0
- package/src/core-turn/short-question.ts +78 -13
- package/src/core-turn/types.ts +10 -0
- package/src/dashboard/acp-active-model.ts +40 -0
- package/src/dashboard/acp-boot.ts +3 -0
- package/src/dashboard/auto-compact-runtime.ts +2 -0
- package/src/dashboard/boot-banner.ts +80 -0
- package/src/dashboard/dashboard-status-lines.ts +11 -0
- package/src/dashboard/detail-viewer-runtime.ts +15 -2
- package/src/dashboard/event-loop-stall-monitor.ts +4 -0
- package/src/dashboard/goal-loop-thinking.ts +16 -0
- package/src/dashboard/hitl-boot.ts +9 -4
- package/src/dashboard/index.ts +448 -998
- package/src/dashboard/input/chat-main-entry-runtime.ts +2 -0
- package/src/dashboard/input/chat-main-log-actions.ts +4 -0
- package/src/dashboard/input/chat-main-log-command.ts +12 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +176 -4
- package/src/dashboard/input/chat-main-session.ts +14 -3
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/chat-main-turn.ts +14 -4
- package/src/dashboard/input/compact-prepass-recovery.ts +130 -0
- package/src/dashboard/input/dashboard-chord-actions.ts +10 -1
- package/src/dashboard/input/dashboard-chord-runtime.ts +2 -0
- package/src/dashboard/input/external-input-host.ts +71 -0
- package/src/dashboard/input/internal-turn.ts +261 -0
- package/src/dashboard/input/log-fold-binding.ts +18 -0
- package/src/dashboard/input/mouse-wiring.ts +17 -4
- package/src/dashboard/input/seat-autowake.ts +318 -0
- package/src/dashboard/input/turn-steer-bridge.ts +164 -0
- package/src/dashboard/log-click-runtime.ts +5 -3
- package/src/dashboard/loop-scheduler.ts +72 -0
- package/src/dashboard/running-build-status.ts +74 -0
- package/src/dashboard/seat-boot-preamble.ts +131 -0
- package/src/dashboard/seat-local-instructions.ts +305 -0
- package/src/dashboard/skill-runtime.ts +2 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +220 -1203
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
- package/src/dashboard/slash-runtime/index.ts +13 -0
- package/src/dashboard/slash-runtime/model-choices.ts +35 -0
- package/src/dashboard/term-slash-runtime.ts +15 -0
- package/src/dashboard/turn-busy-teardown.ts +50 -0
- package/src/dashboard/turn-preamble.ts +30 -2
- package/src/dashboard/turn-session-layers.ts +176 -0
- package/src/dashboard/turn-stream-formatter.ts +14 -6
- package/src/dashboard/turn-stream-presentation-applier.ts +8 -0
- package/src/decisions/decision-ledger.ts +45 -4
- package/src/discord-self-message.ts +4 -4
- package/src/domains/release-tool.ts +26 -10
- package/src/domains/surface-events.ts +4 -1
- package/src/domains/watch-default-scheduler.ts +8 -9
- package/src/field-note/transcribe.ts +17 -0
- package/src/fold-stack.ts +24 -1
- package/src/git-fs/dirty.ts +32 -4
- package/src/git-fs/index.ts +43 -1
- 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 +2 -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 +34 -6
- 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 +166 -26
- package/src/input/external-input-queue.ts +251 -0
- package/src/intake-plane/slash.ts +14 -3
- package/src/interactive-terminal-modal.ts +13 -0
- package/src/keybindings.ts +4 -1
- package/src/llm/route-decision.ts +25 -0
- package/src/llm/tool-loop-steered-rejection.ts +33 -0
- package/src/llm-stream-retry-display.ts +59 -0
- package/src/llm.ts +391 -74
- package/src/log-entry.ts +3 -3
- package/src/log-pane/search.ts +29 -4
- package/src/loops/agent-reply.ts +256 -0
- package/src/loops/budget.ts +37 -7
- package/src/loops/consensus.ts +348 -0
- package/src/loops/loop-cli.ts +3 -2
- package/src/loops/msg-address.ts +57 -0
- package/src/loops/msg-wake.ts +484 -0
- package/src/loops/observe.ts +19 -3
- package/src/loops/orchestrator/inbox.ts +60 -3
- package/src/loops/orchestrator/tick.ts +80 -6
- package/src/loops/orchestrator/traffic.ts +64 -1
- package/src/loops/registry.ts +72 -4
- package/src/market/signed-index.ts +14 -0
- package/src/mcp/mcp-oauth.ts +54 -5
- package/src/memory.ts +20 -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/native-tool-catalog.ts +125 -0
- package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
- package/src/nexus/api/http-server.ts +59 -15
- package/src/nexus/api/loop-resources.ts +19 -3
- package/src/nexus/api/ops-api.ts +13 -0
- package/src/nexus/api/project-autopsy.ts +127 -0
- package/src/nexus/api/terminals.ts +3 -0
- package/src/nexus/api/workflow-approvals.ts +2 -0
- package/src/nexus/daemon-thin-inventory.md +37 -0
- package/src/nexus/index.ts +70 -0
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -2
- package/src/nexus/state/state.ts +1 -0
- package/src/oauth/codex-account-store.ts +15 -3
- package/src/oauth/codex-billing-route.ts +31 -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/overview-collect.ts +19 -2
- package/src/ops/resources.ts +82 -0
- package/src/panes/log-pane.ts +67 -8
- package/src/persona/presets.ts +44 -0
- package/src/plugins/maker/connector-maker.ts +41 -0
- package/src/plugins/maker/skill-maker.ts +42 -0
- package/src/plugins/maker/wizard-generate.ts +6 -4
- package/src/pr-tool/census.ts +288 -0
- package/src/preview/terminal.ts +14 -1
- package/src/prompt-cache/types.ts +2 -0
- package/src/prompt-enhance/enhance.ts +24 -8
- package/src/prompt-library/chat-conciseness.ts +13 -0
- package/src/prompt-library/universal-preamble.ts +283 -61
- package/src/pty-shell/pty-control-ipc.ts +4 -1
- package/src/pty-shell/pty-manifest.ts +77 -5
- package/src/pty-shell/registry.ts +19 -2
- package/src/pty-shell/tui-run-state.ts +253 -0
- 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 +32 -4
- 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/render.ts +5 -1
- 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/seat-report.ts +42 -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 +300 -24
- package/src/self-dev/run-types.ts +20 -0
- package/src/self-dev/shard-aggregate.ts +15 -2
- package/src/self-dev/shard-plan.ts +47 -0
- package/src/self-dev/shard-run.ts +135 -12
- package/src/self-dev/spawn-lane-files.ts +19 -0
- package/src/self-health/signatures.ts +132 -0
- package/src/self-implement/app-api-budget.ts +51 -11
- package/src/self-implement/config-gate.ts +2 -1
- package/src/self-implement/doctor-visit.ts +118 -0
- 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 +212 -18
- package/src/self-implement/gate-remote.ts +110 -25
- package/src/self-implement/gate-scenario.ts +85 -0
- package/src/self-implement/goal-author-decompose.ts +80 -16
- package/src/self-implement/goal-author.ts +270 -76
- package/src/self-implement/goal-authoring-grounding.ts +1 -1
- package/src/self-implement/goal-file-name.ts +65 -0
- package/src/self-implement/graph-authority.ts +38 -6
- package/src/self-implement/graph-overlay-condition.ts +92 -1
- package/src/self-implement/ground-goal.ts +2 -1
- package/src/self-implement/heal-triage.ts +79 -0
- package/src/self-implement/host-regate.ts +74 -2
- package/src/self-implement/orchestrator.ts +14 -123
- package/src/self-implement/pr-title.ts +123 -0
- package/src/self-implement/review-mustfix-class.ts +115 -0
- package/src/self-implement/run-checkpoint.ts +235 -0
- package/src/self-implement/run-ledger.ts +266 -17
- package/src/self-implement/run-stop.ts +4 -3
- package/src/self-implement/run-ttl.ts +28 -4
- package/src/self-implement/running-runs.ts +10 -6
- package/src/self-implement/seams.ts +2 -0
- package/src/self-implement/self-implement-runtime.ts +32 -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 +81 -11
- package/src/session/session-start.ts +224 -0
- package/src/session-runtime/index.ts +7 -1
- package/src/session-runtime/parallel-dispatch.ts +22 -5
- package/src/skills/tools/dev-harness.ts +6 -4
- package/src/skills/tools/ops-ledger.ts +707 -0
- package/src/skills/tools/persistent-grounding.ts +47 -7
- package/src/skills/tools/shell.ts +117 -1
- package/src/status/bar.ts +32 -2
- package/src/status/status-provider-info.ts +58 -0
- 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 +93 -13
- package/src/task-agent/remote-rejudge-bind.ts +62 -13
- package/src/task-agent/repair-cycle.ts +58 -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/kubectl-transient-retry.ts +51 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +138 -22
- 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 +122 -15
- 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 +103 -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 +237 -46
- package/src/telegram.ts +2 -4
- package/src/terminal/session-registry.ts +6 -0
- package/src/thinking-line.ts +12 -3
- package/src/tool-runtime/index.ts +4 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +84 -0
- package/src/tool-runtime/ref-consult-runtime.ts +17 -2
- package/src/tool-runtime/run-shell-runtime.ts +4 -1
- package/src/tool-runtime/self-cognition-runtimes.ts +5 -1
- 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 +53 -0
- package/src/user-config/gemini-server-tools.ts +9 -0
- package/src/user-config.ts +106 -21
- 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/fake-llm.ts +29 -0
- package/src/ux-sim/headless-tui.ts +72 -0
- package/src/ux-sim/in-process-cli.ts +176 -0
- 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/1027.a0f04663d24c2779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +0 -36
- package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1454-29d1d773d5996a49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +0 -32
- package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3259-86f3be56e43eaf6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4084.15ecaf4240bd9e77.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +0 -8
- package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +0 -149
- package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +0 -1
- package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/599-56f2c0a5cc4a7295.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +0 -23
- package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-1e5fce59500a2cc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +0 -226
- package/apps/pwa/out/_next/static/chunks/83a80514-b897b64df43ce108.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +0 -93
- package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +0 -115
- package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +0 -74
- package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/973cbf1b.3bbcf2b41548eca7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-66ad46ed0279feb9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-256ffd365d32e100.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e0de78ae7b99f01c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4c741eb760f2f77c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-e9ba98f5f1440a21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2f6f303fa114ec24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-bb1f05cd51c38944.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-646b50f63b6fe732.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-f736324afa2117c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6f131b51193a36f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-435f5e2faf02bc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-497e0eedf20e7890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a8d28fdf995e16ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-66a67eb19ebd976b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c71267e7681da982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-781cfc5114e097da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-478157214db6a023.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-86141f12cf090b7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-7256c73bb1c36751.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-979d318a534e92da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-601fb77340e63c9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-11bf9e5725a72c22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +0 -1
- package/src/dashboard/bench-slash-runtime.ts +0 -40
- package/src/dashboard/input/search-modal-router.ts +0 -9
- package/src/dashboard/modals/pane-key-router.ts +0 -27
- package/src/dashboard/view-slash-runtime.ts +0 -48
- /package/apps/pwa/out/_next/static/{y1ltt7oCZxVpC6zVPhZ2O → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
// ── 우편 깨움 — 글을 저장한 «뒤» 받는 몸을 한 번 두드린다 ──
|
|
2
|
+
//
|
|
3
|
+
// 주소에 «답할 몸»(replyBody)이 있어도 «깨울 길»이 없으면 죽은 주소다(10-14 grok OP 16분 정지).
|
|
4
|
+
// 종류(`MessageWake`)마다 하는 일:
|
|
5
|
+
// sse — 아무것도 안 한다(구독자가 이미 듣는다)
|
|
6
|
+
// cron — 다음 틱에 읽는다 · `wake-deferred` 로그만
|
|
7
|
+
// pty-inject — elanous TUI(pty 별명 = 자리 소문자)가 턴 idle 일 때만 한 줄 주입
|
|
8
|
+
// herdr — 자리 폴더 `herdr.pane` 의 pane 이 agent_status=idle 일 때만 한 줄 주입
|
|
9
|
+
// none — stderr 경고 한 줄 · 해석 실패는 «모름»으로 남긴다(«없다»로 위장 금지)
|
|
10
|
+
// ⛔ 우편은 입력칸에 넣지 않는다(대표 10-15 01:20) — 기본은 입력칸 주입 0. 10-15 01:10 사고: 대표 가 치던 문장에
|
|
11
|
+
// 깨움 한 줄 ⊕ Enter 가 섞여 제출됐다(«에이전트 idle ≠ 사람이 안 친다»). 자리 폴더에서 푼 대상(pty 별명·
|
|
12
|
+
// pty.ref·herdr.pane)은 `<seat-state>/<자리>/wake-inject` 일반 파일이 있을 때만 주입하고, 없으면
|
|
13
|
+
// `msg.wake skipped{reason}` 만 남긴다.
|
|
14
|
+
// ⚠️ wake-inject 는 «사람이 치지 않는 pane»(무인 에이전트 전용)에만 둔다 — 사람이 치는 pane 에는 켜지 말 것.
|
|
15
|
+
// ⛔ 깨움은 post 의 성패를 바꾸지 않는다 — 실패·시간 초과는 결과 값으로만 돌아온다.
|
|
16
|
+
// ⛔ 시험 우주에서는 실제 pty/herdr 호출 0 — `ELANOUS_MSG_WAKE_LIVE=1` 로만 연다(격리 실물 시험용).
|
|
17
|
+
// ⭐ 버리지 않고 미룬다(TUI-H4 · 10-16 OPT 우편 36 중 18 깨움 0): pty-inject 대상이 턴 중(busy)이거나 5분 창(debounced)이라
|
|
18
|
+
// 못 두드린 글은 `pending_wakes` 에 «주소당 한 줄»로 접어 두고, 그 TUI 안의 폴러(`startPendingWakePoller`)가
|
|
19
|
+
// 턴이 idle 로 «기록»된 뒤 한 번 다시 두드린다. 5분 창은 다시 두드림에도 걸린다 — 창 안이면 버림이 아니라 다음 틱으로 미룸.
|
|
20
|
+
// 상한(시도 3 · 2시간) → `gave-up`. 관측 = `loops.msg-wake` deferred | redelivered | gave-up.
|
|
21
|
+
// 재두드림 «전»에 그 주소 미읽음을 잰다 — 0 이면 두드리지 않고 줄을 지운다(`dropped-read` · H4-FOLLOW ③).
|
|
22
|
+
|
|
23
|
+
import { spawn } from 'node:child_process';
|
|
24
|
+
import { Database } from 'bun:sqlite';
|
|
25
|
+
import { randomUUID } from 'node:crypto';
|
|
26
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync } from 'node:fs';
|
|
27
|
+
import { homedir } from 'node:os';
|
|
28
|
+
import { dirname, join } from 'node:path';
|
|
29
|
+
|
|
30
|
+
import { debug } from '../debug/log.js';
|
|
31
|
+
import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
|
|
32
|
+
import { readUnreadCount } from '../msg/msg-store.js';
|
|
33
|
+
import { listPtyManifestRows } from '../pty-shell/pty-manifest.js';
|
|
34
|
+
import { messageRouteFor, type MessageWake } from './msg-address.js';
|
|
35
|
+
|
|
36
|
+
export const WAKE_DEBOUNCE_MS = 5 * 60_000;
|
|
37
|
+
export const WAKE_TIMEOUT_MS = 3_000;
|
|
38
|
+
/** A deferred wake is retried at most this many times (an attempt = idle ∧ window free ∧ injection tried). */
|
|
39
|
+
export const MAX_REDELIVER_ATTEMPTS = 3;
|
|
40
|
+
/** A deferred wake older than this is given up even if the TUI never went idle. */
|
|
41
|
+
export const PENDING_WAKE_TTL_MS = 2 * 60 * 60_000;
|
|
42
|
+
export const PENDING_WAKE_POLL_MS = 15_000;
|
|
43
|
+
/** Seat-folder file that opts a human pane in to wake injection (presence is the switch). */
|
|
44
|
+
const WAKE_OPT_IN_FILE = 'wake-inject';
|
|
45
|
+
|
|
46
|
+
export interface WakeResolution {
|
|
47
|
+
wake: MessageWake;
|
|
48
|
+
/** pty id (pty-inject) or herdr pane id (herdr). */
|
|
49
|
+
target?: string;
|
|
50
|
+
/** Where the answer came from — `unresolved` means «모름», not a measured absence. */
|
|
51
|
+
source: 'loop-table' | 'pty-name' | 'pty.ref' | 'herdr.pane' | 'unresolved';
|
|
52
|
+
reason?: string;
|
|
53
|
+
/** For a seat-folder target: the seat opted in to injection (`<seat>/wake-inject` exists). Absent = not a seat target. */
|
|
54
|
+
optIn?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type WakeResult = 'none-sse' | 'wake-deferred' | 'injected' | 'busy' | 'debounced' | 'skipped' | 'skipped-reply'
|
|
58
|
+
| 'skipped-self' | 'skipped-test-universe' | 'no-wake' | 'failed' | 'timeout';
|
|
59
|
+
|
|
60
|
+
export interface WakeOutcome extends WakeResolution { address: string; msgId: number; result: WakeResult }
|
|
61
|
+
|
|
62
|
+
export interface WakeDeps {
|
|
63
|
+
/** Seat folders (`<root>/<SEAT>/pty.ref` · `herdr.pane`). Prod: ~/elanous-hq/seat-state · test universe: <root>/seat-state. */
|
|
64
|
+
seatStateRoot?: string;
|
|
65
|
+
/** Debounce claims live here (`<stateRoot>/msg/wake-claims.db`). */
|
|
66
|
+
stateRoot?: string;
|
|
67
|
+
now?: () => number;
|
|
68
|
+
/** Real pty/herdr calls are allowed (default: prod universe or ELANOUS_MSG_WAKE_LIVE=1). */
|
|
69
|
+
live?: boolean;
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
listPtys?: () => Array<{ id: string; nickname?: string; alive: boolean; turnState?: 'busy' | 'idle' }>;
|
|
72
|
+
/** Reads one seat-folder file (`pty.ref` · `herdr.pane`); null when absent. */
|
|
73
|
+
readPane?: (path: string) => string | null;
|
|
74
|
+
/** Does this seat-folder opt-in file exist (`<seat>/wake-inject`)? */
|
|
75
|
+
hasOptIn?: (path: string) => boolean;
|
|
76
|
+
/** Loads the pty writer (the CLI module is heavy, so it is imported only when a pty wake is due). */
|
|
77
|
+
ptyInjector?: () => Promise<(ptyId: string, line: string) => Promise<void>>;
|
|
78
|
+
herdrStatus?: (paneId: string, signal: AbortSignal) => Promise<string>;
|
|
79
|
+
herdrInject?: (paneId: string, line: string, signal: AbortSignal) => Promise<void>;
|
|
80
|
+
warn?: (line: string) => void;
|
|
81
|
+
/** Unread count for an address before a deferred re-knock (H4-FOLLOW ③). null = «모름» (never drops). Default: the msg ledger. */
|
|
82
|
+
readUnread?: (address: string) => number | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isLive(deps: WakeDeps): boolean {
|
|
86
|
+
if (deps.live !== undefined) return deps.live;
|
|
87
|
+
return effectiveInstanceRoot() === prodInstanceRoot() || process.env.ELANOUS_MSG_WAKE_LIVE === '1';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function seatStateRoot(deps: WakeDeps): string {
|
|
91
|
+
if (deps.seatStateRoot) return deps.seatStateRoot;
|
|
92
|
+
const root = effectiveInstanceRoot();
|
|
93
|
+
return root === prodInstanceRoot() ? join(homedir(), 'elanous-hq', 'seat-state') : join(root, 'seat-state');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The opt-in must be a regular file — a directory, a symlink or anything else at that name does not open injection. */
|
|
97
|
+
function isRegularFile(path: string): boolean {
|
|
98
|
+
// lstat — 링크는 따라가지 않는다(자리 자체의 일반 파일만 opt-in).
|
|
99
|
+
try { return lstatSync(path).isFile(); } catch { return false; }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The seat's own opt-in, read independently of whatever target the seat folder points at now. */
|
|
103
|
+
function seatOptedIn(address: string, deps: WakeDeps): boolean {
|
|
104
|
+
return (deps.hasOptIn ?? isRegularFile)(join(seatStateRoot(deps), address.trim().toUpperCase(), WAKE_OPT_IN_FILE));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function readPaneFile(path: string): string | null {
|
|
108
|
+
try { return existsSync(path) ? readFileSync(path, 'utf8').trim() || null : null; }
|
|
109
|
+
catch { return null; }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** How a post to `address` would wake its reader — table first, then a live pty named after the seat, then herdr. */
|
|
113
|
+
export function resolveWake(address: string, deps: WakeDeps = {}): WakeResolution {
|
|
114
|
+
const name = address.trim().toUpperCase();
|
|
115
|
+
if (name === 'ALL') return { wake: 'none', source: 'unresolved', reason: 'topic' };
|
|
116
|
+
const route = messageRouteFor(name);
|
|
117
|
+
if (route?.wake) return { wake: route.wake, source: 'loop-table' };
|
|
118
|
+
// 호스트 해석은 표에 선언된 자리 줄(wakeFrom: 'host')만 — 모르는 주소는 같은 이름의 pty 가 있어도 깨우지 않는다.
|
|
119
|
+
if (route?.wakeFrom !== 'host') return { wake: 'none', source: 'unresolved', reason: 'undeclared-address' };
|
|
120
|
+
// ⭐ 별명은 «정확히» 같은 것만 — pty ref 해석의 부분 일치(op ⊂ opt)로 남의 TUI 에 넣지 않는다.
|
|
121
|
+
const lower = name.toLowerCase();
|
|
122
|
+
let ptys: ReturnType<NonNullable<WakeDeps['listPtys']>> = [];
|
|
123
|
+
try { ptys = (deps.listPtys ?? listPtyManifestRows)(); } catch { ptys = []; }
|
|
124
|
+
const named = ptys.filter(row => row.alive && (row.nickname ?? '').toLowerCase() === lower);
|
|
125
|
+
const optIn = seatOptedIn(name, deps);
|
|
126
|
+
if (named.length === 1) return { wake: 'pty-inject', target: named[0]!.id, source: 'pty-name', optIn };
|
|
127
|
+
// seat-inbox.sh 와 같은 자리 폴더 파일: pty.ref(살아 있는 행의 id·별명과 정확히 같을 때만) → herdr.pane.
|
|
128
|
+
const readSeatFile = deps.readPane ?? readPaneFile;
|
|
129
|
+
const ref = readSeatFile(join(seatStateRoot(deps), name, 'pty.ref'))?.toLowerCase();
|
|
130
|
+
const byRef = ref ? ptys.filter(row => row.alive && (row.id.toLowerCase() === ref || (row.nickname ?? '').toLowerCase() === ref)) : [];
|
|
131
|
+
if (byRef.length === 1) return { wake: 'pty-inject', target: byRef[0]!.id, source: 'pty.ref', optIn };
|
|
132
|
+
const pane = readSeatFile(join(seatStateRoot(deps), name, 'herdr.pane'));
|
|
133
|
+
if (pane) return { wake: 'herdr', target: pane, source: 'herdr.pane', optIn };
|
|
134
|
+
return { wake: 'none', source: 'unresolved', reason: named.length > 1 ? `pty-name-ambiguous:${named.length}` : 'no-pty-name-no-herdr-pane' };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function claimDbPath(deps: WakeDeps): string {
|
|
138
|
+
return join(deps.stateRoot ?? effectiveInstanceRoot(), 'msg', 'wake-claims.db');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface WakeClaim { db: string; address: string; token: string }
|
|
142
|
+
|
|
143
|
+
function openWakeDb(db: string): Database {
|
|
144
|
+
mkdirSync(dirname(db), { recursive: true });
|
|
145
|
+
const conn = new Database(db);
|
|
146
|
+
try {
|
|
147
|
+
conn.exec('PRAGMA busy_timeout = 2000');
|
|
148
|
+
conn.exec('CREATE TABLE IF NOT EXISTS wake_claims (address TEXT PRIMARY KEY, at INTEGER NOT NULL, token TEXT NOT NULL)');
|
|
149
|
+
conn.exec(`CREATE TABLE IF NOT EXISTS pending_wakes (address TEXT PRIMARY KEY, first_msg_id INTEGER NOT NULL,
|
|
150
|
+
last_msg_id INTEGER NOT NULL, last_from TEXT NOT NULL, count INTEGER NOT NULL, since INTEGER NOT NULL,
|
|
151
|
+
attempts INTEGER NOT NULL DEFAULT 0, reason TEXT NOT NULL)`);
|
|
152
|
+
return conn;
|
|
153
|
+
} catch (error) { conn.close(); throw error; }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Atomically claim the 5-minute wake window for one address. One SQLite upsert decides it under the
|
|
158
|
+
* write lock — the row is replaced only when the held claim is older than the window — so two
|
|
159
|
+
* concurrent `msg post` processes cannot both win, including when both saw an expired claim.
|
|
160
|
+
*/
|
|
161
|
+
export function claimWake(db: string, address: string, now: number): WakeClaim | null {
|
|
162
|
+
const token = `${now} ${process.pid} ${randomUUID()}`;
|
|
163
|
+
const conn = openWakeDb(db);
|
|
164
|
+
try {
|
|
165
|
+
const changed = conn.query(`INSERT INTO wake_claims (address, at, token) VALUES (?1, ?2, ?3)
|
|
166
|
+
ON CONFLICT(address) DO UPDATE SET at = excluded.at, token = excluded.token WHERE wake_claims.at <= ?2 - ?4`)
|
|
167
|
+
.run(address, now, token, WAKE_DEBOUNCE_MS).changes;
|
|
168
|
+
return changed === 1 ? { db, address, token } : null;
|
|
169
|
+
} finally { conn.close(); }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Give the window back when nothing was injected (busy · timeout · failure) — only our own claim. */
|
|
173
|
+
function releaseClaim(claim: WakeClaim): void {
|
|
174
|
+
try {
|
|
175
|
+
const conn = new Database(claim.db);
|
|
176
|
+
try { conn.exec('PRAGMA busy_timeout = 2000'); conn.query('DELETE FROM wake_claims WHERE address = ?1 AND token = ?2').run(claim.address, claim.token); }
|
|
177
|
+
finally { conn.close(); }
|
|
178
|
+
} catch { /* a stale claim only delays the next wake by one window */ }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function run(cmd: string, args: string[], timeoutMs: number, signal: AbortSignal): Promise<string> {
|
|
182
|
+
return new Promise((resolve, reject) => {
|
|
183
|
+
if (signal.aborted) { reject(new Error(`${cmd} aborted`)); return; }
|
|
184
|
+
const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], signal });
|
|
185
|
+
let out = '';
|
|
186
|
+
const timer = setTimeout(() => { child.kill('SIGKILL'); reject(new Error(`${cmd} timeout`)); }, timeoutMs);
|
|
187
|
+
child.stdout.on('data', chunk => { out += String(chunk); });
|
|
188
|
+
child.on('error', error => { clearTimeout(timer); reject(error); });
|
|
189
|
+
child.on('close', code => { clearTimeout(timer); code === 0 ? resolve(out) : reject(new Error(`${cmd} exit ${code}`)); });
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function defaultHerdrStatus(paneId: string, signal: AbortSignal): Promise<string> {
|
|
194
|
+
const parsed = JSON.parse(await run('herdr', ['pane', 'get', paneId], WAKE_TIMEOUT_MS, signal)) as { result?: { pane?: { agent_status?: unknown } } };
|
|
195
|
+
const status = parsed.result?.pane?.agent_status;
|
|
196
|
+
return typeof status === 'string' ? status : 'unknown';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function defaultHerdrInject(paneId: string, line: string, signal: AbortSignal): Promise<void> {
|
|
200
|
+
// `pane run` = send-text ⊕ Enter 한 번에.
|
|
201
|
+
await run('herdr', ['pane', 'run', paneId, line], WAKE_TIMEOUT_MS, signal);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function defaultPtyInjector(): Promise<(ptyId: string, line: string) => Promise<void>> {
|
|
205
|
+
const { runPtyText } = await import('../cli/pty-takeover-cli.js');
|
|
206
|
+
return async (ptyId, line) => {
|
|
207
|
+
const result = await runPtyText(ptyId, line, true);
|
|
208
|
+
if (result.exitCode !== 0) throw new Error(result.message);
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function wakeLine(from: string, address: string, msgId: number): string {
|
|
213
|
+
return `[우편 깨움] ${from} → ${address} #${msgId} — eln msg list --to ${address} 로 읽고 처리`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export const NO_WAKE_NOTICE = '이 주소는 깨울 길이 없다 — 받는 몸이 스스로 읽을 때까지 쌓인다';
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Wake the reader of a just-saved message. Never throws; the caller's post outcome is already final.
|
|
220
|
+
* `message.from`/`kind` decide the skips (a reply or a self-addressed note never wakes anyone).
|
|
221
|
+
*/
|
|
222
|
+
export async function wakeRecipient(address: string, msgId: number, message: { from: string; kind?: string }, deps: WakeDeps = {}): Promise<WakeOutcome> {
|
|
223
|
+
const timeoutMs = deps.timeoutMs ?? WAKE_TIMEOUT_MS;
|
|
224
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
225
|
+
let resolution: WakeResolution = { wake: 'none', source: 'unresolved', reason: 'not-resolved' };
|
|
226
|
+
const controller = new AbortController();
|
|
227
|
+
// 마감은 «진입» 시각 기준 — 동기 작업(claim 잠금 대기 등)이 늦어 타이머가 못 울려도 넘기면 주입하지 않는다.
|
|
228
|
+
const deadline = Date.now() + timeoutMs;
|
|
229
|
+
const expired = () => controller.signal.aborted || Date.now() >= deadline;
|
|
230
|
+
let claim: WakeClaim | null = null;
|
|
231
|
+
let injecting = false;
|
|
232
|
+
const attempt = (async (): Promise<WakeOutcome> => {
|
|
233
|
+
const done = (result: WakeResult, reason?: string): WakeOutcome =>
|
|
234
|
+
({ ...resolution, ...(reason ? { reason } : {}), address, msgId, result });
|
|
235
|
+
if (message.kind === 'reply') return done('skipped-reply', 'kind=reply');
|
|
236
|
+
if (message.from.toUpperCase() === address.toUpperCase()) return done('skipped-self', 'from=to');
|
|
237
|
+
resolution = resolveWake(address, deps);
|
|
238
|
+
if (resolution.wake === 'sse') return done('none-sse');
|
|
239
|
+
if (resolution.wake === 'cron') return done('wake-deferred');
|
|
240
|
+
if (resolution.wake === 'none') return done('no-wake');
|
|
241
|
+
// 사람이 앉는 pane 은 명시 opt-in 이 없으면 주입 0 — 에이전트가 idle 이어도 사람이 치는 중일 수 있다.
|
|
242
|
+
if (resolution.optIn === false) return done('skipped', 'human-pane-no-opt-in');
|
|
243
|
+
if (!isLive(deps)) return done('skipped-test-universe');
|
|
244
|
+
claim = claimWake(claimDbPath(deps), address, (deps.now ?? Date.now)());
|
|
245
|
+
if (!claim) return done('debounced');
|
|
246
|
+
try {
|
|
247
|
+
const line = wakeLine(message.from, address, msgId);
|
|
248
|
+
if (resolution.wake === 'pty-inject') {
|
|
249
|
+
// 모듈을 «먼저» 불러오고, 그 뒤에 턴을 읽는다 — 로드 사이 busy 로 바뀐 TUI 에 넣지 않는다.
|
|
250
|
+
const inject = await (deps.ptyInjector ?? defaultPtyInjector)();
|
|
251
|
+
// turnState 는 TUI 가 스스로 적은 값(#27485) — 살아 있고 idle 이 «기록»돼 있을 때만 넣는다(모름 = 넣지 않음).
|
|
252
|
+
// 로드 사이 별명·pty.ref 가 다른 행으로 옮겨 갔으면 넣지 않는다 — 주소→대상을 다시 푼다.
|
|
253
|
+
const again = resolveWake(address, deps);
|
|
254
|
+
// opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
|
|
255
|
+
if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return done('skipped', 'human-pane-no-opt-in'); }
|
|
256
|
+
if (again.wake !== 'pty-inject' || again.target !== resolution.target) return done('busy', `target-moved:${again.target ?? again.wake}`);
|
|
257
|
+
const row = (deps.listPtys ?? listPtyManifestRows)().find(item => item.id === resolution.target);
|
|
258
|
+
if (!row?.alive || row.turnState !== 'idle') return done('busy', `turn=${row?.alive === false ? 'dead' : row?.turnState ?? 'unknown'}`);
|
|
259
|
+
// ⛔ 마감이 지났으면 새 주입을 시작하지 않는다.
|
|
260
|
+
if (expired()) return done('timeout');
|
|
261
|
+
injecting = true;
|
|
262
|
+
await inject(resolution.target!, line);
|
|
263
|
+
} else {
|
|
264
|
+
const status = await (deps.herdrStatus ?? defaultHerdrStatus)(resolution.target!, controller.signal);
|
|
265
|
+
if (status !== 'idle') return done('busy', `agent_status=${status}`);
|
|
266
|
+
// 조회 사이 자리의 pane 이 바뀌었으면 옛 pane 에 넣지 않는다 — 주소→대상을 다시 푼다.
|
|
267
|
+
const again = resolveWake(address, deps);
|
|
268
|
+
// opt-in 은 주입 직전에 «먼저» 다시 본다 — 기다리는 사이 `wake-inject` 를 지웠으면(대상이 바뀌었어도) 주입 0.
|
|
269
|
+
if (!seatOptedIn(address, deps)) { resolution = { ...resolution, optIn: false }; return done('skipped', 'human-pane-no-opt-in'); }
|
|
270
|
+
if (again.wake !== 'herdr' || again.target !== resolution.target) return done('busy', `target-moved:${again.target ?? again.wake}`);
|
|
271
|
+
// ⛔ 마감은 «주입 바로 앞»에서 — 재해석이 늦어 넘겼어도 새 주입 0.
|
|
272
|
+
if (expired()) return done('timeout');
|
|
273
|
+
injecting = true;
|
|
274
|
+
await (deps.herdrInject ?? defaultHerdrInject)(resolution.target!, line, controller.signal);
|
|
275
|
+
}
|
|
276
|
+
return done('injected');
|
|
277
|
+
} catch (error) {
|
|
278
|
+
// 주입이 «시작»됐다 실패하면 들어갔는지 모른다 — 창을 돌려줘 다음 글이 다시 깨우게 한다.
|
|
279
|
+
injecting = false;
|
|
280
|
+
throw error;
|
|
281
|
+
} finally { if (!injecting && claim) releaseClaim(claim); }
|
|
282
|
+
})();
|
|
283
|
+
let outcome: WakeOutcome;
|
|
284
|
+
try {
|
|
285
|
+
outcome = await Promise.race([attempt, new Promise<WakeOutcome>(resolve => {
|
|
286
|
+
timer = setTimeout(() => {
|
|
287
|
+
controller.abort();
|
|
288
|
+
// 시간 초과면 창을 돌려준다 — 주입 전이면 들어간 것이 없고, 주입 중 멈췄으면 들어갔는지 «모른다».
|
|
289
|
+
// 모를 때는 다음 글이 다시 두드리게 둔다(내용 없는 한 줄의 중복은 무해, 깨움 누락은 16분 정지).
|
|
290
|
+
if (claim) releaseClaim(claim);
|
|
291
|
+
resolve({ ...resolution, address, msgId, result: 'timeout' });
|
|
292
|
+
}, timeoutMs);
|
|
293
|
+
})]);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
outcome = { ...resolution, address, msgId, result: 'failed', reason: error instanceof Error ? error.message : String(error) };
|
|
296
|
+
} finally { clearTimeout(timer); }
|
|
297
|
+
attempt.catch(() => { /* a late failure after timeout is already reported as timeout */ });
|
|
298
|
+
try {
|
|
299
|
+
if (outcome.result === 'no-wake') (deps.warn ?? (line => console.error(line)))(
|
|
300
|
+
outcome.source === 'unresolved' ? `${NO_WAKE_NOTICE} (wake=none · 모름: ${outcome.reason})` : `${NO_WAKE_NOTICE} (wake=none)`);
|
|
301
|
+
debug.log('msg.wake', outcome.result === 'skipped' ? 'skipped' : outcome.wake, { address, msgId, wake: outcome.wake, result: outcome.result, reason: outcome.reason ?? outcome.source,
|
|
302
|
+
...(outcome.target ? { target: outcome.target } : {}) });
|
|
303
|
+
} catch { /* reporting never turns a wake outcome into a throw */ }
|
|
304
|
+
try { settlePending(outcome, message.from, deps); } catch { /* the deferral ledger never turns a post into a throw */ }
|
|
305
|
+
return outcome;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ── 미룬 깨움(pending) ─────────────────────────────────────────────────────────
|
|
309
|
+
|
|
310
|
+
interface PendingWakeRow { address: string; first_msg_id: number; last_msg_id: number; last_from: string; count: number; since: number; attempts: number; reason: string }
|
|
311
|
+
|
|
312
|
+
export type PendingWakeEvent = 'deferred' | 'redelivered' | 'gave-up' | 'dropped-read';
|
|
313
|
+
|
|
314
|
+
function logPending(event: PendingWakeEvent, data: Record<string, unknown>): void {
|
|
315
|
+
try { debug.log('loops.msg-wake', event, data); } catch { /* observability is fail-open */ }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* After a fresh wake: a pty-inject TUI that was busy or inside the 5-minute window is remembered (not dropped);
|
|
320
|
+
* an injected wake absorbs whatever was pending for that address (the line tells the reader to list everything).
|
|
321
|
+
*/
|
|
322
|
+
function settlePending(outcome: WakeOutcome, from: string, deps: WakeDeps): void {
|
|
323
|
+
if (!isLive(deps)) return;
|
|
324
|
+
// TTL 은 폴러 «밖»에서도 닫는다 — TUI 가 죽은 채 안 돌아오면 그 폴러는 없다. 어느 주소든 post 가 오면 낡은 줄을 거둔다.
|
|
325
|
+
try { prunePendingWakes(deps); } catch { /* fail-soft */ }
|
|
326
|
+
if (outcome.wake !== 'pty-inject') return;
|
|
327
|
+
const address = outcome.address.trim().toUpperCase();
|
|
328
|
+
if (outcome.result === 'injected') {
|
|
329
|
+
// 이 줄은 «그때까지 저장된 글 전부를 읽어라»라 msgId 이하만 덮는다 — 주입 «뒤»에 저장·미뤄진 글(더 큰 id)이 섞인 줄은 남긴다.
|
|
330
|
+
const conn = openWakeDb(claimDbPath(deps));
|
|
331
|
+
try { conn.query('DELETE FROM pending_wakes WHERE address = ?1 AND last_msg_id <= ?2').run(address, outcome.msgId); } finally { conn.close(); }
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (outcome.result !== 'busy' && outcome.result !== 'debounced') return;
|
|
335
|
+
const reason = outcome.result === 'debounced' ? 'debounced' : outcome.reason ?? 'busy';
|
|
336
|
+
const conn = openWakeDb(claimDbPath(deps));
|
|
337
|
+
let count = 1;
|
|
338
|
+
try {
|
|
339
|
+
// 주소당 한 줄 — 묶음이 늘어도 다시 두드림은 한 번. 범위는 id 순서로(동시 post 가 역순으로 와도 min·max),
|
|
340
|
+
// 보낸 이는 끝 id 의 것. 끝 id 가 바뀌면(새 글) 시도 수는 0 — 새 글은 자기 몫의 시도를 받는다. 시작 시각(TTL)은 첫 미룸 기준.
|
|
341
|
+
conn.query(`INSERT INTO pending_wakes (address, first_msg_id, last_msg_id, last_from, count, since, attempts, reason)
|
|
342
|
+
VALUES (?1, ?2, ?2, ?3, 1, ?4, 0, ?5)
|
|
343
|
+
ON CONFLICT(address) DO UPDATE SET first_msg_id = min(first_msg_id, excluded.first_msg_id),
|
|
344
|
+
last_msg_id = max(last_msg_id, excluded.last_msg_id),
|
|
345
|
+
last_from = CASE WHEN excluded.last_msg_id > last_msg_id THEN excluded.last_from ELSE last_from END,
|
|
346
|
+
attempts = CASE WHEN excluded.last_msg_id > last_msg_id THEN 0 ELSE attempts END,
|
|
347
|
+
count = count + 1, reason = excluded.reason`)
|
|
348
|
+
.run(address, outcome.msgId, from, (deps.now ?? Date.now)(), reason);
|
|
349
|
+
count = (conn.query('SELECT count FROM pending_wakes WHERE address = ?1').get(address) as { count: number } | null)?.count ?? 1;
|
|
350
|
+
} finally { conn.close(); }
|
|
351
|
+
logPending('deferred', { seat: address, count, reason, msgId: outcome.msgId });
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function logGaveUp(row: PendingWakeRow, reason: string, attempts = row.attempts): void {
|
|
355
|
+
logPending('gave-up', { seat: row.address, count: row.count, reason, attempts, firstMsgId: row.first_msg_id, lastMsgId: row.last_msg_id });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Give up deferrals older than the TTL (a TUI that died and never came back has no poller to do it). */
|
|
359
|
+
export function prunePendingWakes(deps: WakeDeps = {}): number {
|
|
360
|
+
const db = claimDbPath(deps);
|
|
361
|
+
if (!existsSync(db)) return 0;
|
|
362
|
+
const cutoff = (deps.now ?? Date.now)() - PENDING_WAKE_TTL_MS;
|
|
363
|
+
const conn = openWakeDb(db);
|
|
364
|
+
try {
|
|
365
|
+
const stale = conn.query('SELECT * FROM pending_wakes WHERE since < ?1').all(cutoff) as PendingWakeRow[];
|
|
366
|
+
for (const row of stale) {
|
|
367
|
+
if (conn.query('DELETE FROM pending_wakes WHERE address = ?1 AND last_msg_id = ?2').run(row.address, row.last_msg_id).changes === 1) logGaveUp(row, 'ttl');
|
|
368
|
+
}
|
|
369
|
+
return stale.length;
|
|
370
|
+
} finally { conn.close(); }
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export interface RedeliverOutcome { seat: string; result: 'redelivered' | 'gave-up' | 'dropped-read' | 'waiting' | 'failed'; count: number; reason?: string }
|
|
374
|
+
|
|
375
|
+
/** Unread count for a deferred address — injected reader first, else the msg ledger beside the claims db. Never throws. */
|
|
376
|
+
function readUnreadFor(address: string, deps: WakeDeps): number | null {
|
|
377
|
+
try {
|
|
378
|
+
if (deps.readUnread) return deps.readUnread(address);
|
|
379
|
+
return readUnreadCount(address, join(deps.stateRoot ?? effectiveInstanceRoot(), 'msg', 'messages.db'));
|
|
380
|
+
} catch { return null; }
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export function redeliverLine(row: Pick<PendingWakeRow, 'address' | 'last_from' | 'first_msg_id' | 'last_msg_id' | 'count'>): string {
|
|
384
|
+
const ids = row.first_msg_id === row.last_msg_id ? `#${row.last_msg_id}` : `#${row.first_msg_id}..#${row.last_msg_id}`;
|
|
385
|
+
return `[우편 깨움 · 미룬 ${row.count}통] ${row.last_from} → ${row.address} ${ids} — eln msg list --to ${row.address} 로 읽고 처리`;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Re-knock deferred wakes whose TUI is now recorded idle. `target` limits the sweep to one pty (the TUI's own poller).
|
|
390
|
+
* Never throws per row; a row stays pending while the TUI is busy or the 5-minute window is held.
|
|
391
|
+
*/
|
|
392
|
+
export async function redeliverPendingWakes(deps: WakeDeps = {}, opts: { target?: string } = {}): Promise<RedeliverOutcome[]> {
|
|
393
|
+
if (!isLive(deps)) return [];
|
|
394
|
+
const db = claimDbPath(deps);
|
|
395
|
+
if (!existsSync(db)) return [];
|
|
396
|
+
const conn = openWakeDb(db);
|
|
397
|
+
let rows: PendingWakeRow[];
|
|
398
|
+
try { rows = conn.query('SELECT * FROM pending_wakes ORDER BY since').all() as PendingWakeRow[]; } finally { conn.close(); }
|
|
399
|
+
const results: RedeliverOutcome[] = [];
|
|
400
|
+
const now = () => (deps.now ?? Date.now)();
|
|
401
|
+
// 지울 때는 «읽은 그 묶음»만 — 그 사이 새로 미룬 글이 오면 줄이 남아 한 번 더 두드린다.
|
|
402
|
+
const drop = (row: PendingWakeRow): boolean => {
|
|
403
|
+
const c = openWakeDb(db);
|
|
404
|
+
try { return c.query('DELETE FROM pending_wakes WHERE address = ?1 AND last_msg_id = ?2').run(row.address, row.last_msg_id).changes === 1; }
|
|
405
|
+
finally { c.close(); }
|
|
406
|
+
};
|
|
407
|
+
// 포기는 «실제로 지운» 묶음만 — 그 사이 새 글이 합쳐졌으면(끝 id 바뀜) 줄은 새 묶음으로 남고 시도 수는 0 으로 돌아가 있다.
|
|
408
|
+
const giveUp = (row: PendingWakeRow, reason: string) => {
|
|
409
|
+
if (drop(row)) {
|
|
410
|
+
logGaveUp(row, reason);
|
|
411
|
+
results.push({ seat: row.address, result: 'gave-up', count: row.count, reason });
|
|
412
|
+
} else results.push({ seat: row.address, result: 'waiting', count: row.count, reason: 'batch-changed' });
|
|
413
|
+
};
|
|
414
|
+
for (const row of rows) {
|
|
415
|
+
try {
|
|
416
|
+
if (row.attempts >= MAX_REDELIVER_ATTEMPTS) { giveUp(row, `attempts>=${MAX_REDELIVER_ATTEMPTS}`); continue; }
|
|
417
|
+
if (now() - row.since > PENDING_WAKE_TTL_MS) { giveUp(row, 'ttl'); continue; }
|
|
418
|
+
// H4-FOLLOW ③ — 그 사이 이미 읽었으면(미읽음 0) 재두드림하지 않고 줄을 지운다(10-16 OPT 가 ack 한 #9250 재두드림).
|
|
419
|
+
// «모름»(원장 없음·못 읽음)은 지우지 않는다 — 0 으로 읽지 않는다.
|
|
420
|
+
const unread = readUnreadFor(row.address, deps);
|
|
421
|
+
if (unread === 0) {
|
|
422
|
+
if (drop(row)) {
|
|
423
|
+
logPending('dropped-read', { seat: row.address, count: row.count, attempts: row.attempts, firstMsgId: row.first_msg_id, lastMsgId: row.last_msg_id });
|
|
424
|
+
results.push({ seat: row.address, result: 'dropped-read', count: row.count });
|
|
425
|
+
} else results.push({ seat: row.address, result: 'waiting', count: row.count, reason: 'batch-changed' });
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
const resolution = resolveWake(row.address, deps);
|
|
429
|
+
if (resolution.optIn === false) { giveUp(row, 'human-pane-no-opt-in'); continue; }
|
|
430
|
+
// TUI 가 없거나(재기동 중) 다른 pty 의 몫이면 이번 틱은 건너뛴다 — 수명은 TTL 이 닫는다.
|
|
431
|
+
if (resolution.wake !== 'pty-inject' || !resolution.target) continue;
|
|
432
|
+
if (opts.target !== undefined && resolution.target !== opts.target) continue;
|
|
433
|
+
const tui = (deps.listPtys ?? listPtyManifestRows)().find(item => item.id === resolution.target);
|
|
434
|
+
if (!tui?.alive || tui.turnState !== 'idle') { results.push({ seat: row.address, result: 'waiting', count: row.count, reason: `turn=${tui?.turnState ?? 'unknown'}` }); continue; }
|
|
435
|
+
const claim = claimWake(db, row.address, now());
|
|
436
|
+
// 5분 창 안 — 버림이 아니라 미룸: 줄은 그대로, 다음 틱.
|
|
437
|
+
if (!claim) { results.push({ seat: row.address, result: 'waiting', count: row.count, reason: 'debounced' }); continue; }
|
|
438
|
+
const c = openWakeDb(db);
|
|
439
|
+
try { c.query('UPDATE pending_wakes SET attempts = attempts + 1 WHERE address = ?1 AND last_msg_id = ?2').run(row.address, row.last_msg_id); } finally { c.close(); }
|
|
440
|
+
let injected = false;
|
|
441
|
+
try {
|
|
442
|
+
const inject = await (deps.ptyInjector ?? defaultPtyInjector)();
|
|
443
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
444
|
+
await Promise.race([inject(resolution.target, redeliverLine(row)), new Promise<never>((_, reject) => {
|
|
445
|
+
timer = setTimeout(() => reject(new Error('timeout')), deps.timeoutMs ?? WAKE_TIMEOUT_MS);
|
|
446
|
+
})]).finally(() => clearTimeout(timer));
|
|
447
|
+
injected = true;
|
|
448
|
+
} catch (error) {
|
|
449
|
+
releaseClaim(claim);
|
|
450
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
451
|
+
// 상한에 닿은 실패는 그 자리에서 닫는다 — 다음 틱을 기다리지 않는다.
|
|
452
|
+
if (row.attempts + 1 >= MAX_REDELIVER_ATTEMPTS) giveUp({ ...row, attempts: row.attempts + 1 }, `attempts>=${MAX_REDELIVER_ATTEMPTS}:${reason}`);
|
|
453
|
+
else {
|
|
454
|
+
logPending('deferred', { seat: row.address, count: row.count, reason: `inject-failed:${reason}`, attempts: row.attempts + 1 });
|
|
455
|
+
results.push({ seat: row.address, result: 'failed', count: row.count, reason });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (injected) {
|
|
459
|
+
drop(row);
|
|
460
|
+
logPending('redelivered', { seat: row.address, count: row.count, reason: row.reason, attempts: row.attempts + 1, target: resolution.target, firstMsgId: row.first_msg_id, lastMsgId: row.last_msg_id });
|
|
461
|
+
results.push({ seat: row.address, result: 'redelivered', count: row.count });
|
|
462
|
+
}
|
|
463
|
+
} catch (error) {
|
|
464
|
+
results.push({ seat: row.address, result: 'failed', count: row.count, reason: error instanceof Error ? error.message : String(error) });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return results;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* The TUI's own poller: every tick, re-knock wakes deferred for this pty once its turn is recorded idle.
|
|
472
|
+
* Reuses the manifest `turn_state` the TUI already writes (#27485) — no new IPC. Unref'd; never throws.
|
|
473
|
+
*/
|
|
474
|
+
export function startPendingWakePoller(surfaceId: string, deps: WakeDeps = {}, intervalMs = PENDING_WAKE_POLL_MS): () => void {
|
|
475
|
+
let inFlight = false;
|
|
476
|
+
const tick = () => {
|
|
477
|
+
if (inFlight) return;
|
|
478
|
+
inFlight = true;
|
|
479
|
+
void redeliverPendingWakes(deps, { target: surfaceId }).catch(() => []).finally(() => { inFlight = false; });
|
|
480
|
+
};
|
|
481
|
+
const timer = setInterval(tick, intervalMs);
|
|
482
|
+
(timer as { unref?: () => void }).unref?.();
|
|
483
|
+
return () => clearInterval(timer);
|
|
484
|
+
}
|
package/src/loops/observe.ts
CHANGED
|
@@ -28,7 +28,18 @@ export function loopCategory(id: string): string {
|
|
|
28
28
|
return `loop.${id}`;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
/**
|
|
31
|
+
/** Collapse whitespace runs so a value stays on a single line. */
|
|
32
|
+
function oneLine(text: string): string {
|
|
33
|
+
return text.replace(/\s+/g, ' ').trim();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Emit an RFC loop event, retaining absent context as a measurable list. The approval
|
|
38
|
+
* observation ('hitl') settles the «왜 한 줄 ⊕ 근거 포인터» convention at this boundary:
|
|
39
|
+
* reason and sourceRef are collapsed onto a copy as single-line strings, so every approval
|
|
40
|
+
* emission carries a one-line why and evidence pointer without mutating caller data or
|
|
41
|
+
* fabricating fields REQUIRED_CONTEXT reports as missing.
|
|
42
|
+
*/
|
|
32
43
|
export function loopEvent(loopId: string, event: string, data: Record<string, unknown>): void {
|
|
33
44
|
if (!validId(loopId)) {
|
|
34
45
|
reject('invalid-loop-id');
|
|
@@ -44,9 +55,14 @@ export function loopEvent(loopId: string, event: string, data: Record<string, un
|
|
|
44
55
|
reject('invalid-data');
|
|
45
56
|
return;
|
|
46
57
|
}
|
|
58
|
+
const payload: Record<string, unknown> = { ...data };
|
|
59
|
+
if (event === 'hitl') {
|
|
60
|
+
if (typeof payload.reason === 'string') payload.reason = oneLine(payload.reason);
|
|
61
|
+
if (typeof payload.sourceRef === 'string') payload.sourceRef = oneLine(payload.sourceRef);
|
|
62
|
+
}
|
|
47
63
|
const missingRequired = REQUIRED_CONTEXT.filter(field =>
|
|
48
|
-
typeof
|
|
49
|
-
debug.log(`loop.${loopId}`, event, { ...
|
|
64
|
+
typeof payload[field] !== 'string' || !(payload[field] as string).trim());
|
|
65
|
+
debug.log(`loop.${loopId}`, event, { ...payload, loopId, missingRequired });
|
|
50
66
|
if (event === 'tick' && (data.outcome === 'failed' || data.status === 'failed')) {
|
|
51
67
|
try {
|
|
52
68
|
recordFailureEvent({ source: 'loop-tick', kind: event, ref: loopId,
|
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
import { openMsgStore, type Message, type MsgStore } from '../../msg/msg-store.js';
|
|
2
2
|
import { classifySeatTrafficProposal } from '../../seat-loop/traffic-signal.js';
|
|
3
3
|
import { debug } from '../../debug/log.js';
|
|
4
|
+
import { LOOP_MESSAGE_ROUTES } from '../msg-address.js';
|
|
5
|
+
import { replyWithAgent, type AgentReplyInput } from '../agent-reply.js';
|
|
6
|
+
import type { RoleLlmSpec } from '../../user-config.js';
|
|
7
|
+
import type { LLMProvider } from '../../llm.js';
|
|
4
8
|
|
|
5
|
-
const RECIPIENT =
|
|
9
|
+
const RECIPIENT = LOOP_MESSAGE_ROUTES.orchestrator.msgAddress;
|
|
6
10
|
|
|
7
11
|
export interface CoordinatorInboxResult { replied: number; acknowledged: number }
|
|
12
|
+
export interface CoordinatorAgentInboxOptions {
|
|
13
|
+
role: RoleLlmSpec;
|
|
14
|
+
pack: string;
|
|
15
|
+
store?: MsgStore;
|
|
16
|
+
path?: string;
|
|
17
|
+
root?: string;
|
|
18
|
+
limit?: number;
|
|
19
|
+
runAgent?: AgentReplyInput['runAgent'];
|
|
20
|
+
provider?: LLMProvider;
|
|
21
|
+
/** Only the ordered tick scan may advance the durable inbox cursor. */
|
|
22
|
+
acknowledge?: boolean;
|
|
23
|
+
}
|
|
8
24
|
|
|
9
25
|
function trafficProposal(request: Message): 'hold' | 'UNHOLD' | null {
|
|
10
26
|
// A question mentioning a signal is not evidence that the signal occurred.
|
|
@@ -26,10 +42,10 @@ export function coordinatorReply(request: Message): string {
|
|
|
26
42
|
function writeCoordinatorReply(store: MsgStore, request: Message): { id: number; posted: boolean } {
|
|
27
43
|
const marker = `re #${request.id}`;
|
|
28
44
|
const linked = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
|
|
29
|
-
AND reply_to = ? ORDER BY id LIMIT 1`).get(RECIPIENT, request.from, request.id) as { id: number } | null;
|
|
45
|
+
AND reply_to = ? AND kind = 'reply' ORDER BY id LIMIT 1`).get(RECIPIENT, request.from, request.id) as { id: number } | null;
|
|
30
46
|
if (linked) return { id: linked.id, posted: false };
|
|
31
47
|
const legacy = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
|
|
32
|
-
AND reply_to IS NULL AND (body = ? OR substr(body, 1, ?) = ?) ORDER BY id LIMIT 1`)
|
|
48
|
+
AND reply_to IS NULL AND kind = 'reply' AND (body = ? OR substr(body, 1, ?) = ?) ORDER BY id LIMIT 1`)
|
|
33
49
|
.get(RECIPIENT, request.from, marker, marker.length + 1, `${marker}\n`) as { id: number } | null;
|
|
34
50
|
if (legacy) return { id: legacy.id, posted: false };
|
|
35
51
|
const reply = store.post({ from: RECIPIENT, to: request.from,
|
|
@@ -71,3 +87,44 @@ export function runCoordinatorInbox(inputStore?: MsgStore, limit = 100, path?: s
|
|
|
71
87
|
return { replied, acknowledged };
|
|
72
88
|
} finally { if (ownStore) store.close(); }
|
|
73
89
|
}
|
|
90
|
+
|
|
91
|
+
/** One SSE delivery or tick scan uses the same durable handler. At-least-once wake is safe. */
|
|
92
|
+
export async function handleCoordinatorAgentMessage(
|
|
93
|
+
request: Message, input: CoordinatorAgentInboxOptions,
|
|
94
|
+
): Promise<CoordinatorInboxResult> {
|
|
95
|
+
const store = input.store ?? openMsgStore(input.path);
|
|
96
|
+
const ownStore = input.store === undefined;
|
|
97
|
+
const acknowledge = input.acknowledge === true;
|
|
98
|
+
try {
|
|
99
|
+
if (request.to !== RECIPIENT || request.from === RECIPIENT ||
|
|
100
|
+
(request.kind !== undefined && request.kind !== 'request' && request.kind !== 'question')) {
|
|
101
|
+
if (acknowledge) store.ack(RECIPIENT, request.id);
|
|
102
|
+
return { replied: 0, acknowledged: acknowledge ? 1 : 0 };
|
|
103
|
+
}
|
|
104
|
+
// With explicit role selection, every request goes through the agent body.
|
|
105
|
+
const result = await replyWithAgent({ address: RECIPIENT, request, role: input.role,
|
|
106
|
+
pack: input.pack, store, observationRoot: input.root,
|
|
107
|
+
...(input.provider ? { provider: input.provider } : {}),
|
|
108
|
+
...(input.runAgent ? { runAgent: input.runAgent } : {}) });
|
|
109
|
+
if (result.replyId === null) throw new Error(`coordinator agent returned no reply for #${request.id}`);
|
|
110
|
+
if (acknowledge) store.ack(RECIPIENT, request.id);
|
|
111
|
+
return { replied: result.posted ? 1 : 0, acknowledged: acknowledge ? 1 : 0 };
|
|
112
|
+
} finally { if (ownStore) store.close(); }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Configured body path; callers must check the explicit roleLlm opt-in before invoking it. */
|
|
116
|
+
export async function runCoordinatorAgentInbox(input: CoordinatorAgentInboxOptions): Promise<CoordinatorInboxResult> {
|
|
117
|
+
const store = input.store ?? openMsgStore(input.path);
|
|
118
|
+
const ownStore = input.store === undefined;
|
|
119
|
+
const result = { replied: 0, acknowledged: 0 };
|
|
120
|
+
try {
|
|
121
|
+
const requests = store.listByRecipient(RECIPIENT, store.getCursor(RECIPIENT), input.limit ?? 100);
|
|
122
|
+
for (const request of requests) {
|
|
123
|
+
const one = await handleCoordinatorAgentMessage(request, { ...input, store, acknowledge: true });
|
|
124
|
+
result.replied += one.replied;
|
|
125
|
+
result.acknowledged += one.acknowledged;
|
|
126
|
+
}
|
|
127
|
+
debug.log('loop.coordinator-inbox', 'agent-tick', result);
|
|
128
|
+
return result;
|
|
129
|
+
} finally { if (ownStore) store.close(); }
|
|
130
|
+
}
|