elanous 0.2.41 → 0.2.42
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/{GiOLWmt4MqDZePubBjA4Q → X1ucLw10Cds_h614NoEnh}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5159.115f1c2ca471386c.js → 1063.2fb8a9dc55c731f2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +36 -0
- package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9048.212083de42d25be3.js → 1262.e804feb8fd1acb8c.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4527.a69f2894d1bc9f4a.js → 1487.2f67b79444062da6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +32 -0
- package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +286 -0
- package/apps/pwa/out/_next/static/chunks/2160.a097e7b138ae1c55.js +23 -0
- package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +34 -0
- package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +1 -0
- package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{530.d26346e18089640a.js → 2690.0521c738b7749931.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4702.4a4adc1f16d7c93b.js → 2974.595d1e29d040cb6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2263.e09b6edea33bad2d.js → 3207.a756c95e9ec8c3c8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9541.eb8e2f8480c7feca.js → 3285.89ee2f298682f5e5.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{9507.7026657a2f47eb64.js → 3347.f846266b5e5f3ede.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +41 -0
- package/apps/pwa/out/_next/static/chunks/{1178.1aa9cad0e7695427.js → 3482.a9ae9d2ad6a5bd97.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3507.97e1977bc4d5fb0a.js +2 -0
- package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +24 -0
- package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1661.0dd330f3d89f73f3.js → 3837.a210d7d0db8d8abd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2fdf2931.b431eee4fb468bc3.js → 3d0154af.5331fec737ffe8c3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4043.6b91203436c9c86b.js +309 -0
- package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +77 -0
- package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +148 -0
- package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +74 -0
- package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{1115.434ae2ecb0ad986d.js → 5112.4b9f300124fab7b3.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +27 -0
- package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5885.0a3e52c8faccec98.js +287 -0
- package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +226 -0
- package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +90 -0
- package/apps/pwa/out/_next/static/chunks/{2073.689dcb2680113d76.js → 6377.bc7df239edbff244.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1800.f7ff51dc4978a958.js → 6632.0eac1c554f8f2ef3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +104 -0
- package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +94 -0
- package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2527-5c636a43c7cc5dde.js → 7279-c199ea83f34338fa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{385e4574.e9886ab32759eda3.js → 73d2eb0e.4966ad55293c801a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5471.1e611302ed3a7c53.js → 7411.9b4b8b747dc7b802.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +1 -0
- package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2fe2c302.41b517f88d6fe502.js → 7a98bc80.fa935989e829f9c2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8138.6c10b2a356d52fca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5574.f35accf4f132b29d.js → 8262.ddc03e06b733f184.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +8 -0
- package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +79 -0
- package/apps/pwa/out/_next/static/chunks/{8050-9b364bdef8f71927.js → 8546-6f03f8ea34dd61d9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5947-135e26537d80a6b9.js → 8673-bab689a55f7e13b9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5937.c2df9e3447e1f667.js → 9249.976f1e69a9d80754.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1971-7efb628c471dc5a0.js → 9353-12bfff0c130104cf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7191.fdc955f7d96064a4.js → 9415.69e4a21c60c7d2db.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1219.7e17964e0e7cd8e5.js → 9427.96aa912ddb5801e0.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5964-7e21164a8f2cf0ce.js → 9656-374232558fd528d0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6552.a3840aa7da35ad68.js → 9832.f4a98c878ecf2c0a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9a852a62-6192a6ea9346ced3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{a0a01613.6d1cca322238d7fe.js → b450776b.3db34d8d965f82d3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{c0c1a699.0ba79f97005965d4.js → e8543907.5b040a5f22a0b0e5.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +1 -0
- package/apps/pwa/out/_next/static/css/{b9d8151e48998417.css → 62c858ad53854f47.css} +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 +23 -24
- 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 +22 -22
- 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 +23 -24
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -24
- 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/04-mock-scenarios.md +13 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/heal/heal-loop.yaml +1 -0
- package/graphs/overlays/stop-heal-ladder.yaml +113 -0
- package/graphs/units/verbs/recipes.yaml +11 -11
- package/graphs/work/research-report.yaml +10 -2
- package/package.json +1 -1
- package/scripts/heal/run-role.ts +99 -5
- package/scripts/land-global-checks.ts +6 -1
- package/scripts/lib/decompose-ab.ts +1 -0
- package/scripts/lib/fixtures/tui-regress/help-insufficient-commands.txt +15 -0
- package/scripts/lib/fixtures/tui-regress/help-live.txt +42 -0
- package/scripts/lib/fixtures/tui-regress/help-missing-keys.txt +21 -0
- package/scripts/lib/fixtures/tui-regress/help-original.txt +51 -0
- package/scripts/lib/fixtures/tui-regress/help-shifted-input.txt +26 -0
- package/scripts/lib/tui-regress-checks.ts +33 -13
- package/scripts/release-loop/gate-baseline-receipt.ts +47 -9
- package/scripts/release-loop/gate-image-pin.ts +81 -0
- package/scripts/release-loop/gate-node-sim.ts +207 -0
- package/scripts/release-loop/gate-node.ts +285 -46
- package/scripts/release-loop/gate-pod-image-sticky-plan.ts +99 -0
- package/scripts/release-loop/gate-radius-live.ts +97 -13
- package/scripts/release-loop/gate-shard-dispatch.ts +43 -0
- package/scripts/release-loop/gate-train-receipts.ts +122 -0
- package/scripts/release-loop/resume-release.ts +83 -8
- package/scripts/ux-sim.ts +18 -1
- package/scripts/warm-pool-provider-config.ts +263 -0
- package/skills/omni-crawl/SKILL.md +5 -2
- package/skills/omni-crawl/scripts/main.ts +84 -23
- package/src/acp/core-turn-bridge.ts +13 -0
- package/src/agent/registry.ts +2 -0
- package/src/agent/task-notification.ts +25 -5
- package/src/agent/types.ts +6 -0
- package/src/agent-mission/mission-cli.ts +24 -0
- package/src/agent-mission/mission-out.ts +595 -0
- package/src/agent-mission/tool-install.ts +88 -2
- package/src/agent-substrate/context-strategy.ts +4 -4
- package/src/agent-substrate/self-review-cli.ts +178 -13
- package/src/auto-research/research-turn.ts +123 -50
- package/src/autopilot/pr-manager.ts +38 -7
- package/src/autopilot/pty-control-loop.ts +2 -0
- package/src/capture/tui-self-report.ts +22 -6
- package/src/chat/index.ts +1 -1
- package/src/cli/fixtures/review-loop-breaker/opwaiver-32646-1694ccc7a170.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-32853-bd8f73595c83.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-33097-1cc85900413c.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-33106-972f31e4a3ca.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/opwaiver-33113-3ab51f05968f.json +1 -0
- package/src/cli/fixtures/review-loop-breaker/pr-33097-1cc85900413c.json +1 -0
- package/src/cli/pr-land-heavy-remote.ts +32 -0
- package/src/cli/pr-land-overlap-evidence.ts +100 -1
- package/src/cli/pr-land-pod-shadow-job.ts +60 -0
- package/src/cli/release-checklist-read-cli.ts +20 -10
- package/src/cli/research-cli.ts +4 -5
- package/src/cli/tasks-cli.ts +7 -0
- package/src/compact/auto.ts +8 -1
- package/src/control-plane/ledger.ts +52 -2
- package/src/control-plane/server.ts +16 -2
- package/src/core-turn/run-core-turn.ts +311 -90
- package/src/core-turn/run-goal-loop.ts +18 -0
- package/src/core-turn/types.ts +2 -0
- package/src/dashboard/classic-sidetab-mission-job.ts +58 -0
- package/src/dashboard/classic-sidetab-mission.ts +185 -0
- package/src/dashboard/index.ts +149 -15
- package/src/dashboard/input/agent-wake.ts +23 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +9 -0
- package/src/dashboard/mission-cli-consumer.ts +153 -0
- package/src/dashboard/seat-boot-preamble.ts +171 -1
- package/src/dashboard/side-basic-runtime.ts +54 -1
- package/src/dashboard/sidetab-runtime.ts +90 -1
- package/src/dashboard/skill-catalog-preamble.ts +101 -0
- package/src/dashboard/skill-detection-runtime.ts +55 -15
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +15 -0
- package/src/dashboard/turn-preamble.ts +53 -15
- package/src/dashboard/turn-prompt-runtime.ts +4 -2
- package/src/graph-runner/graph-cli.ts +23 -7
- package/src/graph-runner/graph-tick.ts +10 -2
- package/src/graph-runner/runner.ts +1 -1
- package/src/grok/agent-search.ts +14 -4
- package/src/grok/credential.ts +28 -11
- package/src/harness/harness-pod-dispatch.ts +81 -15
- package/src/harness/harness-stop.ts +155 -11
- package/src/index.ts +34 -5
- package/src/instance/spawn-elanous.ts +6 -4
- package/src/llm.ts +166 -8
- package/src/loops/orchestrator/coordinator-shadow.ts +226 -0
- package/src/loops/orchestrator/tick.ts +13 -0
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/native-tool-catalog.ts +2 -2
- package/src/nexus/api/harness-traversal.ts +11 -0
- package/src/pr-tool/census.ts +3 -2
- package/src/pty-shell/tui-run-state.ts +188 -2
- package/src/release-loop/checklist-target-path-hint.ts +13 -0
- package/src/release-loop/checklist.ts +9 -1
- package/src/repl/index.ts +43 -2
- package/src/research/axis-fanout.ts +121 -16
- package/src/research/bloom-exemplars.ts +3 -1
- package/src/research/gap-followup.ts +13 -1
- package/src/research/plugin-discovery.ts +36 -14
- package/src/research-bridge/invoke.ts +22 -5
- package/src/research-bridge/types.ts +2 -0
- package/src/self-dev/decompose.ts +119 -5
- package/src/self-dev/launch-preflight-text.ts +5 -6
- package/src/self-dev/orchestrate.ts +12 -2
- package/src/self-dev/review-provider-fallback.ts +9 -2
- package/src/self-dev/run-supervisor.ts +42 -4
- package/src/self-dev/run-types.ts +4 -0
- package/src/self-implement/doctor-visit.ts +88 -0
- package/src/self-implement/goal-author.ts +326 -3
- package/src/self-implement/graph-overlay-yaml.ts +7 -0
- package/src/self-implement/headless-elanous-driver.ts +31 -2
- package/src/self-implement/heal-intake.ts +112 -4
- package/src/self-implement/heal-triage.ts +20 -0
- package/src/self-implement/host-regate.ts +27 -4
- package/src/self-implement/merge-train.ts +5 -0
- package/src/self-implement/orchestrator.ts +126 -11
- package/src/self-implement/regate-detail.ts +38 -1
- package/src/self-implement/rework-child-provider.ts +25 -0
- package/src/self-implement/run-chart.ts +119 -0
- package/src/self-implement/run-ledger.ts +112 -11
- package/src/self-implement/run-stop.ts +188 -4
- package/src/self-implement/stop-autoheal.ts +13 -0
- package/src/session/chat.ts +38 -4
- package/src/session-runtime/index.ts +98 -4
- package/src/session-runtime/tier-flip.ts +3 -3
- package/src/sidetab-core/model.ts +19 -5
- package/src/sidetab-core/visible-agent-mission.ts +186 -0
- package/src/skills/name-match.ts +20 -0
- package/src/skills/tools/agent.ts +30 -2
- package/src/skills/tools/omni-search.ts +67 -5
- package/src/task-agent/pod-distributor-entry.ts +3 -0
- package/src/task-agent/task-hand.ts +27 -0
- package/src/task-orchestrator/surfaces/pod-distributor.ts +48 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +38 -1
- package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +33 -6
- package/src/task-orchestrator/surfaces/pod-source-bundle.ts +45 -9
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +163 -13
- package/src/task-orchestrator/surfaces/pod-source-spec.ts +3 -3
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +209 -39
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +80 -3
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +165 -45
- package/src/tokens.ts +35 -2
- package/src/tool-runtime/agent-runtime.ts +1 -0
- package/src/tool-runtime/elanous-skills-list-runtime.ts +5 -1
- package/src/tool-runtime/skill-exec-runtime.ts +33 -13
- package/src/tool-runtime/types.ts +1 -0
- package/src/tui/entry.ts +14 -4
- package/src/tui/sidetab/attach.ts +47 -0
- package/src/tui-client/local-chat-turn.ts +26 -13
- package/src/tui.ts +22 -0
- package/src/ux-sim/fake-kubectl.ts +37 -3
- package/src/ux-sim/fault-pool-cap.ts +11 -6
- package/src/ux-sim/mock-scenario-catalog.json +41 -0
- package/src/ux-sim/mock-scenario-catalog.ts +156 -0
- package/src/ux-sim/scenario.ts +116 -23
- package/src/version/packed-revision.json +1 -1
- package/src/voice/voice-tts-singleton.ts +18 -3
- package/src/web-search/grok.ts +5 -9
- package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +0 -36
- package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +0 -90
- package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1765.679b29625c8e88d4.js +0 -77
- package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +0 -1
- package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743.5d3f76948be32b34.js +0 -41
- package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +0 -32
- package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +0 -79
- package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3230-49298c3b73ef2268.js +0 -1
- package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4133.2056bb4d78f621af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +0 -148
- package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +0 -226
- package/apps/pwa/out/_next/static/chunks/4667.97e31aa38c95c475.js +0 -309
- package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +0 -94
- package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +0 -8
- package/apps/pwa/out/_next/static/chunks/53aeb4ee-51c92f8d683f5220.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +0 -24
- package/apps/pwa/out/_next/static/chunks/5744.b9415e18ad623100.js +0 -23
- package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +0 -286
- package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +0 -24
- package/apps/pwa/out/_next/static/chunks/6874.d5cf7eb8edb2cabe.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +0 -122
- package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +0 -34
- package/apps/pwa/out/_next/static/chunks/9834.63ab2bbc3153172e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/addc2b32.8c4ff8f0aefe987d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-14949db884bfa672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-40f9e19149024298.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a142dfb0331a05f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/b2271e54.c1de3347976e90b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +0 -1
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +0 -1
- /package/apps/pwa/out/_next/static/{GiOLWmt4MqDZePubBjA4Q → X1ucLw10Cds_h614NoEnh}/_ssgManifest.js +0 -0
package/src/session/chat.ts
CHANGED
|
@@ -42,9 +42,15 @@ import {
|
|
|
42
42
|
// ⭐ substrate 통합(PLAN-unified-autonomous-agent-substrate-2026-07-20) — goal-loop 아밍 시
|
|
43
43
|
// chat 툴루프를 canonical 엔진(runGoalLoop→runCoreTurn→streamLLMWithTools)으로 라우팅.
|
|
44
44
|
// ACP bridge(core-turn-bridge.ts)·dashboard(runGoalLoopHook)와 동일 엔진 재사용(재발명 제거).
|
|
45
|
-
import { runGoalLoop, type CoreTurnContext, type CoreTurnDispatchTool } from '../core-turn/index.js';
|
|
45
|
+
import { runCoreTurn, runGoalLoop, type CoreTurnContext, type CoreTurnDispatchTool } from '../core-turn/index.js';
|
|
46
46
|
import { composeChildContext, type ChildContextProfile } from '../self-implement/child-context-composition.js';
|
|
47
47
|
import { getHarnessSpace } from '../harness/harness-space.js';
|
|
48
|
+
import { isResearchAgentIntent } from '../tool-hints/signals.js';
|
|
49
|
+
import {
|
|
50
|
+
buildSessionRuntimeTurnSystemMessages,
|
|
51
|
+
createSessionPostureState,
|
|
52
|
+
resolveSessionTurnProfileWithHistory,
|
|
53
|
+
} from '../session-runtime/index.js';
|
|
48
54
|
|
|
49
55
|
export interface RunTurnOpts {
|
|
50
56
|
userConfig: UserConfig;
|
|
@@ -59,6 +65,8 @@ export interface RunTurnOpts {
|
|
|
59
65
|
/** Optional callback for each streamed text delta — telegram uses this to
|
|
60
66
|
* accumulate; CLI uses it to render live. */
|
|
61
67
|
onDelta?: (delta: string) => void;
|
|
68
|
+
/** Replace a provisional streamed answer after a grounded TUI synthesis completes. */
|
|
69
|
+
onReplaceText?: (fullText: string) => void;
|
|
62
70
|
/** Optional transient stream recovery status for the originating UI. */
|
|
63
71
|
onStatusLine?: (line: string) => void;
|
|
64
72
|
/** Optional provider override — for tests. */
|
|
@@ -294,6 +302,24 @@ export async function runTurn(opts: RunTurnOpts): Promise<RunTurnResult> {
|
|
|
294
302
|
// just skip and continue.
|
|
295
303
|
let memoryIds: string[] = [];
|
|
296
304
|
let effectiveSystemPrompt = opts.systemPrompt;
|
|
305
|
+
// The Next TUI runs through this shared session adapter rather than the classic dashboard
|
|
306
|
+
// preamble. Give research turns the same verified-reconciliation instruction on this path.
|
|
307
|
+
if (meta.source === 'tui' && !effectiveSystemPrompt?.includes('## Proactive Reconciliation')) {
|
|
308
|
+
const priorUserTexts = messages
|
|
309
|
+
.filter(message => message.role === 'user' && typeof message.content === 'string')
|
|
310
|
+
.map(message => String(message.content));
|
|
311
|
+
const turnProfile = resolveSessionTurnProfileWithHistory({
|
|
312
|
+
userText: opts.userText,
|
|
313
|
+
priorUserTexts,
|
|
314
|
+
chatModeState: createSessionPostureState(),
|
|
315
|
+
});
|
|
316
|
+
const reconciliation = buildSessionRuntimeTurnSystemMessages(turnProfile, opts.userText)
|
|
317
|
+
.filter(message => String(message.content).includes('## Proactive Reconciliation'));
|
|
318
|
+
if (reconciliation.length > 0) {
|
|
319
|
+
const block = reconciliation.map(message => String(message.content)).join('\n\n');
|
|
320
|
+
effectiveSystemPrompt = effectiveSystemPrompt ? `${effectiveSystemPrompt}\n\n${block}` : block;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
297
323
|
if (!opts.skipMemoryInjection) {
|
|
298
324
|
try {
|
|
299
325
|
// LLM-judge recall(2026-07-19 · 기본 ON·대표 지시) — 키워드 대신 luna 의미판정으로 관련
|
|
@@ -485,7 +511,8 @@ export async function runTurn(opts: RunTurnOpts): Promise<RunTurnResult> {
|
|
|
485
511
|
// streamLLMWithTools)으로 라우팅. 미아밍이면 아래 기존 single-turn 경로 그대로(회귀 0).
|
|
486
512
|
const goalLoopCfg = opts.userConfig.llm.goalLoop;
|
|
487
513
|
const armGoalLoop = opts.goalLoop === true || goalLoopCfg?.enabled === true;
|
|
488
|
-
|
|
514
|
+
const armTuiResearchTurn = opts.utteranceSurface === 'tui' && turnTools.length > 0 && isResearchAgentIntent(opts.userText);
|
|
515
|
+
if (armGoalLoop || armTuiResearchTurn) {
|
|
489
516
|
// ⭐ CHILD-CONTEXT-BUDGET(0.2.35 칸) — 구현 자식(self-implement 공간)의 첫 goal-loop
|
|
490
517
|
// 턴에서 실제 effectiveSystemPrompt·turnTools 스키마·userText(골)의 구성 바이트를
|
|
491
518
|
// composeChildContext 로 계측해 child.context-composition 사건 1회로 남긴다.
|
|
@@ -520,6 +547,7 @@ export async function runTurn(opts: RunTurnOpts): Promise<RunTurnResult> {
|
|
|
520
547
|
signal: opts.signal ?? new AbortController().signal,
|
|
521
548
|
callbacks: {
|
|
522
549
|
onText: (delta) => { opts.onDelta?.(delta); },
|
|
550
|
+
onReplaceText: (fullText) => { opts.onReplaceText?.(fullText); },
|
|
523
551
|
onGoalInterim: (interimText) => {
|
|
524
552
|
appendMessage(opts.sessionId, {
|
|
525
553
|
role: 'assistant', content: interimText, ts: new Date().toISOString(),
|
|
@@ -540,8 +568,14 @@ export async function runTurn(opts: RunTurnOpts): Promise<RunTurnResult> {
|
|
|
540
568
|
? { requestSizeGuard: guardedTurnLlmOpts.requestSizeGuard } : {}),
|
|
541
569
|
};
|
|
542
570
|
const maxIterations = opts.goalLoopMaxIterations ?? goalLoopCfg?.maxIterations;
|
|
543
|
-
|
|
544
|
-
|
|
571
|
+
if (armGoalLoop) {
|
|
572
|
+
const gl = await runGoalLoop(coreCtx, maxIterations !== undefined ? { maxIterations } : {});
|
|
573
|
+
text = gl.finalText;
|
|
574
|
+
} else {
|
|
575
|
+
const coreResult = await runCoreTurn(coreCtx);
|
|
576
|
+
text = coreResult.finalText;
|
|
577
|
+
if (coreResult.stopReason === 'auth_rejected') throw new Error(coreResult.errorMessage ?? 'Authentication was rejected');
|
|
578
|
+
}
|
|
545
579
|
} else {
|
|
546
580
|
text = await streamLLMWithTools(
|
|
547
581
|
kept,
|
|
@@ -26,7 +26,7 @@ import type { ToolRunResult, ToolRuntime } from '../tool-runtime/types.js';
|
|
|
26
26
|
import { blockWriteToolSearchHydration, type ToolSearchRunResult } from '../tool-runtime/tool-search-runtime.js';
|
|
27
27
|
import { findNativeTool, isNativeToolModelExposed } from '../native-tool-catalog.js';
|
|
28
28
|
import { hasAstGrep } from '../skills/tools/ast-grep.js';
|
|
29
|
-
import { buildOmniSearchTool,
|
|
29
|
+
import { buildOmniSearchTool, researchOmniSearchAvailable } from '../skills/tools/omni-search.js';
|
|
30
30
|
import { buildWebSearchTool } from '../skills/tools/web-search.js';
|
|
31
31
|
import { buildWebFetchTool } from '../skills/tools/webfetch.js';
|
|
32
32
|
import { buildSelfImplementDaemonSpec } from '../boot/daemon-tools/self-implement.js';
|
|
@@ -170,6 +170,8 @@ export interface SessionPostureSnapshot {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
export interface SessionRuntimeDispatchDeps {
|
|
173
|
+
/** Current conversation session; used to scope background Agent receipts. */
|
|
174
|
+
sessionId?: string;
|
|
173
175
|
signal?: AbortSignal;
|
|
174
176
|
/** Current LLM tool call, for correlating a foreground harness stop target with the TUI call. */
|
|
175
177
|
toolCallId?: string;
|
|
@@ -429,6 +431,7 @@ interface SessionNativeToolRule {
|
|
|
429
431
|
signal?: AbortSignal,
|
|
430
432
|
opts?: {
|
|
431
433
|
pathPolicy?: PathPolicy;
|
|
434
|
+
sessionId?: string;
|
|
432
435
|
agentHostTools?: LLMToolSpec[];
|
|
433
436
|
agentDispatchTool?: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
434
437
|
buildChildToolCatalog?: (cwd: string) => {
|
|
@@ -512,6 +515,7 @@ const SESSION_NATIVE_TOOL_RULES: SessionNativeToolRule[] = [
|
|
|
512
515
|
build: () => buildAgentTool(),
|
|
513
516
|
match: () => false,
|
|
514
517
|
dispatch: async (args, signal, opts) => await dispatchAgent(args, {
|
|
518
|
+
parentSessionId: opts?.sessionId,
|
|
515
519
|
signal,
|
|
516
520
|
hostTools: opts?.agentHostTools,
|
|
517
521
|
dispatchTool: opts?.agentDispatchTool,
|
|
@@ -587,10 +591,10 @@ const SESSION_NATIVE_TOOL_RULES: SessionNativeToolRule[] = [
|
|
|
587
591
|
description: 'Multi-source research and triangulation across external signals.',
|
|
588
592
|
build: () => buildOmniSearchTool(),
|
|
589
593
|
match: (text) => hasResearchSearchIntent(text),
|
|
590
|
-
isAvailable: () =>
|
|
594
|
+
isAvailable: () => researchOmniSearchAvailable(),
|
|
591
595
|
dispatch: async (args) => {
|
|
592
|
-
const {
|
|
593
|
-
return await
|
|
596
|
+
const { dispatchResearchOmniSearch } = await import('../skills/tools/omni-search.js');
|
|
597
|
+
return await dispatchResearchOmniSearch(args);
|
|
594
598
|
},
|
|
595
599
|
},
|
|
596
600
|
{
|
|
@@ -969,9 +973,47 @@ export function buildSessionRuntimeTurnSystemMessages(
|
|
|
969
973
|
if (scopedGuidance) {
|
|
970
974
|
messages.push({ role: 'system', content: scopedGuidance });
|
|
971
975
|
}
|
|
976
|
+
const reconcileGuidance = buildProactiveReconcileGuidance(userText);
|
|
977
|
+
if (turnProfile.surface.domain === 'research') {
|
|
978
|
+
if (reconcileGuidance) {
|
|
979
|
+
messages.push({ role: 'system', content: PROACTIVE_RECONCILIATION_GUIDANCE.join('\n') });
|
|
980
|
+
}
|
|
981
|
+
} else if (reconcileGuidance) {
|
|
982
|
+
messages.push({ role: 'system', content: reconcileGuidance });
|
|
983
|
+
}
|
|
972
984
|
return messages;
|
|
973
985
|
}
|
|
974
986
|
|
|
987
|
+
/** A challenged tool/source claim is a request to repair the answer, not just
|
|
988
|
+
* to narrate whether the earlier answer was grounded. Keep this guidance
|
|
989
|
+
* scoped to explicit evidence challenges so ordinary turns stay unchanged. */
|
|
990
|
+
function buildProactiveReconcileGuidance(userText?: string): string | null {
|
|
991
|
+
const text = String(userText ?? '').toLowerCase();
|
|
992
|
+
if (!text.trim()) return null;
|
|
993
|
+
|
|
994
|
+
const explicitChallenge = [
|
|
995
|
+
/\b(?:did you|have you|were you)\b.{0,80}\b(?:actually|really|use|used|run|check|verify|consult|cite)\b/,
|
|
996
|
+
/\b(?:you (?:did not|didn't|never)\s+(?:use|run|check|verify|consult))\b/,
|
|
997
|
+
/\b(?:verify|check|recheck|re-check|confirm)\b.{0,80}\b(?:previous|prior|original|earlier)\b/,
|
|
998
|
+
/\b(?:earlier|previous|prior|last)\b.{0,40}\b(?:skill|tool|source|evidence)\b.{0,40}\b(?:used|ran|checked|verified|cited)\b.{0,30}\b(?:actually|really|right|correct)\b/,
|
|
999
|
+
/(?:앞서|이전|직전|기존|그때).{0,40}(?:스킬|도구|툴).{0,40}(?:쓴|사용한|실행한).{0,30}(?:맞|했나|했는지)/,
|
|
1000
|
+
/(?:스킬|도구|툴).{0,40}(?:제대로|실제로).{0,40}(?:찾았는지|찾았나|사용했는지|사용했나|썼는지|썼나)/,
|
|
1001
|
+
/(?:라고\s*(?:했는데|했음에도|말했는데)|이야기했음에도).{0,80}(?:확인|결말|결론|답).{0,40}(?:조정|수정|바꾸|고치)/,
|
|
1002
|
+
/(?:스킬|도구|근거|출처).{0,60}(?:실제로\s*사용|제대로\s*사용|확인했나|썼나|쓴\s*게\s*맞|안\s*썼|못\s*찾|재확인)/,
|
|
1003
|
+
];
|
|
1004
|
+
if (!explicitChallenge.some(pattern => pattern.test(text))) return null;
|
|
1005
|
+
|
|
1006
|
+
return [
|
|
1007
|
+
'## Proactive Reconciliation — Tool-use Correction — Reconcile the Original Request This Turn',
|
|
1008
|
+
'',
|
|
1009
|
+
'The user is challenging whether the prior answer used the requested tool, skill, source, or evidence.',
|
|
1010
|
+
'Treat the original task as still open. Recover it and the prior conclusion from the conversation, then verify the challenged claim with an available capability.',
|
|
1011
|
+
'If verification changes or invalidates the prior conclusion, shows the original task was not completed, or finds that evidence is missing, incomplete, or insufficient, continue the original task in this same user turn with verified available tools and give a corrected, evidence-grounded result.',
|
|
1012
|
+
'If the requested capability is unavailable, say so plainly and continue the original task with another suitable available source when possible. Never claim a tool or skill ran when it did not.',
|
|
1013
|
+
'Do not stop at an apology or verification-only report, do not ask the user to repeat the task, and do not emit a raw JSON dump unless explicitly requested. Answer in concise prose.',
|
|
1014
|
+
].join('\n');
|
|
1015
|
+
}
|
|
1016
|
+
|
|
975
1017
|
function buildTurnScopedExplorationGuidance(userText?: string): string | null {
|
|
976
1018
|
if (isScopedAnalysisRequest(userText)) {
|
|
977
1019
|
return [
|
|
@@ -1239,6 +1281,7 @@ function buildSurfaceOperationalGuidance(surface: SessionSurfaceProfile): string
|
|
|
1239
1281
|
'Bias toward multi-source external investigation: use WebSearch, WebFetch, and OmniSearch before concluding.',
|
|
1240
1282
|
'WebSearch is provider-backed and may route through Grok live-search or Firecrawl; OmniSearch is the wider parallel path when you want triangulation across providers.',
|
|
1241
1283
|
'Prefer cited, current, cross-checked findings over repo-local assumptions when the question reaches beyond the workspace.',
|
|
1284
|
+
'',
|
|
1242
1285
|
].join('\n');
|
|
1243
1286
|
case 'research/turn':
|
|
1244
1287
|
return [
|
|
@@ -1247,6 +1290,7 @@ function buildSurfaceOperationalGuidance(surface: SessionSurfaceProfile): string
|
|
|
1247
1290
|
'You are in `research/turn`.',
|
|
1248
1291
|
'Handle the current turn as a lightweight external lookup. Prefer quick verification and concise sourced answers over deep autonomous exploration.',
|
|
1249
1292
|
'Keep WebSearch ready by default. It is provider-backed and may use Grok live-search or Firecrawl; use WebFetch for full page bodies and OmniSearch when the user asks for deeper cross-provider research.',
|
|
1293
|
+
'',
|
|
1250
1294
|
].join('\n');
|
|
1251
1295
|
case 'control/agent':
|
|
1252
1296
|
return [
|
|
@@ -1275,6 +1319,13 @@ function buildSurfaceOperationalGuidance(surface: SessionSurfaceProfile): string
|
|
|
1275
1319
|
}
|
|
1276
1320
|
}
|
|
1277
1321
|
|
|
1322
|
+
const PROACTIVE_RECONCILIATION_GUIDANCE = [
|
|
1323
|
+
'## Proactive Reconciliation — Tool-use Correction — Reconcile the Original Request This Turn',
|
|
1324
|
+
'When the user asks you to verify how an earlier answer was produced (tools, skills, or sources), check the actual results and compare them with the earlier conclusion.',
|
|
1325
|
+
'Treat the original task as still open. If verification changes or invalidates that conclusion, shows the original task was not completed, or finds that the evidence is missing, incomplete, or insufficient to support the conclusion, treat it as unreliable and continue in this same user turn: redo the original task with verified available tools and answer the original task with the corrected, evidence-grounded result in ordinary prose.',
|
|
1326
|
+
'Do not stop at an apology or verification-only report, do not ask the user to repeat the task, and do not emit a raw JSON dump unless explicitly requested. Answer in concise prose.',
|
|
1327
|
+
];
|
|
1328
|
+
|
|
1278
1329
|
export function createSessionPostureState(): SessionPostureState {
|
|
1279
1330
|
return createChatModeState();
|
|
1280
1331
|
}
|
|
@@ -1560,6 +1611,40 @@ export function resolveSessionTurnProfile(opts: {
|
|
|
1560
1611
|
};
|
|
1561
1612
|
}
|
|
1562
1613
|
|
|
1614
|
+
function isProactiveReconciliationFollowUp(userText: string): boolean {
|
|
1615
|
+
const referencesPrior = /(?:earlier|previous|prior|last|앞선|앞서|이전|직전|기존|그때|라고\s*(?:했|말)|이야기했|요청했)/i.test(userText);
|
|
1616
|
+
const referencesEvidence = /(?:answer|response|analysis|conclusion|tool|skill|source|evidence|답|응답|분석|결론|도구|툴|스킬|출처|근거)/i.test(userText);
|
|
1617
|
+
const asksToVerify = /(?:verify|recheck|check|confirm|validate|challenge|correct|used|맞|확인|검증|재확인|사용|사실|실제)/i.test(userText);
|
|
1618
|
+
return referencesPrior && referencesEvidence && asksToVerify;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
/** Preserve an active research turn's surface when the user challenges its prior evidence. */
|
|
1622
|
+
export function resolveSessionTurnProfileWithHistory(opts: {
|
|
1623
|
+
userText: string;
|
|
1624
|
+
priorUserTexts?: readonly string[];
|
|
1625
|
+
chatModeState: ChatModeState;
|
|
1626
|
+
inputSource?: InputSourceRef | null;
|
|
1627
|
+
}): SessionTurnProfile {
|
|
1628
|
+
const current = resolveSessionTurnProfile(opts);
|
|
1629
|
+
if (current.surface.domain === 'research' || !isProactiveReconciliationFollowUp(opts.userText)) return current;
|
|
1630
|
+
for (const priorUserText of [...(opts.priorUserTexts ?? [])].reverse()) {
|
|
1631
|
+
const prior = resolveSessionTurnProfile({
|
|
1632
|
+
userText: priorUserText,
|
|
1633
|
+
chatModeState: opts.chatModeState,
|
|
1634
|
+
inputSource: opts.inputSource,
|
|
1635
|
+
});
|
|
1636
|
+
if (prior.surface.domain === 'research') {
|
|
1637
|
+
return resolveSessionTurnProfile({
|
|
1638
|
+
userText: opts.userText,
|
|
1639
|
+
chatModeState: opts.chatModeState,
|
|
1640
|
+
preferredSurfaceId: prior.surface.id,
|
|
1641
|
+
inputSource: opts.inputSource,
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
return current;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1563
1648
|
export function resolveSessionSurfaceStatus(opts: {
|
|
1564
1649
|
userText?: string;
|
|
1565
1650
|
chatModeState: ChatModeState;
|
|
@@ -1736,6 +1821,7 @@ export function buildSessionRuntimeToolSpecs(opts: {
|
|
|
1736
1821
|
preferredSurfaceId?: SessionSurfaceId;
|
|
1737
1822
|
controlMode?: boolean;
|
|
1738
1823
|
}): LLMToolSpec[] {
|
|
1824
|
+
const catalogStartedAt = performance.now();
|
|
1739
1825
|
// TUI-DIET-D1-TAIL — the legacy userText-driven catalog (`rich !== false`) is gone;
|
|
1740
1826
|
// every caller already passed rich=false, so the essential catalog is the only path.
|
|
1741
1827
|
// The surface profile is still resolved for the always-on observation below.
|
|
@@ -1799,6 +1885,13 @@ export function buildSessionRuntimeToolSpecs(opts: {
|
|
|
1799
1885
|
userTextChars: opts.userText.length,
|
|
1800
1886
|
});
|
|
1801
1887
|
}
|
|
1888
|
+
try {
|
|
1889
|
+
debug.log('session-runtime.latency', 'tool-catalog-ready', {
|
|
1890
|
+
elapsedMs: Math.round((performance.now() - catalogStartedAt) * 10) / 10,
|
|
1891
|
+
toolCount: finalSpecs.length,
|
|
1892
|
+
surfaceId: surface.id,
|
|
1893
|
+
});
|
|
1894
|
+
} catch { /* observation must never delay a turn */ }
|
|
1802
1895
|
return finalSpecs;
|
|
1803
1896
|
}
|
|
1804
1897
|
|
|
@@ -2025,6 +2118,7 @@ export async function dispatchSessionRuntimeTool(
|
|
|
2025
2118
|
}
|
|
2026
2119
|
result = await nativeRule.dispatch(normalizedArgs, deps.signal, {
|
|
2027
2120
|
pathPolicy: deps.pathPolicy,
|
|
2121
|
+
sessionId: deps.sessionId,
|
|
2028
2122
|
agentHostTools: deps.agentHostTools,
|
|
2029
2123
|
agentDispatchTool: deps.agentDispatchTool,
|
|
2030
2124
|
buildChildToolCatalog: deps.buildChildToolCatalog,
|
|
@@ -325,7 +325,7 @@ function joinWithBlankLine(prefix: string, block: string): string {
|
|
|
325
325
|
|
|
326
326
|
function appendTextToMessage(msg: LLMMessage, block: string): LLMMessage {
|
|
327
327
|
if (typeof msg.content === 'string') {
|
|
328
|
-
return {
|
|
328
|
+
return { ...msg, content: joinWithBlankLine(msg.content, block) };
|
|
329
329
|
}
|
|
330
330
|
// ContentBlock[] — append to the LAST text block; if none exists,
|
|
331
331
|
// push a fresh one. Other block kinds (image / tool_use / tool_result)
|
|
@@ -336,11 +336,11 @@ function appendTextToMessage(msg: LLMMessage, block: string): LLMMessage {
|
|
|
336
336
|
if (b.type === 'text') {
|
|
337
337
|
const text = (b as { text?: string }).text ?? '';
|
|
338
338
|
blocks[i] = { ...b, text: joinWithBlankLine(text, block) };
|
|
339
|
-
return {
|
|
339
|
+
return { ...msg, content: blocks };
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
blocks.push({ type: 'text', text: block } as ContentBlock);
|
|
343
|
-
return {
|
|
343
|
+
return { ...msg, content: blocks };
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
/** Wave 2 W2.4 + W2.5 convenience — split specs AND inject the
|
|
@@ -181,11 +181,13 @@ export const NEXT_SIDETAB_TOOL_NAME = 'NextSidetab';
|
|
|
181
181
|
const NEXT_SIDETAB_CALL = 'elanous.sidetab.call';
|
|
182
182
|
const NEXT_SIDETAB_RESULT = 'elanous.sidetab.result';
|
|
183
183
|
|
|
184
|
-
export type NextSidetabAction = 'list' | 'switch' | 'attach' | 'detach' | 'new' | 'kill';
|
|
184
|
+
export type NextSidetabAction = 'list' | 'switch' | 'attach' | 'detach' | 'new' | 'mission' | 'kill';
|
|
185
185
|
export interface NextSidetabRequest {
|
|
186
186
|
action: NextSidetabAction;
|
|
187
187
|
target?: string;
|
|
188
188
|
character?: 'shell' | 'elanous';
|
|
189
|
+
mission?: string;
|
|
190
|
+
agent?: 'codex' | 'claude';
|
|
189
191
|
confirm?: boolean;
|
|
190
192
|
}
|
|
191
193
|
export interface NextSidetabCall { type: typeof NEXT_SIDETAB_CALL; callId: string; request: NextSidetabRequest }
|
|
@@ -198,6 +200,7 @@ export interface NextSidetabHostDeps {
|
|
|
198
200
|
attach(row: SidetabRow): Promise<unknown>;
|
|
199
201
|
detach(): unknown;
|
|
200
202
|
spawn(character: 'shell' | 'elanous'): unknown;
|
|
203
|
+
runMission?(agent: 'codex' | 'claude', mission: string): Promise<unknown>;
|
|
201
204
|
kill(row: SidetabRow): unknown;
|
|
202
205
|
}
|
|
203
206
|
export interface NextSidetabIpcProcess {
|
|
@@ -207,13 +210,15 @@ export interface NextSidetabIpcProcess {
|
|
|
207
210
|
|
|
208
211
|
export const nextSidetabToolSpec: LLMToolSpec = {
|
|
209
212
|
name: NEXT_SIDETAB_TOOL_NAME,
|
|
210
|
-
description: 'Control the Next TUI side tab: list/view sessions and PTYs, switch sessions, attach or detach, start a local shell or elanous PTY, or kill a PTY. Ask the user to confirm before calling kill with confirm=true.
|
|
213
|
+
description: 'Control the Next TUI side tab: list/view sessions and PTYs, switch sessions, attach or detach, start a local shell or elanous PTY, run a mission in a visible Codex or Claude side-tab and return its verified result file, or kill a PTY. Ask the user to confirm before calling kill with confirm=true.',
|
|
211
214
|
parameters: {
|
|
212
215
|
type: 'object',
|
|
213
216
|
properties: {
|
|
214
|
-
action: { type: 'string', enum: ['list', 'switch', 'attach', 'detach', 'new', 'kill'] },
|
|
217
|
+
action: { type: 'string', enum: ['list', 'switch', 'attach', 'detach', 'new', 'mission', 'kill'] },
|
|
215
218
|
target: { type: 'string', description: 'Optional exact or partial row id/label; required for targeted actions.' },
|
|
216
219
|
character: { type: 'string', enum: ['shell', 'elanous'], description: 'Only used with action=new.' },
|
|
220
|
+
mission: { type: 'string', description: 'Mission text to type visibly into a new Codex or Claude side-tab PTY; the tool appends a result-file path and checks the completion marker.' },
|
|
221
|
+
agent: { type: 'string', enum: ['codex', 'claude'], description: 'Coding agent for action=mission; defaults to codex.' },
|
|
217
222
|
confirm: { type: 'boolean', description: 'Must be true only after the user explicitly confirmed killing the selected PTY.' },
|
|
218
223
|
},
|
|
219
224
|
required: ['action'],
|
|
@@ -236,13 +241,20 @@ export async function answerNextSidetabCall(handler: NextSidetabHandler, call: N
|
|
|
236
241
|
|
|
237
242
|
export function createNextSidetabHostHandler(deps: NextSidetabHostDeps): NextSidetabHandler {
|
|
238
243
|
return async (request) => {
|
|
239
|
-
if (!request || !['list', 'switch', 'attach', 'detach', 'new', 'kill'].includes(request.action)) {
|
|
244
|
+
if (!request || !['list', 'switch', 'attach', 'detach', 'new', 'mission', 'kill'].includes(request.action)) {
|
|
240
245
|
return { error: '지원하지 않는 사이드탭 동작입니다' };
|
|
241
246
|
}
|
|
242
247
|
if (request.action === 'new') {
|
|
243
248
|
if (request.character !== 'shell' && request.character !== 'elanous') return { error: 'character는 shell 또는 elanous여야 합니다' };
|
|
244
249
|
return deps.spawn(request.character);
|
|
245
250
|
}
|
|
251
|
+
if (request.action === 'mission') {
|
|
252
|
+
const mission = request.mission?.trim();
|
|
253
|
+
if (!mission) return { error: 'mission 텍스트가 필요합니다' };
|
|
254
|
+
if (!deps.runMission) return { error: '사이드탭 미션 실행기가 연결되지 않았습니다' };
|
|
255
|
+
if (request.agent !== undefined && request.agent !== 'codex' && request.agent !== 'claude') return { error: 'agent는 codex 또는 claude여야 합니다' };
|
|
256
|
+
return deps.runMission(request.agent ?? 'codex', mission);
|
|
257
|
+
}
|
|
246
258
|
if (request.action === 'detach') return deps.detach();
|
|
247
259
|
const rows = await deps.rows();
|
|
248
260
|
if (request.action === 'list') return rows.map(({ id, label, kind, badge, sessionId }) => ({ id, label, kind, badge, ...(sessionId ? { sessionId } : {}) }));
|
|
@@ -265,6 +277,7 @@ export function createReplNextSidetabTool(
|
|
|
265
277
|
proc: NextSidetabIpcProcess,
|
|
266
278
|
env: NodeJS.ProcessEnv = process.env,
|
|
267
279
|
timeoutMs = 15_000,
|
|
280
|
+
missionTimeoutMs = 420_000,
|
|
268
281
|
): { spec: LLMToolSpec; dispatch: (args: Record<string, unknown>) => Promise<unknown> } | null {
|
|
269
282
|
if (env.ELANOUS_NEXT_TUI_SIDETAB_IPC !== '1' || typeof proc.send !== 'function') return null;
|
|
270
283
|
const send = proc.send.bind(proc);
|
|
@@ -283,10 +296,11 @@ export function createReplNextSidetabTool(
|
|
|
283
296
|
spec: nextSidetabToolSpec,
|
|
284
297
|
dispatch: (args) => new Promise((resolve) => {
|
|
285
298
|
const callId = `s${++sequence}`;
|
|
299
|
+
const callTimeoutMs = args.action === 'mission' ? missionTimeoutMs : timeoutMs;
|
|
286
300
|
const timer = setTimeout(() => {
|
|
287
301
|
if (!waiting.delete(callId)) return;
|
|
288
302
|
resolve({ error: 'Next TUI did not answer the side-tab request' });
|
|
289
|
-
},
|
|
303
|
+
}, callTimeoutMs);
|
|
290
304
|
waiting.set(callId, (result) => { clearTimeout(timer); resolve(result); });
|
|
291
305
|
try {
|
|
292
306
|
send({ type: NEXT_SIDETAB_CALL, callId, request: args as unknown as NextSidetabRequest } satisfies NextSidetabCall);
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { screenNeedsTrust } from '../agent-mission/parse.js';
|
|
4
|
+
import { sanitizeForPtyInput } from '../agent-mission/provision.js';
|
|
5
|
+
|
|
6
|
+
export interface VisibleMissionPty {
|
|
7
|
+
snapshot(): string;
|
|
8
|
+
write(bytes: string): void;
|
|
9
|
+
isAlive(): boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface VisibleMissionResult {
|
|
13
|
+
ok: boolean;
|
|
14
|
+
path: string;
|
|
15
|
+
content?: string;
|
|
16
|
+
firstLine?: string;
|
|
17
|
+
promptReady: boolean;
|
|
18
|
+
missionVisible: boolean;
|
|
19
|
+
promptReturned: boolean;
|
|
20
|
+
completionMarker: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface VisibleMissionDeps {
|
|
25
|
+
pty: VisibleMissionPty;
|
|
26
|
+
mission: string;
|
|
27
|
+
outputPath: string;
|
|
28
|
+
handleTrust(screen: string, write: (bytes: string) => void): boolean;
|
|
29
|
+
readFile?(path: string): string;
|
|
30
|
+
sleep?(ms: number): Promise<void>;
|
|
31
|
+
readyTimeoutMs?: number;
|
|
32
|
+
visibilityTimeoutMs?: number;
|
|
33
|
+
completionTimeoutMs?: number;
|
|
34
|
+
pollMs?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const sleepDefault = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));
|
|
38
|
+
|
|
39
|
+
export function isAgentInputPrompt(screen: string): boolean {
|
|
40
|
+
const plain = stripAnsi(screen);
|
|
41
|
+
return /(?:^|\n)\s*[›❯]\s*(?:Ask\b|Try\b|$)/m.test(plain)
|
|
42
|
+
|| /Ask anything|Ask (?:Codex|Claude)(?: Code)? to do anything|What would you like to do\?/i.test(plain);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Drive a visible agent PTY, verify its result, then request a separate completion marker. */
|
|
46
|
+
export async function runVisibleAgentMission(deps: VisibleMissionDeps): Promise<VisibleMissionResult> {
|
|
47
|
+
const sleep = deps.sleep ?? sleepDefault;
|
|
48
|
+
const pollMs = deps.pollMs ?? 150;
|
|
49
|
+
const readFile = deps.readFile ?? ((path: string) => readFileSync(path, 'utf8'));
|
|
50
|
+
let promptReady = false;
|
|
51
|
+
let missionVisible = false;
|
|
52
|
+
let promptReturned = false;
|
|
53
|
+
let completionMarker = false;
|
|
54
|
+
try {
|
|
55
|
+
const readyDeadline = Date.now() + (deps.readyTimeoutMs ?? 60_000);
|
|
56
|
+
let lastScreen = '';
|
|
57
|
+
|
|
58
|
+
while (Date.now() < readyDeadline) {
|
|
59
|
+
if (!deps.pty.isAlive()) return { ok: false, path: deps.outputPath, promptReady: false, missionVisible: false, promptReturned: false, completionMarker: false, error: 'Agent PTY exited before its prompt appeared' };
|
|
60
|
+
lastScreen = deps.pty.snapshot();
|
|
61
|
+
if (screenNeedsTrust(lastScreen) && deps.handleTrust(lastScreen, bytes => deps.pty.write(bytes))) {
|
|
62
|
+
await sleep(500);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (isAgentInputPrompt(lastScreen)) { promptReady = true; break; }
|
|
66
|
+
await sleep(pollMs);
|
|
67
|
+
}
|
|
68
|
+
if (!promptReady) {
|
|
69
|
+
return {
|
|
70
|
+
ok: false, path: deps.outputPath, promptReady: false, missionVisible: false, promptReturned: false, completionMarker: false,
|
|
71
|
+
error: `Agent input prompt was not observed: ${lastScreen.slice(-240).replace(/\s+/g, ' ')}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const mission = sanitizeForPtyInput(deps.mission, 4_000);
|
|
76
|
+
if (!mission) return { ok: false, path: deps.outputPath, promptReady, missionVisible: false, promptReturned: false, completionMarker: false, error: 'Mission text is empty after input sanitization' };
|
|
77
|
+
try {
|
|
78
|
+
readFile(deps.outputPath);
|
|
79
|
+
return { ok: false, path: deps.outputPath, promptReady, missionVisible: false, promptReturned: false, completionMarker: false, error: 'Result path already exists; refusing to reuse a previous mission file' };
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (!isFileNotFound(error)) {
|
|
82
|
+
return { ok: false, path: deps.outputPath, promptReady, missionVisible: false, promptReturned: false, completionMarker: false, error: `Could not verify a fresh result path: ${error instanceof Error ? error.message : String(error)}` };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const missionPrompt = `Write the result to the exact file path ${deps.outputPath} (create parent directories if needed). ${mission}`;
|
|
86
|
+
deps.pty.write(missionPrompt);
|
|
87
|
+
const visibleMissionTail = mission.slice(-Math.min(24, mission.length));
|
|
88
|
+
const visibilityDeadline = Date.now() + (deps.visibilityTimeoutMs ?? 5_000);
|
|
89
|
+
while (Date.now() < visibilityDeadline) {
|
|
90
|
+
const visibleText = stripAnsi(deps.pty.snapshot()).replace(/\s+/g, ' ');
|
|
91
|
+
if (visibleText.includes(visibleMissionTail)) { missionVisible = true; break; }
|
|
92
|
+
await sleep(Math.min(pollMs || 25, Math.max(1, visibilityDeadline - Date.now())));
|
|
93
|
+
}
|
|
94
|
+
if (!missionVisible) {
|
|
95
|
+
return { ok: false, path: deps.outputPath, promptReady, missionVisible: false, promptReturned: false, completionMarker: false, error: 'Mission text was not visible in the agent PTY before submission' };
|
|
96
|
+
}
|
|
97
|
+
deps.pty.write('\r');
|
|
98
|
+
|
|
99
|
+
const completionDeadline = Date.now() + (deps.completionTimeoutMs ?? 300_000);
|
|
100
|
+
let resultFileObserved = false;
|
|
101
|
+
while (Date.now() < completionDeadline) {
|
|
102
|
+
if (!deps.pty.isAlive()) break;
|
|
103
|
+
lastScreen = deps.pty.snapshot();
|
|
104
|
+
if (screenNeedsTrust(lastScreen) && deps.handleTrust(lastScreen, bytes => deps.pty.write(bytes))) {
|
|
105
|
+
await sleep(500);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!resultFileObserved) {
|
|
109
|
+
try {
|
|
110
|
+
const candidate = readFile(deps.outputPath);
|
|
111
|
+
resultFileObserved = Boolean(candidate.trim());
|
|
112
|
+
} catch { /* the agent has not written the result file yet */ }
|
|
113
|
+
}
|
|
114
|
+
if (resultFileObserved && isAgentInputPrompt(lastScreen)) { promptReturned = true; break; }
|
|
115
|
+
await sleep(pollMs);
|
|
116
|
+
}
|
|
117
|
+
if (!resultFileObserved) {
|
|
118
|
+
return { ok: false, path: deps.outputPath, promptReady, missionVisible, promptReturned, completionMarker: false, error: 'Agent did not create a non-empty result file before the timeout' };
|
|
119
|
+
}
|
|
120
|
+
if (!promptReturned) {
|
|
121
|
+
return { ok: false, path: deps.outputPath, promptReady, missionVisible, promptReturned: false, completionMarker: false, error: 'Agent did not return to its input prompt after writing the result file' };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let content: string;
|
|
125
|
+
try { content = readFile(deps.outputPath); }
|
|
126
|
+
catch (error) {
|
|
127
|
+
return { ok: false, path: deps.outputPath, promptReady, missionVisible, promptReturned, completionMarker: false, error: `Result file disappeared after the agent returned: ${error instanceof Error ? error.message : String(error)}` };
|
|
128
|
+
}
|
|
129
|
+
const firstLine = content.split(/\r?\n/).map(line => line.trim()).find(Boolean);
|
|
130
|
+
if (!firstLine) return { ok: false, path: deps.outputPath, promptReady, missionVisible, promptReturned, completionMarker: false, error: 'Result file is empty' };
|
|
131
|
+
|
|
132
|
+
// Keep the marker request separate and short: the marker itself never occurs
|
|
133
|
+
// in the mission prompt, so only the agent's final output can satisfy it.
|
|
134
|
+
const completionMarkerText = `M-${randomUUID().replaceAll('-', '').slice(0, 12)}`;
|
|
135
|
+
const markerPrompt = `Say ${completionMarkerText} alone.`;
|
|
136
|
+
deps.pty.write(markerPrompt);
|
|
137
|
+
const markerVisibleDeadline = Date.now() + (deps.visibilityTimeoutMs ?? 5_000);
|
|
138
|
+
let markerRequestVisible = false;
|
|
139
|
+
while (Date.now() < markerVisibleDeadline) {
|
|
140
|
+
const markerInputScreen = stripAnsi(deps.pty.snapshot()).replace(/\s+/g, ' ');
|
|
141
|
+
if (markerInputScreen.includes(completionMarkerText)) { markerRequestVisible = true; break; }
|
|
142
|
+
await sleep(Math.min(pollMs || 25, Math.max(1, markerVisibleDeadline - Date.now())));
|
|
143
|
+
}
|
|
144
|
+
if (!markerRequestVisible) {
|
|
145
|
+
return { ok: false, path: deps.outputPath, firstLine, promptReady, missionVisible, promptReturned, completionMarker: false, error: 'Completion marker request was not visible in the agent PTY' };
|
|
146
|
+
}
|
|
147
|
+
if (screenShowsCompletionMarker(deps.pty.snapshot(), completionMarkerText)) {
|
|
148
|
+
return { ok: false, path: deps.outputPath, firstLine, promptReady, missionVisible, promptReturned, completionMarker: false, error: 'Completion marker appeared in the PTY input before submission' };
|
|
149
|
+
}
|
|
150
|
+
deps.pty.write('\r');
|
|
151
|
+
|
|
152
|
+
while (Date.now() < completionDeadline) {
|
|
153
|
+
if (!deps.pty.isAlive()) break;
|
|
154
|
+
if (screenShowsCompletionMarker(deps.pty.snapshot(), completionMarkerText)) { completionMarker = true; break; }
|
|
155
|
+
await sleep(pollMs);
|
|
156
|
+
}
|
|
157
|
+
if (!completionMarker) {
|
|
158
|
+
return { ok: false, path: deps.outputPath, firstLine, promptReady, missionVisible, promptReturned, completionMarker: false, error: 'Agent did not show its completion marker before the timeout' };
|
|
159
|
+
}
|
|
160
|
+
return { ok: true, path: deps.outputPath, content, firstLine, promptReady, missionVisible, promptReturned, completionMarker };
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return {
|
|
163
|
+
ok: false,
|
|
164
|
+
path: deps.outputPath,
|
|
165
|
+
promptReady,
|
|
166
|
+
missionVisible,
|
|
167
|
+
promptReturned,
|
|
168
|
+
completionMarker,
|
|
169
|
+
error: error instanceof Error ? error.message : String(error),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function screenShowsCompletionMarker(screen: string, marker: string): boolean {
|
|
175
|
+
const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
176
|
+
return new RegExp(`^\\s*(?:(?:[•⏺└│╰⎿])\\s*)?${escaped}\\s*$`, 'm').test(stripAnsi(screen));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function stripAnsi(screen: string): string {
|
|
180
|
+
return screen.replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, '')
|
|
181
|
+
.replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, '');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function isFileNotFound(error: unknown): boolean {
|
|
185
|
+
return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';
|
|
186
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Canonicalize a spoken/typed skill slug while retaining letters and digits. */
|
|
2
|
+
export function normalizeSkillName(value: string): string {
|
|
3
|
+
return value.normalize('NFKC').toLowerCase().replace(/[\s\p{P}\p{S}_]+/gu, '');
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** Return a canonical catalog entry only when the normalized name is unique. */
|
|
7
|
+
export function resolveSkillName<T extends { name: string }>(
|
|
8
|
+
requested: string,
|
|
9
|
+
entries: readonly T[],
|
|
10
|
+
): { entry?: T; ambiguous: T[] } {
|
|
11
|
+
// Keep accidental surrounding whitespace out of execution; only the
|
|
12
|
+
// slug's internal separators are fuzzy.
|
|
13
|
+
if (requested !== requested.trim()) return { ambiguous: [] };
|
|
14
|
+
const normalized = normalizeSkillName(requested);
|
|
15
|
+
if (!normalized) return { ambiguous: [] };
|
|
16
|
+
const matches = entries.filter((entry) => normalizeSkillName(entry.name) === normalized);
|
|
17
|
+
return matches.length === 1
|
|
18
|
+
? { entry: matches[0], ambiguous: [] }
|
|
19
|
+
: { ambiguous: matches.length > 1 ? matches : [] };
|
|
20
|
+
}
|