elanous 0.2.35 → 0.2.36
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/chunks/{d06f9160.a3d9062f95de8ad7.js → 053a429e.9a63436527cc751c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +287 -0
- package/apps/pwa/out/_next/static/chunks/{4346.8601952e73bf5803.js → 1201.afbfc5b1c5e5cbe4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +64 -0
- package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +36 -0
- package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +149 -0
- package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3103.0df8da390948bb84.js → 2500.cbc1257b774aae52.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7644.17e37ba6f1d4226e.js → 2683.c9773a0c589b031b.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{4718-17d2af636796a330.js → 275-02ea4c2a33980422.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2812ca6a.3b9f4a7a08885744.js +1 -0
- package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8714.ff0b7ce3ec3e3ae2.js → 2941.3c3546f96bc6efa7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{9214.63a510d39178e997.js → 2986.45d7652e4f13557e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3136.30aaaa5fa03662a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3677-4215f826f6aa68e5.js → 3148-98efd4869d660a87.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +226 -0
- package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324.a09703033abcbd2f.js +34 -0
- package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +8 -0
- package/apps/pwa/out/_next/static/chunks/3410.7f9af5ab77cbe65f.js +115 -0
- package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +32 -0
- package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +286 -0
- package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9512.5a76207a730e0491.js → 3727.7949ccaacaa71242.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8557-e7898769499cd56f.js → 3757-180308bc61021b05.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
- package/apps/pwa/out/_next/static/chunks/{359-2250789a2d3499e7.js → 3840-5825d56d46976a92.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{da5176c6.6773b6c5994e1d99.js → 3a3d9966.cc4d4585a2708e7c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +104 -0
- package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9952.5daf5f94063a2b3e.js → 4286.b70c4520306817e8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4304.e9b2512834a9e23e.js +23 -0
- package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{938.66ad1ef0e5abae1c.js → 4615.8525eb0add35eba6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +148 -0
- package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6236.e18cced2d5ba6afb.js → 528.38ce20ef8aa251ff.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{3408.21d1570602f4b6c0.js → 552.b7d061ad91eeac51.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5711.957b095705c12560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1530.0e612369b6fd7ea0.js → 575.d929793a53f27c4b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/599.c39c571b6733f2a2.js +41 -0
- package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +79 -0
- package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +1 -0
- package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6925.562d532110879886.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7385.50a308a477bdfc21.js → 6943.c6b24124853a47b2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{630.fe5a46428d63b013.js → 727.7deb87749b0a343a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2018.a741297bce759490.js → 7481.39f7a4654907bf6e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8444.4c26b379ca2b9596.js → 771.c3cdb6c1f7f47c02.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3589.5444a06bcf6e775c.js → 7891.03f910124a737985.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +1 -0
- package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{b2f6ba4d.fb56fdbbf798df33.js → 873d6c12.09bd499f57171543.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5101.e32282718f99ed6f.js → 8904.7d51af2dc033965c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +90 -0
- package/apps/pwa/out/_next/static/chunks/{5637.281e5dec4ea6ecf1.js → 914.8abefd48d579547b.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4705-194e64e47ca0fbdb.js → 9250-072df22eaadaa6b5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +77 -0
- package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8637.47f5b35afcae5e6b.js → 9514.131c52cc75fe6439.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1674.2a65fd5668e1cc5f.js → 9789.60f723d18097ec30.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9f31e478.fefcbcd3c388ebc5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{0368f25d-ad84af92fefee68f.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{cbe38a15.5a032598e39970c6.js → ceba0382.650712b56b85b582.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{b6705a4f-b9a9047de9eecfd0.js → da5ecc5c-b005ad8cac737d57.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{56d372f2.681ab4ec4c998fae.js → f9a61e4d.1fc2c1dbdd49fe46.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +1 -0
- package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → uC-N0emedeNOFuaBQFv-I}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
- package/docs/goal-context/README.md +3 -0
- package/graphs/default-loop.yaml +6 -1
- package/graphs/implement-loop.yaml +24 -0
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +17 -4
- package/graphs/wizard/recipes.yaml +44 -0
- package/graphs/wizard/wizard-loop.yaml +44 -0
- package/graphs/work/research-report.yaml +2 -0
- package/package.json +1 -1
- package/scripts/ci-typecheck-changed.ts +139 -5
- package/scripts/coord-role-pack.ts +1 -1
- package/scripts/first10-gate.ts +416 -0
- package/scripts/fleet/wsl-node-setup.sh +432 -0
- package/scripts/release-loop/docs-node.ts +204 -8
- package/scripts/release-loop/gate-node.ts +249 -53
- package/scripts/release-loop/node-verdict.ts +2 -0
- package/scripts/release-loop/resume-cap.ts +14 -34
- package/scripts/release-loop/resume-release.ts +37 -11
- package/scripts/release-loop/traffic-node.ts +59 -0
- package/scripts/release-loop/traffic-transition.ts +159 -0
- package/scripts/rhythm/daily.ts +137 -3
- package/scripts/ux-sim.ts +53 -0
- package/skills/README.md +1 -0
- package/src/acp/core-turn-bridge.ts +48 -6
- package/src/agent/delegate-hint.ts +16 -0
- package/src/agent/runner.ts +82 -2
- package/src/agent/task-notification.ts +56 -10
- package/src/agent/types.ts +4 -0
- package/src/agent-substrate/pr-reviewer.ts +55 -3
- package/src/agent-substrate/review-intent.ts +29 -2
- package/src/agent-substrate/review-observation.ts +3 -0
- package/src/agent-substrate/self-review-cli.ts +168 -16
- package/src/autopilot/mission-codebase-gate.ts +141 -12
- package/src/autopilot/pr-manager.ts +25 -5
- package/src/boot/daemon-tools/self-implement.ts +1 -0
- package/src/budget/usage-outcomes.ts +8 -4
- package/src/capture/tui-self-report.ts +102 -0
- package/src/chat/goal-continue-verdict.ts +41 -0
- package/src/chat/index.ts +30 -4
- package/src/chat/internal-turn-origin.ts +1 -0
- package/src/chat/paste-fold.ts +86 -0
- package/src/chat/tool-render/block.ts +32 -0
- package/src/chat/tool-render/dispatch.ts +2 -20
- package/src/chat/tool-render/result-text.ts +98 -0
- package/src/chat/turn-typeahead.ts +70 -7
- package/src/cli/config-audit.ts +119 -0
- package/src/cli/doctor-cli.ts +22 -0
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/herdr-cli.ts +34 -0
- package/src/cli/light-entry-route.ts +6 -3
- package/src/cli/log-event-names.ts +2 -0
- package/src/cli/make-cli.ts +247 -11
- package/src/cli/msg-cli.ts +117 -3
- package/src/cli/pr-cli.ts +29 -16
- package/src/cli/pr-land-base-read.ts +11 -2
- package/src/cli/pr-land-heavy-remote.ts +6 -3
- package/src/cli/pr-land-overlap-evidence.ts +23 -4
- package/src/cli/pr-land-recovery.ts +117 -1
- package/src/cli/pty-takeover-cli.ts +8 -7
- package/src/cli/release-cli.ts +21 -5
- package/src/cli/release-single-flight.ts +1 -1
- package/src/cli/tasks-card-show.ts +162 -0
- package/src/cli/tasks-cli.ts +574 -356
- package/src/cli/tasks-read-cli.ts +197 -0
- package/src/core-turn/run-core-turn.ts +4 -2
- package/src/core-turn/run-goal-loop.ts +73 -16
- package/src/core-turn/types.ts +6 -1
- package/src/dashboard/context/keys.ts +8 -31
- package/src/dashboard/index.ts +202 -49
- package/src/dashboard/input/agent-wake.ts +7 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
- package/src/dashboard/input/chat-main-slash-command.ts +4 -2
- package/src/dashboard/input/goal-continue.ts +210 -0
- package/src/dashboard/input/goal-interim.ts +2 -0
- package/src/dashboard/input/internal-turn.ts +2 -8
- package/src/dashboard/input/seat-autowake.ts +9 -7
- package/src/dashboard/input/turn-autoheal.ts +52 -0
- package/src/dashboard/seat-boot-preamble.ts +132 -5
- package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +3 -2
- package/src/dashboard/slash-runtime/model-choices.ts +15 -0
- package/src/dashboard/stale-install-check.ts +3 -99
- package/src/debug/batch-queue.ts +119 -0
- package/src/debug/tui-log-tag.ts +67 -0
- package/src/display/agent-surface.ts +7 -0
- package/src/domains/standalone-log-sink.ts +15 -2
- package/src/esc-abort-gate.ts +69 -0
- package/src/git-fs/worktree.ts +95 -1
- package/src/graph-runner/graph-cli.ts +18 -0
- package/src/graph-runner/runner.ts +20 -11
- package/src/graph-wizard/generate.ts +108 -4
- package/src/graph-wizard/steps.ts +15 -0
- package/src/grounding/proactive-ground.ts +86 -0
- package/src/harness/control-inbox.ts +49 -1
- package/src/harness/harness-cli-command.ts +51 -7
- package/src/harness/harness-incidents.ts +52 -1
- package/src/harness/pod-control-send.ts +33 -5
- package/src/harness/self-send-remote.ts +69 -0
- package/src/harness/self-send-routing-guard.ts +6 -0
- package/src/harness/self-send-target.ts +4 -3
- package/src/index.ts +327 -12
- package/src/input-core/context-key-runtime.ts +21 -0
- package/src/light-cli.ts +6 -1
- package/src/llm-wellformed.ts +70 -0
- package/src/llm.ts +35 -4
- package/src/loops/msg-wake.ts +35 -39
- package/src/loops/orchestrator/inbox.ts +59 -11
- package/src/loops/orchestrator/knowhow-pack.ts +364 -0
- package/src/loops/orchestrator/tick.ts +5 -1
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/models/prompts.ts +17 -2
- package/src/msg/msg-post-office.ts +116 -0
- package/src/mss/logging/log-store.ts +79 -22
- package/src/nexus/api/decisions-route.ts +38 -18
- package/src/nexus/api/graph-wizard-api.ts +20 -2
- package/src/nexus/boot/register-mcp-clients.ts +263 -38
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
- package/src/onboarding/first-run.ts +37 -6
- package/src/onboarding/web-first.ts +43 -11
- package/src/ops/overview-collect.ts +12 -6
- package/src/ops/overview.ts +3 -3
- package/src/persona/loader.ts +11 -0
- package/src/persona/types.ts +8 -0
- package/src/prompt-library/session-guidance.ts +14 -0
- package/src/provider-summary.ts +8 -0
- package/src/pty-shell/herdr-agent-report.ts +118 -9
- package/src/pty-shell/herdr-prompt.ts +266 -0
- package/src/pty-shell/pty-control-ipc.ts +151 -8
- package/src/pty-shell/pty-special-keys.ts +42 -2
- package/src/pty-shell/stale-install-check.ts +99 -0
- package/src/pty-shell/tui-run-state.ts +14 -2
- package/src/release-loop/auto-start.ts +20 -2
- package/src/release-loop/checklist.ts +76 -4
- package/src/release-loop/rehearsal.ts +36 -20
- package/src/repl/index.ts +19 -1
- package/src/seat-loop/knowhow-lint.ts +1 -1
- package/src/self-dev/decompose-proposal.ts +172 -20
- package/src/self-dev/decompose.ts +61 -0
- package/src/self-dev/dev-cli.ts +37 -3
- package/src/self-dev/dev-pipeline.ts +8 -2
- package/src/self-dev/draft-triage-rules.ts +31 -0
- package/src/self-dev/glm-credential-guard.ts +77 -0
- package/src/self-dev/graph-journey-nodes.ts +1 -0
- package/src/self-dev/graph-journey-route.ts +12 -2
- package/src/self-dev/orchestrate-cli.ts +68 -3
- package/src/self-dev/orchestrate.ts +116 -17
- package/src/self-dev/run-supervisor.ts +55 -2
- package/src/self-dev/run-types.ts +1 -1
- package/src/self-health/autoheal.ts +153 -0
- package/src/self-health/signatures.ts +6 -0
- package/src/self-implement/device-first.ts +116 -0
- package/src/self-implement/doctor-visit.ts +239 -1
- package/src/self-implement/evidence-command-budget.ts +80 -0
- package/src/self-implement/goal-author-cli.ts +1 -0
- package/src/self-implement/goal-author-decompose.ts +265 -4
- package/src/self-implement/goal-author.ts +33 -8
- package/src/self-implement/goal-elaborate.ts +176 -22
- package/src/self-implement/goal-refine.ts +3 -0
- package/src/self-implement/graph-variant.ts +40 -6
- package/src/self-implement/headless-elanous-driver.ts +19 -3
- package/src/self-implement/off-diff-evidence.ts +58 -6
- package/src/self-implement/orchestrator.ts +222 -21
- package/src/self-implement/pod-warm-pool-profile.ts +1 -0
- package/src/self-implement/pwa-import-graph.ts +1 -1
- package/src/self-implement/rework-policy.ts +30 -0
- package/src/self-implement/run-ledger.ts +108 -0
- package/src/self-implement/run-ttl.ts +38 -24
- package/src/self-implement/scope-adjacency.ts +3 -1
- package/src/self-implement/seams.ts +60 -4
- package/src/self-implement/wiring-check.ts +358 -0
- package/src/shell-env-bootstrap.ts +11 -4
- package/src/skills/runner.ts +4 -2
- package/src/skills/tools/agent.ts +290 -48
- package/src/skills/tools/schedule-wakeup.ts +23 -4
- package/src/skills/tools/shell.ts +61 -6
- package/src/skills/tools/terminal-modal-inject.ts +1 -2
- package/src/skills/tools/terminal-modal.ts +10 -8
- package/src/skills/url-router.ts +41 -1
- package/src/smart-wizard/run.ts +66 -0
- package/src/status/bar.ts +34 -6
- package/src/status/status-provider-info.ts +37 -6
- package/src/steward/rejudge-tick.ts +10 -2
- package/src/steward/ta-repair-event-collect.ts +17 -6
- package/src/task-agent/actions.ts +3 -1
- package/src/task-agent/land-queue.ts +21 -8
- package/src/task-agent/live-moves.ts +22 -6
- package/src/task-agent/mission.ts +30 -0
- package/src/task-agent/rejudge-on-head.ts +15 -0
- package/src/task-agent/repair-cycle.ts +138 -32
- package/src/task-agent/repair-next-move.ts +31 -3
- package/src/task-agent/repair-outcomes.ts +29 -0
- package/src/task-agent/repair-worker.ts +14 -4
- package/src/task-agent/shadow.ts +41 -3
- package/src/task-agent/task-card-prefix.ts +2 -0
- package/src/task-agent/task-hand.ts +477 -22
- package/src/task-agent/task-parent-role-llm.ts +36 -0
- package/src/task-agent/tier-split.ts +78 -9
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +9 -0
- package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +86 -5
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
- package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +11 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
- package/src/task-orchestrator/surfaces/pod-provenance.ts +8 -2
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
- package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +485 -36
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +396 -19
- package/src/task-orchestrator/surfaces/self-implement.ts +42 -2
- package/src/tool-runtime/index.ts +15 -2
- package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
- package/src/tty-foreground.ts +155 -0
- package/src/tui/chat/goal-interim.ts +173 -0
- package/src/tui/chat/log-view.ts +205 -18
- package/src/tui/chat/self-health-status.ts +232 -0
- package/src/tui/entry.ts +370 -81
- package/src/tui/input/composer.ts +8 -1
- package/src/tui/slash/compact-command.ts +7 -0
- package/src/tui/slash/compact.ts +1 -7
- package/src/tui/slash/resume.ts +75 -0
- package/src/tui-client/local-chat-turn.ts +45 -2
- package/src/tui-client/next-dashboard-runtime.ts +8 -0
- package/src/tui-client/next-loop-command.ts +70 -0
- package/src/tui-client/next-wakeup.ts +191 -0
- package/src/tui.ts +37 -0
- package/src/ui/modal-adapter.ts +2 -2
- package/src/ux-sim/classic-tui-seat-scenarios.ts +516 -0
- package/src/ux-sim/cli-config-audit-device.ts +121 -0
- package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
- package/src/ux-sim/event-monkey.ts +3 -2
- package/src/ux-sim/fake-bin.ts +45 -0
- package/src/ux-sim/fake-herdr.ts +238 -0
- package/src/ux-sim/fake-llm.ts +111 -6
- package/src/ux-sim/fault-glm-no-credential.ts +116 -0
- package/src/ux-sim/fault-nextmove-dispatch.ts +102 -1
- package/src/ux-sim/fault-scope-escape-lift.ts +33 -6
- package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
- package/src/ux-sim/goal-device.ts +619 -0
- package/src/ux-sim/in-process-cli.ts +22 -5
- package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
- package/src/ux-sim/mock-authoring-first-run.ts +97 -0
- package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
- package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
- package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
- package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +631 -0
- package/src/ux-sim/onboarding-first-run-device.ts +269 -0
- package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
- package/src/ux-sim/subagent-tools-device.ts +81 -0
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
- package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +0 -1
- package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +0 -41
- package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +0 -74
- package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +0 -148
- package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +0 -34
- package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +0 -77
- package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +0 -62
- package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +0 -90
- package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +0 -79
- package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +0 -122
- package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4441-875b97f5821ed58a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +0 -23
- package/apps/pwa/out/_next/static/chunks/5483-dd5d7697f6bdb106.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +0 -287
- package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +0 -1
- package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +0 -93
- package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +0 -149
- package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +0 -226
- package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +0 -64
- package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +0 -115
- package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-47c5d4db587266bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-dc0a532f5b9196ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +0 -1
- /package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// `eln herdr prompt <대상> "<문장>" [--wait] [--timeout MS]` — herdr pane 의 elanous TUI 를 밖에서 깨운다.
|
|
2
|
+
//
|
|
3
|
+
// 왜 herdr `agent prompt` 가 아닌가(10-22 실측 · herdr 소스 v0.9.1·v0.9.5·main 5bd900d 동일):
|
|
4
|
+
// `src/app/api/agents.rs` 의 prompt·send-keys 는 `terminal.effective_known_agent()`(내장 kind 라벨)와
|
|
5
|
+
// `runtime_hosts_agent`(전경 프로세스가 그 kind)를 요구한다. «Add Herdr support to your agent» 계약대로
|
|
6
|
+
// 자기 이름(`elanous`)으로 신고한 agent 는 list·get·wait·read·알림은 되지만 prompt 는
|
|
7
|
+
// `agent_not_ready: … is not an active named agent` 로 늘 거부된다.
|
|
8
|
+
// 그래서 같은 의미를 여기서 낸다:
|
|
9
|
+
// ① `herdr agent get` — 신고 라벨이 elanous 이고 idle/done 인지(blocked/working/unknown 은 입력 0 으로 거부)
|
|
10
|
+
// ② `herdr pane run <pane> <문장>` — agent prompt 와 «같은 바이트»: herdr 의 `pane run` 은 pane 의 bracketed-paste
|
|
11
|
+
// 모드를 따라 `ESC[200~문장ESC[201~` ⊕ Enter 를 한 번에 쓴다(격리 세션 실측 · `pane send-text` 는 날 바이트라 쓰지 않는다)
|
|
12
|
+
// ③ --wait — 제출 뒤 활동 창(5000ms) 안에 working/blocked 를 관측해야 하고(아니면 agent_prompt_stalled),
|
|
13
|
+
// 그 뒤 idle/done/blocked 정착까지 기다린다. 호출자 timeout 이 먼저 끝나면 timeout. herdr agent prompt --wait 의미 그대로.
|
|
14
|
+
// 관측: debug.log('pty.herdr', 'prompt', { target, paneId, accepted, reason, status, ms }) 한 줄.
|
|
15
|
+
// 호출자 둘: CLI `eln herdr prompt`(라벨 elanous 만) ⊕ 우편 깨움 `src/loops/msg-wake.ts`(anyAgent · beforeSubmit 으로 재해석·opt-in·마감 관문).
|
|
16
|
+
// 신고 계약(herdr-agent-report.ts)은 건드리지 않는다 — 이 명령은 그 신고(working/idle)를 «읽기만» 한다.
|
|
17
|
+
|
|
18
|
+
import { spawn } from 'node:child_process';
|
|
19
|
+
|
|
20
|
+
import { debug } from '../debug/log.js';
|
|
21
|
+
|
|
22
|
+
export const HERDR_PROMPT_ACTIVITY_WINDOW_MS = 5000;
|
|
23
|
+
const HERDR_PROMPT_AGENT = 'elanous';
|
|
24
|
+
const CALL_TIMEOUT_MS = 5000;
|
|
25
|
+
const KILL_GRACE_MS = 1500;
|
|
26
|
+
const OUTPUT_CAP = 64 * 1024;
|
|
27
|
+
|
|
28
|
+
export interface HerdrCliResult {
|
|
29
|
+
readonly code: number | null;
|
|
30
|
+
readonly stdout: string;
|
|
31
|
+
readonly stderr: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** herdr CLI 한 번. timeoutMs 가 Infinity 면 끝없이 기다린다. */
|
|
35
|
+
export type HerdrCliRunner = (argv: readonly string[], timeoutMs: number) => Promise<HerdrCliResult>;
|
|
36
|
+
|
|
37
|
+
export interface HerdrPromptOpts {
|
|
38
|
+
readonly target: string;
|
|
39
|
+
readonly text: string;
|
|
40
|
+
readonly wait?: boolean;
|
|
41
|
+
/** 호출자 timeout(제출 포함) — 없으면 정착 대기는 끝이 없다(herdr 와 같다). */
|
|
42
|
+
readonly timeoutMs?: number;
|
|
43
|
+
/**
|
|
44
|
+
* 라벨 확인을 끈다 — 호출자가 대상을 이미 정했을 때(우편 깨움: 자리 폴더 `herdr.pane`). 상태 확인(idle/done 만)과
|
|
45
|
+
* 제출(`pane run`)은 그대로다. CLI(`eln herdr prompt`)는 켜지 않는다 — herdr 내장 kind 는 herdr agent prompt 몫.
|
|
46
|
+
*/
|
|
47
|
+
readonly anyAgent?: boolean;
|
|
48
|
+
/** `agent get` 이 agent_not_found 면 `pane get` 의 agent_status 로 떨어진다(우편 깨움 · #30261 전 경로와 같은 관문).
|
|
49
|
+
* 10-22 cct 아래 Claude 자리가 agent get 에서 간헐적으로 안 잡혀 깨움 18건이 failed 됐다. */
|
|
50
|
+
readonly paneFallback?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 상태 확인을 통과한 대상 — `beforeSubmit` 이 본다. */
|
|
54
|
+
export interface HerdrPromptView {
|
|
55
|
+
readonly agent: string;
|
|
56
|
+
readonly status: string;
|
|
57
|
+
readonly paneId: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface HerdrPromptDeps {
|
|
61
|
+
readonly run?: HerdrCliRunner;
|
|
62
|
+
readonly now?: () => number;
|
|
63
|
+
readonly log?: (event: string, data: Record<string, unknown>) => void;
|
|
64
|
+
/** 시험용 — 제출 뒤 활동 관측 창. 기본 5000ms(herdr 의미). */
|
|
65
|
+
readonly activityWindowMs?: number;
|
|
66
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
67
|
+
/**
|
|
68
|
+
* 상태 확인 «뒤»·제출 «바로 앞» 호출자 관문 — 이유 문자열을 돌려주면 입력 0 으로 그 이유로 끝난다(accepted:false).
|
|
69
|
+
* 우편 깨움이 대상 재해석·opt-in 재확인·마감을 여기서 본다(조회 사이 바뀐 것에 넣지 않는다).
|
|
70
|
+
*/
|
|
71
|
+
readonly beforeSubmit?: (view: HerdrPromptView) => string | undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type HerdrPromptReason =
|
|
75
|
+
| 'submitted' | 'settled'
|
|
76
|
+
| 'empty_agent_prompt' | 'not_elanous' | 'agent_blocked' | 'agent_working' | 'agent_unknown'
|
|
77
|
+
| 'agent_prompt_stalled' | 'timeout'
|
|
78
|
+
| string; // herdr 오류 코드 그대로(agent_not_found · pane_not_found …)
|
|
79
|
+
|
|
80
|
+
export interface HerdrPromptResult {
|
|
81
|
+
readonly ok: boolean;
|
|
82
|
+
/** 문장이 pane 에 들어갔나(실패여도 true 일 수 있다 — 재제출 전에 화면을 읽어라). */
|
|
83
|
+
readonly accepted: boolean;
|
|
84
|
+
readonly reason: HerdrPromptReason;
|
|
85
|
+
readonly target: string;
|
|
86
|
+
readonly paneId?: string;
|
|
87
|
+
readonly agent?: string;
|
|
88
|
+
readonly status?: string;
|
|
89
|
+
readonly message?: string;
|
|
90
|
+
readonly ms: number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface AgentView {
|
|
94
|
+
readonly agent: string;
|
|
95
|
+
readonly status: string;
|
|
96
|
+
readonly paneId: string;
|
|
97
|
+
readonly seq: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** herdr 오류 봉투(stderr 또는 stdout JSON `{"error":{code,message}}`). 없으면 undefined. */
|
|
101
|
+
function herdrError(r: HerdrCliResult): { code: string; message: string } | undefined {
|
|
102
|
+
for (const text of [r.stderr, r.stdout]) {
|
|
103
|
+
const t = text.trim();
|
|
104
|
+
if (!t.startsWith('{')) continue;
|
|
105
|
+
try {
|
|
106
|
+
const e = (JSON.parse(t) as { error?: { code?: unknown; message?: unknown } }).error;
|
|
107
|
+
if (e && typeof e === 'object') {
|
|
108
|
+
return { code: typeof e.code === 'string' ? e.code : 'herdr_error', message: typeof e.message === 'string' ? e.message : '' };
|
|
109
|
+
}
|
|
110
|
+
} catch { /* not an envelope */ }
|
|
111
|
+
}
|
|
112
|
+
if (r.code === 0) return undefined;
|
|
113
|
+
return { code: r.code === null ? 'herdr_killed' : `herdr_rc_${r.code}`, message: r.stderr.trim().slice(0, 240) };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function agentOf(r: HerdrCliResult): AgentView | undefined {
|
|
117
|
+
try {
|
|
118
|
+
const a = (JSON.parse(r.stdout.trim()) as { result?: { agent?: Record<string, unknown> } }).result?.agent;
|
|
119
|
+
if (!a || typeof a.pane_id !== 'string') return undefined;
|
|
120
|
+
return {
|
|
121
|
+
agent: typeof a.agent === 'string' ? a.agent : '',
|
|
122
|
+
status: typeof a.agent_status === 'string' ? a.agent_status : 'unknown',
|
|
123
|
+
paneId: a.pane_id,
|
|
124
|
+
seq: typeof a.state_change_seq === 'number' ? a.state_change_seq : 0,
|
|
125
|
+
};
|
|
126
|
+
} catch {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** `pane get` 봉투에서 agent·agent_status — paneFallback 전용(agent get 이 못 찾을 때). seq 는 없다(0). */
|
|
132
|
+
function paneViewOf(r: HerdrCliResult): AgentView | undefined {
|
|
133
|
+
if (herdrError(r)) return undefined;
|
|
134
|
+
try {
|
|
135
|
+
const p = (JSON.parse(r.stdout.trim()) as { result?: { pane?: Record<string, unknown> } }).result?.pane;
|
|
136
|
+
if (!p || typeof p.pane_id !== 'string' || typeof p.agent_status !== 'string') return undefined;
|
|
137
|
+
return { agent: typeof p.agent === 'string' ? p.agent : '', status: p.agent_status, paneId: p.pane_id, seq: 0 };
|
|
138
|
+
} catch {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** 기본 러너 — HERDR_BIN_PATH(없으면 PATH 의 herdr). HERDR_SOCKET_PATH 등 env 는 그대로 넘긴다. */
|
|
144
|
+
export function defaultHerdrCliRunner(env: NodeJS.ProcessEnv = process.env): HerdrCliRunner {
|
|
145
|
+
const bin = env.HERDR_BIN_PATH?.trim() || 'herdr';
|
|
146
|
+
return (argv, timeoutMs) => new Promise<HerdrCliResult>((resolve) => {
|
|
147
|
+
let child: ReturnType<typeof spawn>;
|
|
148
|
+
try {
|
|
149
|
+
child = spawn(bin, [...argv], { env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
150
|
+
} catch (error) {
|
|
151
|
+
resolve({ code: null, stdout: '', stderr: error instanceof Error ? error.message : String(error) });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
let stdout = '';
|
|
155
|
+
let stderr = '';
|
|
156
|
+
let settled = false;
|
|
157
|
+
const finish = (r: HerdrCliResult): void => {
|
|
158
|
+
if (settled) return;
|
|
159
|
+
settled = true;
|
|
160
|
+
if (timer) clearTimeout(timer);
|
|
161
|
+
resolve(r);
|
|
162
|
+
};
|
|
163
|
+
const timer = Number.isFinite(timeoutMs)
|
|
164
|
+
? setTimeout(() => {
|
|
165
|
+
try { child.kill(); } catch { /* gone */ }
|
|
166
|
+
finish({ code: null, stdout, stderr: stderr || 'herdr call timed out' });
|
|
167
|
+
}, Math.max(1, timeoutMs))
|
|
168
|
+
: undefined;
|
|
169
|
+
child.stdout?.on('data', (c: Buffer | string) => { if (stdout.length < OUTPUT_CAP) stdout += String(c); });
|
|
170
|
+
child.stderr?.on('data', (c: Buffer | string) => { if (stderr.length < OUTPUT_CAP) stderr += String(c); });
|
|
171
|
+
child.on('error', (error) => finish({ code: null, stdout, stderr: error.message }));
|
|
172
|
+
child.on('close', (code) => finish({ code, stdout, stderr }));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function herdrPrompt(opts: HerdrPromptOpts, deps: HerdrPromptDeps = {}): Promise<HerdrPromptResult> {
|
|
177
|
+
const now = deps.now ?? Date.now;
|
|
178
|
+
const run = deps.run ?? defaultHerdrCliRunner(deps.env);
|
|
179
|
+
const log = deps.log ?? ((event: string, data: Record<string, unknown>) => debug.log('pty.herdr', event, data));
|
|
180
|
+
const windowMs = deps.activityWindowMs ?? HERDR_PROMPT_ACTIVITY_WINDOW_MS;
|
|
181
|
+
const start = now();
|
|
182
|
+
const deadline = opts.timeoutMs !== undefined ? start + opts.timeoutMs : undefined;
|
|
183
|
+
const remaining = (): number => (deadline === undefined ? Number.POSITIVE_INFINITY : Math.max(0, deadline - now()));
|
|
184
|
+
const callCap = (): number => Math.min(CALL_TIMEOUT_MS, Math.max(1, remaining()));
|
|
185
|
+
|
|
186
|
+
let view: AgentView | undefined;
|
|
187
|
+
const done = (ok: boolean, accepted: boolean, reason: HerdrPromptReason, message?: string): HerdrPromptResult => {
|
|
188
|
+
const result: HerdrPromptResult = {
|
|
189
|
+
ok, accepted, reason, target: opts.target,
|
|
190
|
+
...(view ? { paneId: view.paneId, agent: view.agent, status: view.status } : {}),
|
|
191
|
+
...(message ? { message } : {}),
|
|
192
|
+
ms: Math.max(0, Math.round(now() - start)),
|
|
193
|
+
};
|
|
194
|
+
log('prompt', { target: opts.target, paneId: view?.paneId, accepted, reason, status: view?.status, ms: result.ms });
|
|
195
|
+
return result;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
if (opts.text.length === 0) return done(false, false, 'empty_agent_prompt', 'prompt text must not be empty');
|
|
199
|
+
|
|
200
|
+
// ① 대상 확인
|
|
201
|
+
const got = await run(['agent', 'get', opts.target], callCap());
|
|
202
|
+
const getErr = herdrError(got);
|
|
203
|
+
if (getErr) {
|
|
204
|
+
if (!(opts.paneFallback && getErr.code === 'agent_not_found')) return done(false, false, getErr.code, getErr.message);
|
|
205
|
+
const pane = paneViewOf(await run(['pane', 'get', opts.target], callCap()));
|
|
206
|
+
if (!pane) return done(false, false, getErr.code, getErr.message);
|
|
207
|
+
log('prompt-pane-fallback', { target: opts.target, paneId: pane.paneId, agent: pane.agent, status: pane.status });
|
|
208
|
+
view = pane;
|
|
209
|
+
} else view = agentOf(got);
|
|
210
|
+
if (!view) return done(false, false, 'unparseable_agent_get');
|
|
211
|
+
if (!opts.anyAgent && view.agent !== HERDR_PROMPT_AGENT) {
|
|
212
|
+
return done(false, false, 'not_elanous', `agent label ${view.agent || '(none)'} — use herdr agent prompt for herdr-supported agents`);
|
|
213
|
+
}
|
|
214
|
+
if (view.status === 'blocked') return done(false, false, 'agent_blocked', 'agent is blocked and requires interactive input');
|
|
215
|
+
if (view.status === 'working') return done(false, false, 'agent_working', 'agent is working — wait for idle first');
|
|
216
|
+
if (view.status !== 'idle' && view.status !== 'done') return done(false, false, 'agent_unknown', `agent status ${view.status}`);
|
|
217
|
+
const seq0 = view.seq;
|
|
218
|
+
const paneId = view.paneId;
|
|
219
|
+
const veto = deps.beforeSubmit?.({ agent: view.agent, status: view.status, paneId });
|
|
220
|
+
if (veto !== undefined) return done(false, false, veto);
|
|
221
|
+
|
|
222
|
+
// ② 제출 — agent prompt 와 같은 bracketed text ⊕ Enter 한 번
|
|
223
|
+
const sent = await run(['pane', 'run', paneId, opts.text], callCap());
|
|
224
|
+
const sendErr = herdrError(sent);
|
|
225
|
+
if (sendErr) return done(false, false, sendErr.code, sendErr.message);
|
|
226
|
+
if (!opts.wait) return done(true, true, 'submitted');
|
|
227
|
+
|
|
228
|
+
const refresh = async (): Promise<AgentView | undefined> => {
|
|
229
|
+
const r = await run(['agent', 'get', paneId], CALL_TIMEOUT_MS);
|
|
230
|
+
const v = herdrError(r) ? undefined : agentOf(r);
|
|
231
|
+
if (v) view = v;
|
|
232
|
+
return v;
|
|
233
|
+
};
|
|
234
|
+
const settledStatus = (s: string): boolean => s === 'idle' || s === 'done' || s === 'blocked';
|
|
235
|
+
|
|
236
|
+
// ③ 활동 관측(working/blocked) — 창 안에 없으면 stalled, 호출자 timeout 이 먼저면 timeout
|
|
237
|
+
const win = Math.min(windowMs, remaining());
|
|
238
|
+
const activity = await run(['agent', 'wait', paneId, '--until', 'working', '--until', 'blocked', '--timeout', String(Math.max(1, Math.floor(win)))], win + KILL_GRACE_MS);
|
|
239
|
+
const actErr = herdrError(activity);
|
|
240
|
+
if (actErr) {
|
|
241
|
+
const v = await refresh();
|
|
242
|
+
// wait 를 걸기 전에 턴이 이미 돌고 끝났다 — seq 가 움직였고 정착 상태면 성공이다.
|
|
243
|
+
if (v && v.seq > seq0 && settledStatus(v.status)) return done(true, true, 'settled');
|
|
244
|
+
if (!(v && v.seq > seq0 && v.status === 'working')) {
|
|
245
|
+
if (actErr.code !== 'timeout') return done(false, true, actErr.code, actErr.message);
|
|
246
|
+
return done(false, true, remaining() <= 0 ? 'timeout' : 'agent_prompt_stalled', 'no working/blocked activity observed after submission');
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
const v = agentOf(activity);
|
|
250
|
+
if (v) view = v;
|
|
251
|
+
if (v?.status === 'blocked') return done(true, true, 'settled');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ④ 정착(idle/done/blocked)까지
|
|
255
|
+
const rem = remaining();
|
|
256
|
+
const settleArgs = ['agent', 'wait', paneId, ...(Number.isFinite(rem) ? ['--timeout', String(Math.max(1, Math.floor(rem)))] : [])];
|
|
257
|
+
const settled = await run(settleArgs, Number.isFinite(rem) ? rem + KILL_GRACE_MS : Number.POSITIVE_INFINITY);
|
|
258
|
+
const setErr = herdrError(settled);
|
|
259
|
+
if (setErr) {
|
|
260
|
+
await refresh();
|
|
261
|
+
return done(false, true, setErr.code, setErr.message);
|
|
262
|
+
}
|
|
263
|
+
const v = agentOf(settled);
|
|
264
|
+
if (v) view = v;
|
|
265
|
+
return done(true, true, 'settled');
|
|
266
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Database } from 'bun:sqlite';
|
|
2
|
-
import { mkdirSync } from 'node:fs';
|
|
3
|
-
import { dirname } from 'node:path';
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
4
|
import { ptyManifestDbPath, getPtyManifest, markPtyControlled } from './pty-manifest.js';
|
|
5
5
|
import { getHarnessRunId } from '../harness/harness-space.js';
|
|
6
6
|
import { renamePty, type PtyControlTarget } from './registry.js';
|
|
@@ -48,6 +48,11 @@ export interface PtyControlRequestOptions {
|
|
|
48
48
|
readonly timeoutMs?: number;
|
|
49
49
|
/** 대상 PTY를 발견한 매니페스트 뿌리. 연합 조회는 이 DB에 제어 요청을 남겨 그 행의 owner가 처리하게 한다. */
|
|
50
50
|
readonly manifestDbPath?: string;
|
|
51
|
+
/** 요청자 poll 루프의 시계(기본 `Date.now`) — deadline·grace 경계를 재는 유일한 시계다.
|
|
52
|
+
* ⛔ 원장 시각(`created_at`/`updated_at`)은 여전히 `Date.now()` 다 — 원장 형식은 이 옵션에 안 흔들린다. */
|
|
53
|
+
readonly now?: () => number;
|
|
54
|
+
/** 요청자 poll 루프의 대기(기본 `Bun.sleep`) — 기본값에서 25ms cadence 계약은 그대로다. */
|
|
55
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
export interface PtyControlResult {
|
|
@@ -144,6 +149,116 @@ function cleanupStale(d: Database): void {
|
|
|
144
149
|
d.run("DELETE FROM pty_control_requests WHERE created_at < ? AND status = 'processing'", [now - PTY_CONTROL_PROCESSING_STALE_MS]);
|
|
145
150
|
}
|
|
146
151
|
|
|
152
|
+
// ── TUI-IDLE-PTY-DEEP-IDLE-FU (#29694) — owner 큐 재읽기의 깊은 유휴 감속 ⊕ 첫 요청 즉시 깨움 ──
|
|
153
|
+
//
|
|
154
|
+
// owner 프로세스는 `registry.startPtyControlPoller` 가 **25ms 마다** 부르는 `processPtyControlRequests` 로
|
|
155
|
+
// 제어 큐(같은 SQLite 원장)를 다시 읽는다. 사람이 자리를 비운 채 TUI 가 몇 시간 떠 있으면 그 재읽기가
|
|
156
|
+
// 시간당 14만 번씩 DB 를 두드린다 — 제어가 **10분 넘게** 없었으면 재읽기 간격을 1.5s 로 늦춘다.
|
|
157
|
+
// ⛔ 감속만 넣으면 첫 원격 요청이 최대 1.5s 뒤에야 처리돼 25ms 응답 계약이 깨진다. 그래서 요청자는
|
|
158
|
+
// 큐와 «별도»인 깨어움 표식을 남기고(`signalPtyControlWake`), owner 는 tick 마다 그 파일의 존재만
|
|
159
|
+
// 싸게 확인한다(`consumePtyControlWake`). DB 재읽기보다 훨씬 싸고, 그 tick 안에서 즉시 깬다.
|
|
160
|
+
interface ControlCadenceState {
|
|
161
|
+
/** 마지막 **제어 요청 처리** 시각 — `markPtyControlled` 와 같은 사건을 앵커로 쓴다. */
|
|
162
|
+
lastControlAt: number | null;
|
|
163
|
+
/** 마지막으로 큐를 실제로 **다시 읽은** 시각 — 감속 간격의 기준점. */
|
|
164
|
+
lastDbReadAt: number | null;
|
|
165
|
+
/** 이 상태를 마지막으로 관측한 시계 값 — 시계가 뒤로 가면 앵커를 버린다(시계 교체 감지). */
|
|
166
|
+
lastSeenAt: number | null;
|
|
167
|
+
observed: 'active' | 'deep-idle' | null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** 큐 원장 경로마다 따로 센다 — 원장 경로가 바뀌면(시험용 `setPtyManifestDbPathForTesting`) 이전
|
|
171
|
+
* 경로의 유휴 앵커가 새 원장에 얹히지 않는다. ⛔ 열쇠는 **읽는 원장과 같은 경로**여야 한다
|
|
172
|
+
* (`processPtyControlRequestsOnce` 가 여는 `db()` 와 동일: `ptyManifestDbPath()`). */
|
|
173
|
+
const controlCadence = new Map<string, ControlCadenceState>();
|
|
174
|
+
|
|
175
|
+
function cadenceState(dbPath: string): ControlCadenceState {
|
|
176
|
+
const known = controlCadence.get(dbPath);
|
|
177
|
+
if (known) return known;
|
|
178
|
+
const fresh: ControlCadenceState = { lastControlAt: null, lastDbReadAt: null, lastSeenAt: null, observed: null };
|
|
179
|
+
controlCadence.set(dbPath, fresh);
|
|
180
|
+
return fresh;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** 재읽기를 늦추기 시작하는 유휴 길이. 「10분+ 유휴 뒤 1.5s」의 앞 절반. */
|
|
184
|
+
const PTY_CONTROL_DEEP_IDLE_AFTER_MS = 10 * 60_000;
|
|
185
|
+
/** 깊은 유휴에서의 재읽기 간격. 요청 wake 는 이 간격을 «기다리지 않는다». */
|
|
186
|
+
const PTY_CONTROL_DEEP_IDLE_POLL_MS = 1_500;
|
|
187
|
+
|
|
188
|
+
/** 깨어움 표식은 큐와 같은 원장 디렉터리에 둔다 — 요청자와 owner 가 같은 원장(`ptyManifestDbPath`)을
|
|
189
|
+
* 볼 때 owner 의 tick 이 곧바로 그 자리를 본다. 연합 큐(`manifestDbPath`)로 남의 원장에 요청하면
|
|
190
|
+
* 표식은 그 원장 자리에 남고 그 owner 는 감속 간격만큼만 늦다(요청 timeout 안쪽 · fail-soft).
|
|
191
|
+
* ⭐ 표식은 **owner 별** 파일이다(`control-wake-<ownerPid>`) — 요청자는 이미 `ownerPid` 를 알고,
|
|
192
|
+
* 같은 `ELANOUS_STATE_DIR` 원장을 공유하는 여러 프로세스의 `startPtyControlPoller` 가 각자 돌아도
|
|
193
|
+
* 비대상 owner 가 대상 owner 의 표식을 가져가 즉시 깨움(25ms)을 훔치지 못하게 한다. */
|
|
194
|
+
function wakeSignalPath(dbPath: string, ownerPid: number): string {
|
|
195
|
+
return join(dirname(dbPath), `control-wake-${ownerPid}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** 구형 요청자가 남기던 공유 표식 — 읽기 «호환 경로»로만 유지한다(새 경로는 owner 별 파일만 쓴다). */
|
|
199
|
+
function legacyWakeSignalPath(dbPath: string): string {
|
|
200
|
+
return join(dirname(dbPath), 'control-wake');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** 요청자가 대상 owner 의 깨움 표식을 남긴다 — owner «별» 파일(`control-wake-<ownerPid>`). */
|
|
204
|
+
export function signalPtyControlWake(dbPath: string, ownerPid: number): void {
|
|
205
|
+
try {
|
|
206
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
207
|
+
writeFileSync(wakeSignalPath(dbPath, ownerPid), '');
|
|
208
|
+
} catch { /* fail-soft — 표식이 없으면 감속 간격만큼만 늦다(timeout 안쪽) */ }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** «자기» `ownerPid` 의 표식이 있으면 지우고 `true` — 요청자는 행을 «넣은 뒤» 그 행의 owner
|
|
212
|
+
* 표식을 남기므로, 그 owner 의 이 tick 재읽기는 그 행을 반드시 본다. 남의 owner 표식과 구형
|
|
213
|
+
* 공유 표식은 잔존 호환으로 «읽기만» 한다(비대상 owner 가 이 표식을 지울 수는 없다). */
|
|
214
|
+
function consumePtyControlWake(dbPath: string): boolean {
|
|
215
|
+
const own = wakeSignalPath(dbPath, process.pid);
|
|
216
|
+
let woke = false;
|
|
217
|
+
if (existsSync(own)) {
|
|
218
|
+
woke = true;
|
|
219
|
+
try { rmSync(own, { force: true }); } catch { /* 다음 tick 이 다시 지운다 */ }
|
|
220
|
+
}
|
|
221
|
+
const legacy = legacyWakeSignalPath(dbPath);
|
|
222
|
+
if (existsSync(legacy)) {
|
|
223
|
+
woke = true;
|
|
224
|
+
try { rmSync(legacy, { force: true }); } catch { /* 다음 tick 이 다시 지운다 */ }
|
|
225
|
+
}
|
|
226
|
+
return woke;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function observeControlCadence(state: ControlCadenceState, mode: 'active' | 'deep-idle', idleMs: number): void {
|
|
230
|
+
if (state.observed === mode) return;
|
|
231
|
+
state.observed = mode;
|
|
232
|
+
debug.log('pty.control', 'poll-cadence', { mode, idleMs });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** 깊은 유휴 감속 gate — `false` 면 이번 tick 은 큐를 **다시 읽지 않는다**.
|
|
236
|
+
* ⛔ 첫 tick 은 언제나 읽는다(기동 직후 도착한 요청을 감속 뒤에 두지 않는다).
|
|
237
|
+
* ⛔ 감속 시계는 `pollClock`(기본 `Date.now`) 뿐이다 — `now`(takeover TTL 시계)를 섞으면 시험이
|
|
238
|
+
* 주입한 값이 실제 tick 을 감속시키는 회귀가 난다. */
|
|
239
|
+
function shouldReadControlQueue(dbPath: string, nowMs: number): boolean {
|
|
240
|
+
const state = cadenceState(dbPath);
|
|
241
|
+
// 시계가 뒤로 갔다 = 이전 관측과 다른 시계다. 그 앵커로는 유휴를 못 재므로 버리고 다시 센다.
|
|
242
|
+
if (state.lastSeenAt !== null && nowMs < state.lastSeenAt) {
|
|
243
|
+
state.lastControlAt = null;
|
|
244
|
+
state.lastDbReadAt = null;
|
|
245
|
+
state.observed = null;
|
|
246
|
+
}
|
|
247
|
+
state.lastSeenAt = nowMs;
|
|
248
|
+
const woke = consumePtyControlWake(dbPath);
|
|
249
|
+
if (state.lastControlAt === null || woke) state.lastControlAt = nowMs;
|
|
250
|
+
const idleMs = nowMs - state.lastControlAt;
|
|
251
|
+
const deepIdle = idleMs >= PTY_CONTROL_DEEP_IDLE_AFTER_MS;
|
|
252
|
+
const sinceReadMs = state.lastDbReadAt === null ? Number.POSITIVE_INFINITY : nowMs - state.lastDbReadAt;
|
|
253
|
+
if (!woke && deepIdle && sinceReadMs < PTY_CONTROL_DEEP_IDLE_POLL_MS) {
|
|
254
|
+
observeControlCadence(state, 'deep-idle', idleMs);
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
state.lastDbReadAt = nowMs;
|
|
258
|
+
observeControlCadence(state, deepIdle ? 'deep-idle' : 'active', idleMs);
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
147
262
|
export async function requestRemotePtyControlCapabilities(id: string, options: PtyControlRequestOptions = {}): Promise<PtyControlCapabilitiesResult> {
|
|
148
263
|
const result = await requestRemotePtyControl(id, 'capabilities', undefined, options);
|
|
149
264
|
if (result.status === 'success') {
|
|
@@ -161,6 +276,10 @@ export async function requestRemotePtyControl(id: string, action: PtyControlActi
|
|
|
161
276
|
const options = typeof timeoutOrOptions === 'number' ? { timeoutMs: timeoutOrOptions } : timeoutOrOptions;
|
|
162
277
|
const timeoutMs = typeof payloadOrTimeout === 'number' ? payloadOrTimeout : options.timeoutMs ?? 2_000;
|
|
163
278
|
const actor: PtyWriteActor = options.actor ?? 'human';
|
|
279
|
+
// 요청자 poll 루프의 시계·대기 — 기본값이면 종전 그대로(`Date.now` ⊕ 25ms `Bun.sleep`)이고,
|
|
280
|
+
// 시험만 가상 시각으로 deadline·grace 경계와 cadence 를 결정론적으로 민다(벽시계 판별 없음).
|
|
281
|
+
const pollNow = options.now ?? Date.now;
|
|
282
|
+
const pollWait = options.sleep ?? ((ms: number): Promise<void> => Bun.sleep(ms));
|
|
164
283
|
const opened = dbAt(options.manifestDbPath);
|
|
165
284
|
const d = opened.database;
|
|
166
285
|
try {
|
|
@@ -175,21 +294,24 @@ export async function requestRemotePtyControl(id: string, action: PtyControlActi
|
|
|
175
294
|
// ⭐ 요청자의 run anchor 를 요청에 실어 보낸다 — 인가는 **owner 가** 자기 PTY 의 run 과 대조해 내린다
|
|
176
295
|
// (요청자 자기 신고를 그대로 믿지 않는다는 뜻이 아니라, 판정 지점이 자원 소유자라는 뜻).
|
|
177
296
|
d.run(`INSERT INTO pty_control_requests (request_id, pty_id, action, payload_json, actor, requester_run_id, owner_pid, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [requestId, id, action, payload ? JSON.stringify(payload) : null, actor, getHarnessRunId(process.env), ownerPid, 'pending', now, now]);
|
|
297
|
+
// ⭐ 깊은 유휴 감속 중인 owner 를 즉시 깨운다 — 행을 넣은 «뒤» 표식을 남기므로 그 재읽기가 이 행을 본다.
|
|
298
|
+
// 표식은 그 행의 `ownerPid` «별» 파일이다 — 같은 원장을 공유하는 다른 owner 가 가져가지 못한다.
|
|
299
|
+
signalPtyControlWake(requestQueuePath(options), ownerPid);
|
|
178
300
|
const readback = (): ControlRow | null => d.query(SELECT_ROW).get(requestId) as ControlRow | null;
|
|
179
301
|
const del = (): void => { d.run('DELETE FROM pty_control_requests WHERE request_id=?', [requestId]); };
|
|
180
|
-
const deadline =
|
|
181
|
-
while (
|
|
302
|
+
const deadline = pollNow() + timeoutMs;
|
|
303
|
+
while (pollNow() < deadline) {
|
|
182
304
|
const row = readback();
|
|
183
305
|
if (row && settled(row.status)) { del(); return resultFrom(row); }
|
|
184
|
-
await
|
|
306
|
+
await pollWait(25);
|
|
185
307
|
}
|
|
186
308
|
if (d.run("DELETE FROM pty_control_requests WHERE request_id=? AND status='pending'", [requestId]).changes > 0) return { status: 'owner-unreachable' };
|
|
187
|
-
const graceDeadline =
|
|
188
|
-
while (
|
|
309
|
+
const graceDeadline = pollNow() + 500;
|
|
310
|
+
while (pollNow() < graceDeadline) {
|
|
189
311
|
const row = readback();
|
|
190
312
|
if (!row) return { status: 'owner-unreachable' };
|
|
191
313
|
if (settled(row.status)) { del(); return resultFrom(row); }
|
|
192
|
-
await
|
|
314
|
+
await pollWait(25);
|
|
193
315
|
}
|
|
194
316
|
const final = readback();
|
|
195
317
|
if (final && settled(final.status)) { del(); return resultFrom(final); }
|
|
@@ -245,6 +367,8 @@ let inFlight: Promise<void> | null = null;
|
|
|
245
367
|
export interface PtyControlProcessOptions {
|
|
246
368
|
readonly now?: () => number;
|
|
247
369
|
readonly takeoverTtlMs?: number;
|
|
370
|
+
/** 깊은 유휴 감속 계단 **전용** 시계(기본 `Date.now`). `now` 는 takeover TTL 시계라 섞지 않는다. */
|
|
371
|
+
readonly pollClock?: () => number;
|
|
248
372
|
}
|
|
249
373
|
|
|
250
374
|
function positiveInteger(value: unknown): number | undefined {
|
|
@@ -281,15 +405,28 @@ function reapExpiredTakeovers(d: Database, getHandle: (id: string) => PtyControl
|
|
|
281
405
|
|
|
282
406
|
export function processPtyControlRequests(getHandle: (id: string) => PtyControlTarget | undefined, takeover: (id: string, actor: 'human') => boolean, options: PtyControlProcessOptions = {}): Promise<void> {
|
|
283
407
|
if (inFlight) return inFlight;
|
|
408
|
+
// 깊은 유휴 감속(#29694) — 이 함수는 `pty-shell/registry.ts:startPtyControlPoller` 가 25ms 마다 부른다.
|
|
409
|
+
// 감속 구간에서는 여기서 «큐를 다시 읽지 않는» 것으로 끝나고, 첫 원격 요청의 표식이 오면 즉시 통과한다.
|
|
410
|
+
// ⛔ 감속 열쇠는 아래 `processPtyControlRequestsOnce` 가 실제로 여는 원장(`db()` = `ptyManifestDbPath()`)과
|
|
411
|
+
// 같은 경로다 — 상태는 한 큐, 읽기는 다른 큐로 갈라지지 않는다.
|
|
412
|
+
if (!shouldReadControlQueue(ptyManifestDbPath(), (options.pollClock ?? Date.now)())) return Promise.resolve();
|
|
284
413
|
inFlight = processPtyControlRequestsOnce(getHandle, takeover, options).finally(() => { inFlight = null; });
|
|
285
414
|
return inFlight;
|
|
286
415
|
}
|
|
287
416
|
|
|
417
|
+
/** 요청이 실제로 들어간 원장 — 깨어움 표식은 «그 원장의 owner» 가 보는 자리에 남겨야 한다.
|
|
418
|
+
* 연합 요청(`manifestDbPath`)이면 그 원장 디렉터리, 내 요청이면 내 원장. */
|
|
419
|
+
function requestQueuePath(options: { readonly manifestDbPath?: string }): string {
|
|
420
|
+
return options.manifestDbPath ?? ptyManifestDbPath();
|
|
421
|
+
}
|
|
422
|
+
|
|
288
423
|
async function processPtyControlRequestsOnce(getHandle: (id: string) => PtyControlTarget | undefined, takeover: (id: string, actor: 'human') => boolean, options: PtyControlProcessOptions): Promise<void> {
|
|
289
424
|
const d = db();
|
|
290
425
|
const now = options.now ?? Date.now;
|
|
291
426
|
reapExpiredTakeovers(d, getHandle, now(), resolveTakeoverTtlMs(options));
|
|
292
427
|
const rows = d.query(`SELECT ${ROW_COLUMNS} FROM pty_control_requests WHERE owner_pid=? AND status='pending' ORDER BY created_at ASC`).all(process.pid) as ControlRow[];
|
|
428
|
+
// 제어를 «처리했다» = 유휴 앵커를 지금으로 되감는다(`markPtyControlled` 와 같은 사건).
|
|
429
|
+
if (rows.length > 0) cadenceState(ptyManifestDbPath()).lastControlAt = (options.pollClock ?? Date.now)();
|
|
293
430
|
for (const row of rows) {
|
|
294
431
|
if (d.run("UPDATE pty_control_requests SET status='processing', updated_at=? WHERE request_id=? AND status='pending'", [Date.now(), row.request_id]).changes === 0) continue;
|
|
295
432
|
let requested: PtyWriteActor | null = null;
|
|
@@ -434,6 +571,12 @@ async function processPtyControlRequestsOnce(getHandle: (id: string) => PtyContr
|
|
|
434
571
|
|
|
435
572
|
export function resetPtyControlIpcForTesting(): void {
|
|
436
573
|
database?.close(); database = null;
|
|
574
|
+
// 깊은 유휴 감속 상태(#29694)도 «같이» 비운다 — 남으면 다음 시험/기동이 감속 구간에서 시작한다.
|
|
575
|
+
controlCadence.clear();
|
|
576
|
+
try {
|
|
577
|
+
rmSync(wakeSignalPath(ptyManifestDbPath(), process.pid), { force: true });
|
|
578
|
+
rmSync(legacyWakeSignalPath(ptyManifestDbPath()), { force: true });
|
|
579
|
+
} catch { /* 표식이 없으면 그만 */ }
|
|
437
580
|
// ⛔⭐ 쓰기 출처 맵도 «같이» 비운다 — 별도 export 로만 두면 아무도 안 부르고 테스트 사이에 샌다
|
|
438
581
|
// (오늘 `index.ts:65 readStdinLine` 이 정확히 그 형태로 죽어 있었다).
|
|
439
582
|
resetExternalWriteProvenanceForTesting();
|
|
@@ -30,18 +30,58 @@ function resolveControlKey(normalized: string): string | undefined {
|
|
|
30
30
|
type PtySpecialKey = keyof typeof PTY_SPECIAL_KEYS;
|
|
31
31
|
type PtySpecialKeyAlias = keyof typeof PTY_SPECIAL_KEY_ALIASES;
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// ── 조합 키 (PTY-KEY-MODIFIERS · 0.2.36 · 2026-10-22) ──────────────────────────────────────
|
|
34
|
+
// `shift+enter` · `alt+enter` · `ctrl+enter` · `ctrl+shift+tab` · `alt+up` … 를 TUI 가 켜 두는 두 프로토콜 중
|
|
35
|
+
// 하나로 보낸다 — 기본 xterm modifyOtherKeys `CSI 27;<mod>;<code>~` · `--kitty` 면 kitty `CSI <code>;<mod>u`.
|
|
36
|
+
// 화살표·home/end 는 `CSI 1;<mod><F>` · delete/pageup/pagedown 은 `CSI <n>;<mod>~`(두 프로토콜 공통).
|
|
37
|
+
// mod = 1 + shift(1) + alt(2) + ctrl(4) — src/tui.ts decodeModifier 와 같은 규약(받는 쪽이 이 값을 그대로 푼다).
|
|
38
|
+
// 수식자 없는 키·`ctrl+<글자>` 는 예전 바이트 그대로(호환).
|
|
39
|
+
export type PtyKeyEncoding = 'xterm' | 'kitty';
|
|
40
|
+
const MODIFIER_BITS: Record<string, number> = { shift: 1, alt: 2, option: 2, ctrl: 4, control: 4 };
|
|
41
|
+
const KEYCODES: Record<string, number> = { enter: 13, tab: 9, esc: 27, escape: 27, space: 32, backspace: 127 };
|
|
42
|
+
const CSI_FINAL: Record<string, string> = { up: 'A', down: 'B', right: 'C', left: 'D', home: 'H', end: 'F' };
|
|
43
|
+
const CSI_TILDE: Record<string, number> = { delete: 3, pageup: 5, pagedown: 6 };
|
|
44
|
+
|
|
45
|
+
function resolveModifiedKey(normalized: string, encoding: PtyKeyEncoding): string | undefined {
|
|
46
|
+
if (!normalized.includes('+') || /^(?:ctrl|control)\+[a-z]$/.test(normalized)) return undefined;
|
|
47
|
+
const parts = normalized.split('+').map((p) => p.trim());
|
|
48
|
+
// 조합은 «이름 있는 키» 에만 — 한 글자(ctrl+1 · meta+c)·빈 칸(ctrl++c)·모르는 이름은 예전처럼 거부한다.
|
|
49
|
+
// 표 조회는 자기 속성만(Object.hasOwn) — «constructor+enter» 같은 프로토타입 이름이 새지 않게(r1 must-fix).
|
|
50
|
+
const key = parts.at(-1) ?? '';
|
|
51
|
+
const mods = parts.slice(0, -1);
|
|
52
|
+
if (!key || mods.length === 0 || mods.some((m) => !m || !Object.hasOwn(MODIFIER_BITS, m))) {
|
|
53
|
+
throw new Error(`unknown PTY special key: ${normalized}; modifiers: shift, alt, ctrl + a named key (enter, tab, esc, space, backspace, up, down, left, right, home, end, delete, pageup, pagedown)`);
|
|
54
|
+
}
|
|
55
|
+
let bits = 0;
|
|
56
|
+
for (const m of mods) bits |= MODIFIER_BITS[m]!;
|
|
57
|
+
const mod = 1 + bits;
|
|
58
|
+
if (Object.hasOwn(CSI_FINAL, key)) return `\x1b[1;${mod}${CSI_FINAL[key]}`;
|
|
59
|
+
if (Object.hasOwn(CSI_TILDE, key)) return `\x1b[${CSI_TILDE[key]};${mod}~`;
|
|
60
|
+
if (Object.hasOwn(KEYCODES, key)) {
|
|
61
|
+
const code = KEYCODES[key]!;
|
|
62
|
+
return encoding === 'kitty' ? `\x1b[${code};${mod}u` : `\x1b[27;${mod};${code}~`;
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`unknown PTY special key: ${normalized}; modifiers apply to named keys only (enter, tab, esc, space, backspace, up, down, left, right, home, end, delete, pageup, pagedown)`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function resolvePtySpecialKey(name: string, opts: { encoding?: PtyKeyEncoding } = {}): string {
|
|
34
68
|
const normalized = name.trim().toLowerCase();
|
|
69
|
+
const encoding = opts.encoding ?? 'xterm';
|
|
35
70
|
const controlBytes = resolveControlKey(normalized);
|
|
36
71
|
if (controlBytes) {
|
|
37
72
|
debug.log('pty.special-key', 'resolved', { inputName: name, resolvedName: normalized, control: true });
|
|
38
73
|
return controlBytes;
|
|
39
74
|
}
|
|
75
|
+
const modified = resolveModifiedKey(normalized, encoding);
|
|
76
|
+
if (modified !== undefined) {
|
|
77
|
+
debug.log('pty.special-key', 'resolved', { inputName: name, resolvedName: normalized, modified: true, encoding });
|
|
78
|
+
return modified;
|
|
79
|
+
}
|
|
40
80
|
const alias = PTY_SPECIAL_KEY_ALIASES[normalized as PtySpecialKeyAlias];
|
|
41
81
|
const resolvedName = alias ?? normalized;
|
|
42
82
|
const bytes = PTY_SPECIAL_KEYS[resolvedName as PtySpecialKey];
|
|
43
83
|
if (!bytes) {
|
|
44
|
-
throw new Error(`unknown PTY special key: ${name}; available names: ${[...Object.keys(PTY_SPECIAL_KEYS), ...Object.keys(PTY_SPECIAL_KEY_ALIASES), 'ctrl+a..ctrl+z'].join(', ')}`);
|
|
84
|
+
throw new Error(`unknown PTY special key: ${name}; available names: ${[...Object.keys(PTY_SPECIAL_KEYS), ...Object.keys(PTY_SPECIAL_KEY_ALIASES), 'ctrl+a..ctrl+z', 'shift|alt|ctrl+<key> (e.g. shift+enter)'].join(', ')}`);
|
|
45
85
|
}
|
|
46
86
|
debug.log('pty.special-key', 'resolved', { inputName: name, resolvedName, alias: alias !== undefined });
|
|
47
87
|
return bytes;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { realpathSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { readInstallMetadataCommit } from '../version/code-revision.js';
|
|
6
|
+
|
|
7
|
+
export type StaleInstallResult = {
|
|
8
|
+
state: 'same' | 'changed' | 'unknown' | 'not-installed';
|
|
9
|
+
bootCommit: string | undefined;
|
|
10
|
+
installedCommit: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const STALE_INSTALL_CHECK_INTERVAL_MS = 60_000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Builds the command that relaunches the TUI on the same daemon session: `elanous --resume <id>` boots the dashboard,
|
|
17
|
+
* loads that session (ACP session/load) and replays its turns (src/index.ts resumeSessionId · dashboard acp-boot).
|
|
18
|
+
* The user-facing hint and its key binding land with the dashboard wiring slice (`r` is the render toggle today).
|
|
19
|
+
* Intentional wiring boundary: the dashboard owns the key binding and executes this command;
|
|
20
|
+
* this scoped helper only constructs it and does not spawn a child process.
|
|
21
|
+
*/
|
|
22
|
+
export function buildStaleInstallRelaunchCommand(sessionId: string): string {
|
|
23
|
+
return `elanous --resume ${JSON.stringify(sessionId)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function formatStaleInstallNotice(result: StaleInstallResult, notifiedCount: number): string {
|
|
27
|
+
const message = `새 판이 깔렸습니다 (부팅 판 ${result.bootCommit!.slice(0, 7)} → 지금 ${result.installedCommit!.slice(0, 7)}) · TUI 를 다시 띄우면 새 판으로 돕니다`;
|
|
28
|
+
return notifiedCount >= 2 ? `${message} · 이 TUI 가 뜬 뒤 ${notifiedCount}번째 새 판` : message;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Identify the immutable installed version containing this module, never the session cwd. */
|
|
32
|
+
export function versionedDashboardInstallDir(
|
|
33
|
+
codeRoot: string,
|
|
34
|
+
installRoot = join(homedir(), '.local', 'share', 'elanous'),
|
|
35
|
+
): string | undefined {
|
|
36
|
+
try {
|
|
37
|
+
const packageRoot = realpathSync(codeRoot);
|
|
38
|
+
if (basename(packageRoot) !== 'elanous' || basename(dirname(packageRoot)) !== 'node_modules') return undefined;
|
|
39
|
+
const versionDir = dirname(dirname(packageRoot));
|
|
40
|
+
let canonicalInstallRoot: string;
|
|
41
|
+
try { canonicalInstallRoot = realpathSync(installRoot); }
|
|
42
|
+
catch { canonicalInstallRoot = resolve(installRoot); }
|
|
43
|
+
if (dirname(versionDir) !== join(canonicalInstallRoot, 'versions')) return undefined;
|
|
44
|
+
const requestedVersionDir = dirname(dirname(resolve(codeRoot)));
|
|
45
|
+
return dirname(requestedVersionDir) === resolve(installRoot, 'versions')
|
|
46
|
+
&& realpathSync(requestedVersionDir) === versionDir
|
|
47
|
+
? requestedVersionDir : versionDir;
|
|
48
|
+
} catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function createStaleInstallCheck(input: {
|
|
54
|
+
bootCommit: string | undefined;
|
|
55
|
+
readInstalledCommit: () => string | undefined;
|
|
56
|
+
now: () => number;
|
|
57
|
+
codeRoot?: string;
|
|
58
|
+
installRoot?: string;
|
|
59
|
+
}) {
|
|
60
|
+
const installed = input.codeRoot === undefined
|
|
61
|
+
|| versionedDashboardInstallDir(input.codeRoot, input.installRoot) !== undefined;
|
|
62
|
+
const notifiedCommits = new Set<string>();
|
|
63
|
+
let lastReadAt = -Infinity;
|
|
64
|
+
let lastResult: StaleInstallResult | undefined;
|
|
65
|
+
const check = (): StaleInstallResult => {
|
|
66
|
+
if (!installed) return { state: 'not-installed', bootCommit: input.bootCommit, installedCommit: undefined };
|
|
67
|
+
const time = input.now();
|
|
68
|
+
if (lastResult && time - lastReadAt < STALE_INSTALL_CHECK_INTERVAL_MS) return lastResult;
|
|
69
|
+
lastReadAt = time;
|
|
70
|
+
let installedCommit: string | undefined;
|
|
71
|
+
try { installedCommit = input.readInstalledCommit(); } catch { /* unreadable metadata */ }
|
|
72
|
+
const result: StaleInstallResult = {
|
|
73
|
+
state: !input.bootCommit || !installedCommit
|
|
74
|
+
? 'unknown'
|
|
75
|
+
: input.bootCommit === installedCommit ? 'same' : 'changed',
|
|
76
|
+
bootCommit: input.bootCommit,
|
|
77
|
+
installedCommit,
|
|
78
|
+
};
|
|
79
|
+
lastResult = result;
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
check,
|
|
84
|
+
shouldNotify(result: StaleInstallResult): boolean {
|
|
85
|
+
if (result.state !== 'changed' || !result.installedCommit || notifiedCommits.has(result.installedCommit)) return false;
|
|
86
|
+
notifiedCommits.add(result.installedCommit);
|
|
87
|
+
return true;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Only the current pointer is polled; boot metadata is read once from the immutable version. */
|
|
93
|
+
export function readDashboardBootCommit(versionDir: string): string | undefined {
|
|
94
|
+
return readInstallMetadataCommit(join(versionDir, 'install.json'));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function readCurrentInstalledCommit(installRoot = join(homedir(), '.local', 'share', 'elanous')): string | undefined {
|
|
98
|
+
return readInstallMetadataCommit(join(installRoot, 'current', 'install.json'));
|
|
99
|
+
}
|