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
package/src/dashboard/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { join } from 'path';
|
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { createRunningBuildStatus } from './running-build-status.js';
|
|
10
10
|
import { reportTuiTurn } from '../pty-shell/tui-run-state.js';
|
|
11
|
+
import { logTurnThrew, runTurnTeardownStep } from './turn-busy-teardown.js';
|
|
11
12
|
import { createStaleInstallCheck, formatStaleInstallNotice, readCurrentInstalledCommit, readDashboardBootCommit, STALE_INSTALL_CHECK_INTERVAL_MS, versionedDashboardInstallDir } from './stale-install-check.js';
|
|
12
13
|
import { spawn, spawnSync } from 'node:child_process';
|
|
13
14
|
import { $ } from 'bun';
|
|
@@ -557,21 +558,50 @@ export function resumeInProcessDashboardSession(
|
|
|
557
558
|
setAttachedSessionId: (sessionId: string) => void;
|
|
558
559
|
setActiveSessionId: (sessionId: string) => void;
|
|
559
560
|
},
|
|
560
|
-
):
|
|
561
|
+
):
|
|
562
|
+
| { resumed: true; sessionId: string; turns: number; repaired?: { removedCalls: number; removedResults: number } }
|
|
563
|
+
| { resumed: false; reason: string } {
|
|
561
564
|
const resolvedId = deps.resolveSessionId(resumeSessionId);
|
|
562
565
|
const loaded = resolvedId ? deps.historyFromSession(resolvedId) : null;
|
|
563
566
|
if (!resolvedId || !loaded) return { resumed: false, reason: resumeSessionId };
|
|
564
567
|
|
|
568
|
+
// ④ 깨진 기록 방어(TUI-H8 · #69) — 도구 호출 도중 죽은 프로세스의 기록은 호출·결과 짝이 깨진 꼬리를 남겨
|
|
569
|
+
// 이어받은 첫 턴이 Codex 400 으로 죽는다. 고아 호출·결과만 잘라(`repairCodexToolPairs` · 짝이 맞는 것은 그대로)
|
|
570
|
+
// 이어받고, 같은 id 가 겹쳐 짝을 못 가리면 이어받지 않는다(새 세션 권고).
|
|
571
|
+
const pairs = repairCodexToolPairs(loaded.history as unknown as LLMMessage[]);
|
|
572
|
+
if (pairs.ambiguousIds.length > 0) {
|
|
573
|
+
try {
|
|
574
|
+
debug.log('session', 'resume-refused', {
|
|
575
|
+
surface: 'tui', sessionId: resolvedId, reason: 'ambiguous-tool-pairs', ambiguousIds: pairs.ambiguousIds.length,
|
|
576
|
+
});
|
|
577
|
+
} catch { /* observation is best-effort */ }
|
|
578
|
+
return { resumed: false, reason: `${resumeSessionId} — 도구 호출·결과 짝이 모호한 기록이다 · 새 세션으로 시작한다(권고)` };
|
|
579
|
+
}
|
|
580
|
+
const repairedCount = pairs.removedCalls + pairs.removedResults;
|
|
581
|
+
const history = repairedCount > 0 ? pairs.messages as unknown as ChatMessage[] : loaded.history;
|
|
582
|
+
if (repairedCount > 0) {
|
|
583
|
+
try {
|
|
584
|
+
debug.log('session', 'resume-history-repaired', {
|
|
585
|
+
surface: 'tui', sessionId: resolvedId, removedCalls: pairs.removedCalls, removedResults: pairs.removedResults,
|
|
586
|
+
});
|
|
587
|
+
} catch { /* observation is best-effort */ }
|
|
588
|
+
}
|
|
589
|
+
|
|
565
590
|
const sysFromDash = deps.chatHistory.find((message) => message.role === 'system');
|
|
566
591
|
deps.chatHistory.length = 0;
|
|
567
592
|
if (sysFromDash) deps.chatHistory.push(sysFromDash);
|
|
568
|
-
for (const message of
|
|
593
|
+
for (const message of history) {
|
|
569
594
|
if (message.role === 'system' && sysFromDash && message.content === sysFromDash.content) continue;
|
|
570
595
|
deps.chatHistory.push(message);
|
|
571
596
|
}
|
|
572
597
|
deps.setAttachedSessionId(resolvedId);
|
|
573
598
|
try { deps.setActiveSessionId(resolvedId); } catch { /* best-effort */ }
|
|
574
|
-
return {
|
|
599
|
+
return {
|
|
600
|
+
resumed: true,
|
|
601
|
+
sessionId: resolvedId,
|
|
602
|
+
turns: history.length,
|
|
603
|
+
...(repairedCount > 0 ? { repaired: { removedCalls: pairs.removedCalls, removedResults: pairs.removedResults } } : {}),
|
|
604
|
+
};
|
|
575
605
|
}
|
|
576
606
|
|
|
577
607
|
/**
|
|
@@ -791,6 +821,7 @@ import { bootBannerStatusLines, normalizeBootBannerMode, renderMinimalBootBand,
|
|
|
791
821
|
import { attachDashboardFilePathToken } from './file-path-attachment.js';
|
|
792
822
|
import { bootDashboardSlashExecutor } from './slash-executor-boot.js';
|
|
793
823
|
import { buildDashboardSlashRegistry, type DashboardSlashContext } from './slash-runtime/index.js';
|
|
824
|
+
import type { LoopScheduler } from './loop-scheduler.js';
|
|
794
825
|
import { unknownSlashReply } from './slash-runtime/unknown-slash-reply.js';
|
|
795
826
|
import { resolveSurfaceUx } from '../agent/surface-ux/build.js';
|
|
796
827
|
import type { SurfaceUx } from '../agent/surface-ux/types.js';
|
|
@@ -984,13 +1015,18 @@ import {
|
|
|
984
1015
|
} from '../render.js';
|
|
985
1016
|
import type { SyncMode } from '../types.js';
|
|
986
1017
|
import type { ChatMessage } from '../chat/index.js';
|
|
1018
|
+
import { repairCodexToolPairs } from './input/compact-prepass-recovery.js';
|
|
1019
|
+
import { observeSessionStart } from '../session/session-start.js';
|
|
987
1020
|
import type { PlainTurnSubmit } from '../input/turn-submit.js';
|
|
988
1021
|
// U-4.2 · `renderLogPane` no longer called from dashboard directly —
|
|
989
1022
|
// wd-log widget owns log rendering via renderLogViaWidget. Only
|
|
990
1023
|
// `findBlock` still used here (chat-input block navigation).
|
|
991
1024
|
import { findBlock, logPaneContentHeight, maxLogPaneScroll, visibleSearchRowOffset } from '../panes/log-pane.js';
|
|
992
1025
|
import { createQuitConfirmationState, gracefulQuit, type QuitConfirmationState } from './graceful-quit.js';
|
|
993
|
-
import { handoffTurnTypeaheadAtTurnEnd, releaseTurnTypeaheadPending, steerLastTurnTypeaheadSubmission } from './input/turn-steer-bridge.js';
|
|
1026
|
+
import { consumeTurnEndInterrupted, handoffTurnTypeaheadAtTurnEnd, releaseTurnTypeaheadPending, runTurnTypeaheadPushNow, steerLastTurnTypeaheadSubmission } from './input/turn-steer-bridge.js';
|
|
1027
|
+
import { abortTurnOnly } from '../turn-abort-scope.js';
|
|
1028
|
+
import { consumeInternalTurnYield, createInternalTurnGate, formatInternalTurnBanner, resolveInternalTurnSubmitIntent, type InternalTurnRequest } from './input/internal-turn.js';
|
|
1029
|
+
import { createSeatAutowake } from './input/seat-autowake.js';
|
|
994
1030
|
import { createAttachmentRowMap } from '../log-pane/attachment-row-map.js';
|
|
995
1031
|
import { createAttachmentPopup, type AttachmentPopupAction } from '../log-pane/attachment-popup.js';
|
|
996
1032
|
import { findLogMatches, findVisibleLogMatches, type LogSearchResult } from '../log-pane/search.js';
|
|
@@ -1022,7 +1058,6 @@ import { enqueueSoftStop, readSoftStopRequestStatus } from '../harness/control-i
|
|
|
1022
1058
|
import { setSelfImplementSoftStopSpaceObserver } from '../self-implement/self-implement-runtime.js';
|
|
1023
1059
|
import { createViEditor, type ViEditorHandle } from '../vi-editor.js';
|
|
1024
1060
|
import { launchEditor, canLaunchEditor } from '../editor-launcher.js';
|
|
1025
|
-
import { createSshPickerModal } from '../ssh/ssh-picker-modal.js';
|
|
1026
1061
|
import {
|
|
1027
1062
|
refreshRemoteWorkingDir,
|
|
1028
1063
|
refreshRemoteWorkingDirPreview,
|
|
@@ -1032,12 +1067,10 @@ import {
|
|
|
1032
1067
|
remoteBadge,
|
|
1033
1068
|
} from '../ssh/remote-browser.js';
|
|
1034
1069
|
import { editRemoteFile } from '../ssh/remote-edit.js';
|
|
1035
|
-
import {
|
|
1036
|
-
import {
|
|
1037
|
-
import {
|
|
1038
|
-
import {
|
|
1039
|
-
import { listTransferTargets, type TransferTarget } from '../transfer/transfer-targets.js';
|
|
1040
|
-
import { createTransferPickerModal } from '../transfer/transfer-picker-modal.js';
|
|
1070
|
+
import { createFolderPickerModal } from '../finder/finder-modal.js';
|
|
1071
|
+
import { hostname } from 'node:os';
|
|
1072
|
+
import { type TransferTarget } from '../transfer/transfer-targets.js';
|
|
1073
|
+
import { createInputPickers } from '../tui/input/pickers.js';
|
|
1041
1074
|
import { sshTransfer, type SshTransferProgress } from '../transfer/ssh-transfer.js';
|
|
1042
1075
|
import { iphoneTransfer } from '../transfer/iphone-transfer.js';
|
|
1043
1076
|
import { DashboardAcpChat, displayBackendName, parseAcpSlash, type AcpBackendId } from './chat/acp-chat.js';
|
|
@@ -1081,7 +1114,6 @@ import {
|
|
|
1081
1114
|
} from '../agent/channel-router.js';
|
|
1082
1115
|
import { initTtySnapshotTools } from '../skills/tools/tty-snapshot.js';
|
|
1083
1116
|
import { initAgentHandoffTool } from '../skills/tools/agent-handoff.js';
|
|
1084
|
-
import { touchSshHost } from '../ssh/ssh-hosts.js';
|
|
1085
1117
|
import { DisplayCoordinator } from '../display/coordinator.js';
|
|
1086
1118
|
import {
|
|
1087
1119
|
createLivePlaygroundHarness,
|
|
@@ -1162,7 +1194,6 @@ import {
|
|
|
1162
1194
|
encodeBrowserScopedSubmitText,
|
|
1163
1195
|
resolveBrowserActionContextFromHit,
|
|
1164
1196
|
} from '../browser-pane/actions.js';
|
|
1165
|
-
import { resolveBrowserTransferCapability } from '../browser-pane/capabilities.js';
|
|
1166
1197
|
import {
|
|
1167
1198
|
cyclePreviewSourceForView,
|
|
1168
1199
|
formatPreviewSourceLabel,
|
|
@@ -1276,7 +1307,7 @@ import {
|
|
|
1276
1307
|
type SpaceLongPressDetector,
|
|
1277
1308
|
} from './input/space-longpress-detector.js';
|
|
1278
1309
|
import { isAllowlistedDictationSurface } from './input/dictation-surface-allowlist.js';
|
|
1279
|
-
import { createDashboardExternalInputHost } from './input/external-input-host.js';
|
|
1310
|
+
import { createDashboardExternalInputHost, stopTurnViaEscGate } from './input/external-input-host.js';
|
|
1280
1311
|
import { registerExternalInputHost } from '../input/external-input-queue.js';
|
|
1281
1312
|
// H3 #6 follow-up #3 — background sessions render as a distinct sidebar
|
|
1282
1313
|
// kind with live state badge + tap-to-Join. Dashboard pulls BG records
|
|
@@ -2793,6 +2824,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2793
2824
|
// execute slashes, etc.
|
|
2794
2825
|
const chatModeState = createSessionPostureState();
|
|
2795
2826
|
|
|
2827
|
+
// TUI-LOOP-COMMAND — 실행 중 스케줄러를 쥐는 ref. showDashboard 인스턴스당
|
|
2828
|
+
// 하나로, 입력 루프 «밖»에서 한 번만 선언한다. slashCtx 는 명령마다 다시
|
|
2829
|
+
// 만들어지므로 리터럴 옆에 선언하면 /loop start 로 만든 스케줄러 ref 가
|
|
2830
|
+
// 다음 명령에서 사라진다 — /loop stop · /session new|clear 세션 끝 정지가
|
|
2831
|
+
// 같은 ref 를 써야 «stop 0»(판정)가 성립한다.
|
|
2832
|
+
const dashboardLoopSchedulerRef: { current: LoopScheduler | null } = { current: null };
|
|
2833
|
+
|
|
2796
2834
|
// T3-C2 — vi-editor mounted in the preview pane. Set by the
|
|
2797
2835
|
// browser pane's `e` key on a file; cleared on :q / :q!. When
|
|
2798
2836
|
// non-null it overrides the preview pane's normal render path.
|
|
@@ -2865,6 +2903,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2865
2903
|
// current value so log analysis can filter "what keys fired while
|
|
2866
2904
|
// a turn was in flight".
|
|
2867
2905
|
let streamingInFlight = false;
|
|
2906
|
+
/** 지금 턴의 escGate 중단 — 외부 `/stop`(TUI-STOP-INPUT-BYPASS)이 대기열을 건너뛰어 부른다. 턴 밖이면 null. */
|
|
2907
|
+
let currentTurnExternalStop: (() => void) | null = null;
|
|
2868
2908
|
const resolveTmuxStatusLabel = (): string | null => {
|
|
2869
2909
|
if (!process.env['TMUX']) return null;
|
|
2870
2910
|
const fallback = process.env['TMUX_PANE'] ?? 'tmux';
|
|
@@ -3333,6 +3373,26 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3333
3373
|
// 즉시 에코 · 턴 종료 시 loop-head 핸드오프가 prefill/자동제출로 넘긴다.
|
|
3334
3374
|
// (외곽 스코프 선언 — 스트리밍 디스패처와 메인 키 루프 양쪽에서 참조.)
|
|
3335
3375
|
const turnTypeaheadRef = { state: createTurnTypeaheadState() };
|
|
3376
|
+
// «지금 밀어 넣기»로 끊은 턴 — 턴 종료가 큐를 composer 로 «복원»하지 않고 곧바로 «제출»하게 한다.
|
|
3377
|
+
const steerInterruptRef = { pending: false };
|
|
3378
|
+
// ⭐ H2 내부 턴 문(TUI-H2-INTERNAL-TURN) — 자율 재개(H3·H4·H5)가 지나갈 «문 하나». 판정은 모듈,
|
|
3379
|
+
// 여기선 상태를 읽어 넘기기만 한다(⚠️ promptCtl·가시성 함수는 아래에서 선언 — 호출 시점엔 있다).
|
|
3380
|
+
const internalTurnGate = createInternalTurnGate({
|
|
3381
|
+
isTurnRunning: () => streamingInFlight,
|
|
3382
|
+
isInputForeground: () =>
|
|
3383
|
+
chatMainInputVisibilityState().inputOwnership?.owner === 'chat-main' && !topBlockingForegroundModal(),
|
|
3384
|
+
getBufferText: () => promptCtl.getBufferText?.(),
|
|
3385
|
+
getTypeaheadCount: () =>
|
|
3386
|
+
turnTypeaheadRef.state.queuedSubmissions.length + (turnTypeaheadRef.state.buffer ? 1 : 0),
|
|
3387
|
+
});
|
|
3388
|
+
// ⭐ H3 턴 끝 자동 재개(OPT-QUEUE-AUTOWAKE) — 자리 TUI ∧ autowake 파일일 때만. 턴 끝에 «남은 일»(안 읽은
|
|
3389
|
+
// 우편 · queue.md «## 대기»)을 재고 H2 문으로 다음 턴을 청한다. 판정·상한은 모듈, 여기선 배선만.
|
|
3390
|
+
const seatAutowake = createSeatAutowake({
|
|
3391
|
+
startTurnIfIdle: (text, opts) => internalTurnGate.startTurnIfIdle(text, opts),
|
|
3392
|
+
getCwd: () => workingDir.cwd,
|
|
3393
|
+
notify: (line) => { chatLines.push(C.muted(line)); draw(); },
|
|
3394
|
+
});
|
|
3395
|
+
const internalTurnYieldPort = seatAutowake.wrapPort(internalTurnGate.port);
|
|
3336
3396
|
// ⭐ `B3` — 큐를 «도는 턴»에 넣으려면 그 턴이 도는 ***ACP 세션 id*** 가 필요하다.
|
|
3337
3397
|
// ⛔ `attachedSessionId`(대화 세션)와 «다른 축»이다 — 루프는 ACP 세션으로 스코프를 연다.
|
|
3338
3398
|
// ⚠️ 세션은 이 함수 «뒤»에서 만들어지므로 참조로 둔다(호출 시점엔 채워져 있다).
|
|
@@ -6458,8 +6518,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6458
6518
|
const attachChatStreamingKeys = (abortCtrl: AbortController): () => void => {
|
|
6459
6519
|
const chatLinesStartIndex = chatLines.length;
|
|
6460
6520
|
userScrolledDuringStream = false;
|
|
6461
|
-
streamingInFlight = true;
|
|
6462
|
-
reportTuiTurn('busy');
|
|
6463
6521
|
const SCROLL_KEYS = new Set(['j', 'k', 'down', 'up', 'pageup', 'pagedown', 'home', 'end', 'g', 'G']);
|
|
6464
6522
|
// T3-B2: ESC abort gate. When the user hits Esc AND sub-agent
|
|
6465
6523
|
// work is running, pop a confirmation modal before tearing down
|
|
@@ -6759,7 +6817,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6759
6817
|
// ⛔ 중복 전송 방지가 계약이다: 레지스트리가 배수되면 `onDrained` 가
|
|
6760
6818
|
// ***여기 큐도 같이 비운다*** — 안 그러면 같은 발화가 턴 끝에 «또» 나간다.
|
|
6761
6819
|
// ⚠️ `immediate`(슬래시 등)는 지금 실행되므로 «넣지 않는다».
|
|
6762
|
-
|
|
6820
|
+
// ⛔ H2 — 내부 턴 중의 사람 입력은 그 턴에 끼워 넣지 않는다(턴 끝 FIFO 로 기다린다).
|
|
6821
|
+
if (r.submissionDisposition === 'fifo' && !r.immediateSubmission && !internalTurnGate.isInternalTurnActive()) {
|
|
6763
6822
|
const queuedText = turnTypeaheadRef.state.queuedSubmissions.at(-1);
|
|
6764
6823
|
const sid = activeSessionIdForTypeahead();
|
|
6765
6824
|
if (queuedText && sid) {
|
|
@@ -6790,6 +6849,22 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6790
6849
|
}
|
|
6791
6850
|
}
|
|
6792
6851
|
if (r.releasedPendingIds) releaseTurnTypeaheadPending(r.releasedPendingIds, 'recalled');
|
|
6852
|
+
if (r.pushNowRequested) {
|
|
6853
|
+
const decision = runTurnTypeaheadPushNow(turnTypeaheadRef, {
|
|
6854
|
+
runningToolNames: () => getEscAbortWaitingToolNames(escAbortToolState),
|
|
6855
|
+
interruptTurn: () => {
|
|
6856
|
+
steerInterruptRef.pending = true;
|
|
6857
|
+
try { globalAgentRegistry.markBackgroundAllRunning(); } catch { /* 승격 실패가 끊기를 막지 않는다 */ }
|
|
6858
|
+
abortTurnOnly(abortCtrl);
|
|
6859
|
+
},
|
|
6860
|
+
pushNotice: (line) => pushChatLine(C.muted(line)),
|
|
6861
|
+
});
|
|
6862
|
+
debug.log('dashboard.turn-typeahead', 'push-now', {
|
|
6863
|
+
kind: decision.kind,
|
|
6864
|
+
tools: decision.kind === 'interrupt' ? decision.runningTools : decision.kind === 'nothing' ? [] : decision.blockingTools,
|
|
6865
|
+
});
|
|
6866
|
+
draw();
|
|
6867
|
+
}
|
|
6793
6868
|
if (r.immediateSubmission) {
|
|
6794
6869
|
turnTypeaheadRef.state = await dispatchStreamingTurnTypeaheadSubmission(
|
|
6795
6870
|
turnTypeaheadRef.state,
|
|
@@ -7015,19 +7090,29 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7015
7090
|
// `runStreamingKeyUnifiedDispatch` above for the route body.
|
|
7016
7091
|
await runStreamingKeyUnifiedDispatch(key);
|
|
7017
7092
|
});
|
|
7093
|
+
// ⛔ TUI-STALE-BUSY-MARKER — busy 는 «끄는 closure 를 돌려주기 직전»에 켠다. 위 준비(ESC 게이트·키 리스너)가
|
|
7094
|
+
// 던지면 호출자는 cleanup 을 못 받으므로, 먼저 켜 두면 아무도 못 끄는 busy 가 남는다(#37).
|
|
7095
|
+
streamingInFlight = true;
|
|
7096
|
+
reportTuiTurn('busy');
|
|
7097
|
+
const externalStop = (): void => { stopTurnViaEscGate(escGate); };
|
|
7098
|
+
currentTurnExternalStop = externalStop;
|
|
7018
7099
|
return () => {
|
|
7019
|
-
|
|
7020
|
-
|
|
7100
|
+
if (currentTurnExternalStop === externalStop) currentTurnExternalStop = null;
|
|
7101
|
+
// 단계마다 격리 — 앞 단계가 던져도 settle·idle 전이에 닿는다(키 층 유휴 ∧ 턴 층 busy 이원 판정 #55 차단).
|
|
7102
|
+
runTurnTeardownStep('stream-keys-detach', cleanup);
|
|
7103
|
+
runTurnTeardownStep('esc-gate-dispose', () => { escGate.dispose(); });
|
|
7021
7104
|
try {
|
|
7022
7105
|
if (!stoppedHarnessSpace) settleEscAbortPendingLines(chatLines, chatLinesStartIndex);
|
|
7023
7106
|
} catch (err) {
|
|
7024
7107
|
const message = err instanceof Error ? err.message : String(err);
|
|
7025
7108
|
const stackHead = err instanceof Error ? err.stack?.split('\n')[1]?.trim() : undefined;
|
|
7026
7109
|
debug.log('dashboard.turn', 'settle-failed', { message, stackHead });
|
|
7110
|
+
logTurnThrew('settle-esc-lines', err);
|
|
7027
7111
|
} finally {
|
|
7028
7112
|
userScrolledDuringStream = false;
|
|
7029
7113
|
streamingInFlight = false;
|
|
7030
7114
|
reportTuiTurn('idle');
|
|
7115
|
+
seatAutowake.noteTurnEnded();
|
|
7031
7116
|
}
|
|
7032
7117
|
};
|
|
7033
7118
|
};
|
|
@@ -11561,63 +11646,53 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11561
11646
|
let agentSearchModal: SearchModalHandle | null = null;
|
|
11562
11647
|
let agentSearchHandle: { dispose: () => void } | null = null;
|
|
11563
11648
|
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
},
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
}
|
|
11612
|
-
closeAgentRosterSearch();
|
|
11613
|
-
},
|
|
11614
|
-
onCancel: () => closeAgentRosterSearch(),
|
|
11615
|
-
theme: currentThemeTokens(),
|
|
11616
|
-
});
|
|
11617
|
-
attachSurfaceToWorkspace(handle.surface, currentWorkspaceOwnerId());
|
|
11618
|
-
agentSearchModal = handle;
|
|
11619
|
-
agentSearchHandle = display.pushModal(handle.surface);
|
|
11620
|
-
}
|
|
11649
|
+
// TUI-DIET-SEAM-PICKERS — the five input pickers (agent-roster search,
|
|
11650
|
+
// transfer, Ctrl+T file finder, Alt+C directory finder, Ctrl+K SSH)
|
|
11651
|
+
// live in src/tui/input/pickers.ts. Mutable dashboard state crosses
|
|
11652
|
+
// the seam as live get/set accessors (never a value copy); `draw` is
|
|
11653
|
+
// re-read at call time because it is reassigned after mount.
|
|
11654
|
+
const {
|
|
11655
|
+
openAgentRosterSearch,
|
|
11656
|
+
openTransferPicker,
|
|
11657
|
+
openFinderPicker,
|
|
11658
|
+
openDirectoryPicker,
|
|
11659
|
+
openSshPicker,
|
|
11660
|
+
} = createInputPickers({
|
|
11661
|
+
state: {
|
|
11662
|
+
get agentSearchModal() { return agentSearchModal; },
|
|
11663
|
+
set agentSearchModal(v: SearchModalHandle | null) { agentSearchModal = v; },
|
|
11664
|
+
get agentSearchHandle() { return agentSearchHandle; },
|
|
11665
|
+
set agentSearchHandle(v: { dispose: () => void } | null) { agentSearchHandle = v; },
|
|
11666
|
+
get agentRosterCursor() { return agentRosterCursor; },
|
|
11667
|
+
set agentRosterCursor(v: number) { agentRosterCursor = v; },
|
|
11668
|
+
get agentCursorLockedId() { return agentCursorLockedId; },
|
|
11669
|
+
set agentCursorLockedId(v: string) { agentCursorLockedId = v; },
|
|
11670
|
+
get agentCursorManual() { return agentCursorManual; },
|
|
11671
|
+
set agentCursorManual(v: boolean) { agentCursorManual = v; },
|
|
11672
|
+
get chatScrollOffset() { return chatScrollOffset; },
|
|
11673
|
+
set chatScrollOffset(v: number) { chatScrollOffset = v; },
|
|
11674
|
+
get chatLines() { return chatLines; },
|
|
11675
|
+
},
|
|
11676
|
+
display,
|
|
11677
|
+
agentSurfaceStore,
|
|
11678
|
+
workingDir,
|
|
11679
|
+
dockedPreview,
|
|
11680
|
+
transferFeedbackRuntime,
|
|
11681
|
+
finderFeedbackRuntime,
|
|
11682
|
+
currentThemeTokens,
|
|
11683
|
+
currentWorkspaceOwnerId,
|
|
11684
|
+
activeBrowserWidgetId,
|
|
11685
|
+
resolveBrowserStateById,
|
|
11686
|
+
fmtBytes,
|
|
11687
|
+
runTransfer,
|
|
11688
|
+
closeAgentRosterSearch,
|
|
11689
|
+
pushDebugLine,
|
|
11690
|
+
refreshRemotePreviewBridge,
|
|
11691
|
+
refreshWorkingDirPreview,
|
|
11692
|
+
setWorkingFocus,
|
|
11693
|
+
startRemoteModeBridge,
|
|
11694
|
+
draw: () => draw(),
|
|
11695
|
+
});
|
|
11621
11696
|
|
|
11622
11697
|
function closeAgentRosterSearch(): void {
|
|
11623
11698
|
if (agentSearchHandle) { agentSearchHandle.dispose(); agentSearchHandle = null; }
|
|
@@ -11625,75 +11700,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11625
11700
|
draw();
|
|
11626
11701
|
}
|
|
11627
11702
|
|
|
11628
|
-
/** T5-J5 — open the transfer picker. Files arg = local paths to
|
|
11629
|
-
* ship; destination comes from the picker. Handles both ssh and
|
|
11630
|
-
* iphone target kinds. Remote-mode browser isn't supported here
|
|
11631
|
-
* yet — the user is transferring LOCAL files (focused entry +
|
|
11632
|
-
* selected set) to a remote destination. Transferring REMOTE→X
|
|
11633
|
-
* is a separate flow (not this phase). */
|
|
11634
|
-
function openTransferPicker(
|
|
11635
|
-
files: Array<{ localPath: string; size?: number }>,
|
|
11636
|
-
browserId: string = activeBrowserWidgetId(),
|
|
11637
|
-
): void {
|
|
11638
|
-
const targetBrowser = resolveBrowserStateById(browserId) ?? (workingDir as BrowserPaneModel);
|
|
11639
|
-
if (files.length === 0) {
|
|
11640
|
-
transferFeedbackRuntime.onNoFilesToTransfer();
|
|
11641
|
-
return;
|
|
11642
|
-
}
|
|
11643
|
-
const capability = resolveBrowserTransferCapability(
|
|
11644
|
-
targetBrowser,
|
|
11645
|
-
listTransferTargets(),
|
|
11646
|
-
);
|
|
11647
|
-
if (!capability.enabled) {
|
|
11648
|
-
transferFeedbackRuntime.onTransferDisabled(capability.reason);
|
|
11649
|
-
return;
|
|
11650
|
-
}
|
|
11651
|
-
const targets = capability.targets;
|
|
11652
|
-
if (targets.length === 0) {
|
|
11653
|
-
transferFeedbackRuntime.onNoTransferTargets();
|
|
11654
|
-
return;
|
|
11655
|
-
}
|
|
11656
|
-
const totalBytes = files.reduce((a, f) => a + (f.size ?? 0), 0);
|
|
11657
|
-
const summary = `${files.length} file${files.length === 1 ? '' : 's'}${
|
|
11658
|
-
totalBytes > 0 ? ` (${fmtBytes(totalBytes)})` : ''
|
|
11659
|
-
}`;
|
|
11660
|
-
|
|
11661
|
-
const { cols, rows } = termSize();
|
|
11662
|
-
const width = Math.min(74, Math.max(46, cols - 6));
|
|
11663
|
-
const visibleRows = Math.min(10, targets.length);
|
|
11664
|
-
const height = visibleRows + 3;
|
|
11665
|
-
const bounds = {
|
|
11666
|
-
row: Math.max(1, Math.floor((rows - height) / 2)),
|
|
11667
|
-
col: Math.max(1, Math.floor((cols - width) / 2)),
|
|
11668
|
-
width,
|
|
11669
|
-
height,
|
|
11670
|
-
};
|
|
11671
|
-
let handle: ReturnType<typeof display.pushModal> | null = null;
|
|
11672
|
-
const picker = createTransferPickerModal({
|
|
11673
|
-
targets,
|
|
11674
|
-
bounds,
|
|
11675
|
-
width,
|
|
11676
|
-
maxVisible: visibleRows,
|
|
11677
|
-
summary,
|
|
11678
|
-
theme: currentThemeTokens(),
|
|
11679
|
-
onAccept: (target) => {
|
|
11680
|
-
agentSearchModal = null;
|
|
11681
|
-
handle?.dispose();
|
|
11682
|
-
void runTransfer(target, files);
|
|
11683
|
-
draw();
|
|
11684
|
-
},
|
|
11685
|
-
onCancel: () => {
|
|
11686
|
-
agentSearchModal = null;
|
|
11687
|
-
handle?.dispose();
|
|
11688
|
-
draw();
|
|
11689
|
-
},
|
|
11690
|
-
});
|
|
11691
|
-
attachSurfaceToWorkspace(picker.surface, currentWorkspaceOwnerId());
|
|
11692
|
-
handle = display.pushModal(picker.surface);
|
|
11693
|
-
agentSearchModal = picker;
|
|
11694
|
-
draw();
|
|
11695
|
-
}
|
|
11696
|
-
|
|
11697
11703
|
async function runTransfer(
|
|
11698
11704
|
target: TransferTarget,
|
|
11699
11705
|
files: Array<{ localPath: string; size?: number }>,
|
|
@@ -11720,465 +11726,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11720
11726
|
}
|
|
11721
11727
|
}
|
|
11722
11728
|
|
|
11723
|
-
/** T4-F2 / T4-F3 — open the Ctrl+T finder modal. Scans the
|
|
11724
|
-
* current working dir (local only at MVP; remote scan is a
|
|
11725
|
-
* follow-up). On accept, cd's the browser pane to the file's
|
|
11726
|
-
* parent dir, focuses the file in the listing, and switches
|
|
11727
|
-
* pane focus to browser so the user can e/enter next. */
|
|
11728
|
-
async function openFinderPicker(): Promise<void> {
|
|
11729
|
-
const targetBrowserId = activeBrowserWidgetId();
|
|
11730
|
-
const targetBrowser = resolveBrowserStateById(targetBrowserId) ?? (workingDir as BrowserPaneModel);
|
|
11731
|
-
// T5-I2 — branch on remote vs local. Both paths produce the
|
|
11732
|
-
// same {absPath, relPath} finder items so the modal + onAccept
|
|
11733
|
-
// handler stay unified.
|
|
11734
|
-
let finderItems: FinderItem[] = [];
|
|
11735
|
-
let backend = 'fd';
|
|
11736
|
-
let truncated = false;
|
|
11737
|
-
let scanDurationMs = 0;
|
|
11738
|
-
|
|
11739
|
-
if (workingDir.remote) {
|
|
11740
|
-
const host = workingDir.remote.host;
|
|
11741
|
-
const remoteRoot = workingDir.remote.cwd;
|
|
11742
|
-
finderFeedbackRuntime.onFinderScanStarted(`${host.name}:${remoteRoot}`);
|
|
11743
|
-
draw();
|
|
11744
|
-
const scan = await scanRemoteFinder({ host, root: remoteRoot });
|
|
11745
|
-
const rels = relativizeRemoteResults(scan.paths, remoteRoot);
|
|
11746
|
-
finderItems = scan.paths.map((absPath, i) => ({
|
|
11747
|
-
absPath, relPath: rels[i] ?? absPath,
|
|
11748
|
-
}));
|
|
11749
|
-
backend = `${scan.backend}@${scan.host}`;
|
|
11750
|
-
truncated = scan.truncated;
|
|
11751
|
-
scanDurationMs = scan.durationMs;
|
|
11752
|
-
} else {
|
|
11753
|
-
// 2026-05-03 — scan from the Session Working Directory (the
|
|
11754
|
-
// "project root"), NOT the browser pane's current navigation
|
|
11755
|
-
// cursor. SWD is mutable only via Ctrl+W / /wd / SetWorkingDir
|
|
11756
|
-
// tool — exactly the user's intent for "project root". Browser
|
|
11757
|
-
// pane's cwd is purely UI navigation and should not narrow
|
|
11758
|
-
// Ctrl+T's search scope (matches working-dir.ts:5-8 contract).
|
|
11759
|
-
const scanRoot = getSessionCwd();
|
|
11760
|
-
finderFeedbackRuntime.onFinderScanStarted(scanRoot);
|
|
11761
|
-
draw();
|
|
11762
|
-
const scan = await scanFinder({ root: scanRoot });
|
|
11763
|
-
const rels = relativizeResults(scan.paths, scanRoot);
|
|
11764
|
-
finderItems = scan.paths.map((absPath, i) => ({
|
|
11765
|
-
absPath, relPath: rels[i] ?? absPath,
|
|
11766
|
-
}));
|
|
11767
|
-
backend = scan.backend;
|
|
11768
|
-
truncated = scan.truncated;
|
|
11769
|
-
scanDurationMs = scan.durationMs;
|
|
11770
|
-
}
|
|
11771
|
-
if (finderItems.length === 0) {
|
|
11772
|
-
finderFeedbackRuntime.onFinderScanEmpty();
|
|
11773
|
-
draw();
|
|
11774
|
-
return;
|
|
11775
|
-
}
|
|
11776
|
-
finderFeedbackRuntime.onFinderScanCompleted({
|
|
11777
|
-
count: finderItems.length,
|
|
11778
|
-
backend,
|
|
11779
|
-
truncated,
|
|
11780
|
-
durationMs: scanDurationMs,
|
|
11781
|
-
});
|
|
11782
|
-
|
|
11783
|
-
const { cols, rows } = termSize();
|
|
11784
|
-
const width = Math.min(90, Math.max(50, cols - 6));
|
|
11785
|
-
const visibleRows = Math.min(15, Math.max(6, rows - 8));
|
|
11786
|
-
const height = visibleRows + 3;
|
|
11787
|
-
const bounds = {
|
|
11788
|
-
row: Math.max(1, Math.floor((rows - height) / 2)),
|
|
11789
|
-
col: Math.max(1, Math.floor((cols - width) / 2)),
|
|
11790
|
-
width,
|
|
11791
|
-
height,
|
|
11792
|
-
};
|
|
11793
|
-
let handle: ReturnType<typeof display.pushModal> | null = null;
|
|
11794
|
-
// Title reflects the actual scan root — SWD for local (project
|
|
11795
|
-
// root), remote cwd for remote mode. Browser pane's nav cursor
|
|
11796
|
-
// is intentionally NOT shown because the scan ignores it.
|
|
11797
|
-
const titleRoot = workingDir.remote
|
|
11798
|
-
? `${workingDir.remote.host.name}:${workingDir.remote.cwd}`
|
|
11799
|
-
: getSessionCwd().replace(homedir(), '~');
|
|
11800
|
-
// 2026-05-03 — preview modes (yazi/fzf-style, on-demand).
|
|
11801
|
-
//
|
|
11802
|
-
// Default mode is OFF — the picker opens cleanly with NO preview
|
|
11803
|
-
// so it's never annoying on tablet / narrow terminals. The user
|
|
11804
|
-
// toggles preview behaviour with `Ctrl+/` (matches zshrc
|
|
11805
|
-
// `--bind 'ctrl-/:toggle-preview'`):
|
|
11806
|
-
//
|
|
11807
|
-
// off → hover → 2pane → off (cycle)
|
|
11808
|
-
//
|
|
11809
|
-
// • off — no preview, ever. The cursor moves freely.
|
|
11810
|
-
// • hover — popup appears after the cursor stays still for
|
|
11811
|
-
// 1 second (HOVER_DELAY_MS). Popup auto-dismisses
|
|
11812
|
-
// after 4s. Centered, the same width as legacy
|
|
11813
|
-
// behaviour but on-demand.
|
|
11814
|
-
// • 2pane — browser-preview style: persistent preview popup
|
|
11815
|
-
// docked to the right of the picker. Updates
|
|
11816
|
-
// instantly as the cursor moves. Falls back to
|
|
11817
|
-
// hover if the terminal is too narrow (<140 cols).
|
|
11818
|
-
//
|
|
11819
|
-
// showPreviewModal supports remote-skip by itself (preview
|
|
11820
|
-
// handlers read local fs), so we simply guard with workingDir
|
|
11821
|
-
// .remote before scheduling.
|
|
11822
|
-
type PreviewMode = 'off' | 'hover' | '2pane';
|
|
11823
|
-
const HOVER_DELAY_MS = 1000;
|
|
11824
|
-
const TWO_PANE_MIN_COLS = 140;
|
|
11825
|
-
const TWO_PANE_GROUP = 'finder-2pane-preview';
|
|
11826
|
-
|
|
11827
|
-
let previewMode: PreviewMode = 'off';
|
|
11828
|
-
let lastSelected: FinderItem | null = null;
|
|
11829
|
-
let hoverTimer: ReturnType<typeof setTimeout> | null = null;
|
|
11830
|
-
let lastPreviewHandle: { dispose(): void } | null = null;
|
|
11831
|
-
|
|
11832
|
-
const clearHoverTimer = () => {
|
|
11833
|
-
if (hoverTimer !== null) { clearTimeout(hoverTimer); hoverTimer = null; }
|
|
11834
|
-
};
|
|
11835
|
-
const disposeActivePreview = () => {
|
|
11836
|
-
if (lastPreviewHandle) {
|
|
11837
|
-
try { lastPreviewHandle.dispose(); } catch { /* ignore */ }
|
|
11838
|
-
lastPreviewHandle = null;
|
|
11839
|
-
}
|
|
11840
|
-
};
|
|
11841
|
-
|
|
11842
|
-
/** Compute the docked-preview bounds for 2-pane mode. Picker
|
|
11843
|
-
* centred at width≈90; preview takes the right gutter. Returns
|
|
11844
|
-
* null when there isn't enough room (caller falls back to
|
|
11845
|
-
* hover). */
|
|
11846
|
-
const computeDockedPreviewBounds = (): {
|
|
11847
|
-
row: number; col: number; width: number; height: number;
|
|
11848
|
-
} | null => {
|
|
11849
|
-
const { cols: tc, rows: tr } = termSize();
|
|
11850
|
-
if (tc < TWO_PANE_MIN_COLS) return null;
|
|
11851
|
-
const pickerWidth = Math.min(90, Math.max(50, tc - 6));
|
|
11852
|
-
const pickerCol = Math.max(1, Math.floor((tc - pickerWidth) / 2));
|
|
11853
|
-
const previewCol = pickerCol + pickerWidth + 2;
|
|
11854
|
-
const previewWidth = Math.max(40, tc - previewCol - 2);
|
|
11855
|
-
if (previewWidth < 40) return null;
|
|
11856
|
-
const previewHeight = Math.max(8, Math.min(tr - 6, 28));
|
|
11857
|
-
const previewRow = Math.max(1, Math.floor((tr - previewHeight) / 2));
|
|
11858
|
-
return { row: previewRow, col: previewCol, width: previewWidth, height: previewHeight };
|
|
11859
|
-
};
|
|
11860
|
-
|
|
11861
|
-
const paintPreviewFor = (item: FinderItem) => {
|
|
11862
|
-
if (workingDir.remote) return; // remote previews unsupported
|
|
11863
|
-
const { rows: tr, cols: tc } = termSize();
|
|
11864
|
-
const docked = previewMode === '2pane' ? computeDockedPreviewBounds() : null;
|
|
11865
|
-
void showPreviewModal(item.absPath, {
|
|
11866
|
-
coordinator: display,
|
|
11867
|
-
termCols: tc,
|
|
11868
|
-
termRows: tr,
|
|
11869
|
-
title: item.relPath,
|
|
11870
|
-
ttlMs: previewMode === '2pane' ? 0 : 4000,
|
|
11871
|
-
bounds: docked ?? undefined,
|
|
11872
|
-
group: previewMode === '2pane' ? TWO_PANE_GROUP : 'image-preview',
|
|
11873
|
-
}).then((r) => {
|
|
11874
|
-
lastPreviewHandle = r?.handle ?? null;
|
|
11875
|
-
}).catch(() => { /* preview failure is non-fatal */ });
|
|
11876
|
-
};
|
|
11877
|
-
|
|
11878
|
-
const scheduleHoverPreview = (item: FinderItem | null) => {
|
|
11879
|
-
lastSelected = item;
|
|
11880
|
-
clearHoverTimer();
|
|
11881
|
-
if (previewMode === 'off') return;
|
|
11882
|
-
if (!item || workingDir.remote) {
|
|
11883
|
-
// Off-screen / remote — kill any straggling popup so the
|
|
11884
|
-
// user doesn't see a preview that no longer matches the
|
|
11885
|
-
// selection.
|
|
11886
|
-
disposeActivePreview();
|
|
11887
|
-
return;
|
|
11888
|
-
}
|
|
11889
|
-
if (previewMode === '2pane') {
|
|
11890
|
-
// Instant update — no debounce. Persistent popup replaces
|
|
11891
|
-
// itself via group dedup.
|
|
11892
|
-
paintPreviewFor(item);
|
|
11893
|
-
return;
|
|
11894
|
-
}
|
|
11895
|
-
// HOVER mode. Selection just changed → the popup currently on
|
|
11896
|
-
// screen (if any) is stale. Drop it immediately so the user
|
|
11897
|
-
// doesn't keep seeing the previous file's preview while their
|
|
11898
|
-
// cursor is on a new file. The next paint waits HOVER_DELAY_MS
|
|
11899
|
-
// of stillness before re-appearing.
|
|
11900
|
-
disposeActivePreview();
|
|
11901
|
-
hoverTimer = setTimeout(() => {
|
|
11902
|
-
hoverTimer = null;
|
|
11903
|
-
paintPreviewFor(item);
|
|
11904
|
-
}, HOVER_DELAY_MS);
|
|
11905
|
-
};
|
|
11906
|
-
|
|
11907
|
-
/** Cycle off → hover → 2pane → off. Surfaces a status line so
|
|
11908
|
-
* the user knows which mode they're in (Ctrl+/ has no chrome
|
|
11909
|
-
* feedback otherwise). 2pane on a narrow terminal degrades
|
|
11910
|
-
* to hover with a warning. */
|
|
11911
|
-
const cyclePreviewMode = (): void => {
|
|
11912
|
-
const next: PreviewMode = previewMode === 'off' ? 'hover'
|
|
11913
|
-
: previewMode === 'hover' ? '2pane'
|
|
11914
|
-
: 'off';
|
|
11915
|
-
previewMode = next;
|
|
11916
|
-
clearHoverTimer();
|
|
11917
|
-
// Drop the active popup whenever the mode changes. The new
|
|
11918
|
-
// mode (if any) re-paints below.
|
|
11919
|
-
disposeActivePreview();
|
|
11920
|
-
|
|
11921
|
-
if (next === 'off') {
|
|
11922
|
-
chatLines.push(C.muted(' finder preview: OFF (Ctrl+/ to cycle modes)'));
|
|
11923
|
-
} else if (next === 'hover') {
|
|
11924
|
-
chatLines.push(C.muted(' finder preview: HOVER (popup after 1 s · Ctrl+/ next)'));
|
|
11925
|
-
} else {
|
|
11926
|
-
// 2pane — refuse if the terminal is too narrow; degrade to
|
|
11927
|
-
// hover so the user gets *some* preview without overlap.
|
|
11928
|
-
const docked = computeDockedPreviewBounds();
|
|
11929
|
-
if (!docked) {
|
|
11930
|
-
previewMode = 'hover';
|
|
11931
|
-
chatLines.push(C.warning(` finder preview: 2-pane needs ≥${TWO_PANE_MIN_COLS} cols — falling back to HOVER`));
|
|
11932
|
-
} else {
|
|
11933
|
-
chatLines.push(C.muted(' finder preview: 2-PANE (docked right · Ctrl+/ to disable)'));
|
|
11934
|
-
if (lastSelected) paintPreviewFor(lastSelected);
|
|
11935
|
-
}
|
|
11936
|
-
}
|
|
11937
|
-
chatScrollOffset = -1;
|
|
11938
|
-
draw();
|
|
11939
|
-
};
|
|
11940
|
-
|
|
11941
|
-
// Declared up here so `onAccept`/`onCancel` closures below can
|
|
11942
|
-
// reference both; assigned right after the picker mounts.
|
|
11943
|
-
let previewToggleDisposable: { dispose(): void } | null = null;
|
|
11944
|
-
let previewDismissDisposable: { dispose(): void } | null = null;
|
|
11945
|
-
const picker = createFinderModal({
|
|
11946
|
-
items: finderItems,
|
|
11947
|
-
bounds, width, maxVisible: visibleRows,
|
|
11948
|
-
truncated,
|
|
11949
|
-
title: `Find file in ${titleRoot}`,
|
|
11950
|
-
theme: currentThemeTokens(),
|
|
11951
|
-
onHover: scheduleHoverPreview,
|
|
11952
|
-
onAccept: (item) => {
|
|
11953
|
-
clearHoverTimer();
|
|
11954
|
-
disposeActivePreview();
|
|
11955
|
-
previewToggleDisposable?.dispose();
|
|
11956
|
-
previewDismissDisposable?.dispose();
|
|
11957
|
-
agentSearchModal = null;
|
|
11958
|
-
handle?.dispose();
|
|
11959
|
-
const parentDir = item.absPath.slice(0, item.absPath.lastIndexOf('/')) || '/';
|
|
11960
|
-
const basename = item.absPath.slice(item.absPath.lastIndexOf('/') + 1);
|
|
11961
|
-
if (workingDir.remote) {
|
|
11962
|
-
// T5-I2 — remote cd + focus-by-basename.
|
|
11963
|
-
enterRemoteDirectory(workingDir, parentDir);
|
|
11964
|
-
(async () => {
|
|
11965
|
-
await refreshRemoteWorkingDir(workingDir, {}, dockedPreview);
|
|
11966
|
-
const idx = workingDir.entries.findIndex(e => e.name === basename);
|
|
11967
|
-
if (idx >= 0) {
|
|
11968
|
-
workingDir.cursor = idx;
|
|
11969
|
-
workingDir.offset = Math.max(0, idx - 3);
|
|
11970
|
-
}
|
|
11971
|
-
await refreshRemotePreviewBridge();
|
|
11972
|
-
pushDebugLine(C.muted(` ${workingDir.remote?.host.name}:${item.relPath}`));
|
|
11973
|
-
chatScrollOffset = -1;
|
|
11974
|
-
draw();
|
|
11975
|
-
})().catch(() => {});
|
|
11976
|
-
} else {
|
|
11977
|
-
enterDirectory(targetBrowser as WorkingDirState, parentDir);
|
|
11978
|
-
refreshWorkingDir(targetBrowser as WorkingDirState);
|
|
11979
|
-
const idx = targetBrowser.entries.findIndex(e => e.name === basename);
|
|
11980
|
-
if (idx >= 0) {
|
|
11981
|
-
targetBrowser.cursor = idx;
|
|
11982
|
-
targetBrowser.offset = Math.max(0, idx - 3);
|
|
11983
|
-
}
|
|
11984
|
-
refreshWorkingDirPreview();
|
|
11985
|
-
pushDebugLine(C.muted(` ${item.relPath}`));
|
|
11986
|
-
chatScrollOffset = -1;
|
|
11987
|
-
}
|
|
11988
|
-
setWorkingFocus('browser', 'agent-roster-search-pick');
|
|
11989
|
-
draw();
|
|
11990
|
-
},
|
|
11991
|
-
onCancel: () => {
|
|
11992
|
-
clearHoverTimer();
|
|
11993
|
-
disposeActivePreview();
|
|
11994
|
-
previewToggleDisposable?.dispose();
|
|
11995
|
-
previewDismissDisposable?.dispose();
|
|
11996
|
-
agentSearchModal = null;
|
|
11997
|
-
handle?.dispose();
|
|
11998
|
-
draw();
|
|
11999
|
-
},
|
|
12000
|
-
});
|
|
12001
|
-
// Ctrl+/ (and Ctrl+_ which some terminals send for the same
|
|
12002
|
-
// physical chord) cycles preview modes. Active for the lifetime
|
|
12003
|
-
// of THIS picker only — disposed in both onAccept and onCancel
|
|
12004
|
-
// above. Q4 (substrate Occam): no per-binding pipe alias, register
|
|
12005
|
-
// each variant separately. (Korean IME aliases unnecessary — Ctrl+/
|
|
12006
|
-
// has no jamo mapping on the 2-set layout.)
|
|
12007
|
-
const togglePreviewMode = (): void => { cyclePreviewMode(); };
|
|
12008
|
-
const previewSlash = display.registerKeyBinding({
|
|
12009
|
-
id: `dashboard:finder-picker-preview-toggle-slash:${Date.now().toString(36)}`,
|
|
12010
|
-
key: 'C-/',
|
|
12011
|
-
scope: 'global',
|
|
12012
|
-
when: () => agentSearchModal === picker,
|
|
12013
|
-
handler: togglePreviewMode,
|
|
12014
|
-
});
|
|
12015
|
-
const previewUnder = display.registerKeyBinding({
|
|
12016
|
-
id: `dashboard:finder-picker-preview-toggle-under:${Date.now().toString(36)}`,
|
|
12017
|
-
key: 'C-_',
|
|
12018
|
-
scope: 'global',
|
|
12019
|
-
when: () => agentSearchModal === picker,
|
|
12020
|
-
handler: togglePreviewMode,
|
|
12021
|
-
});
|
|
12022
|
-
previewToggleDisposable = {
|
|
12023
|
-
dispose: () => { previewSlash.dispose(); previewUnder.dispose(); },
|
|
12024
|
-
};
|
|
12025
|
-
// Ctrl+] — instantly dismiss the active preview popup WITHOUT
|
|
12026
|
-
// closing the picker or changing the mode. Esc would be more
|
|
12027
|
-
// intuitive but the picker captures Esc internally to cancel
|
|
12028
|
-
// itself. Ctrl+\ is unsafe because it raises SIGQUIT in many
|
|
12029
|
-
// terminal drivers. Ctrl+] (historically "telnet escape" =
|
|
12030
|
-
// "exit this context") is universally safe + semantically right.
|
|
12031
|
-
// Active only while a preview is currently visible — otherwise
|
|
12032
|
-
// the binding silently no-ops (no flicker, no log spam).
|
|
12033
|
-
// Mode stays as set; if user is in HOVER mode, the next
|
|
12034
|
-
// cursor stillness re-triggers the popup. To stop the popup
|
|
12035
|
-
// from re-appearing entirely, cycle Ctrl+/ back to OFF.
|
|
12036
|
-
previewDismissDisposable = display.registerKeyBinding({
|
|
12037
|
-
id: `dashboard:finder-picker-preview-dismiss:${Date.now().toString(36)}`,
|
|
12038
|
-
key: 'C-]',
|
|
12039
|
-
scope: 'global',
|
|
12040
|
-
when: () => agentSearchModal === picker && lastPreviewHandle !== null,
|
|
12041
|
-
handler: () => {
|
|
12042
|
-
clearHoverTimer();
|
|
12043
|
-
disposeActivePreview();
|
|
12044
|
-
draw();
|
|
12045
|
-
},
|
|
12046
|
-
});
|
|
12047
|
-
attachSurfaceToWorkspace(picker.surface, currentWorkspaceOwnerId());
|
|
12048
|
-
handle = display.pushModal(picker.surface);
|
|
12049
|
-
agentSearchModal = picker;
|
|
12050
|
-
draw();
|
|
12051
|
-
}
|
|
12052
|
-
|
|
12053
|
-
/** Yazi-style Alt+C — directory finder. Symmetric with openFinder
|
|
12054
|
-
* Picker but enumerates directories only (`scanFinder kind:'dir'`)
|
|
12055
|
-
* and on accept cd's the browser pane to the chosen directory.
|
|
12056
|
-
* Remote-mode is currently unsupported (surfaces a warning) — the
|
|
12057
|
-
* remote finder would need a parallel kind-aware backend. */
|
|
12058
|
-
async function openDirectoryPicker(): Promise<void> {
|
|
12059
|
-
if (workingDir.remote) {
|
|
12060
|
-
chatLines.push(C.warning(' Alt+C: directory finder is local-only — Esc remote first.'));
|
|
12061
|
-
chatScrollOffset = -1;
|
|
12062
|
-
draw();
|
|
12063
|
-
return;
|
|
12064
|
-
}
|
|
12065
|
-
const targetBrowserId = activeBrowserWidgetId();
|
|
12066
|
-
const targetBrowser = resolveBrowserStateById(targetBrowserId) ?? (workingDir as BrowserPaneModel);
|
|
12067
|
-
// Symmetric with openFinderPicker — scan from SWD (project root),
|
|
12068
|
-
// not the browser pane's nav cursor. The accept handler still
|
|
12069
|
-
// mutates targetBrowser to navigate into the chosen dir.
|
|
12070
|
-
const scanRoot = getSessionCwd();
|
|
12071
|
-
finderFeedbackRuntime.onFinderScanStarted(`${scanRoot} (dirs)`);
|
|
12072
|
-
draw();
|
|
12073
|
-
const scan = await scanFinder({ root: scanRoot, kind: 'dir' });
|
|
12074
|
-
const rels = relativizeResults(scan.paths, scanRoot);
|
|
12075
|
-
const dirItems: FinderItem[] = scan.paths.map((absPath, i) => ({
|
|
12076
|
-
absPath, relPath: rels[i] ?? absPath,
|
|
12077
|
-
}));
|
|
12078
|
-
if (dirItems.length === 0) {
|
|
12079
|
-
finderFeedbackRuntime.onFinderScanEmpty();
|
|
12080
|
-
draw();
|
|
12081
|
-
return;
|
|
12082
|
-
}
|
|
12083
|
-
finderFeedbackRuntime.onFinderScanCompleted({
|
|
12084
|
-
count: dirItems.length,
|
|
12085
|
-
backend: scan.backend,
|
|
12086
|
-
truncated: scan.truncated,
|
|
12087
|
-
durationMs: scan.durationMs,
|
|
12088
|
-
});
|
|
12089
|
-
|
|
12090
|
-
const { cols, rows } = termSize();
|
|
12091
|
-
const width = Math.min(90, Math.max(50, cols - 6));
|
|
12092
|
-
const visibleRows = Math.min(15, Math.max(6, rows - 8));
|
|
12093
|
-
const height = visibleRows + 3;
|
|
12094
|
-
const bounds = {
|
|
12095
|
-
row: Math.max(1, Math.floor((rows - height) / 2)),
|
|
12096
|
-
col: Math.max(1, Math.floor((cols - width) / 2)),
|
|
12097
|
-
width,
|
|
12098
|
-
height,
|
|
12099
|
-
};
|
|
12100
|
-
let handle: ReturnType<typeof display.pushModal> | null = null;
|
|
12101
|
-
const titleRoot = scanRoot.replace(homedir(), '~');
|
|
12102
|
-
const picker = createFinderModal({
|
|
12103
|
-
items: dirItems,
|
|
12104
|
-
bounds, width, maxVisible: visibleRows,
|
|
12105
|
-
truncated: scan.truncated,
|
|
12106
|
-
title: `Find directory in ${titleRoot}`,
|
|
12107
|
-
theme: currentThemeTokens(),
|
|
12108
|
-
onAccept: (item) => {
|
|
12109
|
-
agentSearchModal = null;
|
|
12110
|
-
handle?.dispose();
|
|
12111
|
-
enterDirectory(targetBrowser as WorkingDirState, item.absPath);
|
|
12112
|
-
refreshWorkingDir(targetBrowser as WorkingDirState);
|
|
12113
|
-
refreshWorkingDirPreview();
|
|
12114
|
-
pushDebugLine(C.muted(` cd ${item.relPath}`));
|
|
12115
|
-
chatScrollOffset = -1;
|
|
12116
|
-
setWorkingFocus('browser', 'alt-c-dir-pick');
|
|
12117
|
-
draw();
|
|
12118
|
-
},
|
|
12119
|
-
onCancel: () => {
|
|
12120
|
-
agentSearchModal = null;
|
|
12121
|
-
handle?.dispose();
|
|
12122
|
-
draw();
|
|
12123
|
-
},
|
|
12124
|
-
});
|
|
12125
|
-
attachSurfaceToWorkspace(picker.surface, currentWorkspaceOwnerId());
|
|
12126
|
-
handle = display.pushModal(picker.surface);
|
|
12127
|
-
agentSearchModal = picker;
|
|
12128
|
-
draw();
|
|
12129
|
-
}
|
|
12130
|
-
|
|
12131
|
-
/** T4-E4 — open the SSH host picker (Ctrl+K). Accept connects
|
|
12132
|
-
* the browser pane to the remote host; Esc cancels silently.
|
|
12133
|
-
* Routes keys through agentSearchModal (shared pattern with
|
|
12134
|
-
* window + session pickers). */
|
|
12135
|
-
function openSshPicker(): void {
|
|
12136
|
-
const { cols, rows } = termSize();
|
|
12137
|
-
const width = Math.min(72, Math.max(44, cols - 6));
|
|
12138
|
-
const visibleRows = 8;
|
|
12139
|
-
const height = visibleRows + 3;
|
|
12140
|
-
const bounds = {
|
|
12141
|
-
row: Math.max(1, Math.floor((rows - height) / 2)),
|
|
12142
|
-
col: Math.max(1, Math.floor((cols - width) / 2)),
|
|
12143
|
-
width,
|
|
12144
|
-
height,
|
|
12145
|
-
};
|
|
12146
|
-
let handle: ReturnType<typeof display.pushModal> | null = null;
|
|
12147
|
-
const picker = createSshPickerModal({
|
|
12148
|
-
bounds, width, maxVisible: visibleRows,
|
|
12149
|
-
activeHostName: workingDir.remote?.host.name ?? null,
|
|
12150
|
-
theme: currentThemeTokens(),
|
|
12151
|
-
onAccept: async (host) => {
|
|
12152
|
-
agentSearchModal = null;
|
|
12153
|
-
handle?.dispose();
|
|
12154
|
-
touchSshHost(host.name);
|
|
12155
|
-
startRemoteModeBridge(host, '.');
|
|
12156
|
-
finderFeedbackRuntime.onSshConnectStarted({ name: host.name, host: host.host });
|
|
12157
|
-
draw();
|
|
12158
|
-
try {
|
|
12159
|
-
await refreshRemoteWorkingDir(workingDir, {}, dockedPreview);
|
|
12160
|
-
await refreshRemotePreviewBridge();
|
|
12161
|
-
finderFeedbackRuntime.onSshConnectSucceeded(host.name);
|
|
12162
|
-
} catch (err) {
|
|
12163
|
-
finderFeedbackRuntime.onSshConnectFailed(
|
|
12164
|
-
host.name,
|
|
12165
|
-
err instanceof Error ? err.message : String(err),
|
|
12166
|
-
);
|
|
12167
|
-
}
|
|
12168
|
-
draw();
|
|
12169
|
-
},
|
|
12170
|
-
onCancel: () => {
|
|
12171
|
-
agentSearchModal = null;
|
|
12172
|
-
handle?.dispose();
|
|
12173
|
-
draw();
|
|
12174
|
-
},
|
|
12175
|
-
});
|
|
12176
|
-
attachSurfaceToWorkspace(picker.surface, currentWorkspaceOwnerId());
|
|
12177
|
-
handle = display.pushModal(picker.surface);
|
|
12178
|
-
agentSearchModal = picker;
|
|
12179
|
-
draw();
|
|
12180
|
-
}
|
|
12181
|
-
|
|
12182
11729
|
// FU-1 — register ssh-picker / finder-picker openers as display
|
|
12183
11730
|
// key bindings. Moves the dashboard hard branches onto the same
|
|
12184
11731
|
// coordinator dispatch path the rest of the modals / bindings use.
|
|
@@ -12889,6 +12436,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12889
12436
|
// 외부 주입(`pty text`)을 사용자 타이핑과 섞지 않고 별도 대기열로 — 결함 #6(10-14).
|
|
12890
12437
|
const disposeExternalInputHost = registerExternalInputHost(createDashboardExternalInputHost({
|
|
12891
12438
|
isTurnActive: () => streamingInFlight,
|
|
12439
|
+
getTurnStop: () => currentTurnExternalStop,
|
|
12892
12440
|
promptCtl,
|
|
12893
12441
|
pushNotice: (line) => { chatLines.push(C.muted(` ${line}`)); chatScrollOffset = -1; draw(); },
|
|
12894
12442
|
}));
|
|
@@ -15422,8 +14970,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15422
14970
|
// — the boot fell back to a fresh session. Surface the reason
|
|
15423
14971
|
// so the user knows they're on a different session than asked.
|
|
15424
14972
|
// - new (no resume requested): nothing extra to render.
|
|
14973
|
+
// 대표 #73 — 인자 없는 기동 = 새 세션. 이어받았는지는 이 값 하나로 판정한다(관측 ⊕ 자리 부트 카드).
|
|
14974
|
+
let tuiBootSessionStart: { origin: 'new' | 'resume'; reason: string; restoredSessionId?: string } = opts.resumeSessionId
|
|
14975
|
+
? { origin: 'new', reason: 'resume-failed' }
|
|
14976
|
+
: { origin: 'new', reason: 'default-new' };
|
|
15425
14977
|
if (dashboardAcpBootResult.mode === 'resumed' && dashboardAcpBootResult.sessionId) {
|
|
15426
14978
|
const sid = dashboardAcpBootResult.sessionId;
|
|
14979
|
+
tuiBootSessionStart = { origin: 'resume', reason: 'resume-daemon', restoredSessionId: sid };
|
|
15427
14980
|
chatLines.push(C.success(` ✓ resumed daemon session: ${sid}`));
|
|
15428
14981
|
// Best-effort REST history replay over the remote HTTP/WS endpoint.
|
|
15429
14982
|
if (opts.remote) {
|
|
@@ -15485,10 +15038,27 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15485
15038
|
if (!resume.resumed) {
|
|
15486
15039
|
chatLines.push(C.warning(` ⚠ resume failed (${resume.reason}); started new session`));
|
|
15487
15040
|
} else {
|
|
15041
|
+
tuiBootSessionStart = {
|
|
15042
|
+
origin: 'resume',
|
|
15043
|
+
reason: resume.repaired ? 'resume-local-repaired' : 'resume-local',
|
|
15044
|
+
restoredSessionId: resume.sessionId,
|
|
15045
|
+
};
|
|
15488
15046
|
chatLines.push(C.success(` ✓ resumed local session: ${resume.sessionId}`));
|
|
15047
|
+
if (resume.repaired) {
|
|
15048
|
+
chatLines.push(C.muted(` 깨진 도구 호출·결과 짝을 잘라 이어받았다(호출 ${resume.repaired.removedCalls} · 결과 ${resume.repaired.removedResults})`));
|
|
15049
|
+
}
|
|
15489
15050
|
chatLines.push(C.muted(` ${resume.turns} turns restored. Next turn continues this conversation.`));
|
|
15490
15051
|
}
|
|
15491
15052
|
}
|
|
15053
|
+
observeSessionStart({
|
|
15054
|
+
surface: 'tui',
|
|
15055
|
+
origin: tuiBootSessionStart.origin,
|
|
15056
|
+
reason: tuiBootSessionStart.reason,
|
|
15057
|
+
// sessionId = 이 대화가 이어받은(또는 새로 연) 대화 기록의 id · acpSessionId = 백엔드 ACP 세션 id(둘이 다를 수 있다).
|
|
15058
|
+
sessionId: tuiBootSessionStart.restoredSessionId ?? dashboardAcpSession.currentSessionId ?? null,
|
|
15059
|
+
acpSessionId: dashboardAcpSession.currentSessionId ?? null,
|
|
15060
|
+
resumeRequested: opts.resumeSessionId !== undefined,
|
|
15061
|
+
});
|
|
15492
15062
|
// 제안은 세션 작업 폴더 기준 — 시작 폴더 한 번이 아니라 폴더가 바뀔 때마다 다시 계산한다(IA1 리뷰 must-fix).
|
|
15493
15063
|
const nextProjectSuggestion = createProjectSuggester(suggestProjectForFolder);
|
|
15494
15064
|
const pushProjectSuggestion = (folder: string): void => {
|
|
@@ -15529,7 +15099,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15529
15099
|
installSeatSessionRecorder({ getCwd: () => getSessionCwd(), getHistory: () => chat.history });
|
|
15530
15100
|
const seatBoot = describeSeatBoot(getSessionCwd());
|
|
15531
15101
|
if (seatBoot) chatLines.push(C.muted(` 🪪 ${seatBoot.seat} 자리 · 안 읽은 우편 ${seatBoot.unread ?? '미관측'} — 부트 카드를 턴마다 싣는다`));
|
|
15532
|
-
|
|
15102
|
+
// 새 세션(이어받기 실패 포함)이면 자리 부트 카드로 시작한다 — 자리 맥락은 세션이 아니라 자리 문서가 싣는다.
|
|
15103
|
+
if (tuiBootSessionStart.origin === 'new') startSeatBootConversation({ reason: 'boot' });
|
|
15533
15104
|
tuiSeatAskTimer = setInterval(pollTuiSeatAnswers, 10_000);
|
|
15534
15105
|
tuiSeatAskTimer.unref();
|
|
15535
15106
|
pollTuiSeatAnswers();
|
|
@@ -16587,7 +16158,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
16587
16158
|
// 다음 inner-loop 반복이 남은 항목도 같은 순서로 제출한다.
|
|
16588
16159
|
// ⭐ 드레인 순서 자체는 `chat/turn-typeahead.ts` 가 소유한다 — 여기서 베끼면
|
|
16589
16160
|
// 테스트가 그 순서를 다시 베껴야 하고, 베낀 테스트는 배선 회귀를 못 잡는다.
|
|
16590
|
-
|
|
16161
|
+
internalTurnGate.noteTurnSettled();
|
|
16162
|
+
// «지금 밀어 넣기»로 끊은 턴은 «중단»이 아니다 — 복원하지 않고 큐 머리를 곧바로 제출한다.
|
|
16163
|
+
const interrupted = consumeTurnEndInterrupted(lastTurnFinalStatus, steerInterruptRef);
|
|
16591
16164
|
const queuedBeforeDrain = turnTypeaheadRef.state.queuedSubmissions.length;
|
|
16592
16165
|
// ⭐ 드레인 → 레지스트리 해제 → Enter 주입은 다리 모듈이 한 함수로 한다(시험이 같은 함수를 문다).
|
|
16593
16166
|
const drained = handoffTurnTypeaheadAtTurnEnd(turnTypeaheadRef, nextInitial, { interrupted }, () => {
|
|
@@ -16632,6 +16205,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
16632
16205
|
: '/quit /clear (run `elanous setup` — no LLM provider available)',
|
|
16633
16206
|
debugLog: debug.enabled ? (event, label, payload) => debug.log(event, label, payload) : undefined,
|
|
16634
16207
|
textInputOpts: {
|
|
16208
|
+
internalTurnYield: internalTurnYieldPort,
|
|
16635
16209
|
onScrollKey: (name) => {
|
|
16636
16210
|
const { rows } = termSize();
|
|
16637
16211
|
const viewport = computePromptFrameLogViewportBounds(
|
|
@@ -17073,6 +16647,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17073
16647
|
}),
|
|
17074
16648
|
},
|
|
17075
16649
|
});
|
|
16650
|
+
// ⭐ H2 — 입력칸이 내부 턴 문에 «비켜 줬다». 꺼낸 요청을 같은 턴 실행 경로로 보낸다
|
|
16651
|
+
// (슬래시 해석·히스토리·사람 발화 에코 없음). 꺼낼 게 없으면 입력으로 되돌아간다.
|
|
16652
|
+
const consumed = consumeInternalTurnYield(internalTurnGate, input);
|
|
16653
|
+
if (consumed.kind === 'reenter') continue;
|
|
16654
|
+
const internalTurn: InternalTurnRequest | null = consumed.kind === 'internal' ? consumed.request : null;
|
|
16655
|
+
input = consumed.input;
|
|
17076
16656
|
|
|
17077
16657
|
const postTurn = resolveDashboardChatMainPostTurn(input, {
|
|
17078
16658
|
inputLines: dashboardState.getInputLines(),
|
|
@@ -17124,7 +16704,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17124
16704
|
|
|
17125
16705
|
// Save to durable input history. Up/down reads the in-memory
|
|
17126
16706
|
// tail, while slash/LLM tools can search the full store.
|
|
17127
|
-
if (
|
|
16707
|
+
if (!internalTurn) internalTurnGate.noteHumanTurn();
|
|
16708
|
+
if (postTurn.historyRecord && !internalTurn) {
|
|
17128
16709
|
inputHistoryStore.record(postTurn.historyRecord);
|
|
17129
16710
|
refreshInputHistory();
|
|
17130
16711
|
}
|
|
@@ -17282,14 +16863,16 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17282
16863
|
// resource_link blocks so dropped screenshots and PDFs flow
|
|
17283
16864
|
// naturally to the agent. debug.log gates the snapshot so
|
|
17284
16865
|
// off-state stays zero-cost.
|
|
17285
|
-
const submitIntent =
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
16866
|
+
const submitIntent = internalTurn
|
|
16867
|
+
? resolveInternalTurnSubmitIntent(internalTurn, dashboardAcpSession.currentSessionId)
|
|
16868
|
+
: resolveDashboardHarnessSubmitIntent(input.text, {
|
|
16869
|
+
stickyBackend: dashboardAcpChat.getSticky(),
|
|
16870
|
+
source: input.externalSubmitSource,
|
|
16871
|
+
});
|
|
17289
16872
|
const cmdText = submitIntent.kind === 'control-turn'
|
|
17290
16873
|
? (submitIntent.commandText ?? '')
|
|
17291
16874
|
: submitIntent.text;
|
|
17292
|
-
if (submitIntent.kind === 'submit-turn' && parseSeatAsk(submitIntent.text)) {
|
|
16875
|
+
if (submitIntent.kind === 'submit-turn' && !internalTurn && parseSeatAsk(submitIntent.text)) {
|
|
17293
16876
|
try {
|
|
17294
16877
|
const receipt = await askSeat(submitIntent.text, { channel: 'tui', clientId: tuiSeatAskClientId },
|
|
17295
16878
|
ceoTaskDeps(getUserConfig(), null), tuiSeatAskDeps);
|
|
@@ -17959,6 +17542,11 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17959
17542
|
? { url: opts.remote.url, token: opts.remote.token }
|
|
17960
17543
|
: null,
|
|
17961
17544
|
acpSwapTo: (sessionId, cwd) => dashboardAcpSession.swapTo(sessionId, cwd),
|
|
17545
|
+
acpRenew: async (cwd) => {
|
|
17546
|
+
const renewed = await dashboardAcpSession.renew(cwd);
|
|
17547
|
+
acpSessionIdRef.current = renewed;
|
|
17548
|
+
return renewed;
|
|
17549
|
+
},
|
|
17962
17550
|
},
|
|
17963
17551
|
shellSlash: {
|
|
17964
17552
|
slashRuntime: shellSlashRuntime,
|
|
@@ -18021,6 +17609,21 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18021
17609
|
setWorkingFocusPreview: () => { setWorkingFocus('preview', 'slash-term-move-preview'); },
|
|
18022
17610
|
nextTerminalVwSlotId: (terminalId) => `term-slot:${terminalId}`,
|
|
18023
17611
|
},
|
|
17612
|
+
// TUI-LOOP-COMMAND — /loop <간격> <프롬프트> · 쉬는 동안만 발사
|
|
17613
|
+
// (src/dashboard/loop-scheduler.ts · 판정: idle 발사 1 · busy 미룸 · stop 0).
|
|
17614
|
+
// idle/busy 신호는 대시보드 루프가 이미 쓰는 것을 그대로 쓴다 —
|
|
17615
|
+
// 스트리밍 턴(streamingInFlight · reportTuiTurn busy/idle) +
|
|
17616
|
+
// ACP 세션 바쁨(dashboardAcpChat.isBusy()). 프롬프트 제출은
|
|
17617
|
+
// 플러그인 submitDashboardText 와 같은 기존 제출 틈
|
|
17618
|
+
// (dispatchDashboardSubmitText)으로 낸다 — 새 제출 경로를 만들지 않는다.
|
|
17619
|
+
loopCommand: {
|
|
17620
|
+
isIdle: () => !streamingInFlight && !dashboardAcpChat.isBusy(),
|
|
17621
|
+
submitPrompt: (prompt: string) => {
|
|
17622
|
+
if (dispatchDashboardSubmitText) dispatchDashboardSubmitText(prompt);
|
|
17623
|
+
else chatLines.push(C.muted(' /loop: 입력 루프가 아직 제출을 받지 않는다 — 다음 틱을 기다린다'));
|
|
17624
|
+
},
|
|
17625
|
+
schedulerRef: dashboardLoopSchedulerRef,
|
|
17626
|
+
},
|
|
18024
17627
|
};
|
|
18025
17628
|
const slashOutcome = await dashboardSlashRegistry.dispatch(cmdLower, args, slashCtx);
|
|
18026
17629
|
if (debug.enabled) {
|
|
@@ -18468,7 +18071,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18468
18071
|
// pattern. Without this draw(), the echo sits in the chatLines
|
|
18469
18072
|
// array but doesn't paint until after the skill router's
|
|
18470
18073
|
// classifier LLM call returns (~1-2s of visual silence).
|
|
18471
|
-
|
|
18074
|
+
if (internalTurn) {
|
|
18075
|
+
chatLines.push(C.muted(` ${formatInternalTurnBanner(internalTurn)}`));
|
|
18076
|
+
chatScrollOffset = -1;
|
|
18077
|
+
} else {
|
|
18078
|
+
echoSubmittedUserText(tok.text);
|
|
18079
|
+
}
|
|
18472
18080
|
if (queuedTurnEndText !== undefined && input.text === queuedTurnEndText) {
|
|
18473
18081
|
debug.log('dashboard.turn-typeahead', 'echoed', { path: 'turn-end', length: queuedTurnEndText.length });
|
|
18474
18082
|
}
|
|
@@ -18686,7 +18294,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18686
18294
|
let latestTurnUsage: import('../prompt-cache/types.js').LLMUsage | undefined;
|
|
18687
18295
|
const runPlainSubmitTurn = (submit: PlainTurnSubmit) => runDashboardChatMainPlainTurn({
|
|
18688
18296
|
// ⛔⭐ 관측 심을 «실제로» 넘긴다 — 타입만 선택적으로 넓히면 조용히 안 온다(`F12`).
|
|
18689
|
-
debugLog: (category, event, payload) => { try { debug.log(category, event, payload); } catch { /* fail-soft */ } },
|
|
18297
|
+
debugLog: (category, event, payload, opts) => { try { debug.log(category, event, payload, opts); } catch { /* fail-soft */ } },
|
|
18690
18298
|
userText: tok.text,
|
|
18691
18299
|
intent: submit.intent,
|
|
18692
18300
|
contextText: ctx,
|
|
@@ -19046,7 +18654,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19046
18654
|
const { resumeGoalFromUserFollowUp } = await import('../goals/chat-loop-bridge.js');
|
|
19047
18655
|
const { hydrateGoalFromSnapshot } = await import('../goals/registry.js');
|
|
19048
18656
|
hydrateGoalFromSnapshot();
|
|
19049
|
-
|
|
18657
|
+
// ⛔ H2 — 내부 턴은 사람의 «정정·재개» 발화가 아니다: 멈춘 /goal 을 되살리지 않는다.
|
|
18658
|
+
const followUpAction = tok.text.startsWith('/goal') || internalTurn
|
|
19050
18659
|
? { kind: 'no-loop' as const }
|
|
19051
18660
|
: resumeGoalFromUserFollowUp(tok.text);
|
|
19052
18661
|
let goalLoopUserText: string | null = followUpAction.kind === 'continue'
|