elanous 0.2.34 → 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/{abb4b98b.163e0f56e84ae35d.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/1201.afbfc5b1c5e5cbe4.js +1 -0
- 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/2500.cbc1257b774aae52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 2683.c9773a0c589b031b.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 275-02ea4c2a33980422.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/{ffdc3a04.b9c23c1b28dd4a96.js → 2812ca6a.3b9f4a7a08885744.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.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/{8817.61bb7ffbba502ecb.js → 3136.30aaaa5fa03662a3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3148-98efd4869d660a87.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3498.cf2a15a8a9e5b926.js → 3155.2587a55196ecb394.js} +3 -3
- 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/{3103.84470c8445962f04.js → 3324.a09703033abcbd2f.js} +1 -1
- 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/{3819.163d4777f0a597f6.js → 3538.a445e50bb359d068.js} +2 -2
- 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/{3414.172ad4ca2d9b08e8.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/3757-180308bc61021b05.js +1 -0
- package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
- package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.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/{6740.43de73fc427c9fe2.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/{8548.036c344973968847.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/{3411-f87314c6c66ebc73.js → 5085-bce4904931767ca6.js} +1 -1
- 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/{3110.0a7065f25c841818.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/{1644.35dd25240ae24e4b.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/{3837.722e053fb9f321ad.js → 5711.957b095705c12560.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.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/{7562.948255cbc3e79d33.js → 599.c39c571b6733f2a2.js} +2 -2
- 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/{5446.edf141cff9ef647d.js → 6925.562d532110879886.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 6943.c6b24124853a47b2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.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/{2554.3b5e200f5f5cfcd6.js → 771.c3cdb6c1f7f47c02.js} +16 -16
- 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/{3121.779fafe3e44612c5.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/{9a8cb466.cc9fc9e6e46038aa.js → 873d6c12.09bd499f57171543.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.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/914.8abefd48d579547b.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.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/{2547.dd27303624cb4da8.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/9789.60f723d18097ec30.js +1 -0
- 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-4fb31eb476dcbad3.js → page-083747f1d4518f61.js} +1 -1
- 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/{5014f970-22bef0b5210f7d60.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → ceba0382.650712b56b85b582.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/da5ecc5c-b005ad8cac737d57.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +1 -0
- 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/{L04y73dlwKeTW-GetaTF3 → 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/bin/elanous.mjs +3 -2
- package/catalog/providers/opengateway.yaml +25 -0
- package/docs/goal-context/01-goal-authoring-checks.md +8 -0
- package/docs/goal-context/03-verification-menu.md +24 -0
- package/docs/goal-context/04-mock-scenarios.md +100 -0
- package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
- package/docs/goal-context/README.md +7 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/default-loop.yaml +63 -4
- package/graphs/document-loop.yaml +51 -3
- package/graphs/implement-loop.yaml +77 -4
- package/graphs/journey/ta-journey.yaml +11 -1
- package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
- package/graphs/journey/units/author-dialogue/observe.ts +96 -0
- package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
- package/graphs/operate-loop.yaml +51 -3
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +17 -4
- package/graphs/research-loop.yaml +137 -3
- package/graphs/test-diet/test-diet.yaml +3 -0
- 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 +19 -6
- package/scripts/first10-gate.ts +416 -0
- package/scripts/fleet/wsl-node-setup.sh +432 -0
- package/scripts/hq/standby-snapshot.ts +17 -12
- package/scripts/release-loop/docs-land-node.ts +21 -5
- package/scripts/release-loop/docs-node.ts +204 -8
- package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
- package/scripts/release-loop/gate-node.ts +427 -72
- package/scripts/release-loop/gate-partial.ts +65 -11
- package/scripts/release-loop/gate-radius-live.ts +177 -0
- package/scripts/release-loop/gate-radius-shadow.ts +1 -1
- package/scripts/release-loop/node-verdict.ts +14 -1
- package/scripts/release-loop/npm-publish-node.ts +66 -12
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
- package/scripts/release-loop/pwa-remote.ts +166 -0
- package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
- package/scripts/release-loop/resume-cap.ts +14 -34
- package/scripts/release-loop/resume-release.ts +78 -15
- package/scripts/release-loop/traffic-node.ts +59 -0
- package/scripts/release-loop/traffic-transition.ts +159 -0
- package/scripts/release-loop/unattended-release.ts +2 -0
- package/scripts/rhythm/daily.ts +137 -3
- package/scripts/test-diet/lib.ts +6 -1
- package/scripts/test-diet/node.ts +194 -13
- package/scripts/ux-sim.ts +92 -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/self-ambient-cache.ts +8 -0
- package/src/agent/task-notification.ts +56 -10
- package/src/agent/types.ts +4 -0
- package/src/agent-substrate/acp-reviewer.ts +39 -4
- package/src/agent-substrate/pr-reviewer.ts +72 -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 +229 -28
- package/src/autopilot/mission-codebase-gate.ts +141 -12
- package/src/autopilot/pr-manager.ts +240 -41
- package/src/boot/daemon-tools/self-implement.ts +1 -0
- package/src/budget/run-usage-rollup.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 -6
- package/src/chat/internal-turn-origin.ts +1 -0
- package/src/chat/paste-fold.ts +86 -0
- package/src/chat/pickers/modal-runtime.ts +10 -27
- 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/agent-cli.ts +13 -2
- package/src/cli/config-audit.ts +119 -0
- package/src/cli/doctor-cli.ts +26 -1
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/herdr-cli.ts +34 -0
- package/src/cli/light-entry-route.ts +50 -7
- 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/pod-cli.ts +77 -3
- package/src/cli/pr-cli.ts +34 -18
- 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-pod-shadow-job.ts +3 -0
- package/src/cli/pr-land-recovery.ts +117 -1
- package/src/cli/pty-takeover-cli.ts +8 -7
- package/src/cli/release-checklist-read-cli.ts +79 -0
- package/src/cli/release-cli.ts +92 -106
- package/src/cli/release-single-flight.ts +1 -1
- package/src/cli/remote-resolve.ts +1 -1
- package/src/cli/root-tui-entry.ts +48 -0
- package/src/cli/sim-cli.ts +22 -0
- package/src/cli/tasks-card-show.ts +162 -0
- package/src/cli/tasks-cli.ts +1065 -338
- package/src/cli/tasks-read-cli.ts +197 -0
- package/src/cli/usage-cli.ts +13 -11
- package/src/clipboard/history.ts +179 -13
- package/src/config.ts +8 -1
- 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/chat/acp-chat.ts +8 -0
- package/src/dashboard/context/keys.ts +8 -31
- package/src/dashboard/index.ts +280 -59
- 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/render/theme-resolver.ts +33 -4
- 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/schedule-registry.ts +16 -2
- package/src/domains/standalone-log-sink.ts +15 -2
- package/src/esc-abort-gate.ts +69 -0
- package/src/git-fs/idle-refresh.ts +76 -0
- package/src/git-fs/index.ts +18 -7
- package/src/git-fs/worktree.ts +137 -5
- package/src/graph-kinds/registry.ts +2 -2
- package/src/graph-runner/graph-cli.ts +18 -0
- package/src/graph-runner/runner.ts +173 -21
- package/src/graph-wizard/generate.ts +108 -4
- package/src/graph-wizard/steps.ts +15 -0
- package/src/grok/credential.ts +10 -3
- package/src/grounding/proactive-ground.ts +86 -0
- package/src/harness/control-inbox.ts +49 -1
- package/src/harness/harness-cli-command.ts +163 -35
- package/src/harness/harness-incidents.ts +85 -1
- package/src/harness/launch-utterance-ledger.ts +208 -0
- 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/impl-discipline/detector.ts +16 -4
- package/src/impl-discipline/system-prompt.ts +11 -0
- package/src/impl-discipline/types.ts +2 -2
- package/src/index.ts +822 -154
- package/src/input-core/context-key-runtime.ts +21 -0
- package/src/intake-plane/already-built-hint.ts +4 -2
- package/src/intake-plane/requirement-funnel.ts +29 -1
- package/src/light-cli.ts +32 -11
- package/src/llm/opengateway-models.ts +11 -0
- package/src/llm/provider-credentials.ts +14 -0
- package/src/llm/provider-detect.ts +8 -1
- package/src/llm/runtime-model-family.ts +2 -1
- package/src/llm-wellformed.ts +70 -0
- package/src/llm.ts +247 -59
- 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/model-tier/llm-tier-map.ts +15 -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/native-tool-catalog.ts +15 -1
- package/src/nexus/api/decisions-route.ts +38 -18
- package/src/nexus/api/graph-wizard-api.ts +20 -2
- package/src/nexus/api/loop-resources.ts +13 -1
- package/src/nexus/boot/register-mcp-clients.ts +263 -38
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
- package/src/oauth/codex.ts +7 -0
- package/src/onboarding/first-run.ts +37 -6
- package/src/onboarding/web-first.ts +43 -11
- package/src/ops/overview-collect.ts +30 -9
- package/src/ops/overview.ts +22 -9
- package/src/persona/loader.ts +11 -0
- package/src/persona/types.ts +8 -0
- package/src/pr-tool/census.ts +261 -27
- 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-manifest.ts +7 -0
- 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 +100 -4
- package/src/release-loop/landed-but-yellow.ts +129 -5
- package/src/release-loop/light-rc.ts +1 -0
- package/src/release-loop/rehearsal.ts +37 -21
- package/src/repl/index.ts +192 -17
- package/src/repl/ops-msg-bridge.ts +32 -0
- package/src/seat-loop/knowhow-lint.ts +1 -1
- package/src/self-dev/ask-launch-flow.ts +44 -5
- package/src/self-dev/cli-help-text.ts +17 -0
- package/src/self-dev/decompose-proposal.ts +172 -20
- package/src/self-dev/decompose.ts +61 -0
- package/src/self-dev/dev-cli.ts +48 -12
- package/src/self-dev/dev-pipeline.ts +8 -2
- package/src/self-dev/draft-residue.ts +37 -1
- package/src/self-dev/draft-sweep.ts +137 -11
- package/src/self-dev/draft-triage-rules.ts +138 -0
- package/src/self-dev/fleet-reduce.ts +3 -2
- package/src/self-dev/glm-credential-guard.ts +77 -0
- package/src/self-dev/graph-front-nodes.ts +112 -0
- package/src/self-dev/graph-journey-nodes.ts +2 -0
- package/src/self-dev/graph-journey-route.ts +12 -2
- package/src/self-dev/harness-run-cli.ts +3 -15
- package/src/self-dev/orchestrate-cli-text.ts +10 -0
- package/src/self-dev/orchestrate-cli.ts +68 -3
- package/src/self-dev/orchestrate.ts +116 -17
- package/src/self-dev/review-provider-fallback.ts +35 -1
- package/src/self-dev/run-supervisor.ts +55 -2
- package/src/self-dev/run-types.ts +1 -1
- package/src/self-dev/self-orchestrate-runtime.ts +1 -11
- package/src/self-dev/shard-aggregate.ts +42 -5
- package/src/self-dev/shard-run.ts +8 -1
- package/src/self-health/autoheal.ts +153 -0
- package/src/self-health/signatures.ts +6 -0
- package/src/self-implement/blocked-draft-policy.ts +20 -0
- package/src/self-implement/classify-shadow.ts +3 -7
- package/src/self-implement/device-first.ts +116 -0
- package/src/self-implement/doctor-visit.ts +257 -2
- package/src/self-implement/evidence-command-budget.ts +80 -0
- package/src/self-implement/gate-baseline.ts +56 -17
- package/src/self-implement/gate-cli.ts +1 -0
- package/src/self-implement/gate-remote.ts +31 -20
- package/src/self-implement/goal-author-cli.ts +1 -0
- package/src/self-implement/goal-author-decompose.ts +534 -45
- package/src/self-implement/goal-author.ts +282 -7
- package/src/self-implement/goal-elaborate.ts +449 -0
- package/src/self-implement/goal-refine.ts +273 -0
- package/src/self-implement/graph-overlay-yaml.ts +14 -3
- 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 +370 -62
- 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-budget-judgment.ts +5 -8
- package/src/self-implement/rework-policy.ts +30 -0
- package/src/self-implement/run-ledger.ts +108 -0
- package/src/self-implement/run-stop.ts +10 -1
- package/src/self-implement/run-ttl.ts +38 -24
- package/src/self-implement/running-runs.ts +29 -1
- package/src/self-implement/scope-adjacency.ts +115 -0
- package/src/self-implement/seams.ts +187 -28
- package/src/self-implement/stop-autoheal.ts +87 -1
- package/src/self-implement/wiring-check.ts +358 -0
- package/src/session-runtime/index.ts +1 -1
- package/src/setup/llm-env-detect.ts +5 -0
- package/src/shell-env-bootstrap.ts +11 -4
- package/src/skills/runner.ts +4 -2
- package/src/skills/tools/agent.ts +408 -40
- package/src/skills/tools/msg-ask.ts +100 -0
- package/src/skills/tools/ops-ledger.ts +2 -1
- 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/hold-hygiene.ts +24 -6
- package/src/steward/rejudge-tick.ts +10 -2
- package/src/steward/ta-repair-event-collect.ts +17 -6
- package/src/steward/triage-budget.ts +194 -0
- package/src/steward/triage.ts +20 -3
- package/src/task-agent/actions.ts +72 -2
- package/src/task-agent/green-sweep.ts +4 -0
- package/src/task-agent/land-queue.ts +21 -8
- package/src/task-agent/live-moves.ts +182 -10
- package/src/task-agent/mission.ts +30 -0
- package/src/task-agent/parent-host.ts +123 -3
- 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 +48 -4
- package/src/task-agent/task-card-prefix.ts +2 -0
- package/src/task-agent/task-hand.ts +525 -57
- package/src/task-agent/task-parent-role-llm.ts +36 -0
- package/src/task-agent/tier-split.ts +196 -0
- package/src/task-agent/work-order-build.ts +2 -0
- package/src/task-agent/work-order.ts +3 -2
- package/src/task-orchestrator/generator-prompt.ts +60 -11
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +42 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +130 -11
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
- package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
- package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +19 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
- package/src/task-orchestrator/surfaces/pod-provenance.ts +82 -0
- 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-source-receive.ts +18 -0
- package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +7 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +521 -40
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +759 -50
- package/src/task-orchestrator/surfaces/self-implement.ts +65 -2
- package/src/tool-runtime/index.ts +15 -2
- package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
- package/src/tty-foreground.ts +155 -0
- package/src/tui/README.md +2 -0
- package/src/tui/chat/background-job-status.ts +54 -0
- package/src/tui/chat/goal-interim.ts +173 -0
- package/src/tui/chat/log-view.ts +267 -0
- package/src/tui/chat/self-health-status.ts +232 -0
- package/src/tui/entry.ts +695 -0
- package/src/tui/input/composer.ts +151 -0
- package/src/tui/seat-mail-boot.ts +59 -0
- package/src/tui/slash/compact-command.ts +7 -0
- package/src/tui/slash/compact.ts +94 -0
- package/src/tui/slash/new-session.ts +35 -0
- package/src/tui/slash/resume.ts +75 -0
- package/src/tui-client/local-chat-turn.ts +282 -0
- package/src/tui-client/local-harness-command.ts +63 -0
- package/src/tui-client/local-provider-command.ts +184 -0
- 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/user-config.ts +4 -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 +379 -0
- package/src/ux-sim/fake-bin.ts +87 -7
- 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 +367 -0
- package/src/ux-sim/fault-pod-codex-503.ts +211 -0
- package/src/ux-sim/fault-scope-escape-lift.ts +216 -0
- 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/1162.c69abda138c7ce43.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
- package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
- package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
- package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
- package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2987-30cf9c2eb7b8bdd5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
- package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
- package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
- package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
- package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
- package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
- package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
- package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +0 -287
- package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
- package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
- package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
- package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-df3445b207ceceab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
- package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
- /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
package/src/ux-sim/fake-bin.ts
CHANGED
|
@@ -13,17 +13,39 @@
|
|
|
13
13
|
// ⛔ This is not a simulator of the real tool: a spec only fixes stdout · stderr ·
|
|
14
14
|
// exit code · lifetime, and records argv. Behaviour of the real tool stays with
|
|
15
15
|
// tests that run where the tool exists.
|
|
16
|
+
import { spawnSync } from 'node:child_process';
|
|
16
17
|
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
17
18
|
import { tmpdir } from 'node:os';
|
|
18
|
-
import { delimiter, join } from 'node:path';
|
|
19
|
+
import { delimiter, isAbsolute, join } from 'node:path';
|
|
19
20
|
|
|
20
21
|
export interface FakeBinSpec {
|
|
21
22
|
readonly stdout?: string;
|
|
22
23
|
readonly stderr?: string;
|
|
23
24
|
/** Exit code (default 0). */
|
|
24
25
|
readonly exitCode?: number;
|
|
25
|
-
/** Stay alive this long before exiting — for long-running daemons a test kills
|
|
26
|
+
/** Stay alive this long before exiting — for long-running daemons a test kills, or a fractional
|
|
27
|
+
* per-call latency (e.g. 0.2) for a test that measures fan-out. */
|
|
26
28
|
readonly sleepSeconds?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Fake only the calls whose argv starts with these words (e.g. `['worktree', 'add']`);
|
|
31
|
+
* every other call `exec`s `otherwise` with the same argv. Needs `otherwise`.
|
|
32
|
+
*/
|
|
33
|
+
readonly whenArgsStartWith?: readonly string[];
|
|
34
|
+
/** Absolute path of the real executable that serves the calls `whenArgsStartWith` does not match. */
|
|
35
|
+
readonly otherwise?: string;
|
|
36
|
+
/**
|
|
37
|
+
* After stdout/stderr (and any sleep), the fake kills itself with this signal instead of exiting —
|
|
38
|
+
* a «died without a word» failure (`status` null · `signal` set). `exitCode` is then never reached.
|
|
39
|
+
*/
|
|
40
|
+
readonly killSignal?: 'KILL' | 'TERM' | 'INT' | 'HUP' | 'ABRT' | 'SEGV';
|
|
41
|
+
/**
|
|
42
|
+
* Be the util-linux `script -q -e -c` PTY allocator itself: record the call, then `exec` the real
|
|
43
|
+
* util-linux `script` with the same argv. A test that spawns `sh -c 'script -q -e -c "$1" …'`
|
|
44
|
+
* then gets a real TTY (so `process.stdin.isTTY` is true inside the child) and the recording proves
|
|
45
|
+
* the PTY came from util-linux, not from a hand-rolled shim. Requires util-linux on PATH
|
|
46
|
+
* (`utilLinuxScript()`); incompatible with the output-faking fields below.
|
|
47
|
+
*/
|
|
48
|
+
readonly pty?: boolean;
|
|
27
49
|
}
|
|
28
50
|
|
|
29
51
|
export interface FakeBinCall {
|
|
@@ -48,34 +70,75 @@ export interface FakeBins {
|
|
|
48
70
|
}
|
|
49
71
|
|
|
50
72
|
const NAME = /^[A-Za-z0-9._+-]+$/;
|
|
73
|
+
const KILL_SIGNALS: ReadonlySet<string> = new Set(['KILL', 'TERM', 'INT', 'HUP', 'ABRT', 'SEGV']);
|
|
51
74
|
|
|
52
75
|
function shellQuote(value: string): string {
|
|
53
76
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
54
77
|
}
|
|
55
78
|
|
|
79
|
+
let utilLinuxScriptCache: string | null | undefined;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Absolute path of the util-linux `script` on PATH, or `null` when this host has none
|
|
83
|
+
* (macOS ships BSD `script`, whose `-q -e -c` flags differ — see `firstRunPtySupport()`).
|
|
84
|
+
* Probed once per process: `<path>/script --version` must answer `util-linux`.
|
|
85
|
+
*/
|
|
86
|
+
export function utilLinuxScript(): string | null {
|
|
87
|
+
if (utilLinuxScriptCache !== undefined) return utilLinuxScriptCache;
|
|
88
|
+
utilLinuxScriptCache = null;
|
|
89
|
+
for (const dir of (process.env.PATH ?? '').split(delimiter)) {
|
|
90
|
+
if (!dir) continue;
|
|
91
|
+
const candidate = join(dir, 'script');
|
|
92
|
+
if (!existsSync(candidate)) continue;
|
|
93
|
+
const probe = spawnSync(candidate, ['--version'], { encoding: 'utf8', timeout: 5_000 });
|
|
94
|
+
if (probe.status === 0 && `${probe.stdout ?? ''}${probe.stderr ?? ''}`.includes('util-linux')) {
|
|
95
|
+
utilLinuxScriptCache = candidate;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return utilLinuxScriptCache;
|
|
100
|
+
}
|
|
101
|
+
|
|
56
102
|
function script(name: string, spec: FakeBinSpec, dataDir: string, logPath: string): string {
|
|
57
103
|
const lines = ['#!/bin/sh'];
|
|
58
104
|
// One record per call: name and each argv entry NUL-terminated (one printf), then an ASCII record
|
|
59
105
|
// separator \x1e (a second printf). `calls()` drops the unterminated tail, so a reader never sees half a record.
|
|
60
|
-
|
|
106
|
+
// The record is staged in its own file and appended by one `cat` (one write), so concurrent calls never interleave.
|
|
107
|
+
// The fake PATH may itself contain mktemp, cat, or rm. Use the shell's default utility path
|
|
108
|
+
// for recorder and payload reads so a fake of one of those names cannot recursively call itself.
|
|
109
|
+
lines.push(`rec=$(command -p mktemp ${shellQuote(join(dataDir, 'rec.XXXXXX'))})`);
|
|
110
|
+
lines.push(`{ printf '%s\\0' ${shellQuote(name)} "$@"; printf '\\036'; } > "$rec"; command -p cat "$rec" >> ${shellQuote(logPath)}; command -p rm -f "$rec"`);
|
|
111
|
+
if (spec.pty === true) {
|
|
112
|
+
// Recorded already: exec the real util-linux script so the caller gets a genuine TTY.
|
|
113
|
+
lines.push(`exec ${shellQuote(utilLinuxScript()!)} "$@"`);
|
|
114
|
+
return `${lines.join('\n')}\n`;
|
|
115
|
+
}
|
|
116
|
+
if (spec.whenArgsStartWith !== undefined && spec.otherwise !== undefined) {
|
|
117
|
+
const words = spec.whenArgsStartWith;
|
|
118
|
+
const tests = [`[ "$#" -ge ${words.length} ]`, ...words.map((word, index) => `[ "$${index + 1}" = ${shellQuote(word)} ]`)];
|
|
119
|
+
lines.push(`if ${tests.join(' && ')}; then :; else exec ${shellQuote(spec.otherwise)} "$@"; fi`);
|
|
120
|
+
}
|
|
61
121
|
if (spec.stdout !== undefined) {
|
|
62
122
|
const file = join(dataDir, `${name}.stdout`);
|
|
63
123
|
writeFileSync(file, spec.stdout);
|
|
64
|
-
lines.push(`cat ${shellQuote(file)}`);
|
|
124
|
+
lines.push(`command -p cat ${shellQuote(file)}`);
|
|
65
125
|
}
|
|
66
126
|
if (spec.stderr !== undefined) {
|
|
67
127
|
const file = join(dataDir, `${name}.stderr`);
|
|
68
128
|
writeFileSync(file, spec.stderr);
|
|
69
|
-
lines.push(`cat ${shellQuote(file)} >&2`);
|
|
129
|
+
lines.push(`command -p cat ${shellQuote(file)} >&2`);
|
|
70
130
|
}
|
|
71
131
|
const exitCode = spec.exitCode ?? 0;
|
|
72
132
|
if (spec.sleepSeconds !== undefined && spec.sleepSeconds > 0) {
|
|
73
|
-
|
|
133
|
+
// Whole seconds stay as they were; a fraction keeps millisecond precision (`sleep 0.2` — BSD · GNU · busybox).
|
|
134
|
+
const seconds = Number.isInteger(spec.sleepSeconds) ? spec.sleepSeconds : Math.ceil(spec.sleepSeconds * 1000) / 1000;
|
|
74
135
|
// exit 0: `exec` so killing the fake kills the sleep itself. Any other code needs the shell to
|
|
75
136
|
// outlive the sleep; a fake killed mid-sleep then leaves `sleep` until `sleepSeconds` ends.
|
|
76
|
-
|
|
137
|
+
// killSignal must outlive the sleep too, or `exec` would replace the shell before the kill line.
|
|
138
|
+
if (exitCode === 0 && spec.killSignal === undefined) lines.push(`exec sleep ${seconds}`);
|
|
77
139
|
else lines.push(`sleep ${seconds}`);
|
|
78
140
|
}
|
|
141
|
+
if (spec.killSignal !== undefined) lines.push(`kill -s ${spec.killSignal} $$`);
|
|
79
142
|
lines.push(`exit ${exitCode}`);
|
|
80
143
|
return `${lines.join('\n')}\n`;
|
|
81
144
|
}
|
|
@@ -83,6 +146,23 @@ function script(name: string, spec: FakeBinSpec, dataDir: string, logPath: strin
|
|
|
83
146
|
export function createFakeBins(specs: Readonly<Record<string, FakeBinSpec>>): FakeBins {
|
|
84
147
|
for (const name of Object.keys(specs)) {
|
|
85
148
|
if (!NAME.test(name) || name === '.' || name === '..') throw new Error(`fake-bin: invalid executable name ${JSON.stringify(name)}`);
|
|
149
|
+
const spec = specs[name]!;
|
|
150
|
+
if (spec.killSignal !== undefined && !KILL_SIGNALS.has(spec.killSignal)) throw new Error(`fake-bin: ${name}: killSignal must be one of ${[...KILL_SIGNALS].join(', ')}`);
|
|
151
|
+
if (spec.whenArgsStartWith !== undefined) {
|
|
152
|
+
if (spec.whenArgsStartWith.length === 0) throw new Error(`fake-bin: ${name}: whenArgsStartWith needs at least one word`);
|
|
153
|
+
if (spec.otherwise === undefined) throw new Error(`fake-bin: ${name}: whenArgsStartWith needs otherwise (the real executable)`);
|
|
154
|
+
if (!isAbsolute(spec.otherwise)) throw new Error(`fake-bin: ${name}: otherwise must be an absolute path, got ${JSON.stringify(spec.otherwise)}`);
|
|
155
|
+
} else if (spec.otherwise !== undefined) {
|
|
156
|
+
throw new Error(`fake-bin: ${name}: otherwise is only used with whenArgsStartWith`);
|
|
157
|
+
}
|
|
158
|
+
if (spec.pty === true) {
|
|
159
|
+
if (spec.stdout !== undefined || spec.stderr !== undefined || spec.exitCode !== undefined
|
|
160
|
+
|| spec.sleepSeconds !== undefined || spec.killSignal !== undefined
|
|
161
|
+
|| spec.whenArgsStartWith !== undefined || spec.otherwise !== undefined) {
|
|
162
|
+
throw new Error(`fake-bin: ${name}: pty is a pass-through PTY allocator and takes no output/fake fields`);
|
|
163
|
+
}
|
|
164
|
+
if (utilLinuxScript() === null) throw new Error(`fake-bin: ${name}: pty needs the util-linux \`script\` on PATH (this host has none)`);
|
|
165
|
+
}
|
|
86
166
|
}
|
|
87
167
|
const root = mkdtempSync(join(tmpdir(), 'ux-sim-fake-bin-'));
|
|
88
168
|
const dir = join(root, 'bin');
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// Fake herdr server for tests of code that drives the `herdr` CLI (TUI-HERDR-NAMED-AGENT).
|
|
2
|
+
//
|
|
3
|
+
// The real herdr 0.9.1 needs a live server socket and a terminal pane; a gate Pod has neither.
|
|
4
|
+
// This device answers the few agent/pane calls `herdr-prompt.ts` makes, as a `HerdrCliRunner`
|
|
5
|
+
// (argv in → rc · stdout · stderr out), from an in-memory pane table:
|
|
6
|
+
// agent get <target> → {"result":{"agent":{…}}} · agent_not_found (rc1)
|
|
7
|
+
// agent wait <target> [--until S]… [--timeout MS] → returns at once when the status already matches,
|
|
8
|
+
// otherwise on the next matching transition · timeout (rc1)
|
|
9
|
+
// pane run <pane> <text> → records the submission · calls `onRun` (the test's «TUI»)
|
|
10
|
+
// pane report-agent <pane>… --source S --agent A --state X --seq N
|
|
11
|
+
// → self-reported agent (herdr «Integrate your own agent»)
|
|
12
|
+
// pane release-agent <pane> --source S --agent A --seq N → releases it
|
|
13
|
+
// pane report-agent-session … → rc0 · no-op (measured: neither registers nor moves the state seq)
|
|
14
|
+
// agent list → reported agents (`reportedAgents()` is the same list)
|
|
15
|
+
// Report faults (`reportFault`, TUI-HERDR-STATUS-STALE): a `pane report-agent` can answer as a client
|
|
16
|
+
// timeout — `applied-then-timeout` (the server took it, the answer came too late: the 10-22 n8n shape)
|
|
17
|
+
// or `timeout` (never applied). The answer is `{code:null, stderr:'timeout', timedOut:true}`.
|
|
18
|
+
// Report/release seq rule measured on herdr 0.9.1 (10-22 · isolated session `tf-exit-race`):
|
|
19
|
+
// a report/release is applied only when its seq is above the last applied seq of that pane·source
|
|
20
|
+
// (smaller is rc0 and ignored); a release of an agent that is not registered is rc0 and does NOT
|
|
21
|
+
// record its seq — so a smaller-seq report arriving after it still registers (the exit-race ghost).
|
|
22
|
+
// Error envelopes follow the shape measured on herdr 0.9.1 (10-22 · isolated session `tf-herdr-e4`):
|
|
23
|
+
// {"error":{"code":"…","message":"…"},"id":"cli:agent:get"} on stderr, exit 1.
|
|
24
|
+
//
|
|
25
|
+
// ⛔ This is not a herdr simulator: it fixes only those answers and the «matches now → return now»
|
|
26
|
+
// wait rule from the herdr agent-automation doc. Real herdr behaviour stays with the isolated-session E4.
|
|
27
|
+
|
|
28
|
+
export type FakeHerdrStatus = 'idle' | 'working' | 'blocked' | 'done' | 'unknown';
|
|
29
|
+
|
|
30
|
+
export interface FakeHerdrPane {
|
|
31
|
+
readonly paneId: string;
|
|
32
|
+
/** Reported or detected agent label (`elanous`, `codex`, …). */
|
|
33
|
+
agent: string;
|
|
34
|
+
name?: string;
|
|
35
|
+
status: FakeHerdrStatus;
|
|
36
|
+
stateChangeSeq: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface FakeHerdrRunResult {
|
|
40
|
+
readonly code: number | null;
|
|
41
|
+
readonly stdout: string;
|
|
42
|
+
readonly stderr: string;
|
|
43
|
+
/** Set only by `reportFault` — the client gave up waiting (the report may or may not have been applied). */
|
|
44
|
+
readonly timedOut?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** How one `pane report-agent` call fails (see `FakeHerdrOpts.reportFault`). */
|
|
48
|
+
export type FakeHerdrReportFault = 'applied-then-timeout' | 'timeout';
|
|
49
|
+
|
|
50
|
+
export interface FakeHerdrSubmission {
|
|
51
|
+
readonly paneId: string;
|
|
52
|
+
readonly text: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface FakeHerdr {
|
|
56
|
+
/** The `HerdrCliRunner` the code under test receives. */
|
|
57
|
+
run(argv: readonly string[], timeoutMs: number): Promise<FakeHerdrRunResult>;
|
|
58
|
+
/** Move a pane to a new status (bumps `state_change_seq`, wakes matching waits). */
|
|
59
|
+
setStatus(paneId: string, status: FakeHerdrStatus): void;
|
|
60
|
+
pane(paneId: string): FakeHerdrPane | undefined;
|
|
61
|
+
/** Every `pane run` submission, in order. */
|
|
62
|
+
submissions(): FakeHerdrSubmission[];
|
|
63
|
+
/** Every argv the runner saw, in order. */
|
|
64
|
+
calls(): string[][];
|
|
65
|
+
/**
|
|
66
|
+
* The same answers as `run` for the commands that never wait (report-agent · release-agent ·
|
|
67
|
+
* report-agent-session · agent list) — for code whose runner is synchronous (the TUI exit path).
|
|
68
|
+
*/
|
|
69
|
+
runSync(argv: readonly string[]): FakeHerdrRunResult;
|
|
70
|
+
/** Agents registered through `pane report-agent` and not released (what `agent list` shows). */
|
|
71
|
+
reportedAgents(): FakeHerdrReportedAgent[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface FakeHerdrReportedAgent {
|
|
75
|
+
readonly paneId: string;
|
|
76
|
+
readonly source: string;
|
|
77
|
+
readonly agent: string;
|
|
78
|
+
readonly state: string;
|
|
79
|
+
readonly seq: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface FakeHerdrOpts {
|
|
83
|
+
readonly panes: ReadonlyArray<{ paneId: string; agent: string; name?: string; status: FakeHerdrStatus }>;
|
|
84
|
+
/** Called after a `pane run` is recorded — the test's TUI reacts here (e.g. working → idle). */
|
|
85
|
+
readonly onRun?: (submission: FakeHerdrSubmission, herdr: FakeHerdr) => void;
|
|
86
|
+
/**
|
|
87
|
+
* Fault for the n-th `pane report-agent` call (0-based, counted across run/runSync) — undefined answers normally.
|
|
88
|
+
* `applied-then-timeout` applies the report and then answers as a timeout; `timeout` answers without applying.
|
|
89
|
+
*/
|
|
90
|
+
readonly reportFault?: (argv: readonly string[], index: number) => FakeHerdrReportFault | undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const SETTLED: readonly FakeHerdrStatus[] = ['idle', 'done', 'blocked'];
|
|
94
|
+
|
|
95
|
+
function errorBody(id: string, code: string, message: string): FakeHerdrRunResult {
|
|
96
|
+
return { code: 1, stdout: '', stderr: `${JSON.stringify({ error: { code, message }, id })}\n` };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function agentInfo(p: FakeHerdrPane): Record<string, unknown> {
|
|
100
|
+
return {
|
|
101
|
+
agent: p.agent,
|
|
102
|
+
agent_status: p.status,
|
|
103
|
+
pane_id: p.paneId,
|
|
104
|
+
state_change_seq: p.stateChangeSeq,
|
|
105
|
+
...(p.name !== undefined ? { name: p.name } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function createFakeHerdr(opts: FakeHerdrOpts): FakeHerdr {
|
|
110
|
+
const panes = new Map<string, FakeHerdrPane>();
|
|
111
|
+
for (const p of opts.panes) panes.set(p.paneId, { ...p, stateChangeSeq: 1 });
|
|
112
|
+
const subs: FakeHerdrSubmission[] = [];
|
|
113
|
+
const argvLog: string[][] = [];
|
|
114
|
+
const waiters = new Set<{ paneId: string; until: readonly FakeHerdrStatus[]; resolve: () => void }>();
|
|
115
|
+
|
|
116
|
+
/** pane·source → registered agent · last applied seq (kept after release). */
|
|
117
|
+
const reported = new Map<string, FakeHerdrReportedAgent>();
|
|
118
|
+
const lastSeq = new Map<string, number>();
|
|
119
|
+
const optsOf = (args: readonly string[]): { pane?: string; flags: Map<string, string> } => {
|
|
120
|
+
const flags = new Map<string, string>();
|
|
121
|
+
let pane: string | undefined;
|
|
122
|
+
for (let i = 0; i < args.length; i++) {
|
|
123
|
+
const a = args[i]!;
|
|
124
|
+
if (a.startsWith('--')) flags.set(a.slice(2), args[++i] ?? '');
|
|
125
|
+
else if (pane === undefined) pane = a;
|
|
126
|
+
}
|
|
127
|
+
return { pane, flags };
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
let reportIndex = 0;
|
|
131
|
+
const TIMEOUT: FakeHerdrRunResult = { code: null, stdout: '', stderr: 'timeout', timedOut: true };
|
|
132
|
+
/** `applyReport` with the scripted fault for `pane report-agent`. */
|
|
133
|
+
const answerReport = (argv: readonly string[]): FakeHerdrRunResult | undefined => {
|
|
134
|
+
if (argv[0] !== 'pane' || argv[1] !== 'report-agent') return applyReport(argv);
|
|
135
|
+
const fault = opts.reportFault?.(argv, reportIndex++);
|
|
136
|
+
if (fault === 'timeout') return TIMEOUT;
|
|
137
|
+
const r = applyReport(argv);
|
|
138
|
+
return fault === 'applied-then-timeout' ? TIMEOUT : r;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/** report-agent · release-agent · report-agent-session · agent list — answered at once (no waits). */
|
|
142
|
+
const applyReport = (argv: readonly string[]): FakeHerdrRunResult | undefined => {
|
|
143
|
+
const [group, cmd] = argv;
|
|
144
|
+
if (group === 'pane' && cmd === 'report-agent-session') return { code: 0, stdout: '', stderr: '' };
|
|
145
|
+
if (group === 'pane' && (cmd === 'report-agent' || cmd === 'release-agent')) {
|
|
146
|
+
const { pane, flags } = optsOf(argv.slice(2));
|
|
147
|
+
const source = flags.get('source') ?? '';
|
|
148
|
+
const seq = Number(flags.get('seq'));
|
|
149
|
+
if (pane === undefined || !source || !Number.isSafeInteger(seq)) {
|
|
150
|
+
return { code: 2, stdout: '', stderr: `fake-herdr: ${cmd} needs <pane> --source --seq\n` };
|
|
151
|
+
}
|
|
152
|
+
const key = `${pane}\u0000${source}`;
|
|
153
|
+
const prev = lastSeq.get(key);
|
|
154
|
+
if (prev !== undefined && seq <= prev) return { code: 0, stdout: '', stderr: '' };
|
|
155
|
+
if (cmd === 'release-agent') {
|
|
156
|
+
if (!reported.has(key)) return { code: 0, stdout: '', stderr: '' };
|
|
157
|
+
reported.delete(key);
|
|
158
|
+
lastSeq.set(key, seq);
|
|
159
|
+
return { code: 0, stdout: '', stderr: '' };
|
|
160
|
+
}
|
|
161
|
+
reported.set(key, { paneId: pane, source, agent: flags.get('agent') ?? '', state: flags.get('state') ?? reported.get(key)?.state ?? 'unknown', seq });
|
|
162
|
+
lastSeq.set(key, seq);
|
|
163
|
+
return { code: 0, stdout: '', stderr: '' };
|
|
164
|
+
}
|
|
165
|
+
if (group === 'agent' && cmd === 'list') {
|
|
166
|
+
const agents = [...reported.values()].map((a) => ({ agent: a.agent, agent_status: a.state, pane_id: a.paneId }));
|
|
167
|
+
return { code: 0, stdout: `${JSON.stringify({ id: 'cli:agent:list', result: { agents, type: 'agent_list' } })}\n`, stderr: '' };
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const resolveTarget = (target: string): FakeHerdrPane | undefined =>
|
|
173
|
+
panes.get(target) ?? [...panes.values()].find((p) => p.name === target);
|
|
174
|
+
|
|
175
|
+
const herdr: FakeHerdr = {
|
|
176
|
+
async run(argv, timeoutMs) {
|
|
177
|
+
argvLog.push([...argv]);
|
|
178
|
+
const [group, cmd, target, ...rest] = argv;
|
|
179
|
+
if (group === 'agent' && cmd === 'get' && target !== undefined) {
|
|
180
|
+
const p = resolveTarget(target);
|
|
181
|
+
if (!p) return errorBody('cli:agent:get', 'agent_not_found', `agent target ${target} not found`);
|
|
182
|
+
return { code: 0, stdout: `${JSON.stringify({ id: 'cli:agent:get', result: { agent: agentInfo(p), type: 'agent_info' } })}\n`, stderr: '' };
|
|
183
|
+
}
|
|
184
|
+
if (group === 'agent' && cmd === 'wait' && target !== undefined) {
|
|
185
|
+
const p = resolveTarget(target);
|
|
186
|
+
if (!p) return errorBody('cli:agent:wait', 'agent_not_found', `agent target ${target} not found`);
|
|
187
|
+
const until: FakeHerdrStatus[] = [];
|
|
188
|
+
let waitTimeout: number | undefined;
|
|
189
|
+
for (let i = 0; i < rest.length; i++) {
|
|
190
|
+
if (rest[i] === '--until') until.push(rest[++i] as FakeHerdrStatus);
|
|
191
|
+
else if (rest[i] === '--timeout') waitTimeout = Number(rest[++i]);
|
|
192
|
+
}
|
|
193
|
+
const want = until.length > 0 ? until : SETTLED;
|
|
194
|
+
const ok = (): FakeHerdrRunResult => ({ code: 0, stdout: `${JSON.stringify({ id: 'cli:agent:wait', result: { agent: agentInfo(p), type: 'agent_info' } })}\n`, stderr: '' });
|
|
195
|
+
if (want.includes(p.status)) return ok();
|
|
196
|
+
const limit = Math.min(waitTimeout ?? Number.POSITIVE_INFINITY, timeoutMs);
|
|
197
|
+
return new Promise<FakeHerdrRunResult>((resolve) => {
|
|
198
|
+
const waiter = {
|
|
199
|
+
paneId: p.paneId,
|
|
200
|
+
until: want,
|
|
201
|
+
resolve: () => { clearTimeout(timer); waiters.delete(waiter); resolve(ok()); },
|
|
202
|
+
};
|
|
203
|
+
const timer = Number.isFinite(limit)
|
|
204
|
+
? setTimeout(() => { waiters.delete(waiter); resolve(errorBody('cli:agent:wait', 'timeout', `timed out waiting for agent ${target}`)); }, limit)
|
|
205
|
+
: undefined;
|
|
206
|
+
waiters.add(waiter);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (group === 'pane' && cmd === 'run' && target !== undefined) {
|
|
210
|
+
const p = panes.get(target);
|
|
211
|
+
if (!p) return errorBody('cli:pane:run', 'pane_not_found', `pane ${target} not found`);
|
|
212
|
+
const submission = { paneId: p.paneId, text: rest[0] ?? '' };
|
|
213
|
+
subs.push(submission);
|
|
214
|
+
opts.onRun?.(submission, herdr);
|
|
215
|
+
return { code: 0, stdout: '', stderr: '' };
|
|
216
|
+
}
|
|
217
|
+
const reportedResult = answerReport(argv);
|
|
218
|
+
if (reportedResult) return reportedResult;
|
|
219
|
+
return { code: 2, stdout: '', stderr: `fake-herdr: unsupported argv ${argv.join(' ')}\n` };
|
|
220
|
+
},
|
|
221
|
+
setStatus(paneId, status) {
|
|
222
|
+
const p = panes.get(paneId);
|
|
223
|
+
if (!p) throw new Error(`fake-herdr: no pane ${paneId}`);
|
|
224
|
+
p.status = status;
|
|
225
|
+
p.stateChangeSeq += 1;
|
|
226
|
+
for (const w of [...waiters]) if (w.paneId === paneId && w.until.includes(status)) w.resolve();
|
|
227
|
+
},
|
|
228
|
+
pane: (paneId) => panes.get(paneId),
|
|
229
|
+
submissions: () => [...subs],
|
|
230
|
+
runSync(argv) {
|
|
231
|
+
argvLog.push([...argv]);
|
|
232
|
+
return answerReport(argv) ?? { code: 2, stdout: '', stderr: `fake-herdr: runSync supports report/release/agent list only — ${argv.join(' ')}\n` };
|
|
233
|
+
},
|
|
234
|
+
calls: () => argvLog.map((a) => [...a]),
|
|
235
|
+
reportedAgents: () => [...reported.values()],
|
|
236
|
+
};
|
|
237
|
+
return herdr;
|
|
238
|
+
}
|
package/src/ux-sim/fake-llm.ts
CHANGED
|
@@ -2,17 +2,114 @@
|
|
|
2
2
|
* Deterministic, network-free LLM for gate tests without provider credentials.
|
|
3
3
|
* The opt-in is deliberately explicit; production never selects this provider.
|
|
4
4
|
*/
|
|
5
|
+
import { appendFileSync } from 'node:fs';
|
|
5
6
|
import type { LLMMessage, LLMOpts, LLMProvider, LLMStreamEvent } from '../llm.js';
|
|
6
7
|
|
|
7
8
|
export const TEST_FAKE_LLM_ENV = 'ELANOUS_TEST_FAKE_LLM';
|
|
8
9
|
export const TEST_FAKE_LLM_RESPONSE_ENV = 'ELANOUS_TEST_FAKE_LLM_RESPONSE';
|
|
10
|
+
/** TUI-400-AUTOHEAL-FALLBACK — 호출별 결함 스크립트(쉼표 목록 · `400` | `400codex` | `ok`). 예: `400,ok,ok`.
|
|
11
|
+
* `400` 칸은 실측 «대화 기록 어긋남» 꼴(`LLM API 400: … No tool call found for function call output …`)을 던진다.
|
|
12
|
+
* 스크립트가 끝나면 `ok`. 칸 소비는 이 프로세스 안 호출 순서다(라이브 TUI 격리 무대용 — 생산은 이 env 를 안 본다). */
|
|
13
|
+
export const TEST_FAKE_LLM_SCRIPT_ENV = 'ELANOUS_TEST_FAKE_LLM_SCRIPT';
|
|
14
|
+
export const TEST_FAKE_LLM_400_MESSAGE = 'LLM API 400: {"error":{"message":"No tool call found for function call output with call_id call_fake_llm.","type":"invalid_request_error"}}';
|
|
15
|
+
/** TUI-ORPHAN-AUTO-RESUME-STOP — `400codex` 칸: 같은 «고아 도구 출력» 400 을 Codex 공급자 머리(`Codex API 400`)로 던진다.
|
|
16
|
+
* seat-autowake 의 종결 판정은 생산 Codex 문면을 문다 — `400` 칸(`LLM API 400`)으로는 그 길이 안 열린다. */
|
|
17
|
+
export const TEST_FAKE_LLM_CODEX_400_MESSAGE = 'Codex API 400: {"error":{"message":"No tool call found for function call output with call_id call_fake_llm.","type":"invalid_request_error"}}';
|
|
9
18
|
|
|
10
19
|
export function testFakeLlmEnabled(): boolean {
|
|
11
20
|
return process.env[TEST_FAKE_LLM_ENV] === '1';
|
|
12
21
|
}
|
|
13
22
|
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
/** `{step}` in the response becomes the number of user messages (tool results excluded) the model received — a different reply per
|
|
24
|
+
* turn of one conversation (TUI-GOAL-INTERIM-QUIET: «every step ends with 아직 못 했다» without same-reply stops). */
|
|
25
|
+
const TEST_FAKE_LLM_STEP_TOKEN = '{step}';
|
|
26
|
+
|
|
27
|
+
export function testFakeLlmResponse(messages?: readonly LLMMessage[]): string {
|
|
28
|
+
const text = process.env[TEST_FAKE_LLM_RESPONSE_ENV] ?? '[test-fake-llm] OK';
|
|
29
|
+
if (!text.includes(TEST_FAKE_LLM_STEP_TOKEN)) return text;
|
|
30
|
+
// Person/internal-turn text only — a tool result travels as a user-role message and must not count as a step.
|
|
31
|
+
const step = (messages ?? []).filter((m) => m.role === 'user'
|
|
32
|
+
&& !(Array.isArray(m.content) && m.content.some((block) => block.type === 'tool_result'))).length;
|
|
33
|
+
return text.split(TEST_FAKE_LLM_STEP_TOKEN).join(String(step));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let scriptCursor = 0;
|
|
37
|
+
/** 커서가 센 스크립트 문자열 — env 가 바뀌면 처음부터 다시 센다(앞 시험의 진행이 뒤 시험으로 새지 않게). */
|
|
38
|
+
let scriptCursorFor: string | undefined;
|
|
39
|
+
|
|
40
|
+
/** 시험 seam — 스크립트 칸 위치를 처음으로. */
|
|
41
|
+
export function resetTestFakeLlmScript(): void {
|
|
42
|
+
scriptCursor = 0;
|
|
43
|
+
scriptCursorFor = undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** TUI-ORPHAN-AUTO-RESUME-STOP — 마지막 사람 발화가 이 표지를 담으면 스크립트 칸을 안 쓰고 답한다
|
|
47
|
+
* («결함이 계속되는 세션에서도 사람 턴은 답을 받는다» 무대 · 칸 수를 호출 수에 맞춰 세지 않게). */
|
|
48
|
+
export const TEST_FAKE_LLM_SCRIPT_SKIP_WHEN_ENV = 'ELANOUS_TEST_FAKE_LLM_SCRIPT_SKIP_WHEN';
|
|
49
|
+
|
|
50
|
+
/** 다음 호출의 스크립트 칸을 소비한다. 400 칸이면 던진다. */
|
|
51
|
+
function consumeScriptStep(messages: LLMMessage[]): void {
|
|
52
|
+
const raw = process.env[TEST_FAKE_LLM_SCRIPT_ENV];
|
|
53
|
+
if (!raw) return;
|
|
54
|
+
const skipWhen = process.env[TEST_FAKE_LLM_SCRIPT_SKIP_WHEN_ENV];
|
|
55
|
+
if (skipWhen && (lastHumanText(messages) ?? '').includes(skipWhen)) return;
|
|
56
|
+
if (raw !== scriptCursorFor) { scriptCursorFor = raw; scriptCursor = 0; }
|
|
57
|
+
const steps = raw.split(',').map((step) => step.trim()).filter(Boolean);
|
|
58
|
+
const step = steps[scriptCursor];
|
|
59
|
+
scriptCursor += 1;
|
|
60
|
+
if (step === '400') throw new Error(TEST_FAKE_LLM_400_MESSAGE);
|
|
61
|
+
if (step === '400codex') throw new Error(TEST_FAKE_LLM_CODEX_400_MESSAGE);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** TUI-SEAT-MEMORY-RECALL — 요청 기록(격리 무대 전용). 경로를 주면 호출마다 받은 메시지(role·문자열 content)를
|
|
65
|
+
* JSONL 한 줄로 덧붙인다 — «모델이 실제로 받은 preamble» 을 무대 밖에서 단언하기 위함. 생산은 이 env 를 안 본다. */
|
|
66
|
+
export const TEST_FAKE_LLM_CAPTURE_ENV = 'ELANOUS_TEST_FAKE_LLM_CAPTURE';
|
|
67
|
+
|
|
68
|
+
function captureRequest(messages: LLMMessage[]): void {
|
|
69
|
+
const path = process.env[TEST_FAKE_LLM_CAPTURE_ENV];
|
|
70
|
+
if (!path) return;
|
|
71
|
+
const rows = messages.map((message) => ({ role: message.role, content: typeof message.content === 'string' ? message.content : null }));
|
|
72
|
+
appendFileSync(path, `${JSON.stringify({ messages: rows })}\n`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** TUI-NEXT-QUEUE-AND-WAKE — `{"when":"<표지>","name":"<도구>","args":{…}}`. 마지막 메시지가 표지를 담은 사람 발화
|
|
76
|
+
* (도구 결과 아님)면 텍스트 대신 그 도구 호출 하나를 낸다 — 도구가 실제 턴 루프에서 «불리는» 무대(예: ScheduleWakeup).
|
|
77
|
+
* 도구 결과 뒤 호출·표지 없는 발화는 고정 응답. JSON 이 틀리면 없는 것과 같다. */
|
|
78
|
+
export const TEST_FAKE_LLM_TOOL_CALL_ENV = 'ELANOUS_TEST_FAKE_LLM_TOOL_CALL';
|
|
79
|
+
/** 응답 전 지연(ms) — «도는 턴»을 사람 손으로 잡을 만큼 길게 만든다(busy 중 입력 무대). */
|
|
80
|
+
export const TEST_FAKE_LLM_DELAY_MS_ENV = 'ELANOUS_TEST_FAKE_LLM_DELAY_MS';
|
|
81
|
+
/** 주면 마지막 사람 발화가 이 표지를 담을 때만 지연한다. */
|
|
82
|
+
export const TEST_FAKE_LLM_DELAY_WHEN_ENV = 'ELANOUS_TEST_FAKE_LLM_DELAY_WHEN';
|
|
83
|
+
|
|
84
|
+
let toolCallSeq = 0;
|
|
85
|
+
|
|
86
|
+
/** 마지막 메시지가 사람 발화면 그 글, 도구 결과(또는 사람 아님)면 null. */
|
|
87
|
+
function lastHumanText(messages: LLMMessage[]): string | null {
|
|
88
|
+
const last = messages.at(-1);
|
|
89
|
+
if (!last || last.role !== 'user') return null;
|
|
90
|
+
if (typeof last.content === 'string') return last.content;
|
|
91
|
+
if (last.content.some((block) => block.type === 'tool_result')) return null;
|
|
92
|
+
return last.content.map((block) => (block.type === 'text' ? block.text : '')).join('');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function scriptedToolCall(messages: LLMMessage[]): LLMStreamEvent | null {
|
|
96
|
+
const raw = process.env[TEST_FAKE_LLM_TOOL_CALL_ENV];
|
|
97
|
+
if (!raw) return null;
|
|
98
|
+
let spec: { when?: unknown; name?: unknown; args?: unknown };
|
|
99
|
+
try { spec = JSON.parse(raw) as typeof spec; } catch { return null; }
|
|
100
|
+
if (typeof spec.when !== 'string' || typeof spec.name !== 'string') return null;
|
|
101
|
+
const text = lastHumanText(messages);
|
|
102
|
+
if (text === null || !text.includes(spec.when)) return null;
|
|
103
|
+
const args = spec.args && typeof spec.args === 'object' ? spec.args as Record<string, unknown> : {};
|
|
104
|
+
return { type: 'tool_call', id: `call_fake_llm_tool_${++toolCallSeq}`, name: spec.name, args };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function scriptedDelay(messages: LLMMessage[]): Promise<void> {
|
|
108
|
+
const ms = Number(process.env[TEST_FAKE_LLM_DELAY_MS_ENV] ?? 0);
|
|
109
|
+
if (!Number.isFinite(ms) || ms <= 0) return;
|
|
110
|
+
const when = process.env[TEST_FAKE_LLM_DELAY_WHEN_ENV];
|
|
111
|
+
if (when && !(lastHumanText(messages) ?? '').includes(when)) return;
|
|
112
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
113
|
}
|
|
17
114
|
|
|
18
115
|
/** Shares the real LLMProvider contract; only the external model call is replaced. */
|
|
@@ -20,10 +117,18 @@ export const testFakeLlmProvider: LLMProvider = {
|
|
|
20
117
|
name: 'test-fake-llm',
|
|
21
118
|
defaultModel: 'test-fake-llm',
|
|
22
119
|
available: testFakeLlmEnabled,
|
|
23
|
-
async *chat(
|
|
24
|
-
|
|
120
|
+
async *chat(messages: LLMMessage[], _opts?: LLMOpts): AsyncGenerator<string, void, unknown> {
|
|
121
|
+
captureRequest(messages);
|
|
122
|
+
consumeScriptStep(messages);
|
|
123
|
+
await scriptedDelay(messages);
|
|
124
|
+
yield testFakeLlmResponse(messages);
|
|
25
125
|
},
|
|
26
|
-
async *streamChat(
|
|
27
|
-
|
|
126
|
+
async *streamChat(messages: LLMMessage[], _opts?: LLMOpts): AsyncGenerator<LLMStreamEvent, void, unknown> {
|
|
127
|
+
captureRequest(messages);
|
|
128
|
+
consumeScriptStep(messages);
|
|
129
|
+
await scriptedDelay(messages);
|
|
130
|
+
const call = scriptedToolCall(messages);
|
|
131
|
+
if (call) { yield call; return; }
|
|
132
|
+
yield { type: 'text', delta: testFakeLlmResponse(messages) };
|
|
28
133
|
},
|
|
29
134
|
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// 결함 주입 심 «glm 자식 자격 없음» ── 하니스 자식 공급자를 glm(Z.ai GLM Coding Plan)으로 쐈는데 이 프로세스에
|
|
2
|
+
// Z.ai 자격이 없을 때, 발사 직전 해석(생산 `toSelfImplementOptions`)이 무엇을 내는지 프로세스 안(S1)에서 잰다.
|
|
3
|
+
//
|
|
4
|
+
// 🚨 왜 이것이 있나 (GLM-NO-CREDENTIAL-FALLBACK · OP #28375 · 2026-10-22)
|
|
5
|
+
// run-6c85c69f 부검이 «provider: glm / glm-5.3 · no provider configured» 한 줄로 «자격 결손 → 구현 0» 을 추정했다.
|
|
6
|
+
// 실측(Pod 로그)은 자격이 살아 있었고(Z.ai 200 OK) 그 줄은 배너가 glm 칸을 몰라 찍은 «거짓 표시»였다.
|
|
7
|
+
// 이 심은 두 축을 상주 시험으로 만든다 —
|
|
8
|
+
// ① 자격이 정말 없을 때: OpenRouter 키 있음 → openrouter/z-ai/glm-5.3 로 바꿔 발사 · 둘 다 없음 → 발사 전 거부
|
|
9
|
+
// ② 자격이 있을 때: 배너가 «no provider configured» 라고 거짓말하지 않는다
|
|
10
|
+
//
|
|
11
|
+
// ⛔ 흉내 내지 않는다 — 진짜 `toSelfImplementOptions`(dev-pipeline 이 runSelfImplement 직전에 부르는 그 함수) ⊕
|
|
12
|
+
// 진짜 `zaiCodingPlanAvailable`·`getOpenRouterApiKey`(키 캐시 → env) ⊕ 진짜 `oneLineProvider` 를 부른다.
|
|
13
|
+
// 주입은 «자격 env» 하나뿐이다(키 캐시 파일은 ELANOUS_KEEP_ENV_KEYS 로 끄고 기억된 값도 비운다 — 호스트의 진짜 키가 섞이지 않게).
|
|
14
|
+
// 관측 = 결과 선택 · 거부 문면 · self-dev.child-llm 관측 원본 · 배너 한 줄 · 영수증(명령 ⊕ injectionId ⊕ 결과) · 층 L1.
|
|
15
|
+
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
import { _resetKeyCacheForTests } from '../config.js';
|
|
18
|
+
import { debug } from '../debug/log.js';
|
|
19
|
+
import type { ChildLlmSelection } from '../agent/run-context.js';
|
|
20
|
+
import { planDevPipeline, toSelfImplementOptions } from '../self-dev/dev-pipeline.js';
|
|
21
|
+
import type { SelfImplementSeams } from '../self-implement/orchestrator.js';
|
|
22
|
+
import { inspectActiveProvider, oneLineProvider } from '../provider-summary.js';
|
|
23
|
+
import { getUserConfig, setUserConfigOverlay } from '../user-config.js';
|
|
24
|
+
|
|
25
|
+
export const GLM_NO_CREDENTIAL_LEVEL = 'L1' as const;
|
|
26
|
+
export const GLM_NO_CREDENTIAL_EVIDENCE_COMMAND = 'bun test src/ux-sim/fault-glm-no-credential.test.ts';
|
|
27
|
+
|
|
28
|
+
const ISOLATED_KEYS = ['ZAI_API_KEY', 'OPENROUTER_API_KEY'] as const;
|
|
29
|
+
|
|
30
|
+
export interface GlmNoCredentialScenario {
|
|
31
|
+
/** Z.ai 자격(env ZAI_API_KEY)을 둔다. */
|
|
32
|
+
readonly zaiKey: boolean;
|
|
33
|
+
/** OpenRouter 자격(env OPENROUTER_API_KEY)을 둔다. */
|
|
34
|
+
readonly openrouterKey: boolean;
|
|
35
|
+
/** 발사 인자 모델(기본 glm-5.3). */
|
|
36
|
+
readonly model?: string;
|
|
37
|
+
readonly injectionId?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface GlmNoCredentialObservedRow {
|
|
41
|
+
readonly category: string;
|
|
42
|
+
readonly event: string;
|
|
43
|
+
readonly data: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface GlmNoCredentialObservation {
|
|
47
|
+
readonly level: typeof GLM_NO_CREDENTIAL_LEVEL;
|
|
48
|
+
readonly injectionId: string;
|
|
49
|
+
readonly scenario: { zaiKey: boolean; openrouterKey: boolean; model: string };
|
|
50
|
+
/** keep = glm 그대로 · fallback = openrouter 로 바꿈 · refused = 발사 전 거부. */
|
|
51
|
+
readonly result: 'keep' | 'fallback' | 'refused';
|
|
52
|
+
readonly childLlm: ChildLlmSelection | null;
|
|
53
|
+
readonly error: string | null;
|
|
54
|
+
readonly rows: readonly GlmNoCredentialObservedRow[];
|
|
55
|
+
/** 같은 자격 상태에서 llm.provider=glm 일 때 배너가 찍는 한 줄(자식 PTY 첫 줄과 같은 함수). */
|
|
56
|
+
readonly banner: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function glmNoCredentialReceipt(observation: Pick<GlmNoCredentialObservation, 'injectionId' | 'result'>): string {
|
|
60
|
+
return `영수증: ${GLM_NO_CREDENTIAL_EVIDENCE_COMMAND} ⊕ ${observation.injectionId} ⊕ ${observation.result}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function renderGlmNoCredential(observation: GlmNoCredentialObservation): string[] {
|
|
64
|
+
const { scenario } = observation;
|
|
65
|
+
return [
|
|
66
|
+
`glm-no-credential · 층 ${observation.level} · 주입 ${observation.injectionId} · zai=${scenario.zaiKey ? '있음' : '없음'} · openrouter=${scenario.openrouterKey ? '있음' : '없음'} · 결과 ${observation.result}`,
|
|
67
|
+
observation.childLlm ? ` 자식 선택: ${observation.childLlm.provider}/${observation.childLlm.model}` : ` 거부: ${observation.error ?? '-'}`,
|
|
68
|
+
...observation.rows.map((row) => ` ${row.category} ${row.event} ${JSON.stringify(row.data)}`),
|
|
69
|
+
` 배너: ${observation.banner}`,
|
|
70
|
+
glmNoCredentialReceipt(observation),
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 결함 주입 본체 — 생산 `toSelfImplementOptions` 를 그대로 부른다(runSelfImplement 는 부르지 않는다 · 발사 0). */
|
|
75
|
+
export function simGlmNoCredential(scenario: GlmNoCredentialScenario): GlmNoCredentialObservation {
|
|
76
|
+
const injectionId = scenario.injectionId ?? `inj-${randomUUID()}`;
|
|
77
|
+
const model = scenario.model ?? 'glm-5.3';
|
|
78
|
+
const savedEnv: Record<string, string | undefined> = {};
|
|
79
|
+
for (const key of [...ISOLATED_KEYS, 'ELANOUS_KEEP_ENV_KEYS']) savedEnv[key] = process.env[key];
|
|
80
|
+
const savedLog = debug.log;
|
|
81
|
+
const rows: GlmNoCredentialObservedRow[] = [];
|
|
82
|
+
try {
|
|
83
|
+
for (const key of ISOLATED_KEYS) delete process.env[key];
|
|
84
|
+
process.env.ELANOUS_KEEP_ENV_KEYS = '1';
|
|
85
|
+
_resetKeyCacheForTests();
|
|
86
|
+
if (scenario.zaiKey) process.env.ZAI_API_KEY = 'fake-zai-test-only';
|
|
87
|
+
if (scenario.openrouterKey) process.env.OPENROUTER_API_KEY = 'fake-openrouter-test-only';
|
|
88
|
+
debug.log = ((category: string, event: string, data: Record<string, unknown>): void => {
|
|
89
|
+
if (category === 'self-dev.child-llm') rows.push({ category, event, data });
|
|
90
|
+
}) as typeof debug.log;
|
|
91
|
+
const requested: ChildLlmSelection = { provider: 'glm', model, source: 'flag' };
|
|
92
|
+
const plan = planDevPipeline({ input: { text: `glm-no-credential ${injectionId}` }, executor: { kind: 'self' }, completion: 'worktree-only', self: { childLlm: requested } });
|
|
93
|
+
let childLlm: ChildLlmSelection | null = null;
|
|
94
|
+
let error: string | null = null;
|
|
95
|
+
try {
|
|
96
|
+
childLlm = toSelfImplementOptions(plan.input && 'text' in plan.input ? plan.input.text : '', plan, {} as SelfImplementSeams).childLlm ?? null;
|
|
97
|
+
} catch (caught) {
|
|
98
|
+
error = caught instanceof Error ? caught.message : String(caught);
|
|
99
|
+
}
|
|
100
|
+
setUserConfigOverlay((config) => ({ ...config, llm: { ...config.llm, provider: 'glm', model } }));
|
|
101
|
+
let banner: string;
|
|
102
|
+
// 자격이 없으면 생산 해석기가 glm 을 «배선 안 됨» 오류로 던진다 — 그 문면을 그대로 배너 칸에 싣는다(삼키지 않는다).
|
|
103
|
+
try { banner = oneLineProvider(inspectActiveProvider(getUserConfig())); }
|
|
104
|
+
catch (caught) { banner = `throw: ${caught instanceof Error ? caught.message : String(caught)}`; }
|
|
105
|
+
finally { setUserConfigOverlay(null); }
|
|
106
|
+
const result = error !== null ? 'refused' as const : childLlm?.provider === 'glm' ? 'keep' as const : 'fallback' as const;
|
|
107
|
+
return { level: GLM_NO_CREDENTIAL_LEVEL, injectionId, scenario: { zaiKey: scenario.zaiKey, openrouterKey: scenario.openrouterKey, model }, result, childLlm, error, rows, banner };
|
|
108
|
+
} finally {
|
|
109
|
+
debug.log = savedLog;
|
|
110
|
+
for (const [key, value] of Object.entries(savedEnv)) {
|
|
111
|
+
if (value === undefined) delete process.env[key];
|
|
112
|
+
else process.env[key] = value;
|
|
113
|
+
}
|
|
114
|
+
_resetKeyCacheForTests();
|
|
115
|
+
}
|
|
116
|
+
}
|