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,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* K3 knowledge pack — the coordinator reads OP knowhow from `내부 문서 `KNOWHOW``
|
|
3
|
+
* on every tick, so a doc landing alone (no code deploy) refreshes what is resident.
|
|
4
|
+
*
|
|
5
|
+
* A pack holds only items whose `상태:` is `active` **and** that carry a `재는 명령:`;
|
|
6
|
+
* every item is ordered by id and the pack carries a content hash so a reply can cite
|
|
7
|
+
* exactly which pack it read.
|
|
8
|
+
*
|
|
9
|
+
* The inbox may then *propose* an item's 처방 — it never writes, and it never changes a lock.
|
|
10
|
+
* A measurement command is executed only when it passes the read-only allowlist; when its
|
|
11
|
+
* output contradicts the item's `기대`, the advice is stale and the inbox answers 모름.
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
15
|
+
import { spawnSync } from 'node:child_process';
|
|
16
|
+
import { dirname, join } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { debug } from '../../debug/log.js';
|
|
19
|
+
|
|
20
|
+
export const KNOWHOW_PACK_VERSION = 'K3';
|
|
21
|
+
export const KNOWHOW_DOC_RELATIVE_PATH = 'docs/roles/OP/KNOWHOW.md';
|
|
22
|
+
|
|
23
|
+
export interface KnowhowItem {
|
|
24
|
+
id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
status: string;
|
|
27
|
+
situation: string;
|
|
28
|
+
signal: string;
|
|
29
|
+
prescription: string;
|
|
30
|
+
command: string;
|
|
31
|
+
expectation: string;
|
|
32
|
+
validWhen: string;
|
|
33
|
+
source: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface KnowhowPack {
|
|
37
|
+
version: string;
|
|
38
|
+
hash: string;
|
|
39
|
+
docPath: string;
|
|
40
|
+
items: KnowhowItem[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface KnowhowCommandRun {
|
|
44
|
+
status: number;
|
|
45
|
+
output: string;
|
|
46
|
+
/** Set when the runner refused to execute (placeholder, timeout, spawn failure). */
|
|
47
|
+
skipped?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type KnowhowCommandRunner = (command: string) => KnowhowCommandRun;
|
|
51
|
+
|
|
52
|
+
export interface KnowhowOptions {
|
|
53
|
+
/** Explicit doc path; otherwise `ELANOUS_KNOWHOW_DOC`, otherwise the repository copy. */
|
|
54
|
+
docPath?: string;
|
|
55
|
+
/** Working directory for measurement commands. */
|
|
56
|
+
cwd?: string;
|
|
57
|
+
/** Measurement seam: replaced by tests, defaults to the guarded read-only runner. */
|
|
58
|
+
runCommand?: KnowhowCommandRunner;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type KnowhowFreshness = 'confirmed' | 'stale' | 'unmeasured' | 'unverifiable';
|
|
62
|
+
|
|
63
|
+
export interface KnowhowMatch {
|
|
64
|
+
item: KnowhowItem;
|
|
65
|
+
score: number;
|
|
66
|
+
matchedTokens: string[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface KnowhowAdvice extends KnowhowMatch {
|
|
70
|
+
packVersion: string;
|
|
71
|
+
packHash: string;
|
|
72
|
+
freshness: KnowhowFreshness;
|
|
73
|
+
detail: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Label → item field. Labels keep their parenthetical form when the doc uses one. */
|
|
77
|
+
const FIELD_LABELS: Array<[RegExp, keyof KnowhowItem]> = [
|
|
78
|
+
[/^상황$/i, 'situation'],
|
|
79
|
+
[/^신호(?:\(관측\))?$/i, 'signal'],
|
|
80
|
+
[/^처방(?:\(힐링\))?$/i, 'prescription'],
|
|
81
|
+
[/^재는 명령$/i, 'command'],
|
|
82
|
+
[/^기대$/i, 'expectation'],
|
|
83
|
+
[/^유효 조건$/i, 'validWhen'],
|
|
84
|
+
[/^출처$/i, 'source'],
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
function stripTicks(value: string): string {
|
|
88
|
+
const trimmed = value.trim();
|
|
89
|
+
const match = /^`([\s\S]*)`$/.exec(trimmed);
|
|
90
|
+
return match ? match[1]!.trim() : trimmed;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function labeledLine(section: string, field: keyof KnowhowItem): string {
|
|
94
|
+
for (const line of section.split('\n')) {
|
|
95
|
+
const entry = /^-\s+([^:]{1,24}):\s*(.+)$/.exec(line.trim());
|
|
96
|
+
if (!entry) continue;
|
|
97
|
+
const label = entry[1]!.trim();
|
|
98
|
+
if (FIELD_LABELS.some(([pattern, name]) => name === field && pattern.test(label))) return stripTicks(entry[2]!);
|
|
99
|
+
}
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Split the markdown inventory into K items. Unknown labels are ignored, not fatal. */
|
|
104
|
+
export function parseKnowhowDoc(text: string): KnowhowItem[] {
|
|
105
|
+
const sections = text.split(/^## /m).slice(1);
|
|
106
|
+
const items: KnowhowItem[] = [];
|
|
107
|
+
for (const section of sections) {
|
|
108
|
+
const heading = /^(K-OP-(?:[A-Z]{1,4}-)?\d+)\s+(.*)$/.exec(section.split('\n', 1)[0] ?? '');
|
|
109
|
+
if (!heading) continue;
|
|
110
|
+
const item: KnowhowItem = {
|
|
111
|
+
id: heading[1]!, title: heading[2]!.trim(), status: '', situation: labeledLine(section, 'situation'),
|
|
112
|
+
signal: labeledLine(section, 'signal'), prescription: labeledLine(section, 'prescription'),
|
|
113
|
+
command: labeledLine(section, 'command'), expectation: labeledLine(section, 'expectation'),
|
|
114
|
+
validWhen: labeledLine(section, 'validWhen'), source: labeledLine(section, 'source'),
|
|
115
|
+
};
|
|
116
|
+
const status = /상태:\s*([A-Za-z][A-Za-z-]*)/.exec(item.source);
|
|
117
|
+
if (status) item.status = status[1]!;
|
|
118
|
+
if (item.status !== 'active') continue;
|
|
119
|
+
if (!item.command || /^\(없음/.test(item.command)) continue;
|
|
120
|
+
items.push(item);
|
|
121
|
+
}
|
|
122
|
+
return items.sort((a, b) => a.id.localeCompare(b.id));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function buildKnowhowPack(items: KnowhowItem[], docPath: string): KnowhowPack {
|
|
126
|
+
const body = items.map(item => [item.id, item.title, item.situation, item.signal, item.prescription,
|
|
127
|
+
item.command, item.expectation].join('\n')).join('\n---\n');
|
|
128
|
+
const hash = createHash('sha256').update(`${KNOWHOW_PACK_VERSION}\n${body}`).digest('hex').slice(0, 16);
|
|
129
|
+
return { version: KNOWHOW_PACK_VERSION, hash, docPath, items };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Marker text for a command that still carries `<...>` placeholders from the doc. */
|
|
133
|
+
const PLACEHOLDER_SOURCE = '<[^<>\\n]{1,60}>';
|
|
134
|
+
const PLACEHOLDER = new RegExp(PLACEHOLDER_SOURCE, 'g');
|
|
135
|
+
|
|
136
|
+
function repositoryRoot(): string | null {
|
|
137
|
+
let current = dirname(fileURLToPath(import.meta.url));
|
|
138
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
139
|
+
if (existsSync(join(current, KNOWHOW_DOC_RELATIVE_PATH))) return current;
|
|
140
|
+
const parent = dirname(current);
|
|
141
|
+
if (parent === current) break;
|
|
142
|
+
current = parent;
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function resolveKnowhowDocPath(explicit?: string): string | null {
|
|
148
|
+
if (explicit) return existsSync(explicit) ? explicit : null;
|
|
149
|
+
const fromEnv = process.env.ELANOUS_KNOWHOW_DOC;
|
|
150
|
+
if (fromEnv) return existsSync(fromEnv) ? fromEnv : null;
|
|
151
|
+
if (existsSync(join(process.cwd(), KNOWHOW_DOC_RELATIVE_PATH))) return join(process.cwd(), KNOWHOW_DOC_RELATIVE_PATH);
|
|
152
|
+
const root = repositoryRoot();
|
|
153
|
+
return root ? join(root, KNOWHOW_DOC_RELATIVE_PATH) : null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const packCache = new Map<string, { stamp: string; pack: KnowhowPack }>();
|
|
157
|
+
|
|
158
|
+
/** Resident pack for one tick: re-read whenever the doc's mtime/size changes. */
|
|
159
|
+
export function loadKnowhowPack(docPath: string): KnowhowPack | null {
|
|
160
|
+
if (!existsSync(docPath)) return null;
|
|
161
|
+
let stamp: string;
|
|
162
|
+
try {
|
|
163
|
+
const info = statSync(docPath);
|
|
164
|
+
stamp = `${info.mtimeMs}:${info.size}`;
|
|
165
|
+
} catch { return null; }
|
|
166
|
+
const cached = packCache.get(docPath);
|
|
167
|
+
if (cached && cached.stamp === stamp) return cached.pack;
|
|
168
|
+
const pack = buildKnowhowPack(parseKnowhowDoc(readFileSync(docPath, 'utf8')), docPath);
|
|
169
|
+
packCache.set(docPath, { stamp, pack });
|
|
170
|
+
debug.log('loop.knowhow-pack', 'load', { version: pack.version, hash: pack.hash,
|
|
171
|
+
items: pack.items.length, docPath });
|
|
172
|
+
return pack;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const STOPWORDS = new Set(['그리고', '그러나', '하지만', '그러면', '어떻게', '무엇', '뭐가', '뭘', '이거', '그거',
|
|
176
|
+
'저거', '지금', '오늘', '내일', '확인', '요청', '질문', '경우', '때문', '때는', '먼저', '다시', '대한', '위해',
|
|
177
|
+
'에서', '으로', '하는', '하지', '한다', '있다', '없다', '같다', '되는', '되나', '됐다', '있나', '인가', '무슨',
|
|
178
|
+
'어느', '이런', '그런', '저런', '좀', '더', '또는', '그게', '이게', '저게', '합니까', '인지', '하는데',
|
|
179
|
+
'보다', '라며', '해도', '하면', '해서', '부터', '까지', '아직', '이미', '모두', '이후', '이전', '동안',
|
|
180
|
+
'the', 'and', 'for', 'you', 'can', 'this', 'that', 'what', 'which', 'how', 'why', 'when', 'with', 'from',
|
|
181
|
+
'are', 'was', 'were', 'has', 'have', 'had', 'not', 'but', 'all', 'any', 'our', 'your', 'its', 'it', 'is',
|
|
182
|
+
'of', 'to', 'in', 'on', 'do', 'does', 'did', 'please', 'anyone']);
|
|
183
|
+
|
|
184
|
+
const KOREAN_SUFFIXES = ['에서부터', '으로부터', '에서는', '으로는', '이었습니다', '했습니다', '됩니다', '됐습니다',
|
|
185
|
+
'합니까', '했나요', '되나요', '인가요', '에서', '으로', '부터', '까지', '했나', '됐나', '되나', '했지', '하지',
|
|
186
|
+
'됐다', '한다', '된다', '이다', '있다', '없다', '었던', '였던', '라는', '이라', '거나', '면서', '지만',
|
|
187
|
+
'에게', '한테', '보다', '처럼', '만큼', '라고', '하고', '해도', '하면', '인데', '나요', '가요', '세요',
|
|
188
|
+
'은', '는', '을', '를', '이', '가', '의', '에', '와', '과', '로', '도', '만', '라', '며', '서', '나', '고', '면'];
|
|
189
|
+
|
|
190
|
+
function normalizeToken(raw: string): string {
|
|
191
|
+
let token = raw.toLowerCase();
|
|
192
|
+
for (const suffix of KOREAN_SUFFIXES) {
|
|
193
|
+
if (token.length > suffix.length + 1 && token.endsWith(suffix)) {
|
|
194
|
+
token = token.slice(0, -suffix.length);
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return token;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function tokenize(text: string): string[] {
|
|
202
|
+
const tokens: string[] = [];
|
|
203
|
+
for (const raw of text.toLowerCase().split(/[^0-9a-z가-힣-]+/)) {
|
|
204
|
+
const token = normalizeToken(raw);
|
|
205
|
+
if (token.length < 2 || STOPWORDS.has(raw) || STOPWORDS.has(token)) continue;
|
|
206
|
+
if (/^\d+$/.test(token)) continue;
|
|
207
|
+
tokens.push(token);
|
|
208
|
+
}
|
|
209
|
+
return tokens;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function tokensMatch(a: string, b: string): boolean {
|
|
213
|
+
if (a === b) return true;
|
|
214
|
+
if (a.length >= 3 && b.length >= 3 && (a.startsWith(b) || b.startsWith(a))) return true;
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const MIN_MATCH_SCORE = 2.2;
|
|
219
|
+
const MIN_MATCH_TOKENS = 2;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Match a question against the pack item text (title ⊕ 상황 ⊕ 신호) using inverse document
|
|
223
|
+
* frequency, so a word shared by most items ("착지", "PR") cannot carry a match alone.
|
|
224
|
+
*/
|
|
225
|
+
export function matchKnowhowItem(pack: KnowhowPack, question: string, minScore = MIN_MATCH_SCORE): KnowhowMatch | null {
|
|
226
|
+
const questionTokens = [...new Set(tokenize(question))];
|
|
227
|
+
if (questionTokens.length === 0 || pack.items.length === 0) return null;
|
|
228
|
+
const itemTokens = pack.items.map(item => [...new Set(tokenize(`${item.title} ${item.situation} ${item.signal}`))]);
|
|
229
|
+
const total = pack.items.length;
|
|
230
|
+
const scored = pack.items.map((item, index) => {
|
|
231
|
+
const matched: string[] = [];
|
|
232
|
+
let score = 0;
|
|
233
|
+
for (const token of questionTokens) {
|
|
234
|
+
const hits = itemTokens.filter(tokens => tokens.some(candidate => tokensMatch(token, candidate))).length;
|
|
235
|
+
if (hits === 0 || !itemTokens[index]!.some(candidate => tokensMatch(token, candidate))) continue;
|
|
236
|
+
matched.push(token);
|
|
237
|
+
score += Math.log((total + 1) / (hits + 0.5));
|
|
238
|
+
}
|
|
239
|
+
return { item, score: Number(score.toFixed(3)), matchedTokens: matched };
|
|
240
|
+
}).sort((a, b) => b.score - a.score || a.item.id.localeCompare(b.item.id));
|
|
241
|
+
const best = scored[0];
|
|
242
|
+
if (!best || best.matchedTokens.length < MIN_MATCH_TOKENS || best.score < minScore) return null;
|
|
243
|
+
return best;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const READ_ONLY_BINARIES = new Set(['rg', 'grep', 'cat', 'head', 'tail', 'wc', 'ls', 'jq', 'awk', 'find',
|
|
247
|
+
'sort', 'uniq', 'cut', 'echo', 'pwd', 'stat', 'file', 'date', 'printf', 'true', 'test']);
|
|
248
|
+
const GIT_READ_ONLY_SUBCOMMANDS = new Set(['status', 'log', 'show', 'diff', 'rev-parse', 'rev-list',
|
|
249
|
+
'ls-files', 'ls-tree', 'worktree', 'shortlog', 'blame', 'describe', 'branch', 'tag', 'remote', 'config', 'cat-file']);
|
|
250
|
+
const GIT_WRITE_ARGS = new Set(['-d', '-D', '-m', '-M', '--delete', '--move', '--force', '--set', '--unset',
|
|
251
|
+
'--add', '--edit', '--prune', 'add', 'commit', 'push', 'merge', 'reset', 'checkout', 'switch', 'clean',
|
|
252
|
+
'rm', 'mv', 'apply', 'stash', 'gc', 'update-ref', 'submodule', 'rebase', 'cherry-pick', 'revert']);
|
|
253
|
+
const ELANOUSH_READ_ONLY: Record<string, string[] | null> = {
|
|
254
|
+
logs: null, 'tasks:show': null, 'tasks:list': null,
|
|
255
|
+
release: ['checklist'], decisions: ['list'], msg: ['list'], memory: ['list'],
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export type ReadOnlyVerdict = { ok: true } | { ok: false; reason: string };
|
|
259
|
+
|
|
260
|
+
/** Allowlist guard: only commands that cannot mutate the repository or the ledgers run. */
|
|
261
|
+
export function isReadOnlyCommand(command: string): ReadOnlyVerdict {
|
|
262
|
+
const stripped = command.replace(PLACEHOLDER, ' ');
|
|
263
|
+
if (!stripped.trim()) return { ok: false, reason: 'empty command' };
|
|
264
|
+
if (/[<>`$]|[;\n]/.test(stripped)) return { ok: false, reason: 'shell redirect, substitution or sequence' };
|
|
265
|
+
const segments = stripped.split(/\s*(?:&&|\|\||\||&)\s*/).map(part => part.trim()).filter(Boolean);
|
|
266
|
+
if (segments.length === 0) return { ok: false, reason: 'empty command' };
|
|
267
|
+
for (const segment of segments) {
|
|
268
|
+
const words = segment.split(/\s+/);
|
|
269
|
+
const binary = words[0]!.replace(/^.*\//, '');
|
|
270
|
+
const args = words.slice(1);
|
|
271
|
+
if (binary === 'git') {
|
|
272
|
+
const sub = args.find(word => !word.startsWith('-'));
|
|
273
|
+
if (!sub) return { ok: false, reason: 'git without subcommand' };
|
|
274
|
+
if (!GIT_READ_ONLY_SUBCOMMANDS.has(sub)) return { ok: false, reason: `git ${sub} is not read-only` };
|
|
275
|
+
if (args.some(word => GIT_WRITE_ARGS.has(word))) return { ok: false, reason: `git ${sub} write flag` };
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (binary === 'eln' || binary === 'elanous') {
|
|
279
|
+
const verbs = args.filter(word => !word.startsWith('-'));
|
|
280
|
+
const [first, second, third] = verbs;
|
|
281
|
+
// `eln tasks show` and `eln release checklist status` name the verb in two words.
|
|
282
|
+
if (first && second && `${first}:${second}` in ELANOUSH_READ_ONLY) {
|
|
283
|
+
const allowed = ELANOUSH_READ_ONLY[`${first}:${second}`];
|
|
284
|
+
if (allowed && (!third || !allowed.includes(third))) {
|
|
285
|
+
return { ok: false, reason: `${binary} ${first} ${second} ${third ?? ''} is not read-only` };
|
|
286
|
+
}
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (!first || !(first in ELANOUSH_READ_ONLY)) return { ok: false, reason: `${binary} ${first ?? ''} is not read-only` };
|
|
290
|
+
const allowed = ELANOUSH_READ_ONLY[first];
|
|
291
|
+
if (allowed && (!second || !allowed.includes(second))) return { ok: false, reason: `${binary} ${first} ${second ?? ''} is not read-only` };
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (!READ_ONLY_BINARIES.has(binary)) return { ok: false, reason: `${binary} is not on the read-only allowlist` };
|
|
295
|
+
}
|
|
296
|
+
return { ok: true };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export type ExpectationVerdict = 'confirmed' | 'stale' | 'unverifiable';
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Compare a measurement output against the item's 기대. Only machine-checkable wordings
|
|
303
|
+
* are judged: `N 줄/건/개` (exact count) and `≥N` / `N 이상` (lower bound).
|
|
304
|
+
*/
|
|
305
|
+
export function evaluateExpectation(expectation: string, output: string): { verdict: ExpectationVerdict; detail: string } {
|
|
306
|
+
const lines = output.split('\n').map(line => line.trim()).filter(line => line.length > 0);
|
|
307
|
+
const counted = /(\d+)\s*(줄|행|건|개|line)/.exec(expectation);
|
|
308
|
+
if (counted) {
|
|
309
|
+
const expected = Number(counted[1]);
|
|
310
|
+
const ok = lines.length === expected;
|
|
311
|
+
return { verdict: ok ? 'confirmed' : 'stale', detail: `기대 ${expected}${counted[2]} · 실제 ${lines.length}줄` };
|
|
312
|
+
}
|
|
313
|
+
const lower = /(?:[≥>=]\s*(\d+))|(?:(\d+)\s*이상)/.exec(expectation);
|
|
314
|
+
if (lower) {
|
|
315
|
+
const expected = Number(lower[1] ?? lower[2]);
|
|
316
|
+
const numbers = (output.match(/\d+/g) ?? []).map(Number);
|
|
317
|
+
const ok = numbers.length > 0 && numbers.every(value => value >= expected);
|
|
318
|
+
return { verdict: ok ? 'confirmed' : 'stale',
|
|
319
|
+
detail: `기대 ≥${expected} · 실제 ${numbers.length > 0 ? numbers.join(',') : '(수 없음)'}` };
|
|
320
|
+
}
|
|
321
|
+
if (!lines.length) return { verdict: 'stale', detail: '기대 비교 불가 · 재는 명령 출력이 비었다' };
|
|
322
|
+
return { verdict: 'unverifiable', detail: `기대 문면: ${expectation.slice(0, 120)} — 자동 비교 규칙 없음` };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Default runner: guarded, bounded, and never shells a doc placeholder. */
|
|
326
|
+
export function readOnlyRunner(cwd: string): KnowhowCommandRunner {
|
|
327
|
+
return (command: string): KnowhowCommandRun => {
|
|
328
|
+
const verdict = isReadOnlyCommand(command);
|
|
329
|
+
if (!verdict.ok) return { status: -1, output: '', skipped: verdict.reason };
|
|
330
|
+
if (new RegExp(PLACEHOLDER_SOURCE).test(command)) return { status: -1, output: '', skipped: 'placeholder 미치환' };
|
|
331
|
+
const run = spawnSync('bash', ['-c', command], { cwd, encoding: 'utf8', timeout: 15_000, maxBuffer: 1 << 20 });
|
|
332
|
+
if (run.error) return { status: -1, output: '', skipped: run.error.message.slice(0, 120) };
|
|
333
|
+
return { status: run.status ?? -1, output: `${run.stdout ?? ''}${run.stderr ?? ''}` };
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export function measureKnowhowItem(
|
|
338
|
+
item: KnowhowItem, run: KnowhowCommandRunner,
|
|
339
|
+
): { freshness: KnowhowFreshness; detail: string } {
|
|
340
|
+
const verdict = isReadOnlyCommand(item.command);
|
|
341
|
+
if (!verdict.ok) return { freshness: 'unmeasured', detail: `재지 못함 — ${verdict.reason} (읽기 전용 허용 목록 밖)` };
|
|
342
|
+
const result = run(item.command);
|
|
343
|
+
if (result.skipped) return { freshness: 'unmeasured', detail: `재지 못함 — ${result.skipped}` };
|
|
344
|
+
if (result.status !== 0) return { freshness: 'unmeasured', detail: `재지 못함 — rc=${result.status}` };
|
|
345
|
+
const judged = evaluateExpectation(item.expectation, result.output);
|
|
346
|
+
return { freshness: judged.verdict, detail: judged.detail };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** The advice the inbox may propose: item ⊕ pack identity ⊕ freshness of its measurement. */
|
|
350
|
+
export function knowhowAdvice(question: string, options: KnowhowOptions = {}): KnowhowAdvice | null {
|
|
351
|
+
const docPath = resolveKnowhowDocPath(options.docPath);
|
|
352
|
+
if (!docPath) return null;
|
|
353
|
+
const pack = loadKnowhowPack(docPath);
|
|
354
|
+
if (!pack) return null;
|
|
355
|
+
const match = matchKnowhowItem(pack, question);
|
|
356
|
+
if (!match) return null;
|
|
357
|
+
const run = options.runCommand ?? readOnlyRunner(options.cwd ?? process.cwd());
|
|
358
|
+
const measured = measureKnowhowItem(match.item, run);
|
|
359
|
+
const advice: KnowhowAdvice = { ...match, packVersion: pack.version, packHash: pack.hash,
|
|
360
|
+
freshness: measured.freshness, detail: measured.detail };
|
|
361
|
+
debug.log('loop.knowhow-pack', 'advice', { id: match.item.id, score: match.score,
|
|
362
|
+
freshness: advice.freshness, packHash: pack.hash });
|
|
363
|
+
return advice;
|
|
364
|
+
}
|
|
@@ -24,6 +24,7 @@ import { seatCapDetails } from '../budget.js';
|
|
|
24
24
|
export { isLaunchEligible } from './traffic.js';
|
|
25
25
|
import { readTaskAgentState, TASK_SEATS, type HandTaskOptions, type TaskCard as TaskAgentCard, type HandTaskResult, type TaskLauncher, type TaskSeat } from '../../task-agent/task-hand.js';
|
|
26
26
|
import { runCoordinatorAgentInbox, runCoordinatorInbox, type CoordinatorInboxResult } from './inbox.js';
|
|
27
|
+
import type { KnowhowOptions } from './knowhow-pack.js';
|
|
27
28
|
import { loadAgentRolePack, type AgentReplyInput } from '../agent-reply.js';
|
|
28
29
|
import type { LLMProvider } from '../../llm.js';
|
|
29
30
|
|
|
@@ -90,6 +91,8 @@ export interface TickDeps {
|
|
|
90
91
|
/** Production still uses the restricted turn; tests can supply a deterministic turn. */
|
|
91
92
|
coordinatorAgentRun?: AgentReplyInput['runAgent'];
|
|
92
93
|
coordinatorAgentProvider?: LLMProvider;
|
|
94
|
+
/** Resident knowhow pack seam; the real intake reads 내부 문서 `KNOWHOW` every tick. */
|
|
95
|
+
coordinatorKnowhow?: KnowhowOptions | false;
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
/** ORCH-TA-HAND ledger — one row per handed `orch:<card>:<cell>` key so a cell is handed once across ticks and processes. */
|
|
@@ -498,7 +501,8 @@ export async function runOrchestratorNode(node: Node, deps: TickDeps = {}): Prom
|
|
|
498
501
|
? runCoordinatorAgentInbox({ role, pack: loadAgentRolePack('coordinator'), path: inboxPath, root,
|
|
499
502
|
...(deps.coordinatorAgentRun ? { runAgent: deps.coordinatorAgentRun } : {}),
|
|
500
503
|
...(deps.coordinatorAgentProvider ? { provider: deps.coordinatorAgentProvider } : {}) })
|
|
501
|
-
: runCoordinatorInbox(undefined, 100, inboxPath
|
|
504
|
+
: runCoordinatorInbox(undefined, 100, inboxPath,
|
|
505
|
+
deps.coordinatorKnowhow === undefined ? {} : { knowhow: deps.coordinatorKnowhow });
|
|
502
506
|
}))();
|
|
503
507
|
if (inbox.replied || inbox.acknowledged) {
|
|
504
508
|
observe('exchange', 'coordinator-inbox-replied', inbox.replied);
|
|
@@ -62,7 +62,7 @@ export const FEATURE_MATURITY = {
|
|
|
62
62
|
preview: 'beta', pty: 'beta', pr: 'beta', repo: 'beta', role: 'beta', machine: 'beta', image: 'beta', 'agent-env': 'beta',
|
|
63
63
|
where: 'stable', bench: 'beta', shadow: 'beta', llm: 'beta', storage: 'beta', leader: 'beta',
|
|
64
64
|
pod: 'beta', browser: 'beta', questions: 'beta', usage: 'stable', live: 'beta',
|
|
65
|
-
research: 'beta', release: 'beta', rfc: 'beta', know: 'beta', freeze: 'beta', flow: 'beta', seat: 'beta', hq: 'beta', steward: 'beta', coord: 'beta', context: 'beta', 'model-watch': 'beta', doctor: 'stable',
|
|
65
|
+
research: 'beta', release: 'beta', rfc: 'beta', know: 'beta', freeze: 'beta', herdr: 'beta', flow: 'beta', seat: 'beta', hq: 'beta', steward: 'beta', coord: 'beta', context: 'beta', 'model-watch': 'beta', doctor: 'stable',
|
|
66
66
|
control: 'beta', resources: 'beta', hooks: 'beta', setup: 'stable', start: 'stable',
|
|
67
67
|
grounding: 'beta', graph: 'beta', loop: 'stable', resource: 'beta', card: 'stable', 'launch-head': 'beta',
|
|
68
68
|
a2a: 'beta', plugin: 'stable', make: 'beta', skills: 'beta', connect: 'beta', import: 'beta',
|
package/src/models/prompts.ts
CHANGED
|
@@ -189,7 +189,14 @@ export function getModelTier(
|
|
|
189
189
|
|
|
190
190
|
/** Minimal tool-call hygiene for older GPT/o-series models. Kept
|
|
191
191
|
* short and generic so stronger providers do not get burdened with
|
|
192
|
-
* Codex-specific anti-loop rules they do not need.
|
|
192
|
+
* Codex-specific anti-loop rules they do not need.
|
|
193
|
+
*
|
|
194
|
+
* TUI-OPS-TURN-GUARD gap ② (2026-10-22): rule 4 states the ops-turn
|
|
195
|
+
* guard split — it must live here too, not only in the codex addon,
|
|
196
|
+
* because gpt-6 ids stay in the 'gpt' family (usesCodexBehaviorGuards
|
|
197
|
+
* widens the behavior predicate, not the family) and gpt-6 models run
|
|
198
|
+
* those llm.ts phase guards. The tool names mirror the allow lists in
|
|
199
|
+
* src/llm/tool-loop-steered-rejection.ts that llm.ts consumes. */
|
|
193
200
|
const TOOL_DISCIPLINE_GPT = [
|
|
194
201
|
'',
|
|
195
202
|
'## Tool-call hygiene',
|
|
@@ -197,6 +204,7 @@ const TOOL_DISCIPLINE_GPT = [
|
|
|
197
204
|
'1. NEVER call the same tool with identical arguments twice in a row. If you already Read a file, use its previous tool_result from history — do not re-Read.',
|
|
198
205
|
'2. After each tool_result, emit AT LEAST one sentence of reasoning (what you learned, what you will do next) BEFORE issuing the next tool call. Silent tool-spam is a failure mode we actively block.',
|
|
199
206
|
'3. If any tool_result contains "DUPLICATE CALL", "RUNTIME BLOCKED", "TOOL CALL REJECTED", or "SYSTEM BUDGET NOTICE" — STOP. Your next output MUST be plain text (the final answer or a clear "impossible because X"), not another tool call.',
|
|
207
|
+
'4. Ops turns (TUI-OPS-TURN-GUARD): read-only ops observation tools (`logs_query`, `PtyShellPoll`) stay runnable mid-ops-turn — keep observing the run with them. Write-capable ops tools (`schedule_manage`, `se_build`) are phase-governed: when one returns "TOOL CALL REJECTED" it is out of phase for this turn — do not retry it; rule 3 applies (finish in plain text).',
|
|
200
208
|
'',
|
|
201
209
|
].join('\n');
|
|
202
210
|
|
|
@@ -204,7 +212,13 @@ const TOOL_DISCIPLINE_GPT = [
|
|
|
204
212
|
* Their common failure mode is read-only polling on stable state
|
|
205
213
|
* (Read / GetDashboardState / similar) instead of acting on the
|
|
206
214
|
* result they already have. Keep this focused on tool-loop hygiene,
|
|
207
|
-
* not orchestration prose.
|
|
215
|
+
* not orchestration prose.
|
|
216
|
+
*
|
|
217
|
+
* TUI-OPS-TURN-GUARD gap ② (2026-10-22): rule 5 states the ops-turn
|
|
218
|
+
* guard split so the prompt half matches the ACTION_PHASE_OPS_TOOLS /
|
|
219
|
+
* REPAIR_PHASE_READ_ONLY_OPS_TOOLS allow lists llm.ts consumes —
|
|
220
|
+
* read-only ops observation stays runnable mid-ops-turn, write-capable
|
|
221
|
+
* ops tools stay phase-governed. */
|
|
208
222
|
const TOOL_DISCIPLINE_CODEX = [
|
|
209
223
|
'',
|
|
210
224
|
'## Tool-call hygiene',
|
|
@@ -213,6 +227,7 @@ const TOOL_DISCIPLINE_CODEX = [
|
|
|
213
227
|
'2. Treat read-only state tools as stable within the current turn. Do NOT re-call a state-inspection tool unless an intervening action could have changed the state.',
|
|
214
228
|
'3. After each tool_result, emit AT LEAST one sentence of reasoning (what you learned, what you will do next) BEFORE issuing the next tool call.',
|
|
215
229
|
'4. If any tool_result contains "DUPLICATE CALL", "RUNTIME BLOCKED", "TOOL CALL REJECTED", or "SYSTEM BUDGET NOTICE" — STOP. Your next output MUST be plain text, not another tool call.',
|
|
230
|
+
'5. Ops turns (TUI-OPS-TURN-GUARD): read-only ops observation tools (`logs_query`, `PtyShellPoll`) stay runnable mid-ops-turn — keep observing the run with them. Write-capable ops tools (`schedule_manage`, `se_build`) are phase-governed: when one returns "TOOL CALL REJECTED" it is out of phase for this turn — do not retry it; rule 4 applies (finish in plain text).',
|
|
216
231
|
'',
|
|
217
232
|
].join('\n');
|
|
218
233
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// ── 우편국(post office) 발견 ⊕ 재시작 — `msg serve --sse` 가 자기 포트를 적고, `msg post` 가 죽은 것을 다시 띄운다 ──
|
|
2
|
+
//
|
|
3
|
+
// 왜 «발견 파일» 인가: `eln msg serve --sse` 는 원장을 빨리 밀어 주는 별도 프로세스이고 설치본을 갈아 끼우면
|
|
4
|
+
// 그 프로세스는 조용히 사라진다. `watch --sse` 는 폴링으로 돌아가므로 «동작은 하지만» 구독자는 늦어진다.
|
|
5
|
+
// 서비스가 자기 포트·pid 를 `<상태 루트>/msg/sse.json` 에 적으면, 글을 저장한 «뒤» post 경로가
|
|
6
|
+
// 그 줄을 읽어 «응답하지 않는 우편국» 을 같은 포트로 한 번 다시 띄울 수 있다.
|
|
7
|
+
//
|
|
8
|
+
// ⛔ 원장이 정본이다 — 다시 띄운 서비스는 저장된 글을 처음부터(=`since`·`Last-Event-ID`) 재생하므로
|
|
9
|
+
// 서비스가 죽어 있던 동안 저장된 글도 잃지 않는다.
|
|
10
|
+
// ⛔ 재시작은 글의 성패를 바꾸지 않는다 — 어떤 실패도 결과 값으로만 돌아온다(fail-open).
|
|
11
|
+
// ⛔ 시험 우주에서는 실제 프로세스를 띄우지 않는다 — `ELANOUS_MSG_SSE_LIVE=1` 로만 연다(격리 실물 시험용).
|
|
12
|
+
|
|
13
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
14
|
+
import { dirname, join } from 'node:path';
|
|
15
|
+
|
|
16
|
+
import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
|
|
17
|
+
|
|
18
|
+
export interface PostOfficeInfo {
|
|
19
|
+
/** Loopback port the SSE service answers on. */
|
|
20
|
+
port: number;
|
|
21
|
+
/** Process that wrote the line; a dead pid means the service is gone. */
|
|
22
|
+
pid: number;
|
|
23
|
+
url: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type PostOfficeEnsure =
|
|
27
|
+
| { state: 'absent' }
|
|
28
|
+
| { state: 'skipped'; reason: string }
|
|
29
|
+
| { state: 'listening'; port: number }
|
|
30
|
+
| { state: 'restarted'; port: number };
|
|
31
|
+
|
|
32
|
+
/** `<상태 루트>/msg/sse.json` — the ledger directory `msg serve` and `msg post` already share. */
|
|
33
|
+
export function postOfficeFile(stateRoot: string): string {
|
|
34
|
+
return join(stateRoot, 'msg', 'sse.json');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The recorded service, or null when nothing registered one — 파일이 없으면 «모름»이지 «서비스 없음»의 측정이 아니다. */
|
|
38
|
+
export function readPostOffice(stateRoot: string): PostOfficeInfo | null {
|
|
39
|
+
let raw: unknown;
|
|
40
|
+
try { raw = JSON.parse(readFileSync(postOfficeFile(stateRoot), 'utf8')); }
|
|
41
|
+
catch { return null; }
|
|
42
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;
|
|
43
|
+
const { port, pid } = raw as { port?: unknown; pid?: unknown };
|
|
44
|
+
if (typeof port !== 'number' || !Number.isSafeInteger(port) || port < 0 || port > 65535) return null;
|
|
45
|
+
if (typeof pid !== 'number' || !Number.isSafeInteger(pid) || pid <= 0) return null;
|
|
46
|
+
return { port, pid, url: `http://127.0.0.1:${port}` };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Called by `msg serve --sse` right after the service binds its port. */
|
|
50
|
+
export function writePostOffice(stateRoot: string, info: { port: number; pid?: number }): PostOfficeInfo {
|
|
51
|
+
const path = postOfficeFile(stateRoot);
|
|
52
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
53
|
+
const value: PostOfficeInfo = { port: info.port, pid: info.pid ?? process.pid, url: `http://127.0.0.1:${info.port}` };
|
|
54
|
+
writeFileSync(path, `${JSON.stringify(value)}\n`);
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Called when the service stops — only the writer's own line is removed, never a newer one. */
|
|
59
|
+
export function clearPostOffice(stateRoot: string, pid: number = process.pid): boolean {
|
|
60
|
+
const current = readPostOffice(stateRoot);
|
|
61
|
+
if (current !== null && current.pid !== pid) return false;
|
|
62
|
+
try { rmSync(postOfficeFile(stateRoot), { force: true }); return true; }
|
|
63
|
+
catch { return false; }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function pidAlive(pid: number): boolean {
|
|
67
|
+
try { process.kill(pid, 0); return true; } catch { return false; }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Any HTTP answer (401 included) means the service is listening; silence means it is gone. */
|
|
71
|
+
async function probePostOffice(url: string): Promise<boolean> {
|
|
72
|
+
try {
|
|
73
|
+
const response = await fetch(`${url}/stream`, { signal: AbortSignal.timeout(500) });
|
|
74
|
+
try { await response.body?.cancel(); } catch { /* body already closed */ }
|
|
75
|
+
return true;
|
|
76
|
+
} catch { return false; }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function liveUniverse(): boolean {
|
|
80
|
+
return effectiveInstanceRoot() === prodInstanceRoot() || process.env.ELANOUS_MSG_SSE_LIVE === '1';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Restart the same installed CLI entry that is running this command — `eln msg serve --sse --port <p>`. */
|
|
84
|
+
function spawnPostOffice({ port }: { port: number }): void {
|
|
85
|
+
const entry = process.argv[1];
|
|
86
|
+
if (!entry) throw new Error('post office restart needs the running CLI entry (process.argv[1])');
|
|
87
|
+
const child = Bun.spawn([process.execPath, entry, 'msg', 'serve', '--sse', '--port', String(port)], {
|
|
88
|
+
detached: true, stdio: ['ignore', 'ignore', 'ignore'], env: process.env,
|
|
89
|
+
});
|
|
90
|
+
(child as unknown as { unref?: () => void }).unref?.();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface EnsurePostOfficeInput {
|
|
94
|
+
/** State root that holds `msg/sse.json`. */
|
|
95
|
+
stateRoot: string;
|
|
96
|
+
/** Test seam — liveness of the recorded pid (default: signal 0). */
|
|
97
|
+
alive?: (pid: number) => boolean;
|
|
98
|
+
/** Test seam — does the recorded service answer on its port? (default: one HTTP probe). */
|
|
99
|
+
probe?: (url: string) => Promise<boolean>;
|
|
100
|
+
/** Test seam / fake-bin — start a new service on the recorded port. */
|
|
101
|
+
launch?: (input: { port: number }) => void;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Restart a registered post office that no longer answers. Absent registration and a live service are no-ops,
|
|
106
|
+
* so a plain `msg post` keeps its current behavior.
|
|
107
|
+
*/
|
|
108
|
+
export async function ensurePostOffice(input: EnsurePostOfficeInput): Promise<PostOfficeEnsure> {
|
|
109
|
+
const info = readPostOffice(input.stateRoot);
|
|
110
|
+
if (info === null) return { state: 'absent' };
|
|
111
|
+
const alive = (input.alive ?? pidAlive)(info.pid);
|
|
112
|
+
if (alive && await (input.probe ?? probePostOffice)(info.url)) return { state: 'listening', port: info.port };
|
|
113
|
+
if (input.launch === undefined && !liveUniverse()) return { state: 'skipped', reason: 'test-universe' };
|
|
114
|
+
(input.launch ?? spawnPostOffice)({ port: info.port });
|
|
115
|
+
return { state: 'restarted', port: info.port };
|
|
116
|
+
}
|