elanous 0.2.0 → 0.2.5
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/.env.example +6 -0
- package/README.md +17 -15
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1751.50b96ea9c37b49b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +25 -0
- package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +5 -0
- package/apps/pwa/out/_next/static/chunks/4440-18bb160d95819f4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2a79f15a-2013e4d421d6df88.js → 4daa2798-1363d725c79f3593.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5348-bbf838e119661eee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5391-8793f88b03b30161.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5927.8378481a12cc8044.js → 7527.943753b6ed829f09.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6804.8ed6ab492bc5fc0a.js → 8617.465ca22a319c95b3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{320-d7013ec072863e5e.js → 8918-482b30ce2a8ebf4c.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2598.814f64e3268634e7.js → 9238.2cd5f47f4bf7a2c3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9704-3221c102623c8d73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f89e9a303515a033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-4f403cd060442c95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-0ac5d053f0444d21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-72bd384898d88955.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-bccce0babceae30f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f6f3850d-7f324c6566002113.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-2bf59c720fe9542c.js +1 -0
- package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +1 -0
- package/apps/pwa/out/_next/static/ktMqfrBbf8BMGac0jqLrb/_buildManifest.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -0
- package/apps/pwa/out/approvals/index.txt +32 -0
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +29 -26
- package/apps/pwa/out/board/index.html +1 -0
- package/apps/pwa/out/board/index.txt +32 -0
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +26 -23
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +26 -23
- package/apps/pwa/out/chat/index.html +1 -2
- package/apps/pwa/out/chat/index.txt +26 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +29 -26
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +29 -26
- package/apps/pwa/out/editor/index.html +1 -0
- package/apps/pwa/out/editor/index.txt +33 -0
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/icons/elanous-16.png +0 -0
- package/apps/pwa/out/icons/elanous-180.png +0 -0
- package/apps/pwa/out/icons/elanous-192.png +0 -0
- package/apps/pwa/out/icons/elanous-32.png +0 -0
- package/apps/pwa/out/icons/elanous-512.png +0 -0
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +26 -23
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +29 -26
- package/apps/pwa/out/live/index.html +1 -0
- package/apps/pwa/out/live/index.txt +32 -0
- package/apps/pwa/out/manifest.webmanifest +5 -2
- package/apps/pwa/out/market/index.html +1 -0
- package/apps/pwa/out/market/index.txt +29 -0
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +26 -23
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +29 -26
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +29 -26
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +27 -24
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +29 -26
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +26 -23
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +29 -26
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +29 -26
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +29 -26
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +29 -26
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +29 -26
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +26 -23
- package/apps/pwa/out/sw-strategies.js +44 -0
- package/apps/pwa/out/sw.js +6 -44
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +29 -26
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +29 -26
- package/apps/pwa/out/trace/index.html +1 -0
- package/apps/pwa/out/trace/index.txt +32 -0
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +29 -26
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +29 -26
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +29 -27
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +29 -26
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +29 -26
- package/catalog/resources.yaml +14 -17
- package/docs/design/systems/LICENSE +201 -0
- package/docs/design/systems/NOTICE.md +29 -0
- package/docs/design/systems/SOURCE.json +291 -0
- package/docs/design/systems/application/DESIGN.md +71 -0
- package/docs/design/systems/application/manifest.json +54 -0
- package/docs/design/systems/application/tokens.css +63 -0
- package/docs/design/systems/artistic/DESIGN.md +71 -0
- package/docs/design/systems/artistic/manifest.json +54 -0
- package/docs/design/systems/artistic/tokens.css +63 -0
- package/docs/design/systems/bento/DESIGN.md +71 -0
- package/docs/design/systems/bento/manifest.json +54 -0
- package/docs/design/systems/bento/tokens.css +63 -0
- package/docs/design/systems/bold/DESIGN.md +71 -0
- package/docs/design/systems/bold/manifest.json +54 -0
- package/docs/design/systems/bold/tokens.css +63 -0
- package/docs/design/systems/brutalism/DESIGN.md +71 -0
- package/docs/design/systems/brutalism/manifest.json +54 -0
- package/docs/design/systems/brutalism/tokens.css +63 -0
- package/docs/design/systems/cafe/DESIGN.md +71 -0
- package/docs/design/systems/cafe/manifest.json +54 -0
- package/docs/design/systems/cafe/tokens.css +63 -0
- package/docs/design/systems/claymorphism/DESIGN.md +71 -0
- package/docs/design/systems/claymorphism/manifest.json +54 -0
- package/docs/design/systems/claymorphism/tokens.css +63 -0
- package/docs/design/systems/clean/DESIGN.md +71 -0
- package/docs/design/systems/clean/manifest.json +54 -0
- package/docs/design/systems/clean/tokens.css +63 -0
- package/docs/design/systems/colorful/DESIGN.md +71 -0
- package/docs/design/systems/colorful/manifest.json +54 -0
- package/docs/design/systems/colorful/tokens.css +63 -0
- package/docs/design/systems/contemporary/DESIGN.md +71 -0
- package/docs/design/systems/contemporary/manifest.json +54 -0
- package/docs/design/systems/contemporary/tokens.css +63 -0
- package/docs/design/systems/corporate/DESIGN.md +71 -0
- package/docs/design/systems/corporate/manifest.json +54 -0
- package/docs/design/systems/corporate/tokens.css +63 -0
- package/docs/design/systems/cosmic/DESIGN.md +71 -0
- package/docs/design/systems/cosmic/manifest.json +54 -0
- package/docs/design/systems/cosmic/tokens.css +63 -0
- package/docs/design/systems/creative/DESIGN.md +71 -0
- package/docs/design/systems/creative/manifest.json +54 -0
- package/docs/design/systems/creative/tokens.css +63 -0
- package/docs/design/systems/dashboard/DESIGN.md +71 -0
- package/docs/design/systems/dashboard/manifest.json +54 -0
- package/docs/design/systems/dashboard/tokens.css +63 -0
- package/docs/design/systems/default/DESIGN.md +62 -0
- package/docs/design/systems/default/manifest.json +69 -0
- package/docs/design/systems/default/tokens.css +200 -0
- package/docs/design/systems/dithered/DESIGN.md +71 -0
- package/docs/design/systems/dithered/manifest.json +54 -0
- package/docs/design/systems/dithered/tokens.css +63 -0
- package/docs/design/systems/doodle/DESIGN.md +71 -0
- package/docs/design/systems/doodle/manifest.json +54 -0
- package/docs/design/systems/doodle/tokens.css +63 -0
- package/docs/design/systems/dramatic/DESIGN.md +71 -0
- package/docs/design/systems/dramatic/manifest.json +54 -0
- package/docs/design/systems/dramatic/tokens.css +63 -0
- package/docs/design/systems/editorial/DESIGN.md +71 -0
- package/docs/design/systems/editorial/manifest.json +54 -0
- package/docs/design/systems/editorial/tokens.css +63 -0
- package/docs/design/systems/elegant/DESIGN.md +71 -0
- package/docs/design/systems/elegant/manifest.json +54 -0
- package/docs/design/systems/elegant/tokens.css +63 -0
- package/docs/design/systems/energetic/DESIGN.md +72 -0
- package/docs/design/systems/energetic/manifest.json +54 -0
- package/docs/design/systems/energetic/tokens.css +63 -0
- package/docs/design/systems/enterprise/DESIGN.md +71 -0
- package/docs/design/systems/enterprise/manifest.json +54 -0
- package/docs/design/systems/enterprise/tokens.css +63 -0
- package/docs/design/systems/expressive/DESIGN.md +71 -0
- package/docs/design/systems/expressive/manifest.json +54 -0
- package/docs/design/systems/expressive/tokens.css +63 -0
- package/docs/design/systems/fantasy/DESIGN.md +71 -0
- package/docs/design/systems/fantasy/manifest.json +54 -0
- package/docs/design/systems/fantasy/tokens.css +63 -0
- package/docs/design/systems/flat/DESIGN.md +71 -0
- package/docs/design/systems/flat/manifest.json +54 -0
- package/docs/design/systems/flat/tokens.css +63 -0
- package/docs/design/systems/friendly/DESIGN.md +71 -0
- package/docs/design/systems/friendly/manifest.json +54 -0
- package/docs/design/systems/friendly/tokens.css +63 -0
- package/docs/design/systems/glassmorphism/DESIGN.md +71 -0
- package/docs/design/systems/glassmorphism/manifest.json +54 -0
- package/docs/design/systems/glassmorphism/tokens.css +63 -0
- package/docs/design/systems/gradient/DESIGN.md +71 -0
- package/docs/design/systems/gradient/manifest.json +54 -0
- package/docs/design/systems/gradient/tokens.css +63 -0
- package/docs/design/systems/luxury/DESIGN.md +71 -0
- package/docs/design/systems/luxury/manifest.json +54 -0
- package/docs/design/systems/luxury/tokens.css +63 -0
- package/docs/design/systems/minimal/DESIGN.md +71 -0
- package/docs/design/systems/minimal/manifest.json +54 -0
- package/docs/design/systems/minimal/tokens.css +63 -0
- package/docs/design/systems/modern/DESIGN.md +71 -0
- package/docs/design/systems/modern/manifest.json +54 -0
- package/docs/design/systems/modern/tokens.css +63 -0
- package/docs/design/systems/mono/DESIGN.md +71 -0
- package/docs/design/systems/mono/manifest.json +54 -0
- package/docs/design/systems/mono/tokens.css +63 -0
- package/docs/design/systems/neobrutalism/DESIGN.md +71 -0
- package/docs/design/systems/neobrutalism/manifest.json +54 -0
- package/docs/design/systems/neobrutalism/tokens.css +63 -0
- package/docs/design/systems/neon/DESIGN.md +71 -0
- package/docs/design/systems/neon/manifest.json +54 -0
- package/docs/design/systems/neon/tokens.css +63 -0
- package/docs/design/systems/neumorphism/DESIGN.md +71 -0
- package/docs/design/systems/neumorphism/manifest.json +54 -0
- package/docs/design/systems/neumorphism/tokens.css +63 -0
- package/docs/design/systems/paper/DESIGN.md +71 -0
- package/docs/design/systems/paper/manifest.json +54 -0
- package/docs/design/systems/paper/tokens.css +63 -0
- package/docs/design/systems/perspective/DESIGN.md +71 -0
- package/docs/design/systems/perspective/manifest.json +54 -0
- package/docs/design/systems/perspective/tokens.css +63 -0
- package/docs/design/systems/premium/DESIGN.md +71 -0
- package/docs/design/systems/premium/manifest.json +54 -0
- package/docs/design/systems/premium/tokens.css +63 -0
- package/docs/design/systems/professional/DESIGN.md +71 -0
- package/docs/design/systems/professional/manifest.json +54 -0
- package/docs/design/systems/professional/tokens.css +63 -0
- package/docs/design/systems/publication/DESIGN.md +71 -0
- package/docs/design/systems/publication/manifest.json +54 -0
- package/docs/design/systems/publication/tokens.css +63 -0
- package/docs/design/systems/refined/DESIGN.md +71 -0
- package/docs/design/systems/refined/manifest.json +54 -0
- package/docs/design/systems/refined/tokens.css +63 -0
- package/docs/design/systems/retro/DESIGN.md +71 -0
- package/docs/design/systems/retro/manifest.json +54 -0
- package/docs/design/systems/retro/tokens.css +63 -0
- package/docs/design/systems/shadcn/DESIGN.md +71 -0
- package/docs/design/systems/shadcn/manifest.json +54 -0
- package/docs/design/systems/shadcn/tokens.css +255 -0
- package/docs/design/systems/simple/DESIGN.md +71 -0
- package/docs/design/systems/simple/manifest.json +54 -0
- package/docs/design/systems/simple/tokens.css +63 -0
- package/docs/design/systems/skeumorphism/DESIGN.md +71 -0
- package/docs/design/systems/skeumorphism/manifest.json +54 -0
- package/docs/design/systems/skeumorphism/tokens.css +63 -0
- package/docs/design/systems/sleek/DESIGN.md +71 -0
- package/docs/design/systems/sleek/manifest.json +54 -0
- package/docs/design/systems/sleek/tokens.css +63 -0
- package/docs/design/systems/spacious/DESIGN.md +71 -0
- package/docs/design/systems/spacious/manifest.json +54 -0
- package/docs/design/systems/spacious/tokens.css +63 -0
- package/docs/design/systems/storytelling/DESIGN.md +71 -0
- package/docs/design/systems/storytelling/manifest.json +54 -0
- package/docs/design/systems/storytelling/tokens.css +63 -0
- package/docs/design/systems/tom-modern/DESIGN.md +361 -0
- package/docs/design/systems/tom-modern/manifest.json +16 -0
- package/docs/design/systems/tom-modern/tokens.css +99 -0
- package/docs/design/systems/vibrant/DESIGN.md +71 -0
- package/docs/design/systems/vibrant/manifest.json +54 -0
- package/docs/design/systems/vibrant/tokens.css +63 -0
- package/docs/design/systems/vintage/DESIGN.md +71 -0
- package/docs/design/systems/vintage/manifest.json +54 -0
- package/docs/design/systems/vintage/tokens.css +63 -0
- package/docs/design/systems/warm-editorial/DESIGN.md +65 -0
- package/docs/design/systems/warm-editorial/manifest.json +54 -0
- package/docs/design/systems/warm-editorial/tokens.css +63 -0
- package/docs/goal-context/01-goal-authoring-checks.md +18 -0
- package/docs/goal-context/steward-directives-2026-09-28.md +42 -0
- package/graphs/catalog/catalog.yaml +615 -0
- package/graphs/default-loop.yaml +1 -1
- package/graphs/document-loop.yaml +1 -1
- package/graphs/examples/stale-draft-digest/digest.ts +26 -0
- package/graphs/examples/stale-draft-digest/recipes.yaml +8 -0
- package/graphs/examples/stale-draft-digest/stale-draft-digest.yaml +22 -0
- package/graphs/heal/heal-loop.yaml +155 -0
- package/graphs/heal/recipes.yaml +19 -0
- package/graphs/implement-loop.yaml +2 -2
- package/graphs/intake/intake-daily.yaml +55 -0
- package/graphs/intake/recipes.yaml +16 -0
- package/graphs/landing/landing-heal.yaml +22 -0
- package/graphs/landing/recipes.yaml +8 -0
- package/graphs/launch/launch-head.yaml +66 -0
- package/graphs/launch/recipes.yaml +8 -0
- package/graphs/operate-loop.yaml +1 -1
- package/graphs/ops/docs-publish.yaml +31 -0
- package/graphs/ops/recipes.yaml +8 -0
- package/graphs/release/recipes.yaml +45 -0
- package/graphs/release/release-loop.yaml +45 -0
- package/graphs/research-loop.yaml +1 -1
- package/graphs/steward/recipes.yaml +12 -0
- package/graphs/steward/steward.yaml +45 -0
- package/graphs/video/README.md +1 -0
- package/graphs/video/broll-line.yaml +54 -0
- package/graphs/video/explainer-line.yaml +58 -0
- package/package.json +9 -5
- package/plugins/job-coach/.agents/plugins/marketplace.json +12 -0
- package/plugins/job-coach/.codex-plugin/plugin.json +23 -0
- package/plugins/job-coach/.mcp.json +9 -0
- package/plugins/job-coach/README.md +32 -0
- package/plugins/job-coach/connectors/ncs/server.ts +90 -0
- package/plugins/job-coach/examples/interview-sample.md +11 -0
- package/plugins/job-coach/graphs/course-links.ts +46 -0
- package/plugins/job-coach/graphs/gap-judge.ts +44 -0
- package/plugins/job-coach/graphs/recipes.yaml +45 -0
- package/plugins/job-coach/graphs/report-enterprise.yaml +28 -0
- package/plugins/job-coach/graphs/report.yaml +20 -0
- package/plugins/job-coach/graphs/run-step.ts +302 -0
- package/plugins/job-coach/plugin.json +26 -0
- package/plugins/job-coach/plugin.ts +6 -0
- package/plugins/job-coach/skills/career-report/SKILL.md +6 -0
- package/plugins/job-coach/skills/enterprise-ai-fit/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-competency/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-needs/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-roadmap/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-task-analysis/SKILL.md +8 -0
- package/plugins/job-coach/skills/interview-to-profile/SKILL.md +23 -0
- package/plugins/job-coach/skills/run-report/SKILL.md +15 -0
- package/scripts/backup/elanous-backup.sh +143 -14
- package/scripts/backup/elanous-restore.sh +122 -0
- package/scripts/build-docs-site.ts +4 -3
- package/scripts/ci-daemon-port-gate.ts +164 -0
- package/scripts/ci-typecheck-changed.ts +15 -1
- package/scripts/cli-json-exit-scan.ts +126 -0
- package/scripts/codex-quota-alert-format.ts +52 -0
- package/scripts/codex-quota-alert.ts +63 -13
- package/scripts/continuation-dogfood.ts +2 -1
- package/scripts/coord-channel-watch.sh +28 -9
- package/scripts/coord-post.sh +49 -12
- package/scripts/coord-tracks.json +6 -5
- package/scripts/cron-run.ts +37 -16
- package/scripts/daemon-port-baseline.txt +9 -0
- package/scripts/design/extract-corpus-bench.ts +469 -0
- package/scripts/design/extract-corpus-score.ts +510 -0
- package/scripts/design/vendor-open-design-systems.ts +100 -0
- package/scripts/docs-lint.ts +1 -1
- package/scripts/eval-bot-vs-grok.ts +79 -0
- package/scripts/eval-grok-live-baseline.ts +36 -0
- package/scripts/fixtures/front-route-corpus.sample.json +17 -0
- package/scripts/fleet/node-setup.sh +80 -7
- package/scripts/heal/run-role.ts +328 -0
- package/scripts/install-role-watch.sh +95 -0
- package/scripts/install.ps1 +11 -1
- package/scripts/install.sh +81 -9
- package/scripts/isolation-hardcode-baseline.txt +1 -1
- package/scripts/landing-heal/must-fix-match.ts +63 -0
- package/scripts/landing-heal/run-mission.ts +195 -0
- package/scripts/lib/front-route-measurement.ts +131 -0
- package/scripts/lib/pwa-scenarios/acp-replay.ts +79 -0
- package/scripts/lib/pwa-scenarios/cdp-driver.ts +67 -0
- package/scripts/lib/pwa-scenarios/runner.ts +200 -0
- package/scripts/lib/pwa-scenarios/scenarios.ts +202 -0
- package/scripts/lib/tui-sim-keys.ts +42 -0
- package/scripts/market/db-check.ts +212 -0
- package/scripts/market-posture-cycle.ts +63 -4
- package/scripts/measure-front-route-classifier.ts +56 -0
- package/scripts/media/ocr-leak-scan.sh +21 -0
- package/scripts/nightly-docops.ts +1 -1
- package/scripts/ops/channel-bot-token-migrate.ts +146 -0
- package/scripts/ops-health-check.ts +15 -3
- package/scripts/pty-scenarios/run.ts +272 -0
- package/scripts/public-export.ts +2 -3
- package/scripts/public-import-pr.ts +80 -6
- package/scripts/public-leak-baseline.txt +0 -7
- package/scripts/publish-internal-dist.ts +118 -0
- package/scripts/pwa-scenarios.ts +106 -0
- package/scripts/rebrand-elanous.ts +1 -1
- package/scripts/red-sweep-diff.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +72 -0
- package/scripts/release-loop/cutoff.ts +139 -0
- package/scripts/release-loop/docs-land-node.ts +65 -0
- package/scripts/release-loop/docs-node.ts +172 -0
- package/scripts/release-loop/gate-diff.ts +29 -0
- package/scripts/release-loop/gate-node.ts +641 -0
- package/scripts/release-loop/node-verdict.ts +85 -0
- package/scripts/release-loop/prepare-node.ts +31 -0
- package/scripts/release-loop/publish-node.ts +61 -0
- package/scripts/release-loop/pwa-node-verdict.ts +45 -0
- package/scripts/release-loop/pwa-scenarios-node.ts +140 -0
- package/scripts/release-loop/release-docs.ts +109 -0
- package/scripts/release-loop/test-durations.ts +63 -0
- package/scripts/release-loop/tui-node-checks.ts +29 -0
- package/scripts/release-loop/tui-sim-node.ts +113 -0
- package/scripts/release-loop/upgrade-node.ts +26 -0
- package/scripts/release-loop/verify-node.ts +21 -0
- package/scripts/release-loop/version-node.ts +147 -0
- package/scripts/release-upgrade-check.sh +53 -0
- package/scripts/se-mission-prepare.ts +9 -15
- package/scripts/test-audit-coverage-per-file.sh +16 -0
- package/scripts/test-audit-meaningless.ts +88 -0
- package/scripts/test-audit-overlap-and-weak.ts +73 -0
- package/scripts/test-deterministic.ts +29 -6
- package/scripts/tui-sim.ts +59 -14
- package/scripts/uninstall.sh +10 -3
- package/scripts/ux/bump-installed.sh +20 -0
- package/scripts/ux/lib/cdp.ts +72 -0
- package/scripts/ux/record-page.ts +50 -0
- package/scripts/video-broll-line.ts +89 -0
- package/scripts/waitlist-daily-digest.ts +108 -0
- package/scripts/window-landings.sh +1 -1
- package/skills/explainer-video/SKILL.md +99 -0
- package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -0
- package/skills/explainer-video/engine/build.mjs +431 -0
- package/skills/explainer-video/engine/vo.ts +37 -0
- package/skills/explainer-video/examples/elanous-0.2.5/script.json +155 -0
- package/skills/motion-broll/LICENSE +25 -0
- package/skills/motion-broll/SKILL.md +150 -0
- package/skills/motion-broll/SOURCE.md +6 -0
- package/skills/motion-broll/engine/base.css +19 -0
- package/skills/motion-broll/engine/beats.js +11 -0
- package/skills/motion-broll/engine/build.py +21 -0
- package/skills/motion-broll/engine/fonts/Geist-Variable.woff2 +0 -0
- package/skills/motion-broll/engine/fonts/GeistMono-Medium.woff2 +0 -0
- package/skills/motion-broll/engine/fonts/OFL-Geist.txt +92 -0
- package/skills/motion-broll/engine/motion.js +146 -0
- package/skills/motion-broll/engine/render.js +22 -0
- package/skills/motion-broll/examples/opus-aoe2/01-opus-drop.html +41 -0
- package/skills/motion-broll/examples/opus-aoe2/02-pip-builds.html +110 -0
- package/skills/motion-broll/examples/opus-aoe2/03-effort-slider.html +38 -0
- package/skills/motion-broll/examples/opus-aoe2/04-master-prompt.html +56 -0
- package/skills/motion-broll/examples/opus-aoe2/05-low-vs-max.html +49 -0
- package/skills/motion-broll/examples/opus-aoe2/06-chapter.html +18 -0
- package/skills/motion-broll/examples/opus-aoe2/plan.json +14 -0
- package/skills/motion-broll/reference/engine-api.md +106 -0
- package/skills/motion-broll/scripts/composite.py +14 -0
- package/skills/motion-broll/scripts/inspect_video.py +34 -0
- package/skills/motion-broll/scripts/make_pages.py +34 -0
- package/skills/motion-broll/scripts/setup.sh +16 -0
- package/skills/motion-broll/scripts/words.py +13 -0
- package/skills/motion-broll/templates/compare.html +135 -0
- package/skills/motion-broll/templates/viewer.html +97 -0
- package/skills/omni-digest/SKILL.md +260 -0
- package/skills/omni-digest/digest.md +197 -0
- package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +32 -0
- package/skills/omni-digest/package-lock.json +558 -0
- package/skills/omni-digest/package.json +13 -0
- package/skills/omni-digest/scripts/main.ts +404 -0
- package/skills/omni-digest/src/delegate.ts +34 -0
- package/skills/omni-digest/src/detect.ts +46 -0
- package/skills/omni-digest/src/diagram.ts +72 -0
- package/skills/omni-digest/src/domain-staging.ts +50 -0
- package/skills/omni-digest/src/env.ts +38 -0
- package/skills/omni-digest/src/fetch.ts +237 -0
- package/skills/omni-digest/src/media.ts +180 -0
- package/skills/omni-digest/src/obsidian.ts +69 -0
- package/skills/omni-digest/src/ocr.ts +149 -0
- package/skills/omni-digest/src/router.ts +60 -0
- package/skills/omni-digest/src/summarize.ts +87 -0
- package/skills/omni-digest/src/types.ts +124 -0
- package/skills/omni-digest/src/util.ts +34 -0
- package/skills/omni-digest/src/visual.ts +129 -0
- package/skills/omni-digest/src/x-api.ts +151 -0
- package/skills/omni-digest/tsconfig.json +13 -0
- package/src/a2a/agent-card.ts +29 -0
- package/src/a2a/server.ts +173 -0
- package/src/acp/auto-persist.ts +3 -6
- package/src/acp/backend-registry.ts +6 -10
- package/src/acp/channel-browser-shell.ts +1 -535
- package/src/acp/client.ts +106 -36
- package/src/acp/fs-roots.ts +20 -4
- package/src/acp/obsidian-tags.ts +6 -3
- package/src/acp/server.ts +189 -32
- package/src/agent/nested-agent-env.ts +1 -0
- package/src/agent/pty-binding.ts +1 -1
- package/src/agent/spawn-embodied-agent-in-vw.ts +5 -336
- package/src/agent/subagent-callable.ts +39 -1
- package/src/agent-mission/browser-login.ts +241 -0
- package/src/agent-mission/capabilities-cli.ts +33 -0
- package/src/agent-mission/capability-matrix.ts +31 -0
- package/src/agent-mission/capability-readers.ts +79 -0
- package/src/agent-mission/capability-types.ts +15 -0
- package/src/agent-mission/claude-headless.ts +131 -0
- package/src/agent-mission/claude-subscription.ts +57 -0
- package/src/agent-mission/doc-guided-install.ts +185 -0
- package/src/agent-mission/driver.ts +900 -69
- package/src/agent-mission/env-profile.ts +68 -0
- package/src/agent-mission/handoff.ts +128 -0
- package/src/agent-mission/in-agent-plugin.ts +311 -0
- package/src/agent-mission/mission-cli.ts +25 -1
- package/src/agent-mission/parse.ts +9 -4
- package/src/agent-mission/pr-review-watch.ts +62 -13
- package/src/agent-mission/resource-ladder.ts +235 -0
- package/src/agent-mission/tool-install.ts +249 -0
- package/src/agent-mission/tool-ladder.ts +37 -0
- package/src/agent-room/room-builder.ts +6 -600
- package/src/agent-substrate/review-intent.ts +43 -1
- package/src/auth/acp-token.ts +16 -0
- package/src/auth/github-app-token.ts +112 -0
- package/src/auth/scope.ts +8 -4
- package/src/auth/temp-tokens.ts +131 -0
- package/src/auto-research/obsidian-bridge.ts +2 -0
- package/src/autopilot/build/integrity-gate.ts +27 -4
- package/src/autopilot/build/isolated-instance.ts +2 -1
- package/src/autopilot/build/llm-conflict-merge.ts +27 -0
- package/src/autopilot/gh-rest-fallback.ts +177 -0
- package/src/autopilot/llm-control-brain.ts +54 -12
- package/src/autopilot/mission-engine.ts +15 -1
- package/src/autopilot/mission-notify.ts +4 -2
- package/src/autopilot/mission-origin.ts +5 -5
- package/src/autopilot/mission-phase-track.ts +52 -0
- package/src/autopilot/mission-tool.ts +1 -1
- package/src/autopilot/pr-manager.ts +51 -4
- package/src/autopilot/pty-control-loop.ts +94 -2
- package/src/autopilot/track-agent.ts +138 -0
- package/src/autopilot/track-courier.ts +153 -0
- package/src/boot/acp-server.ts +18 -18
- package/src/boot/check-same-origin.ts +19 -5
- package/src/boot/daemon-multi-llm-runtime.ts +14 -8
- package/src/boot/daemon-prompt-turn.ts +2 -0
- package/src/boot/daemon-runtime.ts +36 -14
- package/src/boot/daemon-tools/index.ts +16 -0
- package/src/boot/daemon-tools/self-implement.ts +4 -0
- package/src/boot/daemon-tools/types.ts +3 -0
- package/src/boot/daemon-tools/web-search.ts +2 -1
- package/src/boot/ws-bridge.ts +11 -0
- package/src/browser-cdp/chrome-flags.ts +7 -0
- package/src/browser-cdp/client.ts +2 -0
- package/src/browser-pane/mount.ts +1 -246
- package/src/budget/codex-reset-credit-state.ts +15 -0
- package/src/budget/fetchers/codex.ts +2 -1
- package/src/budget/run-usage-rollup.ts +11 -4
- package/src/budget/unified-usage.ts +2 -1
- package/src/capture/tui-self-report.ts +10 -0
- package/src/channel-bot-token.ts +126 -0
- package/src/chat/index.ts +57 -52
- package/src/chat/input-text-key.ts +2 -2
- package/src/chat/log-scroll-key.ts +12 -0
- package/src/chat/mode/manual.ts +2 -4
- package/src/chat/pickers/state.ts +10 -27
- package/src/chat/search/modal.ts +14 -2
- package/src/chat/submit-trace.ts +30 -0
- package/src/chat/tool-render/types.ts +1 -1
- package/src/chat/turn-typeahead.ts +2 -1
- package/src/chat/wrap.ts +6 -8
- package/src/cli/__fixtures__/agent-help-before/agent.txt +18 -0
- package/src/cli/__fixtures__/agent-help-before/registry.txt +13 -0
- package/src/cli/__fixtures__/agent-help-before/root.txt +100 -0
- package/src/cli/__fixtures__/agent-help-before/tier.txt +15 -0
- package/src/cli/a2a-cli.ts +52 -0
- package/src/cli/agent-cli.ts +726 -0
- package/src/cli/autopilot-cli.ts +739 -0
- package/src/cli/bg-launch.ts +20 -4
- package/src/cli/claude-plugin-setup.ts +199 -0
- package/src/cli/config-test-sync.ts +94 -10
- package/src/cli/connector-cli.ts +204 -0
- package/src/cli/control-cli.ts +220 -0
- package/src/cli/control-join-cli.ts +142 -0
- package/src/cli/decisions-cli.ts +94 -0
- package/src/cli/docs-cli.ts +38 -0
- package/src/cli/doctor-cli.ts +262 -77
- package/src/cli/doctor-distro.ts +17 -1
- package/src/cli/doctor-fix.ts +145 -17
- package/src/cli/doctor-llm-assist.ts +71 -0
- package/src/cli/doctor-private-files.ts +66 -0
- package/src/cli/doctor-readiness.ts +23 -28
- package/src/cli/fleet-cli.ts +63 -0
- package/src/cli/g6a-registration-probe.ts +16 -0
- package/src/cli/git-install-plan.ts +51 -0
- package/src/cli/hooks-cli.ts +44 -0
- package/src/cli/ingest-token-cli.ts +21 -0
- package/src/cli/intake-cli.ts +416 -0
- package/src/cli/labels-cli.ts +74 -0
- package/src/cli/leader-cli.ts +10 -159
- package/src/cli/live-cli.ts +48 -0
- package/src/cli/llm-detect-cli.ts +130 -0
- package/src/cli/logs-cli.ts +231 -7
- package/src/cli/machine-cli.ts +38 -0
- package/src/cli/mcp-call.ts +52 -13
- package/src/cli/mcp-gateway-cli.ts +94 -0
- package/src/cli/mcp-login.ts +116 -8
- package/src/cli/mcp-reload.ts +20 -3
- package/src/cli/nexus-dist.ts +18 -13
- package/src/cli/nexus-ios-bind.ts +20 -7
- package/src/cli/ops-cli.ts +225 -0
- package/src/cli/plugin-cli.ts +201 -0
- package/src/cli/pod-cli.ts +83 -0
- package/src/cli/port-lease-local.ts +124 -0
- package/src/cli/pr-cli.ts +12 -1
- package/src/cli/pr-lineage.ts +2 -1
- package/src/cli/provider-cli.ts +720 -0
- package/src/cli/pty-record-cli.ts +63 -0
- package/src/cli/pty-takeover-cli.ts +57 -40
- package/src/cli/pty-web-address.ts +52 -0
- package/src/cli/publish-cli.ts +44 -0
- package/src/cli/pwa-build.ts +18 -12
- package/src/cli/pwa-dev.ts +13 -8
- package/src/cli/pwa-registry.ts +6 -0
- package/src/cli/pwa-share.ts +65 -22
- package/src/cli/pwa-show.ts +20 -4
- package/src/cli/pwa-start.ts +102 -27
- package/src/cli/pwa-test.ts +201 -96
- package/src/cli/release-cli.ts +177 -7
- package/src/cli/remotes-cli.ts +20 -1
- package/src/cli/remotes.ts +2 -1
- package/src/cli/repo-cli.ts +315 -36
- package/src/cli/research-cli.ts +66 -0
- package/src/cli/role-cli.ts +320 -0
- package/src/cli/schedule-cli.ts +246 -0
- package/src/cli/self-update.ts +103 -12
- package/src/cli/setup-cli.ts +64 -2
- package/src/cli/shadow-cli.ts +188 -0
- package/src/cli/share-auto-mount.ts +12 -8
- package/src/cli/start-cli.ts +240 -0
- package/src/cli/stdout-flush.ts +8 -0
- package/src/cli/storage-cli.ts +334 -0
- package/src/cli/tailscale-serve.ts +34 -19
- package/src/cli/tasks-cli.ts +176 -0
- package/src/cli/test-state-dir-flag.ts +1 -1
- package/src/cli/usage-cli.ts +15 -4
- package/src/cli/where-cli.ts +22 -55
- package/src/code-edit/diff-render.ts +6 -32
- package/src/code-edit/source-delta-browser.ts +0 -1
- package/src/codex/models.ts +1 -1
- package/src/config.ts +8 -13
- package/src/connectors/event-ledger.ts +41 -0
- package/src/connectors/linear-projector.ts +88 -0
- package/src/connectors/linear.ts +143 -0
- package/src/connectors/types.ts +19 -0
- package/src/control-plane/lease-holder.ts +41 -0
- package/src/control-plane/ledger.ts +146 -0
- package/src/control-plane/light-member.ts +164 -0
- package/src/control-plane/member-tokens.ts +88 -0
- package/src/control-plane/member.ts +159 -0
- package/src/control-plane/port-lease-heartbeat.ts +101 -0
- package/src/control-plane/ports.ts +40 -0
- package/src/control-plane/primary.ts +169 -0
- package/src/control-plane/server.ts +216 -0
- package/src/dashboard/acp-boot.ts +14 -38
- package/src/dashboard/assistant-render-state-runtime.ts +2 -2
- package/src/dashboard/assistant-sample-runtime.ts +2 -2
- package/src/dashboard/auto-compact-runtime.ts +11 -16
- package/src/dashboard/browser-help-runtime.ts +2 -3
- package/src/dashboard/chat/acp-chat.ts +2 -5
- package/src/dashboard/code-edit-post-turn-runtime.ts +1 -2
- package/src/dashboard/compact-surface-assembly.ts +0 -14
- package/src/dashboard/compact-surface-dispatch.ts +1 -38
- package/src/dashboard/compact-surface-inventory.ts +0 -8
- package/src/dashboard/compact-surface-runtime.ts +0 -14
- package/src/dashboard/context-menu-provider-boot.ts +0 -9
- package/src/dashboard/context-window-runtime-boot.ts +0 -37
- package/src/dashboard/index.ts +331 -2562
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +0 -6
- package/src/dashboard/input/chat-main-slash-command.ts +2 -2
- package/src/dashboard/input/dashboard-priority-key-route.ts +1 -43
- package/src/dashboard/input/mouse-modal-surface-runtime.ts +1 -5
- package/src/dashboard/input/mouse-wiring.ts +2 -3
- package/src/dashboard/input/no-provider-reply.ts +13 -0
- package/src/dashboard/layout-display-runtime-registration.ts +0 -10
- package/src/dashboard/modals/pane-multi.ts +1 -1
- package/src/dashboard/replay-preview.ts +1 -1
- package/src/dashboard/runtime/approvers.ts +0 -1
- package/src/dashboard/runtime/state-snapshot.ts +0 -90
- package/src/dashboard/scenario-runtime-boot.ts +16 -16
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +134 -1456
- package/src/dashboard/slash-runtime/design-pick.ts +96 -0
- package/src/dashboard/slash-runtime/help-from-registry.ts +77 -0
- package/src/dashboard/slash-runtime/unknown-slash-reply.ts +78 -0
- package/src/dashboard/stale-install-check.ts +77 -0
- package/src/dashboard/surface-registry-wiring.ts +2 -15
- package/src/dashboard/turn-message-runtime.ts +0 -4
- package/src/dashboard/turn-preamble.ts +1 -1
- package/src/dashboard/turn-stream-formatter.ts +2 -2
- package/src/dashboard/turn-stream-runtime.ts +2 -2
- package/src/dashboard-pane-context-menu.ts +0 -14
- package/src/debug/log.ts +7 -0
- package/src/decide/boundary-shadow.ts +131 -0
- package/src/decisions/decision-ledger.ts +404 -0
- package/src/design/apply-direction.ts +209 -0
- package/src/design/css-root-tokens.ts +89 -0
- package/src/design/custom-system-create.ts +230 -0
- package/src/design/design-directions.ts +61 -41
- package/src/design/design-gate.ts +241 -0
- package/src/design/design-library.ts +57 -0
- package/src/design/design-previews.ts +138 -0
- package/src/design/design-systems.ts +61 -0
- package/src/design/lint-artifact-run.ts +46 -6
- package/src/design/lint-artifact.ts +5 -1
- package/src/design/open-design-client.ts +247 -0
- package/src/design/system-from-extract.ts +767 -0
- package/src/design/system-schema.ts +123 -0
- package/src/discord-slash-wire.ts +2 -1
- package/src/discord-test-runner.ts +2 -1
- package/src/discord-voice-wire.ts +2 -1
- package/src/discord.ts +1 -1
- package/src/dispatch/opportunistic-launcher.ts +24 -1
- package/src/domains/ops-status.ts +35 -2
- package/src/domains/outbound-alert.ts +24 -6
- package/src/domains/repeated-failure.ts +89 -0
- package/src/domains/schedule-manage-tool.ts +28 -8
- package/src/domains/schedule-migrate.ts +22 -4
- package/src/domains/schedule-registry.ts +88 -33
- package/src/domains/schedule-runs.ts +132 -0
- package/src/domains/schedule-state.ts +152 -0
- package/src/domains/telegram-kind-route.ts +21 -0
- package/src/element-registry/address.ts +1 -3
- package/src/execution-loop/dispatch-task.ts +139 -0
- package/src/execution-loop/gate-decision-summary.ts +29 -0
- package/src/execution-loop/gates.ts +197 -0
- package/src/git-fs/gh-cli.ts +47 -17
- package/src/git-fs/retry.ts +1 -0
- package/src/git-fs/runner.ts +1 -0
- package/src/git-fs/worktree.ts +6 -5
- package/src/github/pr-labels.ts +68 -0
- package/src/graph-kinds/installed-plugin-nodes.ts +95 -0
- package/src/graph-kinds/plugin-nodes.ts +68 -0
- package/src/graph-kinds/registry.ts +118 -0
- package/src/graph-runner/graph-cli.ts +103 -0
- package/src/graph-runner/graph-notify.ts +220 -0
- package/src/graph-runner/graph-tick.ts +119 -0
- package/src/graph-runner/release-manifest.ts +93 -0
- package/src/graph-runner/runner.ts +487 -0
- package/src/grok/credential.ts +158 -5
- package/src/grounding/ensure-grounding.ts +131 -0
- package/src/grounding/mirror-export.ts +89 -0
- package/src/grounding/mirror-manifest.ts +252 -0
- package/src/grounding/sources-cli.ts +209 -0
- package/src/grounding/sources.ts +333 -0
- package/src/grounding/token.ts +121 -0
- package/src/harness/harness-cli-command.ts +415 -23
- package/src/harness/harness-pod-dispatch.ts +116 -0
- package/src/harness/harness-stop.ts +260 -0
- package/src/harness/harness-substrate-default.ts +40 -0
- package/src/harness/harness-worktrees.ts +1 -1
- package/src/harness/harness-write-boundary.ts +2 -0
- package/src/harness/llm-decompose.ts +2 -1
- package/src/harness/self-send-decide.ts +233 -0
- package/src/harness/self-send-target.ts +22 -1
- package/src/harness/shell-relay.ts +5 -0
- package/src/harness/worktree-branch-prefix.ts +4 -3
- package/src/hooks/providers.ts +77 -0
- package/src/hooks/queue.ts +73 -0
- package/src/hooks/receiver.ts +133 -0
- package/src/index.ts +712 -3409
- package/src/input-core/dispatcher.ts +1 -1
- package/src/input-core/drag-esc-interceptor.ts +1 -1
- package/src/instance/current.ts +5 -5
- package/src/instance/leader.ts +10 -326
- package/src/instance/nexus-run-refusal.ts +27 -92
- package/src/instance/project-local-exclude.ts +27 -0
- package/src/instance/resolve.ts +46 -175
- package/src/intake-plane/capture.ts +14 -1
- package/src/intake-plane/check.ts +34 -14
- package/src/intake-plane/collect-github.ts +258 -0
- package/src/intake-plane/collect-pod.ts +100 -0
- package/src/intake-plane/collect-telegram-saved.ts +91 -0
- package/src/intake-plane/digest.ts +111 -0
- package/src/intake-plane/enrich-plugins.ts +1 -1
- package/src/intake-plane/front-classifier.ts +56 -0
- package/src/intake-plane/front-route-classifier.ts +80 -0
- package/src/intake-plane/front-route-rules.ts +152 -0
- package/src/intake-plane/grounding-docs.ts +185 -0
- package/src/intake-plane/harness-target.ts +20 -0
- package/src/intake-plane/intake-to-tasks.ts +303 -0
- package/src/intake-plane/items.ts +247 -0
- package/src/intake-plane/link-ledger.ts +27 -0
- package/src/intake-plane/route.ts +104 -0
- package/src/intake-plane/runtime-callables.ts +3 -1
- package/src/intake-plane/sketch-ledger.ts +34 -0
- package/src/intake-plane/slash.ts +30 -2
- package/src/intake-plane/submit-intake-work.ts +160 -0
- package/src/intake-plane/telegram-work.ts +56 -0
- package/src/iul/sidebar-shell.ts +0 -165
- package/src/launch-head/capability-check.ts +162 -0
- package/src/launch-head/launch-head-cli.ts +242 -0
- package/src/launch-head/load-balance.ts +81 -0
- package/src/live/detail-switch.ts +180 -0
- package/src/llm/provider-detect.ts +247 -0
- package/src/llm/provider-probe.ts +57 -0
- package/src/llm/usable-llm.ts +32 -0
- package/src/llm.ts +55 -23
- package/src/log-entry.ts +1 -1
- package/src/log-pane/attachment-popup.ts +1 -2
- package/src/loops/loop-cli.ts +37 -0
- package/src/loops/registry.ts +196 -0
- package/src/market/official-keys.ts +5 -0
- package/src/market/publish.ts +329 -0
- package/src/market/signed-index.ts +156 -0
- package/src/market/tgz.ts +121 -0
- package/src/mcp/client.ts +1 -1
- package/src/mcp/mcp-oauth.ts +40 -5
- package/src/mcp/server.ts +75 -7
- package/src/mcp-gateway/gateway.ts +128 -0
- package/src/mcp-gateway/pat-store.ts +124 -0
- package/src/mss/logging/log-store.ts +91 -2
- package/src/mss/logging/scoped-level.ts +5 -9
- package/src/native-tool-catalog.ts +66 -345
- package/src/nexus/api/connect-info.ts +23 -25
- package/src/nexus/api/context-url.ts +1 -1
- package/src/nexus/api/design-check.ts +90 -59
- package/src/nexus/api/design-previews-route.ts +182 -0
- package/src/nexus/api/design-system-create-route.ts +123 -0
- package/src/nexus/api/graph-approvals.ts +125 -0
- package/src/nexus/api/graph-kinds.ts +69 -0
- package/src/nexus/api/graphs-api.ts +221 -0
- package/src/nexus/api/harness-api.ts +31 -2
- package/src/nexus/api/health.ts +15 -0
- package/src/nexus/api/http-server.ts +328 -43
- package/src/nexus/api/image-generate.ts +3 -0
- package/src/nexus/api/ingest-token.ts +175 -0
- package/src/nexus/api/intake-ledger-api.ts +54 -0
- package/src/nexus/api/intake-route.ts +111 -0
- package/src/nexus/api/json-response.ts +33 -0
- package/src/nexus/api/live-detail.ts +47 -0
- package/src/nexus/api/live-shipped.ts +78 -0
- package/src/nexus/api/log-fabric.ts +42 -2
- package/src/nexus/api/markdown-publish.ts +3 -2
- package/src/nexus/api/mcp-http.ts +14 -9
- package/src/nexus/api/mcp-oauth-hint.ts +31 -0
- package/src/nexus/api/mcp-public-allowlist.ts +33 -0
- package/src/nexus/api/merge-approvals-gate.ts +79 -0
- package/src/nexus/api/merge-approvals.ts +307 -0
- package/src/nexus/api/meta-api.ts +18 -0
- package/src/nexus/api/next-fluent-wiring.ts +7 -9
- package/src/nexus/api/plugins-credentials-api.ts +47 -0
- package/src/nexus/api/plugins-market.ts +209 -0
- package/src/nexus/api/pod-credential-api.ts +187 -0
- package/src/nexus/api/public-routes.ts +87 -0
- package/src/nexus/api/rest-route-paths.ts +15 -0
- package/src/nexus/api/schedules-action.ts +12 -3
- package/src/nexus/api/schedules-read.ts +228 -0
- package/src/nexus/api/sessions-store.ts +8 -2
- package/src/nexus/api/setup-answer-priority.ts +130 -0
- package/src/nexus/api/setup-channel-bot.ts +56 -0
- package/src/nexus/api/setup-child-llm.ts +228 -0
- package/src/nexus/api/setup-obsidian-skills.ts +93 -0
- package/src/nexus/api/task-cards-api.ts +34 -0
- package/src/nexus/api/tasks-create.ts +136 -0
- package/src/nexus/api/telegram-trigger-bot.ts +3 -3
- package/src/nexus/api/terminals.ts +204 -18
- package/src/nexus/api/trace.ts +405 -0
- package/src/nexus/api/vault-api.ts +140 -7
- package/src/nexus/api/worktrees.ts +18 -2
- package/src/nexus/boot/register-mcp-clients.ts +135 -16
- package/src/nexus/daemon-endpoint.ts +85 -0
- package/src/nexus/default-port.ts +1 -0
- package/src/nexus/index.ts +362 -143
- package/src/nexus/onboarding/pwa-share-prompt.ts +31 -8
- package/src/nexus/onboarding/tailscale-probe.ts +9 -1
- package/src/nexus/outbound/router.ts +1 -1
- package/src/nexus/setup-status.ts +58 -0
- package/src/nexus/supervisor/lock.ts +8 -0
- package/src/nexus/webterm/pty.ts +15 -0
- package/src/oauth/codex-account-rotation.ts +122 -16
- package/src/oauth/codex-account-store.ts +88 -19
- package/src/oauth/codex-quota-policy.ts +55 -0
- package/src/oauth/store.ts +28 -25
- package/src/obsidian/default-vault.ts +17 -0
- package/src/obsidian/vault-write-guard.ts +46 -0
- package/src/onboarding/help/llm.md +2 -2
- package/src/onboarding.ts +27 -4
- package/src/panes/alt-skip-predicate.ts +4 -3
- package/src/panes/external-terminal-pane.ts +3 -4
- package/src/panes/factory.ts +1 -18
- package/src/panes/index.ts +1 -5
- package/src/panes/pane-cycle.ts +1 -1
- package/src/panes/types.ts +1 -1
- package/src/platform/env-literal.ts +4 -0
- package/src/plugin-hooks/dispatcher.ts +10 -4
- package/src/plugins/core/host.ts +108 -4
- package/src/plugins/core/manifest.ts +104 -7
- package/src/plugins/install/market-fetch.ts +250 -0
- package/src/plugins/install/plugin-credentials.ts +106 -0
- package/src/plugins/install/plugin-install.ts +518 -0
- package/src/policy/claude-subscription-guard.ts +25 -0
- package/src/preview/terminal.ts +24 -1
- package/src/preview-pane/mount.ts +1 -142
- package/src/prompt/references.ts +4 -51
- package/src/prompt-library/universal-preamble.ts +8 -2
- package/src/pty-shell/pty-control-ipc.ts +57 -3
- package/src/pty-shell/pty-mouse.ts +75 -0
- package/src/pty-shell/pty-recording.ts +108 -0
- package/src/pty-shell/registry.ts +53 -3
- package/src/python/resolve-python.ts +1 -1
- package/src/release-loop/checklist.ts +191 -0
- package/src/release-loop/manifest.ts +65 -0
- package/src/release-loop/release-note.ts +177 -0
- package/src/roles/lease-cas.ts +52 -0
- package/src/roles/machine-name.ts +48 -0
- package/src/roles/machine-profile.ts +65 -0
- package/src/roles/role-lease-read.ts +81 -0
- package/src/roles/role-lease.ts +63 -0
- package/src/roles/role-watch.ts +69 -0
- package/src/self-dev/ask-launch-flow.ts +39 -22
- package/src/self-dev/ask-launch-io.ts +1 -1
- package/src/self-dev/dev-cli.ts +290 -159
- package/src/self-dev/dev-pipeline.ts +157 -9
- package/src/self-dev/draft-sweep.ts +231 -0
- package/src/self-dev/draft-triage-rules.ts +42 -0
- package/src/self-dev/entrance-baseline.ts +156 -4
- package/src/self-dev/fabric-decompose-adapter.ts +10 -0
- package/src/self-dev/launch-preflight.ts +1 -1
- package/src/self-dev/orchestrate.ts +297 -20
- package/src/self-dev/repair-signals.ts +6 -0
- package/src/self-dev/run-store.ts +20 -5
- package/src/self-dev/run-supervisor.ts +43 -3
- package/src/self-implement/abandoned-classification.ts +15 -1
- package/src/self-implement/blocked-draft-policy.ts +6 -0
- package/src/self-implement/budget-gate.ts +236 -0
- package/src/self-implement/child-llm-preference.ts +84 -0
- package/src/self-implement/decision-events.ts +57 -0
- package/src/self-implement/decision-signal-press.ts +5 -2
- package/src/self-implement/dependency-change-gate.ts +90 -0
- package/src/self-implement/gate-baseline.ts +35 -2
- package/src/self-implement/gate-cli.ts +29 -7
- package/src/self-implement/gate-scope.ts +7 -1
- package/src/self-implement/goal-author-decompose.ts +22 -4
- package/src/self-implement/goal-author.ts +41 -3
- package/src/self-implement/goal-boundary.ts +65 -0
- package/src/self-implement/goal-clarification-escalation.ts +1 -0
- package/src/self-implement/goal-documents-dir.ts +6 -1
- package/src/self-implement/goal-execution-records.ts +58 -0
- package/src/self-implement/goal-run-store.ts +42 -24
- package/src/self-implement/graph-authority.ts +13 -28
- package/src/self-implement/graph-catalog.ts +48 -0
- package/src/self-implement/graph-run-contract.ts +127 -0
- package/src/self-implement/graph-templates.ts +14 -7
- package/src/self-implement/graph-yaml.ts +35 -6
- package/src/self-implement/harness-policy-gates.ts +42 -0
- package/src/self-implement/headless-elanous-driver.ts +30 -6
- package/src/self-implement/heal-triage.ts +229 -0
- package/src/self-implement/host-regate.ts +244 -0
- package/src/self-implement/non-git-consent.ts +23 -0
- package/src/self-implement/orchestrator.ts +488 -134
- package/src/self-implement/pipeline-shape.ts +1 -1
- package/src/self-implement/pr-evidence-artifact.ts +6 -19
- package/src/self-implement/prior-draft-findings.ts +128 -0
- package/src/self-implement/pwa-import-graph.ts +65 -0
- package/src/self-implement/repo-provision.ts +18 -21
- package/src/self-implement/report-origin.ts +39 -0
- package/src/self-implement/rework-policy.ts +21 -0
- package/src/self-implement/run-ledger-compact.ts +438 -0
- package/src/self-implement/run-ledger.ts +212 -29
- package/src/self-implement/run-report.ts +24 -0
- package/src/self-implement/run-status-mapping.ts +2 -0
- package/src/self-implement/running-runs.ts +112 -14
- package/src/self-implement/scoped-typecheck-config.ts +49 -0
- package/src/self-implement/seams.ts +207 -40
- package/src/self-implement/self-implement-cli.ts +17 -2
- package/src/self-implement/shadow-repo.ts +350 -0
- package/src/self-implement/supervision-vocabulary.ts +7 -0
- package/src/shell-runner/dispatch.ts +3 -0
- package/src/shell-runner/index.ts +0 -7
- package/src/skills/runner.ts +0 -69
- package/src/skills/tools/agent-room-slash.ts +2 -1
- package/src/skills/tools/agent-room.ts +8 -140
- package/src/skills/tools/agent.ts +5 -3
- package/src/skills/tools/context.ts +5 -140
- package/src/skills/tools/control.ts +4 -188
- package/src/skills/tools/dashboard-slash.ts +3 -11
- package/src/skills/tools/dashboard-state.ts +3 -5
- package/src/skills/tools/dev-harness.ts +45 -2
- package/src/skills/tools/omni-search.ts +29 -1
- package/src/skills/tools/shell.ts +11 -29
- package/src/skills/tools/spawn-coding-agent-headless.ts +6 -9
- package/src/ssh/ssh-picker-modal.ts +1 -1
- package/src/steward/directive.ts +99 -0
- package/src/steward/steward-cards.ts +45 -0
- package/src/steward/triage.ts +239 -0
- package/src/storage/cli-bin.ts +67 -0
- package/src/storage/object-store-visibility.ts +169 -0
- package/src/storage/object-store.ts +452 -0
- package/src/storage/s3.ts +53 -10
- package/src/storage/storage-detect.ts +337 -0
- package/src/surface/address.ts +3 -5
- package/src/surface/index.ts +0 -6
- package/src/surface/llm-tools.ts +1 -2
- package/src/surface/shell-runner-boot.ts +4 -89
- package/src/task-cards/card-cli.ts +64 -0
- package/src/task-cards/card-store.ts +241 -0
- package/src/task-orchestrator/boot.ts +27 -1
- package/src/task-orchestrator/dispatcher.ts +49 -7
- package/src/task-orchestrator/external-fingerprint.ts +10 -0
- package/src/task-orchestrator/external-policy.ts +86 -0
- package/src/task-orchestrator/feedback-loop.ts +4 -2
- package/src/task-orchestrator/graph.ts +18 -1
- package/src/task-orchestrator/runtimes/create.ts +128 -0
- package/src/task-orchestrator/store.ts +78 -18
- package/src/task-orchestrator/surface-registry.ts +5 -2
- package/src/task-orchestrator/surfaces/external-exec.ts +180 -0
- package/src/task-orchestrator/surfaces/idea-approval-pr.ts +118 -0
- package/src/task-orchestrator/surfaces/index.ts +4 -3
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +60 -5
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +194 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +369 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +207 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +128 -12
- package/src/task-orchestrator/surfaces/pod-skills.ts +11 -3
- package/src/task-orchestrator/surfaces/pod-source-bundle.ts +147 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +129 -0
- package/src/task-orchestrator/surfaces/pod-source-spec.ts +77 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +930 -45
- package/src/task-orchestrator/surfaces/self-implement.ts +8 -1
- package/src/task-orchestrator/tox-loop.ts +204 -0
- package/src/task-orchestrator/types.ts +21 -1
- package/src/telegram-commands.ts +8 -0
- package/src/telegram-report.ts +14 -7
- package/src/telegram-run.ts +18 -5
- package/src/telegram.ts +92 -22
- package/src/tool-runtime/acp-session-runtime.ts +28 -7
- package/src/tool-runtime/agent-runtime.ts +1 -0
- package/src/tool-runtime/context-runtime.ts +18 -35
- package/src/tool-runtime/control-runtime.ts +8 -21
- package/src/tool-runtime/dashboard-state-runtime.ts +1 -5
- package/src/tool-runtime/elanous-asana-runtimes.ts +205 -0
- package/src/tool-runtime/elanous-control-runtimes.ts +16 -2
- package/src/tool-runtime/elanous-task-submit-runtime.ts +124 -0
- package/src/tool-runtime/index.ts +4 -1
- package/src/tool-runtime/scenario-runtimes.ts +22 -21
- package/src/tool-runtime/scenario-target-mount.ts +6 -32
- package/src/tool-runtime/types.ts +8 -0
- package/src/tui/chat/attachment-summary.ts +4 -4
- package/src/tui-client/acp-transport-ws-client.ts +72 -5
- package/src/tui-client/headless-core-guard.ts +0 -1
- package/src/tui.ts +11 -7
- package/src/typecheck-ratchet.ts +15 -0
- package/src/ui/hover-presenter.ts +3 -7
- package/src/user-config.ts +453 -190
- package/src/util/spawn-sync-output.ts +15 -0
- package/src/version/code-revision.ts +34 -9
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/broll-agent.ts +102 -0
- package/src/video-pipeline/recipes/broll.ts +263 -0
- package/src/video-pipeline/walk-line.ts +2 -1
- package/src/views/scratch-image-size.ts +10 -0
- package/src/voice/channel-adapters/pwa-voice-adapter.ts +2 -18
- package/src/voice/channel-adapters/telegram-voice-adapter.ts +1 -6
- package/src/voice/voice-tts-singleton.ts +46 -8
- package/src/web-push/vapid-keys.ts +1 -1
- package/src/web-search/free.ts +77 -0
- package/src/web-search/index.ts +7 -5
- package/src/web-terminal/preview-tap-registry.ts +152 -43
- package/src/workflow-runtime/deps-bridge.ts +4 -3
- package/src/workflow-runtime/executor.ts +18 -22
- package/src/workflow-runtime/node-catalog.ts +20 -1
- package/src/workflow-runtime/nodes/bash.ts +1 -0
- package/src/workflow-runtime/nodes/task.ts +74 -0
- package/src/workflow-runtime/nodes/triggers.ts +24 -1
- package/src/workflow-runtime/plugin-kind-node.ts +166 -0
- package/src/workflow-runtime/schema.ts +98 -2
- package/src/workflow-runtime/triggers/webhook-router.ts +43 -3
- package/src/workflow-runtime/triggers/webhook-source.ts +19 -1
- package/src/workflow-runtime/types.ts +76 -5
- package/apps/pwa/out/_next/static/Ksn99fVf2HUWhSyV1-FC8/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1176-4943bd83b00e53a2.js +0 -25
- package/apps/pwa/out/_next/static/chunks/1380-9c652e1002032c86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1863-2ea170dfec26b88b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2091-2d6b7f4f16300f83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2347-366617ec73babe3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3089-e60cc8f5d35ee239.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3158-c77ed9ea34f9cc9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3607-f0b5c5ee18fcf56a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3659-05b2d5d971b42dbc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3736-b6a7bfdcb8f56ec6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3839-eebf298e89a7bb77.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4012.832a2824b978e7ee.js +0 -5
- package/apps/pwa/out/_next/static/chunks/4706-d85d7f3345f3ff91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/526-17a6a2e0e6dc4498.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5508-676ac75f2757ad40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5583-8a0317f4b8e68db9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6258-b58f722b10e8d31d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6820-32fd097e6186fdc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6852-983db7ca958634b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7235-e583e4a015e159b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7482-7b417330b24a996a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7701-99b7d4dedb955bf8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/77f1928d-bd3777589042d3ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8366-36956cafc5e33614.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8370-23d0de995be666f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8617-307421f3b0e8b2a2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8837-e45de46a9fedf1f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9058-0e8055a5ea3ebdd6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-84b84eca12acada4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1f23568c29e88f7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-bf6fc9aafd6135a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-3f8539ae4b719d2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d2900febb74ecf32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-e82dec647dd79c36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/dashboard/page-096ec743a8ee955a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-255c2ceded4b3493.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-84b84eca12acada4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2db61b2f9efba61f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-e11ee17f221aaa9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e075974e029ce4c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-ec5b68a9af3366a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-986c177afb4adae6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-a72781461af2f2a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-92781cbaafc487ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2c14d2a1f2930f33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-22ee4bf8070b2b4d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9c06e4a8297942a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d0cd32f6d373798f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0c1642018d87ebb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-93e5e97d614df487.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-84b84eca12acada4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b1ce871940d7393e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-ae154addf345febe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-90af3aa813d2053c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f3f962fda428a738.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-1c1f7cc1d5def06d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-09d4cbdaaacf06c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e877b8e8ca90b27f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-71d902f463dea526.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-40ea576cefa25fe6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a56a3f178c3831f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/bcc499d1-804a270d878e0842.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-b25b7c5501c59b6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-a9ec9da43387afff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-aa2c05954aaa6754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-bb3768fb4b84aebb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-2820ba75b87b2f5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-58c73b145f189b1c.js +0 -1
- package/apps/pwa/out/_next/static/css/effec8adf767aa75.css +0 -1
- package/apps/pwa/out/dashboard/index.html +0 -1
- package/apps/pwa/out/dashboard/index.txt +0 -26
- package/src/acp/resident-shell.ts +0 -244
- package/src/agent/spawn-local-llm-in-vw.ts +0 -240
- package/src/dashboard/agent-spawn-tools-boot.ts +0 -14
- package/src/dashboard/dock-picker-inventory.ts +0 -41
- package/src/dashboard/goal-plan-hud-bridge.ts +0 -112
- package/src/dashboard/hud-mirror.ts +0 -207
- package/src/dashboard/input/mouse-dock-runtime.ts +0 -156
- package/src/dashboard/input/mouse-hover-runtime.ts +0 -46
- package/src/dashboard/input/mouse-pill-context-runtime.ts +0 -74
- package/src/dashboard/input/mouse-workspace-restore-runtime.ts +0 -64
- package/src/dashboard/input/scratch-actions.ts +0 -36
- package/src/dashboard/input/virtual-window-key-router.ts +0 -24
- package/src/dashboard/rich-scratch-viewers.ts +0 -77
- package/src/dashboard/scratch-slash-runtime.ts +0 -36
- package/src/dashboard/scratch-state-runtime.ts +0 -42
- package/src/dashboard/scratch-widget-runtime.ts +0 -37
- package/src/dashboard/sim-shell.ts +0 -313
- package/src/dashboard/virtual-window-control-runtime.ts +0 -57
- package/src/dashboard/virtual-window-help-runtime.ts +0 -113
- package/src/dashboard/virtual-window-input-runtime.ts +0 -99
- package/src/dashboard/virtual-window-mutation-runtime.ts +0 -102
- package/src/dashboard/virtual-window-split-runtime.ts +0 -70
- package/src/dashboard/vw-popup-openers.ts +0 -126
- package/src/dashboard/window-picker-popup.ts +0 -74
- package/src/dashboard/window-slash-runtime.ts +0 -108
- package/src/dashboard/windowing/companion-slash.ts +0 -78
- package/src/dashboard/windowing/fast-switch.ts +0 -138
- package/src/dashboard/windowing/lifecycle.ts +0 -185
- package/src/dashboard/windowing/virtual-windows.ts +0 -259
- package/src/dashboard/windowing/visibility-chord.ts +0 -77
- package/src/iul/resident-vw.ts +0 -55
- package/src/panes/content-adapter.ts +0 -162
- package/src/prompt/vw-reference.ts +0 -153
- package/src/shell-runner/external-terminal-pane.ts +0 -157
- package/src/sim/resident-vw.ts +0 -48
- package/src/skills/tools/spawn-coding-agent-vw.ts +0 -181
- package/src/skills/tools/virtual-windows.ts +0 -632
- package/src/surface/adapters/window-surface-adapter.ts +0 -141
- package/src/tool-runtime/layout-runtimes.ts +0 -81
- package/src/tool-runtime/scenario-window-mount.ts +0 -207
- package/src/views/ui-mode.ts +0 -100
- package/src/virtual-window-context-menu.ts +0 -97
- package/src/virtual-windows/addressing.ts +0 -195
- package/src/virtual-windows/benchmark-preset.ts +0 -119
- package/src/virtual-windows/event-bus.ts +0 -202
- package/src/virtual-windows/layout/apply-planner.ts +0 -189
- package/src/virtual-windows/layout/index.ts +0 -68
- package/src/virtual-windows/layout/layout-commands.ts +0 -186
- package/src/virtual-windows/layout/layout-tools.ts +0 -262
- package/src/virtual-windows/layout/persistence.ts +0 -219
- package/src/virtual-windows/layout/presets.ts +0 -114
- package/src/virtual-windows/layout/restore-planner.ts +0 -223
- package/src/virtual-windows/layout/serializer.ts +0 -197
- package/src/virtual-windows/layout/tree.ts +0 -147
- package/src/virtual-windows/layout/types.ts +0 -63
- package/src/virtual-windows/layout-tree.ts +0 -389
- package/src/virtual-windows/navigation.ts +0 -251
- package/src/virtual-windows/pane-capture.ts +0 -142
- package/src/virtual-windows/pane-content.ts +0 -611
- package/src/virtual-windows/pane-spawner.ts +0 -278
- package/src/virtual-windows/pty-tail-content.ts +0 -291
- package/src/virtual-windows/resident-window.ts +0 -59
- package/src/virtual-windows/secondary-action.ts +0 -25
- package/src/virtual-windows/terminal-slot-content.ts +0 -165
- package/src/virtual-windows/virtual-window.ts +0 -1301
- package/src/virtual-windows/vw-local-input-target-popup.ts +0 -110
- package/src/virtual-windows/vw-rename-modal.ts +0 -77
- package/src/virtual-windows/vw-selector-popup.ts +0 -177
- package/src/virtual-windows/window-registry.ts +0 -519
- package/src/voice/channel-adapters/discord-voice-adapter.ts +0 -202
- package/src/voice/voice-pwa-dispatch.ts +0 -245
- package/src/window-picker-modal.ts +0 -135
- /package/apps/pwa/out/_next/static/{Ksn99fVf2HUWhSyV1-FC8 → ktMqfrBbf8BMGac0jqLrb}/_ssgManifest.js +0 -0
- /package/src/dashboard/{companion-slash-runtime.ts → companion-messages-runtime.ts} +0 -0
package/src/dashboard/index.ts
CHANGED
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
7
7
|
import { join } from 'path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { createStaleInstallCheck, readCurrentInstalledCommit, readDashboardBootCommit, STALE_INSTALL_CHECK_INTERVAL_MS, versionedDashboardInstallDir } from './stale-install-check.js';
|
|
8
10
|
import { spawn, spawnSync } from 'node:child_process';
|
|
9
11
|
import { $ } from 'bun';
|
|
10
12
|
import { LOCAL_SKILLS_DIR, SERVICE_NAMES, DATA_DIR, OBSIDIAN_VAULT } from '../config.js';
|
|
11
13
|
import { dispatchDashboardSessionRuntimeTool } from './session-runtime-dispatch.js';
|
|
12
14
|
import { buildAdRunSetup } from '../ad-pipeline/ad-run-setup.js';
|
|
15
|
+
import { nextChatScrollOffset } from '../chat/log-scroll-key.js';
|
|
13
16
|
import type { CommandRunner } from '../ad-pipeline/higgsfield-backend.js';
|
|
14
17
|
import type { ShootRunOptions } from '../ad-pipeline/shoot-run.js';
|
|
15
18
|
import type { QcThresholds } from '../ad-pipeline/qc.js';
|
|
@@ -295,24 +298,10 @@ export interface RegisterDashboardGlobalKeysDeps {
|
|
|
295
298
|
register: (binding: DashboardGlobalKeyRegistration) => void;
|
|
296
299
|
openSurfaceCatalog: () => void;
|
|
297
300
|
surfaceCatalogWhen?: () => boolean;
|
|
298
|
-
dispatchVirtualWindowChord: (event: DisplayKeyEvent) => void;
|
|
299
301
|
}
|
|
300
302
|
|
|
301
|
-
/** Registers optional dashboard controls
|
|
303
|
+
/** Registers optional dashboard controls. */
|
|
302
304
|
export function registerDashboardGlobalKeys(deps: RegisterDashboardGlobalKeysDeps): void {
|
|
303
|
-
const registerVwChord = (id: string, key: string, event: DisplayKeyEvent): void => {
|
|
304
|
-
deps.register({
|
|
305
|
-
id: `dashboard:vw-chord:${id}`,
|
|
306
|
-
chordPrefix: 'C-b',
|
|
307
|
-
key,
|
|
308
|
-
scope: 'global',
|
|
309
|
-
handler: () => deps.dispatchVirtualWindowChord(event),
|
|
310
|
-
});
|
|
311
|
-
};
|
|
312
|
-
const vwKey = (name: string, mods: Partial<DisplayKeyEvent> = {}): DisplayKeyEvent => ({
|
|
313
|
-
name, ctrl: false, shift: false, alt: false, ...mods,
|
|
314
|
-
});
|
|
315
|
-
|
|
316
305
|
if (deps.enableSupplementalGlobalKeys) {
|
|
317
306
|
deps.register({
|
|
318
307
|
id: 'dashboard:open-surface-catalog',
|
|
@@ -321,14 +310,7 @@ export function registerDashboardGlobalKeys(deps: RegisterDashboardGlobalKeysDep
|
|
|
321
310
|
handler: deps.openSurfaceCatalog,
|
|
322
311
|
when: deps.surfaceCatalogWhen,
|
|
323
312
|
});
|
|
324
|
-
registerVwChord('picker', '0', vwKey('0'));
|
|
325
|
-
registerVwChord('close-window', 'S-x', vwKey('x', { shift: true }));
|
|
326
|
-
registerVwChord('last-pane', 'tab', vwKey('tab'));
|
|
327
313
|
}
|
|
328
|
-
|
|
329
|
-
registerVwChord('new-window', 'c', vwKey('c'));
|
|
330
|
-
registerVwChord('close-pane', 'x', vwKey('x'));
|
|
331
|
-
registerVwChord('zoom-toggle', 'z', vwKey('z'));
|
|
332
314
|
}
|
|
333
315
|
|
|
334
316
|
export type ForkableSessionTurn = {
|
|
@@ -509,13 +491,10 @@ import {
|
|
|
509
491
|
} from '../primitives/damage-region/index.js';
|
|
510
492
|
import {
|
|
511
493
|
createArtifactStore,
|
|
512
|
-
createLegacyLayoutProvider,
|
|
513
494
|
createLegacyTimelineProvider,
|
|
514
495
|
} from '../artifact/index.js';
|
|
515
496
|
import { defaultTimelineBaseDir } from '../tool-runtime/recording-runtimes-paths.js';
|
|
516
|
-
import { layoutsDir } from '../virtual-windows/layout/persistence.js';
|
|
517
497
|
import { createVisualStateStore } from '../panes/visual-state.js';
|
|
518
|
-
import { skipWindowWhenStorePredicate } from '../panes/alt-skip-predicate.js';
|
|
519
498
|
import { composeIdentityHooks } from '../display/modal-identity-wiring.js';
|
|
520
499
|
import { composeWorkspaceHostHooks } from '../display/workspace-host-wiring.js';
|
|
521
500
|
import {
|
|
@@ -626,6 +605,7 @@ import {
|
|
|
626
605
|
import { createDashboardInlineSetupFlow } from './setup-inline.js';
|
|
627
606
|
import { resolveDashboardChatMainThemeCommand } from './input/chat-main-theme-command.js';
|
|
628
607
|
import { resolveDashboardChatMainLogCommand } from './input/chat-main-log-command.js';
|
|
608
|
+
import { noProviderReply } from './input/no-provider-reply.js';
|
|
629
609
|
import {
|
|
630
610
|
dashboardLogHelpLines,
|
|
631
611
|
resolveDashboardLogFilterAction,
|
|
@@ -650,7 +630,6 @@ import {
|
|
|
650
630
|
matchDashboardChordAction,
|
|
651
631
|
} from './input/dashboard-chord-actions.js';
|
|
652
632
|
import { createDashboardChordRuntime } from './input/dashboard-chord-runtime.js';
|
|
653
|
-
import { createMouseDockRuntime } from './input/mouse-dock-runtime.js';
|
|
654
633
|
import { handleDashboardDisplayKeyRoute } from './input/dashboard-display-key-route.js';
|
|
655
634
|
import { routeDashboardPriorityKey } from './input/dashboard-priority-key-route.js';
|
|
656
635
|
import { shouldPassthroughDashboardHostOwnedInputCoreAction } from './input/input-core-host-action.js';
|
|
@@ -915,15 +894,12 @@ import {
|
|
|
915
894
|
import { globalVoiceCostTracker } from '../voice/cost-tracker.js';
|
|
916
895
|
import { createDashboardMouseWiring } from './input/mouse-wiring.js';
|
|
917
896
|
import { createMouseConversationPopupRuntime } from './input/mouse-conversation-popup-runtime.js';
|
|
918
|
-
import { createMouseHoverRuntime } from './input/mouse-hover-runtime.js';
|
|
919
897
|
import { createMouseModalHitRuntime } from './input/mouse-modal-hit-runtime.js';
|
|
920
898
|
import { createMouseModalSurfaceRuntime } from './input/mouse-modal-surface-runtime.js';
|
|
921
899
|
import { createMouseModeSwitchRuntime } from './input/mouse-mode-switch-runtime.js';
|
|
922
900
|
import { createMousePaneHitRuntime } from './input/mouse-pane-hit-runtime.js';
|
|
923
901
|
import { createMousePickerRuntime } from './input/mouse-picker-runtime.js';
|
|
924
|
-
import { createMousePillContextRuntime } from './input/mouse-pill-context-runtime.js';
|
|
925
902
|
import { createMouseShellRollupRuntime } from './input/mouse-shell-rollup-runtime.js';
|
|
926
|
-
import { createMouseWorkspaceRestoreRuntime } from './input/mouse-workspace-restore-runtime.js';
|
|
927
903
|
import { createDashboardPluginBaseRuntime } from './plugin-base-runtime.js';
|
|
928
904
|
import { createDashboardPluginExecutionRuntime } from './plugin-execution-runtime.js';
|
|
929
905
|
import { createDashboardPluginPaneRuntime } from './plugin-pane-runtime.js';
|
|
@@ -987,7 +963,6 @@ import { runDashboardSkillByName } from './skill-runtime.js';
|
|
|
987
963
|
import { createDashboardClipboardActions } from './clipboard-actions.js';
|
|
988
964
|
import {
|
|
989
965
|
buildDashboardEditorOpenPayload,
|
|
990
|
-
buildDashboardScratchDumpLines,
|
|
991
966
|
} from './clipboard-message-runtime.js';
|
|
992
967
|
import { createDashboardCopyRuntime } from './copy-runtime.js';
|
|
993
968
|
import { createDashboardMediaRuntime } from './media-runtime.js';
|
|
@@ -998,18 +973,14 @@ import { createDashboardContextMenuFeedbackRuntime } from './context-menu-feedba
|
|
|
998
973
|
import { createDashboardStatusFeedbackRuntime } from './status-feedback-runtime.js';
|
|
999
974
|
import { createDashboardTransferFeedbackRuntime } from './transfer-feedback-runtime.js';
|
|
1000
975
|
import { createDashboardFinderFeedbackRuntime } from './finder-feedback-runtime.js';
|
|
1001
|
-
import { createDashboardWindowSlashRuntime } from './window-slash-runtime.js';
|
|
1002
|
-
import { createDashboardBenchSlashRuntime } from './bench-slash-runtime.js';
|
|
1003
976
|
import { createDashboardTermSlashRuntime } from './term-slash-runtime.js';
|
|
1004
977
|
import { createDashboardShellSlashRuntime } from './shell-slash-runtime.js';
|
|
1005
978
|
import { createDashboardRunSkillSlashRuntime } from './run-skill-slash-runtime.js';
|
|
1006
979
|
import { createDashboardSkillTriggersSlashRuntime } from './skill-triggers-slash-runtime.js';
|
|
1007
980
|
import { createDashboardProviderSlashRuntime } from './provider-slash-runtime.js';
|
|
1008
981
|
import { createDashboardPreviewSlashRuntime } from './preview-slash-runtime.js';
|
|
1009
|
-
import {
|
|
1010
|
-
import { createDashboardCompanionSlashRuntime } from './companion-slash-runtime.js';
|
|
982
|
+
import { createDashboardCompanionSlashRuntime } from './companion-messages-runtime.js';
|
|
1011
983
|
import { createDashboardAgentsSlashRuntime } from './agents-slash-runtime.js';
|
|
1012
|
-
import { createDashboardViewSlashRuntime } from './view-slash-runtime.js';
|
|
1013
984
|
import { createDashboardControlSignalSlashRuntime } from './control-signal-slash-runtime.js';
|
|
1014
985
|
import { createDashboardBrowserCdpSlashRuntime } from './browser-cdp-slash-runtime.js';
|
|
1015
986
|
import { collectGroundingFactsViaCdp } from '../product-grounding/cdp-collect.js';
|
|
@@ -1025,9 +996,6 @@ import { resolveDashboardMediaSlash } from './media-slash-runtime.js';
|
|
|
1025
996
|
import { createDashboardMemoCompanionRuntime } from './memo-companion-runtime.js';
|
|
1026
997
|
import { createDashboardDetailViewerRuntime } from './detail-viewer-runtime.js';
|
|
1027
998
|
import { createDashboardCompanionWidgetRuntime } from './companion-widget-runtime.js';
|
|
1028
|
-
import { createDashboardScratchWidgetRuntime } from './scratch-widget-runtime.js';
|
|
1029
|
-
import { createDashboardScratchStateRuntime } from './scratch-state-runtime.js';
|
|
1030
|
-
import { createRichScratchViewers } from './rich-scratch-viewers.js';
|
|
1031
999
|
import { createDashboardClipboardHistoryRuntime } from './clipboard-history-runtime.js';
|
|
1032
1000
|
import { createDashboardClipboardCompanionRuntime } from './clipboard-companion-runtime.js';
|
|
1033
1001
|
import { createDashboardMemoWidgetRuntime } from './memo-widget-runtime.js';
|
|
@@ -1082,7 +1050,6 @@ import {
|
|
|
1082
1050
|
import { createDashboardTerminalPopupRuntime } from './terminal-popup-runtime.js';
|
|
1083
1051
|
import { toggleDashboardAssistantRenderState } from './assistant-render-state-runtime.js';
|
|
1084
1052
|
import { bootDashboardAcpBgSweep } from './acp-bg-sweep-boot.js';
|
|
1085
|
-
import { bootDashboardAgentSpawnTools } from './agent-spawn-tools-boot.js';
|
|
1086
1053
|
import { bootDashboardConfigTools } from './config-tools-boot.js';
|
|
1087
1054
|
import { bootDashboardConversationPopupRuntime } from './conversation-popup-boot.js';
|
|
1088
1055
|
import { bootDashboardTerminalRuntime } from './terminal-runtime-boot.js';
|
|
@@ -1103,20 +1070,16 @@ import { bootDashboardHitl } from './hitl-boot.js';
|
|
|
1103
1070
|
import { attachDashboardFilePathToken } from './file-path-attachment.js';
|
|
1104
1071
|
import { bootDashboardSlashExecutor } from './slash-executor-boot.js';
|
|
1105
1072
|
import { buildDashboardSlashRegistry, type DashboardSlashContext } from './slash-runtime/index.js';
|
|
1073
|
+
import { unknownSlashReply } from './slash-runtime/unknown-slash-reply.js';
|
|
1106
1074
|
import { resolveSurfaceUx } from '../agent/surface-ux/build.js';
|
|
1107
1075
|
import type { SurfaceUx } from '../agent/surface-ux/types.js';
|
|
1108
1076
|
import { getDefaultQuestionChannels, type QuestionChannel } from '../hitl/question.js';
|
|
1109
1077
|
import { getDefaultCompactProvider, scheduleArchiveRetentionOnce } from '../compact/index.js';
|
|
1110
1078
|
import { attachDashboardWorkingDirSelection } from './working-dir-selection-attachment.js';
|
|
1111
|
-
import { createDashboardVirtualWindowControlRuntime } from './virtual-window-control-runtime.js';
|
|
1112
|
-
import { createDashboardVirtualWindowHelpRuntime } from './virtual-window-help-runtime.js';
|
|
1113
1079
|
import { createBrowserHelpRuntime } from './browser-help-runtime.js';
|
|
1114
1080
|
import { createBrowserChordRuntime } from './browser-chord-runtime.js';
|
|
1115
1081
|
import { summarizeFileWithLLM } from './browser-llm-summary.js';
|
|
1116
|
-
import { createDashboardVirtualWindowInputRuntime } from './virtual-window-input-runtime.js';
|
|
1117
1082
|
import { resolveDashboardHostChromePolicy } from './host-chrome-policy.js';
|
|
1118
|
-
import { createDashboardVirtualWindowMutationRuntime } from './virtual-window-mutation-runtime.js';
|
|
1119
|
-
import { createDashboardVirtualWindowSplitRuntime } from './virtual-window-split-runtime.js';
|
|
1120
1083
|
import {
|
|
1121
1084
|
bootDashboardPlanModeRuntime,
|
|
1122
1085
|
cleanupDashboardWorktreeSessions,
|
|
@@ -1152,11 +1115,7 @@ import {
|
|
|
1152
1115
|
import {
|
|
1153
1116
|
type DashboardPaneTitleMenuPayload,
|
|
1154
1117
|
} from '../dashboard-pane-context-menu.js';
|
|
1155
|
-
import {
|
|
1156
|
-
type VirtualWindowTitleMenuPayload,
|
|
1157
|
-
} from '../virtual-window-context-menu.js';
|
|
1158
1118
|
// writeClipboard imported below with other clipboard helpers (line ~185).
|
|
1159
|
-
import { registerVwFastSwitchBindings } from './windowing/fast-switch.js';
|
|
1160
1119
|
import {
|
|
1161
1120
|
renderPaneNav, paneAtColumn, paneNavLabel,
|
|
1162
1121
|
type PaneNavHitArea,
|
|
@@ -1204,15 +1163,9 @@ import { createInteractiveTerminalModal } from '../interactive-terminal-modal.js
|
|
|
1204
1163
|
import { showToast } from './render/toast.js';
|
|
1205
1164
|
import {
|
|
1206
1165
|
browserWidgetInstanceIdForView,
|
|
1207
|
-
renderPaneModalHint,
|
|
1208
1166
|
shortcutFor,
|
|
1209
|
-
SHORTCUT_TABLE as PANE_SHORTCUT_TABLE,
|
|
1210
|
-
PANE_MODAL_CHORD_TIMEOUT_MS,
|
|
1211
1167
|
} from './modals/pane.js';
|
|
1212
|
-
|
|
1213
|
-
// 의 registerKeyBinding chord 경로로 이전. imperative 호출용 파일은
|
|
1214
|
-
// dashboard-virtual-window-key-router.ts 에 그대로 유지.
|
|
1215
|
-
import { showTransientTerminalModal } from './modals/transient.js';
|
|
1168
|
+
import { showTransientTerminalModal, currentTransientTerminalModal } from './modals/transient.js';
|
|
1216
1169
|
import { showPaneMultiModal, showLivePaneMultiModal, currentPaneMultiModal, type PaneMultiModalHandle } from './modals/pane-multi.js';
|
|
1217
1170
|
import {
|
|
1218
1171
|
resolveCompanionPopupChrome,
|
|
@@ -1234,26 +1187,10 @@ import {
|
|
|
1234
1187
|
TerminalRegistry,
|
|
1235
1188
|
BroadcastBus,
|
|
1236
1189
|
PreviewSlotAdapter,
|
|
1237
|
-
VwPlacementAdapter,
|
|
1238
1190
|
getChannelBus,
|
|
1239
1191
|
type TerminalPlacement,
|
|
1240
1192
|
} from '../terminal-matrix/index.js';
|
|
1241
|
-
import {
|
|
1242
|
-
resolveTerminalMoveDestination,
|
|
1243
|
-
resolveVwTerminalInstanceForPane,
|
|
1244
|
-
} from '../terminal-matrix/mobility.js';
|
|
1245
|
-
import {
|
|
1246
|
-
createVwExitPaneCloser,
|
|
1247
|
-
installVwLifecycleHandlers,
|
|
1248
|
-
} from './windowing/lifecycle.js';
|
|
1249
|
-
import { parseWindowCompanionSlash } from './windowing/companion-slash.js';
|
|
1250
|
-
import { createVisibilityChordHandler } from './windowing/visibility-chord.js';
|
|
1251
|
-
import { createPaneContent } from '../virtual-windows/pane-content.js';
|
|
1252
|
-
import type { PaneId } from '../virtual-windows/addressing.js';
|
|
1253
|
-
import {
|
|
1254
|
-
initDashboardVirtualWindows,
|
|
1255
|
-
type DashboardVirtualWindows,
|
|
1256
|
-
} from './windowing/virtual-windows.js';
|
|
1193
|
+
import { resolveTerminalMoveDestination } from '../terminal-matrix/mobility.js';
|
|
1257
1194
|
import { initElementObservability } from '../element-registry/index.js';
|
|
1258
1195
|
import {
|
|
1259
1196
|
armSessionQuickControl,
|
|
@@ -1278,8 +1215,6 @@ import {
|
|
|
1278
1215
|
import {
|
|
1279
1216
|
initDashboardApprovers,
|
|
1280
1217
|
createInjectApprover,
|
|
1281
|
-
createPaneInjectApprover,
|
|
1282
|
-
createBroadcastApprover,
|
|
1283
1218
|
createConfigSetApprover,
|
|
1284
1219
|
createAcpPermissionApprover,
|
|
1285
1220
|
openGenericApproval,
|
|
@@ -1303,7 +1238,6 @@ import { createDashboardCompactSurfaceAssembly } from './compact-surface-assembl
|
|
|
1303
1238
|
import { openCompactSurfaceCatalogPopup } from './compact-surface-popup.js';
|
|
1304
1239
|
import { approvalModalRouter, type ApprovalModalRouter } from '../approval-modal.js';
|
|
1305
1240
|
import { routeApprovalModalKey } from './input/approval-key-router.js';
|
|
1306
|
-
import { createWindowPickerModal } from '../window-picker-modal.js';
|
|
1307
1241
|
|
|
1308
1242
|
export function routeStreamingApprovalModalKey(
|
|
1309
1243
|
key: Parameters<typeof routeApprovalModalKey>[0],
|
|
@@ -1320,21 +1254,9 @@ export function routeStreamingApprovalModalKey(
|
|
|
1320
1254
|
import {
|
|
1321
1255
|
attachSurfaceToWorkspace,
|
|
1322
1256
|
DASHBOARD_MAIN_WORKSPACE_ID,
|
|
1323
|
-
workspaceOwnerIdForVirtualWindow,
|
|
1324
1257
|
} from '../display/workspace-affinity.js';
|
|
1325
|
-
import { createVwSelectorPopup } from '../virtual-windows/vw-selector-popup.js';
|
|
1326
|
-
import { createVwLocalInputTargetPopup } from '../virtual-windows/vw-local-input-target-popup.js';
|
|
1327
|
-
import { createVwRenameModal } from '../virtual-windows/vw-rename-modal.js';
|
|
1328
|
-
import { spawnLLMBenchmark, MAX_BENCHMARK_PANES } from '../virtual-windows/benchmark-preset.js';
|
|
1329
|
-
import { PROVIDERS as LLM_PROVIDERS } from '../llm.js';
|
|
1330
1258
|
import { initDashboardHitl, stopDashboardHitl } from './runtime/hitl.js';
|
|
1331
|
-
import { openDashboardWindowPickerPopup } from './window-picker-popup.js';
|
|
1332
|
-
import { createIulSidebarShellPaneContent } from '../iul/sidebar-shell.js';
|
|
1333
1259
|
import { openDashboardShellRollupPopup } from './shell-rollup-popup.js';
|
|
1334
|
-
import {
|
|
1335
|
-
openVwLocalInputTargetPopupLauncher,
|
|
1336
|
-
openVwRenameModalLauncher,
|
|
1337
|
-
} from './vw-popup-openers.js';
|
|
1338
1260
|
import { expandPromptReferences } from '../prompt/references.js';
|
|
1339
1261
|
import { spawnCodingAgent, CodingAgentBinaryMissing } from '../terminal/coding-agent.js';
|
|
1340
1262
|
import type { TerminalSession } from '../terminal/session-registry.js';
|
|
@@ -1367,7 +1289,7 @@ import { enqueuePendingUserInput } from '../session/pending-input.js';
|
|
|
1367
1289
|
import { createAttachmentRowMap } from '../log-pane/attachment-row-map.js';
|
|
1368
1290
|
import { createAttachmentPopup, type AttachmentPopupAction } from '../log-pane/attachment-popup.js';
|
|
1369
1291
|
import { findLogMatches, type LogSearchResult } from '../log-pane/search.js';
|
|
1370
|
-
import { createLogSearchModal } from '../log-pane/search-modal.js';
|
|
1292
|
+
import { createLogSearchModal, type LogSearchModalOpts } from '../log-pane/search-modal.js';
|
|
1371
1293
|
// U-4.3 · direct imports of tryAttachmentHitAtBodyRow /
|
|
1372
1294
|
// tryHandleLogAreaClick are gone · wd-log.onMouse owns the hit-test.
|
|
1373
1295
|
// LogClickDispatchDeps type still needed for buildLogClickDeps +
|
|
@@ -1379,7 +1301,7 @@ import {
|
|
|
1379
1301
|
import { fileColor, fileIcon, sizeStr, dirColor } from '../panes/file-icons.js';
|
|
1380
1302
|
import { canPreview } from '../panes/preview-pane.js';
|
|
1381
1303
|
import { colorLine } from '../panes/syntax-color.js';
|
|
1382
|
-
import { createHud, setSegment, clearSegment
|
|
1304
|
+
import { createHud, setSegment, clearSegment } from '../panes/hud.js';
|
|
1383
1305
|
import {
|
|
1384
1306
|
paneHeightBeforeTargetRow,
|
|
1385
1307
|
paneHeightForTargetRows,
|
|
@@ -1429,11 +1351,9 @@ import { initWidgetInspectorTools } from '../skills/tools/widget-inspector.js';
|
|
|
1429
1351
|
import {
|
|
1430
1352
|
initDashboardViewTools,
|
|
1431
1353
|
} from '../skills/tools/dashboard-view.js';
|
|
1432
|
-
import { initSpawnCodingAgentInVW } from '../skills/tools/spawn-coding-agent-vw.js';
|
|
1433
1354
|
import {
|
|
1434
1355
|
findLiveSessionById,
|
|
1435
1356
|
findLiveSessionByPaneId,
|
|
1436
|
-
initSpawnEmbodiedAgentInVW,
|
|
1437
1357
|
listLiveEmbodiedSessions,
|
|
1438
1358
|
} from '../agent/spawn-embodied-agent-in-vw.js';
|
|
1439
1359
|
import { findSessionObserver } from '../agent/observer-registry.js';
|
|
@@ -1496,7 +1416,7 @@ import { buildAstGrepHostTool } from '../skills/tools/ast-grep.js';
|
|
|
1496
1416
|
import { buildLspHostTool } from '../skills/tools/lsp/index.js';
|
|
1497
1417
|
import { PluginHost } from '../plugins/core/host.js';
|
|
1498
1418
|
import { registerDashboardPaneHostTools } from './panes/host-tools.js';
|
|
1499
|
-
import { DEFAULT_THEME_TOKENS, mergeThemeTokens, resolveThemeTokens, type ThemeTokenInput } from '../theme/tokens.js';
|
|
1419
|
+
import { DEFAULT_THEME_TOKENS, mergeThemeTokens, resolveThemeTokens, type ThemeTokenInput, type ThemeTokens } from '../theme/tokens.js';
|
|
1500
1420
|
import { resolveActiveTheme, setActivePresetInConfig } from './render/theme-resolver.js';
|
|
1501
1421
|
import { getTheme, listThemes } from '../themes/index.js';
|
|
1502
1422
|
import type { PaneFocus, PreviewSource, WorkingDirView } from '../workspace-types.js';
|
|
@@ -1525,9 +1445,8 @@ import {
|
|
|
1525
1445
|
resolveBrowserActionContextFromHit,
|
|
1526
1446
|
} from '../browser-pane/actions.js';
|
|
1527
1447
|
import { resolveBrowserTransferCapability } from '../browser-pane/capabilities.js';
|
|
1528
|
-
import {
|
|
1448
|
+
import { openBrowserPaneModal } from '../browser-pane/mount.js';
|
|
1529
1449
|
import { openPreviewPaneModal } from '../preview-pane/mount.js';
|
|
1530
|
-
import { createPreviewPaneContent } from '../preview-pane/mount.js';
|
|
1531
1450
|
import {
|
|
1532
1451
|
cyclePreviewSourceForView,
|
|
1533
1452
|
formatPreviewSourceLabel,
|
|
@@ -1558,7 +1477,6 @@ import {
|
|
|
1558
1477
|
pruneSurfaceCatalogForCompactMode,
|
|
1559
1478
|
productCompactModeForViewport,
|
|
1560
1479
|
} from '../views/product-compact-mode.js';
|
|
1561
|
-
import { isDashboardHeavyFeatureEnabled, resolveDashboardUiMode, type DashboardUiMode } from '../views/ui-mode.js';
|
|
1562
1480
|
import { readScopedRenderLogs, resolveRenderSuppressed, readScopedDebugLevel, resolveStartupDebugLevel, hotPathGateOpen } from '../mss/logging/scoped-level.js';
|
|
1563
1481
|
import { resolveCurrentInstance } from '../instance/current.js';
|
|
1564
1482
|
import { createPushLog } from '../push-log.js';
|
|
@@ -1658,34 +1576,16 @@ import {
|
|
|
1658
1576
|
TERMINAL_BACKGROUND_STATES,
|
|
1659
1577
|
withBgApprovalSignals,
|
|
1660
1578
|
} from '../acp/background-manager.js';
|
|
1661
|
-
import { dispatchAcpSessionJoin
|
|
1662
|
-
// PLAN-tui-redundancy-cleanup T1 (2026-05-16) — ACP resident window
|
|
1663
|
-
// 자산은 사용자 미사용 명시로 trim. `acp-shell` pane kind 자체는
|
|
1664
|
-
// resident-shell.ts (ACP Browser · ACP History) 가 의존하므로 보존 ·
|
|
1665
|
-
// vw-join-bridge / vw-live-bridge / resident-vw 의 boot init + resident
|
|
1666
|
-
// auto-mount 만 제거.
|
|
1667
|
-
import { createAcpResidentShellPaneContent } from '../acp/resident-shell.js';
|
|
1668
|
-
import { createSimShellPaneContent } from './sim-shell.js';
|
|
1579
|
+
import { dispatchAcpSessionJoin } from '../skills/tools/acp-session.js';
|
|
1669
1580
|
import {
|
|
1670
1581
|
listDashboardSimulationScenarios,
|
|
1671
1582
|
runDashboardSimulationScenario,
|
|
1672
1583
|
} from './sim-shell-runtime.js';
|
|
1673
|
-
import {
|
|
1674
|
-
bootSimResidentWindow,
|
|
1675
|
-
focusOrSpawnSimResidentWindow,
|
|
1676
|
-
isSimResidentEnabled,
|
|
1677
|
-
} from '../sim/resident-vw.js';
|
|
1678
|
-
import {
|
|
1679
|
-
bootIulResidentWindow,
|
|
1680
|
-
focusOrSpawnIulResidentWindow,
|
|
1681
|
-
isIulForegroundStartupEnabled,
|
|
1682
|
-
isIulResidentEnabled,
|
|
1683
|
-
} from '../iul/resident-vw.js';
|
|
1684
1584
|
import { preservesHostChromeInput } from '../display/host-chrome-profile.js';
|
|
1685
1585
|
// H3 #6 follow-up #1 — auto-persist on turn-end. Subscribes DRM +
|
|
1686
1586
|
// BG managers to the H2 #5 persistence primitive so
|
|
1687
1587
|
// `AcpSessionList` returns real records instead of empty arrays.
|
|
1688
|
-
// Mode
|
|
1588
|
+
// Mode is always 'auto' (the ELANOUS_ACP_PERSIST_MODE off-switch was graduated 2026-09-26).
|
|
1689
1589
|
import { wireAutoPersist } from '../acp/auto-persist.js';
|
|
1690
1590
|
import { globalAcpSessionPersistence } from '../acp/session-persistence.js';
|
|
1691
1591
|
import { AgentStatusStore } from '../agent-status/store.js';
|
|
@@ -1752,10 +1652,6 @@ export interface ShowDashboardOptions {
|
|
|
1752
1652
|
* input). Useful on tablets where the 3-pane grid is too narrow
|
|
1753
1653
|
* to read. Toggle at runtime with /chat or the chord in the HUD. */
|
|
1754
1654
|
chatOnly?: boolean;
|
|
1755
|
-
/** TUI 부활 T0 — CLI `--rich`. 이번 실행만 uiMode 를 rich 로 강제
|
|
1756
|
-
* (config 무변). essential 이 기본이 된 뒤 기존 full dashboard 로
|
|
1757
|
-
* 들어가는 탈출구. 해석은 views/ui-mode.ts resolveDashboardUiMode. */
|
|
1758
|
-
rich?: boolean;
|
|
1759
1655
|
/** Flip code-edit policy to unsupervised at boot — every Edit/Write
|
|
1760
1656
|
* from the LLM applies without an approval modal. Equivalent to
|
|
1761
1657
|
* typing `/code-edit policy unsupervised` right after launch.
|
|
@@ -1771,15 +1667,8 @@ export interface ShowDashboardOptions {
|
|
|
1771
1667
|
* (resolved in `main()`). Tool dispatch + history live on the
|
|
1772
1668
|
* daemon side; the local TUI is a thin client. */
|
|
1773
1669
|
remote?: { url: string; token?: string; label?: string };
|
|
1774
|
-
/**
|
|
1775
|
-
* dashboard
|
|
1776
|
-
* unix socket instead of booting an in-process server. Driven by
|
|
1777
|
-
* `ELANOUS_USE_DAEMON=1` env (resolved in `main()`). `ELANOUS_NO_DAEMON=1`
|
|
1778
|
-
* force-disables even when a daemon is alive. `remote` (above)
|
|
1779
|
-
* takes precedence when both are somehow set. */
|
|
1780
|
-
localDaemon?: { socketPath: string };
|
|
1781
|
-
/** Tier 1 daemon-resume — when set together with `remote` /
|
|
1782
|
-
* `localDaemon`, the dashboard attaches to this existing
|
|
1670
|
+
/** Tier 1 daemon-resume — when set together with `remote`,
|
|
1671
|
+
* the dashboard attaches to this existing
|
|
1783
1672
|
* daemon-side sessionId instead of minting a new one. The boot
|
|
1784
1673
|
* also fetches the session's prior turns via REST (when an HTTP
|
|
1785
1674
|
* endpoint is reachable, derived from `remote.url`) and replays
|
|
@@ -1901,18 +1790,16 @@ export function renderDashboardCoordinatorModalOverlay(display: Pick<DisplayCoor
|
|
|
1901
1790
|
* ⭐⭐⭐ **essential 은 커서 값을 Z축에 묻지 않는다**(2026-08-02 · RFC essential-z-axis-off).
|
|
1902
1791
|
* 입력 루프가 끝나면 `setCursor(null)` 로 소유가 비므로 물어보면 빈손이고, 그래서 턴이 도는
|
|
1903
1792
|
* 동안 커서가 사라졌다(라이브 14 표본 전부 `visible false`). ⇒ 모달이 **실제로 claim** 했으면
|
|
1904
|
-
* 그 값을 쓰고, 아니면 **프롬프트 caret** 을 쓴다. 프롬프트가 감춰졌으면 숨긴다.
|
|
1905
|
-
* ⚠️ rich 는 Z축을 실제로 쓰므로 종전 동작(조율자가 정한 값)을 그대로 둔다. */
|
|
1793
|
+
* 그 값을 쓰고, 아니면 **프롬프트 caret** 을 쓴다. 프롬프트가 감춰졌으면 숨긴다. */
|
|
1906
1794
|
export interface DashboardFrameInput {
|
|
1907
1795
|
overlay: string;
|
|
1908
1796
|
force: boolean;
|
|
1909
|
-
essential: boolean;
|
|
1910
1797
|
/** ⭐ Z축이 **실제로 누구에게** 커서를 준 결정. essential 은 `modal`·`terminal` 일 때만
|
|
1911
1798
|
* 그 값에 양보한다 — `coordinator` fallback 은 소유자가 없다는 뜻이지 claim 이 아니다. */
|
|
1912
1799
|
cursorOwner: CursorDecision['owner'];
|
|
1913
1800
|
claimedCursor: CursorState | null;
|
|
1914
|
-
/**
|
|
1915
|
-
coordinatorCursor
|
|
1801
|
+
/** essential 결정이 커서를 안 낼 때(null)의 폴백 — 조율자가 emit 하던 값(종전 동작 보존). */
|
|
1802
|
+
coordinatorCursor?: CursorState | null;
|
|
1916
1803
|
promptCaret: CursorState | null;
|
|
1917
1804
|
suppressPromptArea: boolean;
|
|
1918
1805
|
onEssentialFrameCursorDecision?: (observation: EssentialFrameCursorObservation) => void;
|
|
@@ -1948,31 +1835,27 @@ export function createDashboardEssentialCursorObserver(deps: DashboardEssentialC
|
|
|
1948
1835
|
|
|
1949
1836
|
export function renderDashboardFrame(
|
|
1950
1837
|
lines: string[],
|
|
1951
|
-
input: DashboardFrameInput
|
|
1838
|
+
input: DashboardFrameInput,
|
|
1952
1839
|
renderFrame: DashboardFrameRenderer = render,
|
|
1953
1840
|
): void {
|
|
1954
1841
|
const cursorDecisionExists = input.cursorOwner !== 'none';
|
|
1955
|
-
const essentialDecision =
|
|
1956
|
-
?
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
})
|
|
1961
|
-
: null;
|
|
1842
|
+
const essentialDecision = resolveEssentialFrameCursorDecision({
|
|
1843
|
+
claimedCursor: cursorDecisionExists ? input.claimedCursor : null,
|
|
1844
|
+
promptCaret: input.promptCaret,
|
|
1845
|
+
suppressPromptArea: input.suppressPromptArea,
|
|
1846
|
+
});
|
|
1962
1847
|
renderFrame(lines, {
|
|
1963
1848
|
overlay: input.overlay,
|
|
1964
1849
|
force: input.force,
|
|
1965
|
-
cursor: paintCursor(essentialDecision
|
|
1850
|
+
cursor: paintCursor(essentialDecision.cursor ?? input.coordinatorCursor ?? null),
|
|
1851
|
+
});
|
|
1852
|
+
input.onEssentialFrameCursorDecision?.({
|
|
1853
|
+
caret: essentialDecision.cursor,
|
|
1854
|
+
cursorOwner: input.cursorOwner,
|
|
1855
|
+
reason: essentialDecision.reason,
|
|
1856
|
+
source: essentialDecision.source,
|
|
1857
|
+
suppressPromptArea: input.suppressPromptArea,
|
|
1966
1858
|
});
|
|
1967
|
-
if (essentialDecision) {
|
|
1968
|
-
input.onEssentialFrameCursorDecision?.({
|
|
1969
|
-
caret: essentialDecision.cursor,
|
|
1970
|
-
cursorOwner: input.cursorOwner,
|
|
1971
|
-
reason: essentialDecision.reason,
|
|
1972
|
-
source: essentialDecision.source,
|
|
1973
|
-
suppressPromptArea: input.suppressPromptArea,
|
|
1974
|
-
});
|
|
1975
|
-
}
|
|
1976
1859
|
}
|
|
1977
1860
|
|
|
1978
1861
|
/** Production frame input: append coordinator modals after every dashboard-owned overlay. */
|
|
@@ -2175,6 +2058,47 @@ export async function dispatchDashboardAdSlash(
|
|
|
2175
2058
|
afterRun();
|
|
2176
2059
|
}
|
|
2177
2060
|
|
|
2061
|
+
export function createDashboardLogSearchOpener(deps: {
|
|
2062
|
+
display: () => DisplayCoordinator;
|
|
2063
|
+
linesGetter: LogSearchModalOpts['linesGetter'];
|
|
2064
|
+
initialQuery: () => string;
|
|
2065
|
+
termSize: () => { cols: number; rows: number };
|
|
2066
|
+
computePaneH: (rows: number) => number;
|
|
2067
|
+
currentThemeTokens: () => ThemeTokens;
|
|
2068
|
+
currentWorkspaceOwnerId: () => string;
|
|
2069
|
+
draw: () => void;
|
|
2070
|
+
onJump: LogSearchModalOpts['onJump'];
|
|
2071
|
+
onCancel: NonNullable<LogSearchModalOpts['onCancel']>;
|
|
2072
|
+
}): () => void {
|
|
2073
|
+
return () => {
|
|
2074
|
+
let modalHandle: { dispose(): void } | null = null;
|
|
2075
|
+
const closeLogSearchModal = (): void => { modalHandle?.dispose(); modalHandle = null; };
|
|
2076
|
+
const { cols: tc, rows: tr } = deps.termSize();
|
|
2077
|
+
const anchorRow = Math.max(1, deps.computePaneH(tr) + 2);
|
|
2078
|
+
const anchorCol = Math.max(2, Math.floor(tc / 4));
|
|
2079
|
+
const popup = createLogSearchModal({
|
|
2080
|
+
linesGetter: deps.linesGetter,
|
|
2081
|
+
initialQuery: deps.initialQuery(),
|
|
2082
|
+
termCols: tc,
|
|
2083
|
+
termRows: tr,
|
|
2084
|
+
anchorRow,
|
|
2085
|
+
anchorCol,
|
|
2086
|
+
theme: deps.currentThemeTokens(),
|
|
2087
|
+
onJump: (result, query) => {
|
|
2088
|
+
closeLogSearchModal();
|
|
2089
|
+
deps.onJump(result, query);
|
|
2090
|
+
},
|
|
2091
|
+
onCancel: query => {
|
|
2092
|
+
closeLogSearchModal();
|
|
2093
|
+
deps.onCancel(query);
|
|
2094
|
+
},
|
|
2095
|
+
});
|
|
2096
|
+
attachSurfaceToWorkspace(popup.surface, deps.currentWorkspaceOwnerId());
|
|
2097
|
+
modalHandle = deps.display().pushModal(popup.surface);
|
|
2098
|
+
deps.draw();
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2178
2102
|
export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<DashboardAction> {
|
|
2179
2103
|
const dashboardQuitConfirmationState = createQuitConfirmationState();
|
|
2180
2104
|
const signalQuitConfirmationState = createQuitConfirmationState();
|
|
@@ -2196,7 +2120,6 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2196
2120
|
forceQuit: true,
|
|
2197
2121
|
});
|
|
2198
2122
|
});
|
|
2199
|
-
let virtualWindows!: DashboardVirtualWindows;
|
|
2200
2123
|
// E3 (§7.4 TS baseline reduction · 2026-05-17) — forward declarations
|
|
2201
2124
|
// for handler functions that get assigned later via destructure from
|
|
2202
2125
|
// createDashboardCopyRuntime / createDashboardMediaRuntime (lines
|
|
@@ -2404,10 +2327,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2404
2327
|
* same file isn't re-loading twice. Repeats inside the same call
|
|
2405
2328
|
* (same id appearing twice in `added`) are also collapsed.
|
|
2406
2329
|
*
|
|
2407
|
-
|
|
2408
|
-
* detail viewer (set via setScratchImage) so the user sees what
|
|
2409
|
-
* they grabbed without an intrusive modal — only on the first
|
|
2410
|
-
* appearance to keep `(already attached)` cases quiet. */
|
|
2330
|
+
* Image attachments stay in the chat log without a scratch preview. */
|
|
2411
2331
|
const renderAttachmentSummary = (added: { attachment: Attachment; isNew: boolean }[]): void => {
|
|
2412
2332
|
renderDashboardAttachmentSummary(added, {
|
|
2413
2333
|
formatNewLine: (attachment) =>
|
|
@@ -2419,16 +2339,6 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2419
2339
|
return chatLines.length - 1;
|
|
2420
2340
|
},
|
|
2421
2341
|
trackRow: (row, attachmentId) => { attachmentRowMap.track(row, attachmentId); },
|
|
2422
|
-
// TUI 부활 T4 — attach 시 detail viewer(scratch) 프리뷰 push 는
|
|
2423
|
-
// rich 전용. essential 은 chat log 의 attachment summary 줄만
|
|
2424
|
-
// (codex 패리티 · dogfood: @픽커 Tab attach 가 프리뷰 팝업을 띄워
|
|
2425
|
-
// 흐름을 끊는다는 피드백). 런타임 /ui 전환을 따르도록 호출 시점 게이트.
|
|
2426
|
-
setScratchImage: async (...args: Parameters<typeof setScratchImage>) => {
|
|
2427
|
-
if (isDashboardHeavyFeatureEnabled(dashboardUiMode, 'scratch-image')) await setScratchImage(...args);
|
|
2428
|
-
},
|
|
2429
|
-
setScratchFile: (...args: Parameters<typeof setScratchFile>) => {
|
|
2430
|
-
if (isDashboardHeavyFeatureEnabled(dashboardUiMode, 'scratch-file')) setScratchFile(...args);
|
|
2431
|
-
},
|
|
2432
2342
|
});
|
|
2433
2343
|
};
|
|
2434
2344
|
|
|
@@ -2572,7 +2482,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2572
2482
|
});
|
|
2573
2483
|
},
|
|
2574
2484
|
foldMode: logFoldMode,
|
|
2575
|
-
expandHint:
|
|
2485
|
+
expandHint: false,
|
|
2576
2486
|
});
|
|
2577
2487
|
|
|
2578
2488
|
// Session-scoped skill decline memory (session 21). When the user
|
|
@@ -2633,32 +2543,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2633
2543
|
pushDebugLine(C.muted(` \u251c\u2500 `) + C.text(att.token) + ' ' + C.subtext('(already attached)'));
|
|
2634
2544
|
}
|
|
2635
2545
|
clearSegment(hud, 'clipimg');
|
|
2636
|
-
//
|
|
2637
|
-
// first registration so repeat Ctrl+V on the same clipboard
|
|
2638
|
-
// doesn't churn the pane. TUI 부활 T4 — rich 전용 (essential 은
|
|
2639
|
-
// summary 줄 + [Image #N] 토큰만 · codex 패리티).
|
|
2640
|
-
if (isNew && isDashboardHeavyFeatureEnabled(dashboardUiMode, 'scratch-image')) void setScratchImage(att.sourcePath, att.filename);
|
|
2641
|
-
// P3 — also pop a transient centered modal so the user gets
|
|
2642
|
-
// immediate confirmation that the paste landed (scratch pane
|
|
2643
|
-
// may be out of view on narrow layouts). 2.5s TTL, replaces
|
|
2644
|
-
// any prior image modal in flight.
|
|
2645
|
-
//
|
|
2646
|
-
// Clipboard confirmation preview: routes through showPreviewModal
|
|
2647
|
-
// (previewFile → handler pipeline). Identical result for PNG
|
|
2648
|
-
// clips; forward-compat for non-image clipboard drops (PDFs /
|
|
2649
|
-
// SVGs / archives) once the extractor grows those types.
|
|
2650
|
-
// TUI 부활 T4 — 확인용 transient 모달도 rich 전용. essential 은
|
|
2651
|
-
// attach summary 줄이 이미 즉시 확인을 제공한다.
|
|
2652
|
-
if (isNew && isDashboardHeavyFeatureEnabled(dashboardUiMode, 'clipboard-preview-modal')) {
|
|
2653
|
-
const { rows: tr, cols: tc } = termSize();
|
|
2654
|
-
void showPreviewModal(att.sourcePath, {
|
|
2655
|
-
coordinator: display,
|
|
2656
|
-
termCols: tc,
|
|
2657
|
-
termRows: tr,
|
|
2658
|
-
title: att.filename,
|
|
2659
|
-
ttlMs: 2500,
|
|
2660
|
-
}).catch(() => { /* modal render failure is non-fatal */ });
|
|
2661
|
-
}
|
|
2546
|
+
// The attachment summary confirms the paste without a scratch preview or modal.
|
|
2662
2547
|
return `${att.token} `;
|
|
2663
2548
|
} catch (err: any) {
|
|
2664
2549
|
// grabClipboardImage now throws with the osascript diagnostic
|
|
@@ -2675,19 +2560,21 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2675
2560
|
}
|
|
2676
2561
|
};
|
|
2677
2562
|
|
|
2678
|
-
const renderContextList = ():
|
|
2563
|
+
const renderContextList = (): string[] => {
|
|
2679
2564
|
const items = ctxList(contextRegistry);
|
|
2565
|
+
const lines: string[] = [];
|
|
2566
|
+
const output = (line: string): void => { pushDebugLine(line); lines.push(line); };
|
|
2680
2567
|
pushDebugBlank();
|
|
2681
|
-
|
|
2568
|
+
output(C.accent('\u276f /context'));
|
|
2682
2569
|
if (!items.length) {
|
|
2683
|
-
|
|
2684
|
-
return;
|
|
2570
|
+
output(C.muted(' (empty)'));
|
|
2571
|
+
return lines;
|
|
2685
2572
|
}
|
|
2686
2573
|
const totalBytes = ctxTotalBytes(contextRegistry);
|
|
2687
2574
|
const total = fmtBytes(totalBytes);
|
|
2688
|
-
|
|
2575
|
+
output(C.muted(` ${items.length} items, ${total} total`));
|
|
2689
2576
|
if (totalBytes > CTX_WARN_BYTES) {
|
|
2690
|
-
|
|
2577
|
+
output(C.warning(` ⚠ ${total} exceeds 10MB — consider /context clear big`));
|
|
2691
2578
|
}
|
|
2692
2579
|
|
|
2693
2580
|
// Table columns: ✓ id kind filename(trunc) size [source-tail]
|
|
@@ -2695,7 +2582,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2695
2582
|
// left indent; filename gets the slack column so long paths just clip.
|
|
2696
2583
|
const { cols } = termSize();
|
|
2697
2584
|
const filenameMax = Math.max(18, cols - 36);
|
|
2698
|
-
|
|
2585
|
+
output(C.muted(
|
|
2699
2586
|
` ${' '}${'id'.padEnd(4)}${'kind'.padEnd(7)}${'file'.padEnd(filenameMax)}${'size'.padStart(8)}`
|
|
2700
2587
|
));
|
|
2701
2588
|
for (const a of items) {
|
|
@@ -2704,8 +2591,9 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2704
2591
|
const kindCol = (KIND_DISPLAY[a.kind] ?? a.kind).padEnd(7);
|
|
2705
2592
|
const file = ellipsize(a.filename, filenameMax).padEnd(filenameMax);
|
|
2706
2593
|
const size = fmtBytes(a.sizeBytes).padStart(8);
|
|
2707
|
-
|
|
2594
|
+
output(` ${mark} ${C.muted(idCol)}${C.muted(kindCol)}${C.text(file)}${C.subtext(size)}`);
|
|
2708
2595
|
}
|
|
2596
|
+
return lines;
|
|
2709
2597
|
};
|
|
2710
2598
|
|
|
2711
2599
|
const chat = createChatState(
|
|
@@ -2863,40 +2751,30 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2863
2751
|
const target = logSearchResults[logSearchCursor]!;
|
|
2864
2752
|
scrollToSearchResult(target);
|
|
2865
2753
|
};
|
|
2866
|
-
const openLogSearchModal = (
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
// Keep the query so n/N still works after cancel — tmux
|
|
2891
|
-
// `copy-mode -s` convention.
|
|
2892
|
-
if (query.trim()) applyLogSearch(query);
|
|
2893
|
-
draw();
|
|
2894
|
-
},
|
|
2895
|
-
});
|
|
2896
|
-
attachSurfaceToWorkspace(popup.surface, currentWorkspaceOwnerId());
|
|
2897
|
-
display.pushModal(popup.surface);
|
|
2898
|
-
draw();
|
|
2899
|
-
};
|
|
2754
|
+
const openLogSearchModal = createDashboardLogSearchOpener({
|
|
2755
|
+
display: () => display,
|
|
2756
|
+
linesGetter: () => chatLines,
|
|
2757
|
+
initialQuery: () => logSearchQuery,
|
|
2758
|
+
termSize,
|
|
2759
|
+
computePaneH: rows => computePaneH(rows),
|
|
2760
|
+
currentThemeTokens: () => currentThemeTokens(),
|
|
2761
|
+
currentWorkspaceOwnerId: () => currentWorkspaceOwnerId(),
|
|
2762
|
+
draw: () => draw(),
|
|
2763
|
+
onJump: (result, query) => {
|
|
2764
|
+
applyLogSearch(query);
|
|
2765
|
+
// Position cursor on the picked result. applyLogSearch reset
|
|
2766
|
+
// it to 0; advance it to the result the user actually picked.
|
|
2767
|
+
const idx = logSearchResults.findIndex(r => r.lineIdx === result.lineIdx);
|
|
2768
|
+
logSearchCursor = idx >= 0 ? idx : 0;
|
|
2769
|
+
scrollToSearchResult(result);
|
|
2770
|
+
draw();
|
|
2771
|
+
},
|
|
2772
|
+
onCancel: query => {
|
|
2773
|
+
// Keep the query so n/N still works after cancel — tmux convention.
|
|
2774
|
+
if (query.trim()) applyLogSearch(query);
|
|
2775
|
+
draw();
|
|
2776
|
+
},
|
|
2777
|
+
});
|
|
2900
2778
|
|
|
2901
2779
|
// TUI 부활 S-a — /resume 세션 픽커 (codex 패리티). chat 세션 스토어를
|
|
2902
2780
|
// 필터형 모달로 띄우고, 선택 시 기존 `/session load <id>` slash 를
|
|
@@ -2920,7 +2798,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2920
2798
|
draw();
|
|
2921
2799
|
return;
|
|
2922
2800
|
}
|
|
2923
|
-
//
|
|
2801
|
+
// Pickers share the composer bottom slot.
|
|
2924
2802
|
const placement = resolveDecisionPickerPlacement({ height: 16 });
|
|
2925
2803
|
const modalWidth = placement.width;
|
|
2926
2804
|
const fmtRow = (m: (typeof rows)[number]): string => {
|
|
@@ -2979,12 +2857,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2979
2857
|
browserMode?: 'all' | 'files' | 'turns',
|
|
2980
2858
|
): Promise<boolean> => {
|
|
2981
2859
|
const diffCfg = getUserConfig().chat.rendering.diff;
|
|
2982
|
-
if (!diffCfg.turnBrowser) {
|
|
2983
|
-
pushDebugLine(C.muted(' source delta browser disabled by chat.rendering.diff.turnBrowser=false'));
|
|
2984
|
-
chatScrollOffset = -1;
|
|
2985
|
-
draw();
|
|
2986
|
-
return false;
|
|
2987
|
-
}
|
|
2988
2860
|
const { getSourceDeltaManager, createSourceDeltaBrowserPopup } = await import('../code-edit/index.js');
|
|
2989
2861
|
const turns = mode === 'latest'
|
|
2990
2862
|
? getSourceDeltaManager().recentTurns(1)
|
|
@@ -3284,7 +3156,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3284
3156
|
})
|
|
3285
3157
|
.reverse(); // 최신 턴 먼저
|
|
3286
3158
|
const items: SearchItem[] = turnItems;
|
|
3287
|
-
//
|
|
3159
|
+
// Pickers share the composer bottom slot.
|
|
3288
3160
|
const placement = resolveDecisionPickerPlacement({ height: 16 });
|
|
3289
3161
|
const modalWidth = placement.width;
|
|
3290
3162
|
const handle = createSearchModal({
|
|
@@ -3350,7 +3222,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3350
3222
|
...HITL_REVISE_PRESETS.map((p): SearchItem => ({ label: `${p.label} — 재분해`, payload: `preset:${p.action}` })),
|
|
3351
3223
|
{ label: '✏️ 직접입력 — 정정 코멘트 작성', payload: 'custom' },
|
|
3352
3224
|
];
|
|
3353
|
-
//
|
|
3225
|
+
// Pickers share the composer bottom slot.
|
|
3354
3226
|
const placement = resolveDecisionPickerPlacement({ height: 14 });
|
|
3355
3227
|
const modalWidth = placement.width;
|
|
3356
3228
|
const handle = createSearchModal({
|
|
@@ -3681,33 +3553,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3681
3553
|
let lastAssistantRaw: string | null = null;
|
|
3682
3554
|
let lastAssistantRange: { start: number; end: number } | null = null;
|
|
3683
3555
|
let lastAssistantMode: 'rendered' | 'raw' = 'rendered';
|
|
3684
|
-
//
|
|
3685
|
-
// grows the log at the expense of the 3-pane grid, negative shrinks
|
|
3686
|
-
// the log. Clamped inside computeVLayout so paneH >= 5 and logH >= 3.
|
|
3556
|
+
// Log-pane resize remains available when chatOnlyMode is toggled off.
|
|
3687
3557
|
let logHeightBias = 0;
|
|
3688
|
-
// TUI 부활 T0 (PLAN-tui-revival-essentials-2026-07-12) — 단일 UI 모드
|
|
3689
|
-
// 축. essential(기본) = codex/claude-code 패리티 chat-first; rich =
|
|
3690
|
-
// 기존 full dashboard. `--rich` CLI > config `dashboard.uiMode` >
|
|
3691
|
-
// 레거시 `defaultMode` 매핑 > 기본 essential. T1(chrome 게이트)·
|
|
3692
|
-
// T3(VW 게이트)가 이 값을 소비한다. `let` — T2 의 `/ui` 런타임
|
|
3693
|
-
// 전환이 재할당.
|
|
3694
|
-
let dashboardUiMode = resolveDashboardUiMode({
|
|
3695
|
-
cliRich: opts.rich,
|
|
3696
|
-
configUiMode: getUserConfig().dashboard.uiMode,
|
|
3697
|
-
legacyDefaultMode: getUserConfig().dashboard.defaultMode,
|
|
3698
|
-
});
|
|
3699
3558
|
// Chat-only mode: 3-pane grid collapses, log pane owns all space above
|
|
3700
3559
|
// the input. Toggled by /chat or /dashboard. Input loop stays alive
|
|
3701
3560
|
// across Escape while this is true — feels like a dedicated LLM REPL.
|
|
3702
|
-
//
|
|
3703
|
-
|
|
3704
|
-
// screen real estate). T0 이후 essential uiMode 가 기본 시드 —
|
|
3705
|
-
// essential 이면 chat 전체화면으로 부팅한다 (레거시
|
|
3706
|
-
// `dashboard.defaultMode: 'chat'` 은 uiMode 해석에 흡수됨).
|
|
3707
|
-
let chatOnlyMode = opts.chatOnly === true
|
|
3708
|
-
|| opts.debug === true
|
|
3709
|
-
|| opts.benchmark === true
|
|
3710
|
-
|| dashboardUiMode === 'essential';
|
|
3561
|
+
// Essential layout starts chat-only; /chat and /dashboard still toggle it.
|
|
3562
|
+
let chatOnlyMode = true;
|
|
3711
3563
|
|
|
3712
3564
|
// Debug log — auto-start forensic file capture so every run has a
|
|
3713
3565
|
// tail-able JSONL trail without the user thinking about it. Default
|
|
@@ -3739,12 +3591,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3739
3591
|
debug.setFileEnabled(dbgCfg.file);
|
|
3740
3592
|
// OH9 — 렌더 로그 무음 시드(레벨과 직교). 우선순위:
|
|
3741
3593
|
// level.json.render(명시) > config.debug.renderLogs(true=override) >
|
|
3742
|
-
//
|
|
3594
|
+
// essential 기본 억제. 부팅 시 렌더 노이즈를 자동으로
|
|
3743
3595
|
// 끄고, 대표가 diag 로 올려도 진단은 그대로 흐른다.
|
|
3744
3596
|
debug.setRenderSuppressed(resolveRenderSuppressed({
|
|
3745
3597
|
scopedRender: readScopedRenderLogs(),
|
|
3746
3598
|
configRenderLogs: dbgCfg.renderLogs,
|
|
3747
|
-
|
|
3599
|
+
defaultSuppressed: true,
|
|
3748
3600
|
}));
|
|
3749
3601
|
// Announce the path so the user knows where to tail. Prefixed
|
|
3750
3602
|
// with (muted) so it doesn't compete with real chat output.
|
|
@@ -3771,9 +3623,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3771
3623
|
debugScrollOffset = -1;
|
|
3772
3624
|
mirrorDrawThrottle.request();
|
|
3773
3625
|
});
|
|
3774
|
-
// --debug launch flag: force both sinks ON and announce it in the
|
|
3775
|
-
// log pane. The caller has already set chatOnlyMode=true above so
|
|
3776
|
-
// the mirror feed is actually visible.
|
|
3626
|
+
// --debug launch flag: force both sinks ON and announce it in the log pane.
|
|
3777
3627
|
if (opts.debug) {
|
|
3778
3628
|
debug.setFileEnabled(true);
|
|
3779
3629
|
debug.enable();
|
|
@@ -3837,14 +3687,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3837
3687
|
// ── Plugin host (Phase 2) ──
|
|
3838
3688
|
const hud = createHud();
|
|
3839
3689
|
|
|
3840
|
-
// FU-3 (2026-05-05) — wire goal + plan-mode HUD pills. Subscribes
|
|
3841
|
-
// to both registries so the status reflects state changes without
|
|
3842
|
-
// dashboard polling. Idempotent on attach (paints current state).
|
|
3843
|
-
void (async () => {
|
|
3844
|
-
const { wireGoalPlanHudBridge } = await import('./goal-plan-hud-bridge.js');
|
|
3845
|
-
wireGoalPlanHudBridge({ hud, draw: () => { try { draw(); } catch { /* draw not yet defined during boot */ } } });
|
|
3846
|
-
})();
|
|
3847
|
-
|
|
3848
3690
|
// Reasoning HUD segment — provider-agnostic emoji + label that
|
|
3849
3691
|
// sits in the top transient HUD row (next to voice / streaming
|
|
3850
3692
|
// indicators), NOT the bottom status bar. Capability-driven: pill
|
|
@@ -3929,42 +3771,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3929
3771
|
const toggleChatOnlyLayout = (opts: { announce?: boolean } = {}): void => {
|
|
3930
3772
|
setChatOnlyLayout(!chatOnlyMode, opts);
|
|
3931
3773
|
};
|
|
3932
|
-
// TUI 부활 T2 — /ui 런타임 전환. uiMode 재할당 + chat-only 동기 +
|
|
3933
|
-
// config persist(dashboard.uiMode). T1 chrome 게이트(·T3 VW 게이트)가
|
|
3934
|
-
// draw 마다 dashboardUiMode 를 읽으므로 재할당만으로 다음 프레임 반영.
|
|
3935
|
-
// draw 는 아래에서 늦게 바인딩되는 let — 슬래시 시점엔 실체 존재.
|
|
3936
|
-
const applyDashboardUiMode = (
|
|
3937
|
-
mode: DashboardUiMode,
|
|
3938
|
-
applyOpts: { persist?: boolean; announce?: boolean } = {},
|
|
3939
|
-
): void => {
|
|
3940
|
-
dashboardUiMode = mode;
|
|
3941
|
-
setChatOnlyLayout(mode === 'essential');
|
|
3942
|
-
// OH9 — /ui 전환 즉시 렌더 무음 시드 재해석(전환이 바로 반영되게).
|
|
3943
|
-
// level.json.render / config.renderLogs 명시가 있으면 uiMode 보다 우선
|
|
3944
|
-
// (resolveRenderSuppressed) — /ui essential 이 사용자 override 를 안 덮는다.
|
|
3945
|
-
debug.setRenderSuppressed(resolveRenderSuppressed({
|
|
3946
|
-
scopedRender: readScopedRenderLogs(),
|
|
3947
|
-
configRenderLogs: getUserConfig().debug.renderLogs,
|
|
3948
|
-
uiModeEssential: mode === 'essential',
|
|
3949
|
-
}));
|
|
3950
|
-
if (applyOpts.announce) {
|
|
3951
|
-
chatLines.push(C.muted(mode === 'essential'
|
|
3952
|
-
? '-- ui: essential (chat 전체화면) — /ui rich 로 전체 대시보드 --'
|
|
3953
|
-
: '-- ui: rich (full dashboard) — /ui essential 로 복귀 --'));
|
|
3954
|
-
chatScrollOffset = -1;
|
|
3955
|
-
}
|
|
3956
|
-
if (applyOpts.persist) {
|
|
3957
|
-
try {
|
|
3958
|
-
const cfg = getUserConfig();
|
|
3959
|
-
cfg.dashboard.uiMode = mode;
|
|
3960
|
-
saveUserConfig(cfg);
|
|
3961
|
-
} catch {
|
|
3962
|
-
chatLines.push(C.warning(' ui mode config persist 실패 — 이번 세션만 적용'));
|
|
3963
|
-
}
|
|
3964
|
-
}
|
|
3965
|
-
resetRenderCache();
|
|
3966
|
-
draw();
|
|
3967
|
-
};
|
|
3968
3774
|
// Mirror chatOnly launch flag into the HUD pill (same style /chat
|
|
3969
3775
|
// toggle uses) so the user sees "mode: chat" from the first frame.
|
|
3970
3776
|
if (chatOnlyMode) setSegment(hud, 'mode', C.info('mode: chat'), 10);
|
|
@@ -4004,25 +3810,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4004
3810
|
}
|
|
4005
3811
|
: {};
|
|
4006
3812
|
const liveShells = listPty().filter(h => h.isAlive()).length;
|
|
4007
|
-
// VW-U1 — foreground VW summary for the 🪟 pill. vwSegment hides
|
|
4008
|
-
// itself when there's only one single-pane window (nothing worth
|
|
4009
|
-
// showing). When there's no foreground at all we pass null.
|
|
4010
|
-
let vwSummary: Parameters<typeof mouseWiring.buildStatusLine>[0]['vw'] = null;
|
|
4011
|
-
try {
|
|
4012
|
-
const current = virtualWindows.registry.current();
|
|
4013
|
-
const list = virtualWindows.registry.list();
|
|
4014
|
-
if (current) {
|
|
4015
|
-
const panes = current.listPanes();
|
|
4016
|
-
const focusedIdx = panes.findIndex(p => p.id === current.focused);
|
|
4017
|
-
vwSummary = {
|
|
4018
|
-
windowId: current.id,
|
|
4019
|
-
paneIdx: focusedIdx >= 0 ? focusedIdx + 1 : 1,
|
|
4020
|
-
paneTotal: panes.length,
|
|
4021
|
-
windowTotal: list.length,
|
|
4022
|
-
zoomed: current.isZoomed(),
|
|
4023
|
-
};
|
|
4024
|
-
}
|
|
4025
|
-
} catch { /* vw not yet initialised */ }
|
|
4026
3813
|
pruneConversationPopupHost();
|
|
4027
3814
|
const conversationSnapshot = conversationPopupHost.snapshot();
|
|
4028
3815
|
const metrics = getSessionMetrics();
|
|
@@ -4039,7 +3826,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4039
3826
|
controller: process.env.ELANOUS_CONTROLLER?.trim() || undefined,
|
|
4040
3827
|
shellCount: liveShells,
|
|
4041
3828
|
shellRollup: latestShellRollup ?? undefined,
|
|
4042
|
-
vw:
|
|
3829
|
+
vw: null,
|
|
4043
3830
|
conversationPopups: {
|
|
4044
3831
|
liveCount: conversationSnapshot.live.length,
|
|
4045
3832
|
minimizedCount: conversationSnapshot.minimized.length,
|
|
@@ -4368,9 +4155,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4368
4155
|
cols: termSize().cols,
|
|
4369
4156
|
syntax: true,
|
|
4370
4157
|
colorTier: diffRendering.colorTier,
|
|
4371
|
-
adaptiveBg: diffRendering.adaptiveBg,
|
|
4372
|
-
syntaxPerHunk: diffRendering.syntaxPerHunk,
|
|
4373
|
-
cache: diffRendering.cache,
|
|
4374
4158
|
headerStyle: diffRendering.headerStyle,
|
|
4375
4159
|
})
|
|
4376
4160
|
.then((rows) => {
|
|
@@ -4460,6 +4244,36 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4460
4244
|
} catch { /* noop */ }
|
|
4461
4245
|
}, 5_000);
|
|
4462
4246
|
(gitDirtyTimer as unknown as { unref?: () => void }).unref?.();
|
|
4247
|
+
// The running module's installed version, not the user's working directory, is the baseline.
|
|
4248
|
+
const dashboardCodeRoot = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
4249
|
+
const versionDir = versionedDashboardInstallDir(dashboardCodeRoot);
|
|
4250
|
+
const staleInstallCheck = createStaleInstallCheck({
|
|
4251
|
+
codeRoot: dashboardCodeRoot,
|
|
4252
|
+
bootCommit: versionDir ? readDashboardBootCommit(versionDir) : undefined,
|
|
4253
|
+
readInstalledCommit: readCurrentInstalledCommit,
|
|
4254
|
+
now: Date.now,
|
|
4255
|
+
});
|
|
4256
|
+
if (versionDir) {
|
|
4257
|
+
const checkInstall = (): void => {
|
|
4258
|
+
const result = staleInstallCheck.check();
|
|
4259
|
+
debug.log('dashboard.version', 'install-check', {
|
|
4260
|
+
state: result.state, bootCommit: result.bootCommit, installedCommit: result.installedCommit,
|
|
4261
|
+
});
|
|
4262
|
+
if (staleInstallCheck.shouldNotify(result)) {
|
|
4263
|
+
chatLines.push(C.warning(`elanous 가 새 판으로 바뀌었다 (${result.bootCommit!.slice(0, 7)} → ${result.installedCommit!.slice(0, 7)}) · TUI 를 다시 띄워라`));
|
|
4264
|
+
chatScrollOffset = -1;
|
|
4265
|
+
try { draw(); } catch { /* TUI torn down */ }
|
|
4266
|
+
}
|
|
4267
|
+
};
|
|
4268
|
+
checkInstall();
|
|
4269
|
+
const installCheckTimer = setInterval(checkInstall, STALE_INSTALL_CHECK_INTERVAL_MS);
|
|
4270
|
+
installCheckTimer.unref?.();
|
|
4271
|
+
} else {
|
|
4272
|
+
const result = staleInstallCheck.check();
|
|
4273
|
+
debug.log('dashboard.version', 'install-check', {
|
|
4274
|
+
state: result.state, bootCommit: result.bootCommit, installedCommit: result.installedCommit,
|
|
4275
|
+
});
|
|
4276
|
+
}
|
|
4463
4277
|
// Phase T1 — unified terminal matrix. Wraps sessionRegistry during
|
|
4464
4278
|
// the migration window: spawns flow through `matrix.spawn()` so we
|
|
4465
4279
|
// get a single `term:<N>` id space, character/transport fields,
|
|
@@ -4471,13 +4285,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4471
4285
|
// tools) has one place to fan keys + clipboard across groups.
|
|
4472
4286
|
// Phase T5 — terminal IPC channel bus. Fetched via getChannelBus()
|
|
4473
4287
|
// here so the /term channel slashes can publish / list.
|
|
4474
|
-
// Phase T3b-b — VW slot bookkeeping. `<windowId>/<slotId>` → PaneId
|
|
4475
|
-
// so the adapter's removeSlot can find the right pane to close.
|
|
4476
|
-
// Populated by installSlot, drained by removeSlot. Slot id equals
|
|
4477
|
-
// the PaneId on the split-chord path (paneId is already globally
|
|
4478
|
-
// unique); externally-chosen slotIds from /term move are free-form.
|
|
4479
|
-
const vwSlotBindings = new Map<string, PaneId>();
|
|
4480
|
-
const suppressedVwPaneKills = new Set<PaneId>();
|
|
4481
4288
|
// P16 — mirror session metadata to
|
|
4482
4289
|
// ~/.config/monad-agent/terminal-sessions.json on each lifecycle
|
|
4483
4290
|
// change (debounced 250ms). /term resume later re-spawns from this.
|
|
@@ -4508,22 +4315,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4508
4315
|
// dispatch so browser Ctrl+W / /wd retargets Bash immediately.
|
|
4509
4316
|
setBashRuntimeDeps({});
|
|
4510
4317
|
|
|
4511
|
-
//
|
|
4512
|
-
// • registry → auto-bg (15s) + TTL (5m) + ShellList/Poll/Kill backend.
|
|
4513
|
-
// • fileEngine → inline/bg mode (spawn+pipe).
|
|
4514
|
-
// • ptyHostFactory → NT-C1b-3 (session nt): per-label persistent
|
|
4515
|
-
// PreviewTerminal for mode='vw' / 'modal'.
|
|
4516
|
-
// Sequential commands in the same label
|
|
4517
|
-
// share PTY + scrollback. VW pane binding
|
|
4518
|
-
// itself lives in NT-C1b-4.
|
|
4318
|
+
// ShellRunner registry tracks handles; file capture runs inline/bg commands.
|
|
4519
4319
|
{
|
|
4520
4320
|
const { initShellRegistry } = await import('../shell-runner/registry.js');
|
|
4521
4321
|
const { createFileCaptureEngine } = await import('../shell-runner/file-engine.js');
|
|
4522
4322
|
const { setShellRunnerDeps } = await import('../shell-runner/dispatch.js');
|
|
4523
|
-
const { createRunnerHostFactory } = await import('../shell-runner/runner-host-factory.js');
|
|
4524
|
-
const { createExternalTerminalPaneContent } = await import('../shell-runner/external-terminal-pane.js');
|
|
4525
4323
|
const { createBackgroundSurface } = await import('../shell-runner/background-surface.js');
|
|
4526
|
-
const { registerPaneContentKind } = await import('../virtual-windows/pane-content.js');
|
|
4527
4324
|
// The boot seam types the registry as the opaque `ShellRegistryLike`
|
|
4528
4325
|
// stub (decoupling), while the real `wireShellRunnerSurface` takes a
|
|
4529
4326
|
// concrete `ShellRegistry`. At runtime `initShellRegistry` returns the
|
|
@@ -4538,161 +4335,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4538
4335
|
deps: { shellRegistry: unknown },
|
|
4539
4336
|
) => void;
|
|
4540
4337
|
} catch { /* never break boot */ }
|
|
4541
|
-
registerPaneContentKind('vw-browser', (spec: any, deps: any) =>
|
|
4542
|
-
createBrowserPaneContent(spec, {
|
|
4543
|
-
browserPaneRegistry: deps.browserPaneRegistry,
|
|
4544
|
-
refreshRemoteBrowserPane: deps.refreshRemoteBrowserPane,
|
|
4545
|
-
}),
|
|
4546
|
-
);
|
|
4547
|
-
registerPaneContentKind('vw-preview', (spec: any, deps: any) =>
|
|
4548
|
-
createPreviewPaneContent(spec, {
|
|
4549
|
-
previewPaneRegistry: deps.previewPaneRegistry,
|
|
4550
|
-
}),
|
|
4551
|
-
);
|
|
4552
|
-
registerPaneContentKind('iul-shell', (spec: any) =>
|
|
4553
|
-
createIulSidebarShellPaneContent(spec, {
|
|
4554
|
-
iulThemePreviewControl: {
|
|
4555
|
-
getActiveThemeName: () => currentThemeTokens().name,
|
|
4556
|
-
previewTheme: (name: string) => {
|
|
4557
|
-
iulThemePreviewOverride = name;
|
|
4558
|
-
requestDashboardRender();
|
|
4559
|
-
},
|
|
4560
|
-
revertPreview: () => {
|
|
4561
|
-
iulThemePreviewOverride = null;
|
|
4562
|
-
requestDashboardRender();
|
|
4563
|
-
},
|
|
4564
|
-
commitTheme: (name: string) => {
|
|
4565
|
-
iulThemePreviewOverride = null;
|
|
4566
|
-
const cfg = getUserConfig();
|
|
4567
|
-
cfg.dashboard.theme = { ...(cfg.dashboard.theme as object ?? {}), active: name } as never;
|
|
4568
|
-
saveUserConfig(cfg);
|
|
4569
|
-
requestDashboardRender();
|
|
4570
|
-
},
|
|
4571
|
-
},
|
|
4572
|
-
}),
|
|
4573
|
-
);
|
|
4574
|
-
registerPaneContentKind('acp-shell', (spec: any) =>
|
|
4575
|
-
createAcpResidentShellPaneContent(spec, {
|
|
4576
|
-
runPrimaryAction: async (action, stub) => {
|
|
4577
|
-
switch (action.id) {
|
|
4578
|
-
case 'open-live-client-room':
|
|
4579
|
-
case 'open-live-server-room': {
|
|
4580
|
-
const opened = await openConversationModal(stub.id);
|
|
4581
|
-
return opened
|
|
4582
|
-
? `Opened live ACP room for ${stub.id}`
|
|
4583
|
-
: `Live ACP room not mounted for ${stub.id}`;
|
|
4584
|
-
}
|
|
4585
|
-
case 'promote-background-vw': {
|
|
4586
|
-
const result = await dispatchAcpSessionJoin({ backgroundId: stub.id, promoteToVW: true });
|
|
4587
|
-
return result.promoted && result.windowId
|
|
4588
|
-
? `Promoted to VW ${result.windowId}`
|
|
4589
|
-
: 'Joined background lane';
|
|
4590
|
-
}
|
|
4591
|
-
case 'join-background-transcript': {
|
|
4592
|
-
await dispatchAcpSessionJoin({ backgroundId: stub.id, promoteToVW: false });
|
|
4593
|
-
return 'Loaded background transcript';
|
|
4594
|
-
}
|
|
4595
|
-
case 'resume-persisted-session': {
|
|
4596
|
-
await dispatchAcpSessionResume({ sessionId: stub.id });
|
|
4597
|
-
return 'Resumed persisted ACP session';
|
|
4598
|
-
}
|
|
4599
|
-
default:
|
|
4600
|
-
return 'No ACP action wired for this lane';
|
|
4601
|
-
}
|
|
4602
|
-
},
|
|
4603
|
-
}),
|
|
4604
|
-
);
|
|
4605
|
-
registerPaneContentKind('sim-shell', (spec: any) =>
|
|
4606
|
-
createSimShellPaneContent(spec, {
|
|
4607
|
-
seedAssistantSample: (text) => {
|
|
4608
|
-
({ lastAssistantRaw, lastAssistantRange, lastAssistantMode } = appendDashboardAssistantSampleOutput({
|
|
4609
|
-
chatLines,
|
|
4610
|
-
text,
|
|
4611
|
-
termCols: termSize().cols,
|
|
4612
|
-
wrapEnabled: getUserConfig().chat.rendering.wrap,
|
|
4613
|
-
formatResponse,
|
|
4614
|
-
renderTextLine: C.text,
|
|
4615
|
-
}));
|
|
4616
|
-
chatScrollOffset = -1;
|
|
4617
|
-
draw();
|
|
4618
|
-
},
|
|
4619
|
-
clearAssistantSample: () => {
|
|
4620
|
-
lastAssistantRaw = null;
|
|
4621
|
-
lastAssistantRange = null;
|
|
4622
|
-
lastAssistantMode = 'rendered';
|
|
4623
|
-
chatScrollOffset = -1;
|
|
4624
|
-
draw();
|
|
4625
|
-
},
|
|
4626
|
-
openLastAssistantMediaPreview: async () => {
|
|
4627
|
-
await openLastAssistantMediaPreview();
|
|
4628
|
-
},
|
|
4629
|
-
getBrowserStatusLines: () => browserCdpSlashRuntime.statusLines(),
|
|
4630
|
-
getBrowserSmokeLines: async () => browserCdpSlashRuntime.smokeLines(),
|
|
4631
|
-
getBrowserStopLines: () => browserCdpSlashRuntime.stopLines(),
|
|
4632
|
-
signalBus: dashboardControlSignals,
|
|
4633
|
-
signalScope: { surface: 'dashboard-chat-main', channel: 'dashboard' },
|
|
4634
|
-
source: { kind: 'keyboard', surface: 'dashboard-chat-main' },
|
|
4635
|
-
}),
|
|
4636
|
-
);
|
|
4637
4338
|
bootDashboardShellRunner({
|
|
4638
4339
|
createBackgroundSurface,
|
|
4639
4340
|
initShellRegistry,
|
|
4640
4341
|
wireShellRunnerSurface,
|
|
4641
|
-
registerPaneContentKind,
|
|
4642
|
-
createExternalTerminalPaneContent,
|
|
4643
|
-
createRunnerHostFactory,
|
|
4644
4342
|
createFileCaptureEngine,
|
|
4645
4343
|
setShellRunnerDeps,
|
|
4646
|
-
getSessionCwd: () => getSessionCwd(),
|
|
4647
|
-
termSize: () => termSize(),
|
|
4648
4344
|
setLatestShellRollup: (rollup) => { latestShellRollup = rollup; },
|
|
4649
|
-
onSpawnError: (label, err) => {
|
|
4650
|
-
// SP-E — visible failure mode. Factory already degrades to
|
|
4651
|
-
// file engine + null return; without this the user only
|
|
4652
|
-
// sees "no VW appeared" with no hint as to why.
|
|
4653
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
4654
|
-
pushDebugLine(C.warning(` [shell] spawn failed for label=${label}: ${msg}`));
|
|
4655
|
-
pushDebugLine(C.muted(' (file engine fallback — output still captured; no VW pane)'));
|
|
4656
|
-
chatScrollOffset = -1;
|
|
4657
|
-
try { draw(); } catch { /* TUI torn down */ }
|
|
4658
|
-
},
|
|
4659
|
-
spawnVirtualWindowTerminal: (label, host) => {
|
|
4660
|
-
const extSpec = {
|
|
4661
|
-
kind: 'external-terminal',
|
|
4662
|
-
preview: host,
|
|
4663
|
-
title: label,
|
|
4664
|
-
label,
|
|
4665
|
-
focusPolicy: 'output-only',
|
|
4666
|
-
onTerminalMouseIntent: (event: {
|
|
4667
|
-
paneId: string;
|
|
4668
|
-
paneKind: 'external-terminal';
|
|
4669
|
-
mouseType: DisplayMouseEvent['type'];
|
|
4670
|
-
row: number;
|
|
4671
|
-
col: number;
|
|
4672
|
-
exposure: TerminalExposureSnapshot;
|
|
4673
|
-
interactionPolicy: TerminalInteractionPolicy;
|
|
4674
|
-
}) => {
|
|
4675
|
-
emitTerminalMouseIntent({
|
|
4676
|
-
surfaceId: event.paneId,
|
|
4677
|
-
paneKind: event.paneKind,
|
|
4678
|
-
mouseType: event.mouseType,
|
|
4679
|
-
row: event.row,
|
|
4680
|
-
col: event.col,
|
|
4681
|
-
exposure: event.exposure,
|
|
4682
|
-
interactionPolicy: event.interactionPolicy,
|
|
4683
|
-
});
|
|
4684
|
-
},
|
|
4685
|
-
} as any;
|
|
4686
|
-
virtualWindows.registry.spawn({ title: label, initialContent: extSpec });
|
|
4687
|
-
},
|
|
4688
|
-
subscribeVirtualWindowClose: (cb) => {
|
|
4689
|
-
virtualWindows.registry.subscribe((ev) => {
|
|
4690
|
-
cb({
|
|
4691
|
-
type: ev.type,
|
|
4692
|
-
spawnTitle: 'spawnTitle' in ev ? ev.spawnTitle : undefined,
|
|
4693
|
-
});
|
|
4694
|
-
});
|
|
4695
|
-
},
|
|
4696
4345
|
});
|
|
4697
4346
|
}
|
|
4698
4347
|
const { setShellApprover } = await import('../shell-primitive/index.js');
|
|
@@ -4819,9 +4468,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4819
4468
|
} catch { return []; }
|
|
4820
4469
|
});
|
|
4821
4470
|
setTerminalMouseIntentsGetter(() => [...recentTerminalMouseIntents]);
|
|
4822
|
-
// Phase C — wire context.* tools
|
|
4823
|
-
// later once virtualWindows is built (a few lines down); until
|
|
4824
|
-
// then ContextWindowsList returns (no windows).
|
|
4471
|
+
// Phase C — wire context.* tools without virtual-window state.
|
|
4825
4472
|
const { setContextRuntimeDeps } = await import('../tool-runtime/index.js');
|
|
4826
4473
|
// Surface-unification v2.2 V2.2-5 (2026-05-11) — scheduler store
|
|
4827
4474
|
// wire retired together with `context.jobs.list` LLM tool.
|
|
@@ -4924,103 +4571,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4924
4571
|
debug.log(scope, area, details);
|
|
4925
4572
|
},
|
|
4926
4573
|
});
|
|
4927
|
-
//
|
|
4928
|
-
// PaneVisualStateStore singleton + SetFocusPolicy/DescribePane LLM
|
|
4929
|
-
// tools. Store is dashboard-local so consumers (Alt+N skip migration
|
|
4930
|
-
// landed in B-7-α, `^B !` toggle migration, visibility pill) subscribe
|
|
4931
|
-
// via the same instance. Constructed ahead of initDashboardVirtualWindows
|
|
4932
|
-
// so the VW init can plumb the store-driven skip predicate (B-7-α).
|
|
4933
|
-
// Chord hints `^B p` / `^B d` reserved for Bundle B-2 symmetry registry wire.
|
|
4574
|
+
// PaneVisualStateStore serves dashboard pane tools.
|
|
4934
4575
|
const paneVisualStateStore = createVisualStateStore();
|
|
4935
4576
|
let browserPaneRegistry!: BrowserPaneRegistry;
|
|
4936
4577
|
let previewPaneRegistry!: PreviewPaneRegistry;
|
|
4937
4578
|
|
|
4938
|
-
//
|
|
4939
|
-
// VWEventBus + WindowRegistry, wires PaneCapture's pane→content
|
|
4940
|
-
// lookup, registers the skill-runner tool singletons, and creates
|
|
4941
|
-
// the navigation router. Host UI callbacks (picker / new /
|
|
4942
|
-
// split / help / close-window) are intentionally left as no-ops
|
|
4943
|
-
// here — they are follow-ups (VW §10.2, §10.6). The chord still
|
|
4944
|
-
// works for digits, arrows, n/p, x/X, etc. which don't need UI.
|
|
4945
|
-
const vwInputRuntime = createDashboardVirtualWindowInputRuntime({
|
|
4946
|
-
getRegistry: () => virtualWindows.registry,
|
|
4947
|
-
pushMutedLine: (line) => {
|
|
4948
|
-
chatLines.push(C.muted(line));
|
|
4949
|
-
chatScrollOffset = -1;
|
|
4950
|
-
},
|
|
4951
|
-
openLocalInputTargetPopup: openVwLocalInputTargetPopup,
|
|
4952
|
-
openSelectorPopup: openVwSelectorPopup,
|
|
4953
|
-
routeContextMenu: (req) => ctxMenuWire.onMouse(req),
|
|
4954
|
-
skipWindowWhen: skipWindowWhenStorePredicate(paneVisualStateStore),
|
|
4955
|
-
resolvePaneVisibility: (windowId, paneId) =>
|
|
4956
|
-
paneVisualStateStore.snapshot({ windowId: String(windowId), paneId }).visibility,
|
|
4957
|
-
termSize,
|
|
4958
|
-
});
|
|
4959
|
-
const vwControlRuntime = createDashboardVirtualWindowControlRuntime({
|
|
4960
|
-
openWindowPicker,
|
|
4961
|
-
getCurrentWindow: () => virtualWindows.registry.current(),
|
|
4962
|
-
closeWindow: (windowId) => { virtualWindows.registry.close(windowId); },
|
|
4963
|
-
pushMutedLine: (line) => {
|
|
4964
|
-
chatLines.push(C.muted(line));
|
|
4965
|
-
chatScrollOffset = -1;
|
|
4966
|
-
},
|
|
4967
|
-
draw,
|
|
4968
|
-
});
|
|
4969
|
-
const vwMutationRuntime = createDashboardVirtualWindowMutationRuntime({
|
|
4970
|
-
spawnWindow: () => virtualWindows.registry.spawn({
|
|
4971
|
-
title: 'terminal',
|
|
4972
|
-
initialContent: { kind: 'terminal' },
|
|
4973
|
-
foreground: true,
|
|
4974
|
-
}),
|
|
4975
|
-
getForegroundSession: () => sessionRegistry.foreground(),
|
|
4976
|
-
detachSession: (id) => {
|
|
4977
|
-
sessionRegistry.detach(id);
|
|
4978
|
-
},
|
|
4979
|
-
getLatestBackgroundSession: () =>
|
|
4980
|
-
sessionRegistry.list()
|
|
4981
|
-
.filter(s => s.state === 'background')
|
|
4982
|
-
.sort((a, b) => b.lastFocusedAt - a.lastFocusedAt)[0] ?? null,
|
|
4983
|
-
attachSession: (id, dims) => {
|
|
4984
|
-
sessionRegistry.attach(id, dims);
|
|
4985
|
-
},
|
|
4986
|
-
termSize,
|
|
4987
|
-
getCurrentWindow: () => virtualWindows.registry.current(),
|
|
4988
|
-
renameWindow: (windowId, next) => virtualWindows.registry.renameWindow(windowId, next),
|
|
4989
|
-
renamePane: (windowId, paneId, next) => { virtualWindows.registry.renamePane(windowId, paneId, next); },
|
|
4990
|
-
openRenameModal: openVwRenameModal,
|
|
4991
|
-
pushMutedLine: (line) => {
|
|
4992
|
-
chatLines.push(C.muted(line));
|
|
4993
|
-
chatScrollOffset = -1;
|
|
4994
|
-
},
|
|
4995
|
-
pushWarningLine: (line) => {
|
|
4996
|
-
chatLines.push(C.warning(line));
|
|
4997
|
-
chatScrollOffset = -1;
|
|
4998
|
-
},
|
|
4999
|
-
draw,
|
|
5000
|
-
});
|
|
5001
|
-
const vwHelpRuntime = createDashboardVirtualWindowHelpRuntime({
|
|
5002
|
-
termSize,
|
|
5003
|
-
registrationState: {
|
|
5004
|
-
supplementalGlobalKeys: getUserConfig().dashboard.enableSupplementalGlobalKeys,
|
|
5005
|
-
virtualWindowSwitchKeys: getUserConfig().dashboard.enableVirtualWindowSwitchKeys,
|
|
5006
|
-
},
|
|
5007
|
-
keyLabel: (key, desc) => ` ${C.key(pad(key, 14))} ${C.text(desc)}`,
|
|
5008
|
-
sectionLabel: (title) => C.bold(title),
|
|
5009
|
-
muted: (text) => C.muted(text),
|
|
5010
|
-
showHelpModal: ({ title, lines, termCols, termRows, ttlMs, group }) => {
|
|
5011
|
-
showTransientTerminalModal({
|
|
5012
|
-
title,
|
|
5013
|
-
lines,
|
|
5014
|
-
coordinator: display,
|
|
5015
|
-
termCols,
|
|
5016
|
-
termRows,
|
|
5017
|
-
ttlMs,
|
|
5018
|
-
group,
|
|
5019
|
-
});
|
|
5020
|
-
},
|
|
5021
|
-
});
|
|
5022
|
-
// Yazi-style browser-pane help (`~`). Same shape as vwHelpRuntime —
|
|
5023
|
-
// shares the showTransientTerminalModal primitive.
|
|
4579
|
+
// Browser-pane help (`~`) uses the transient modal primitive.
|
|
5024
4580
|
const browserHelpRuntime = createBrowserHelpRuntime({
|
|
5025
4581
|
termSize,
|
|
5026
4582
|
keyLabel: (key, desc) => ` ${C.key(pad(key, 14))} ${C.text(desc)}`,
|
|
@@ -5038,243 +4594,11 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5038
4594
|
});
|
|
5039
4595
|
},
|
|
5040
4596
|
});
|
|
5041
|
-
|
|
5042
|
-
getCurrentWindow: () => virtualWindows.registry.current(),
|
|
5043
|
-
spawnTerminal: ({ title, cwd }) => terminalMatrix.spawn({ title, cwd }),
|
|
5044
|
-
cwd: () => workingDir.cwd,
|
|
5045
|
-
detachSession: (id) => {
|
|
5046
|
-
try { sessionRegistry.detach(id); } catch {}
|
|
5047
|
-
},
|
|
5048
|
-
getCurrentTerminalModalId: () => terminalModalRouter.current()?.id ?? null,
|
|
5049
|
-
clearCurrentTerminalModal: () => { terminalModalRouter.set(null); },
|
|
5050
|
-
createTerminalSlotContent: ({ terminalId, title }) => createPaneContent({
|
|
5051
|
-
kind: 'terminal-slot',
|
|
5052
|
-
terminalId,
|
|
5053
|
-
title,
|
|
5054
|
-
}),
|
|
5055
|
-
bindSlot: (slotKey, paneId) => { vwSlotBindings.set(slotKey, paneId); },
|
|
5056
|
-
setPlacement: (terminalId, placement) => { terminalMatrix.setPlacement(terminalId, placement); },
|
|
5057
|
-
pushMutedLine: (line) => {
|
|
5058
|
-
chatLines.push(C.muted(line));
|
|
5059
|
-
chatScrollOffset = -1;
|
|
5060
|
-
},
|
|
5061
|
-
pushWarningLine: (line) => {
|
|
5062
|
-
chatLines.push(C.warning(line));
|
|
5063
|
-
chatScrollOffset = -1;
|
|
5064
|
-
},
|
|
5065
|
-
draw,
|
|
5066
|
-
});
|
|
5067
|
-
|
|
5068
|
-
// TUI 부활 T3 (2026-07-12) — VW 는 essential 에서 "실질 OFF" 게이트.
|
|
5069
|
-
// 설계 노트: init 자체는 유지한다 (빈 레지스트리 + 이벤트버스 뿐 —
|
|
5070
|
-
// 부팅 시 무조건적 윈도우 스폰이 없어 타이머/렌더 비용 0 확인).
|
|
5071
|
-
// 완전 스킵(no-op registry)을 택하지 않은 이유: WindowRegistry 는
|
|
5072
|
-
// private 필드를 가진 concrete class 라 구조적 타입 위조가 불가하고,
|
|
5073
|
-
// 부팅 시 registry 참조를 캡처하는 소비처들이 stale no-op 을 물게 돼
|
|
5074
|
-
// /ui rich 런타임 전환이 재시작 없이는 불가능해진다. 대신 사용자
|
|
5075
|
-
// 노출 표면 3곳을 uiMode 로 게이트: ① ^B chord 깔때기(vwBody) ②
|
|
5076
|
-
// draw 의 workspace frame 합성 ③ /workspace slash. essential 에서
|
|
5077
|
-
// LLM tool 이 프로그래매틱하게 스폰한 윈도우는 레지스트리에 남고
|
|
5078
|
-
// /ui rich 전환 시 그대로 보인다 (의도 — 비파괴).
|
|
5079
|
-
virtualWindows = initDashboardVirtualWindows({
|
|
5080
|
-
coordinator: display,
|
|
5081
|
-
injectApprover: createPaneInjectApprover(),
|
|
5082
|
-
broadcastApprover: createBroadcastApprover(),
|
|
5083
|
-
// Per-window local composer submit. Route through the pane-level
|
|
5084
|
-
// broadcast contract so mixed PTY/chat/markdown lanes share the
|
|
5085
|
-
// same submit semantics instead of falling back to raw PTY bytes.
|
|
5086
|
-
onLocalInputSubmit: vwInputRuntime.onLocalInputSubmit,
|
|
5087
|
-
onOpenLocalInputTargetPicker: vwInputRuntime.onOpenLocalInputTargetPicker,
|
|
5088
|
-
onShowSelector: vwInputRuntime.onShowSelector,
|
|
5089
|
-
onShowContextMenu: vwInputRuntime.onShowContextMenu,
|
|
5090
|
-
// B-7-α — PaneVisualStateStore-driven Alt+N skip predicate.
|
|
5091
|
-
// Composed (OR) with the built-in !hasInteractableFocus() default
|
|
5092
|
-
// in dashboard-virtual-windows.ts. When every pane in a window is
|
|
5093
|
-
// skip-eligible (focusPolicy=skip/no-focus · visibility=hidden/
|
|
5094
|
-
// dormant), Alt+N/P cycling bypasses the window. LLM's
|
|
5095
|
-
// SetFocusPolicy tool becomes a real effect on cycling.
|
|
5096
|
-
extraSkipWindowWhen: vwInputRuntime.extraSkipWindowWhen,
|
|
5097
|
-
// B-7-γ — per-window resolver that reads PaneVisualStateStore so
|
|
5098
|
-
// paintPane can stamp a visibility badge on the focused pane's
|
|
5099
|
-
// label (`·H·` / `·D·` / `·ᴸ·`). The store is written by the LLM
|
|
5100
|
-
// `SetFocusPolicy` tool (B-1) and the `^B H` chord (B-7-β);
|
|
5101
|
-
// this factory is the consumer that makes those writes visible.
|
|
5102
|
-
visibilityResolverFactory: vwInputRuntime.visibilityResolverFactory,
|
|
5103
|
-
// T2-P5 — wire llm-chat panes to the same provider set the
|
|
5104
|
-
// rest of the app uses. spawnLLMBenchmark now routes to a real
|
|
5105
|
-
// backend; unknown providers surface as an error line inside
|
|
5106
|
-
// the pane rather than a silent hang.
|
|
5107
|
-
paneDeps: {
|
|
5108
|
-
onTerminalMouseIntent: (ev, meta) => {
|
|
5109
|
-
emitTerminalMouseIntent({
|
|
5110
|
-
surfaceId: meta.paneId,
|
|
5111
|
-
paneKind: meta.paneKind,
|
|
5112
|
-
mouseType: ev.type,
|
|
5113
|
-
row: ev.row,
|
|
5114
|
-
col: ev.col,
|
|
5115
|
-
exposure: meta.exposure,
|
|
5116
|
-
interactionPolicy: meta.interactionPolicy,
|
|
5117
|
-
});
|
|
5118
|
-
},
|
|
5119
|
-
llmChatBackend: async function* (req) {
|
|
5120
|
-
const provider = LLM_PROVIDERS[req.provider];
|
|
5121
|
-
if (!provider) {
|
|
5122
|
-
yield `[unknown provider: ${req.provider}]`;
|
|
5123
|
-
return;
|
|
5124
|
-
}
|
|
5125
|
-
if (!provider.chat) {
|
|
5126
|
-
yield `[provider ${req.provider} missing chat()]`;
|
|
5127
|
-
return;
|
|
5128
|
-
}
|
|
5129
|
-
try {
|
|
5130
|
-
for await (const chunk of provider.chat(req.messages, { model: req.model })) {
|
|
5131
|
-
yield chunk;
|
|
5132
|
-
}
|
|
5133
|
-
} catch (err) {
|
|
5134
|
-
yield `\n[error: ${err instanceof Error ? err.message : String(err)}]`;
|
|
5135
|
-
}
|
|
5136
|
-
},
|
|
5137
|
-
get browserPaneRegistry() { return browserPaneRegistry; },
|
|
5138
|
-
get previewPaneRegistry() { return previewPaneRegistry; },
|
|
5139
|
-
refreshRemoteBrowserPane: async (state: BrowserPaneModel) => {
|
|
5140
|
-
await refreshRemoteWorkingDir(
|
|
5141
|
-
state as WorkingDirState,
|
|
5142
|
-
{},
|
|
5143
|
-
{ previewPath: null, previewLines: [], previewOffset: 0 },
|
|
5144
|
-
);
|
|
5145
|
-
},
|
|
5146
|
-
},
|
|
5147
|
-
defaultBounds: vwInputRuntime.defaultBounds,
|
|
5148
|
-
callbacks: {
|
|
5149
|
-
// FU-2 — chord help popup. Shows a grouped keybinding cheatsheet
|
|
5150
|
-
// as a transient modal instead of a single muted chat line, so
|
|
5151
|
-
// the user actually gets to read + reference it while experimenting.
|
|
5152
|
-
// Auto-dismisses after 8 s; spawning the popup again while it's
|
|
5153
|
-
// open replaces the prior instance (group='vw-chord-help').
|
|
5154
|
-
onHelp: vwHelpRuntime.onHelp,
|
|
5155
|
-
onPicker: vwControlRuntime.onPicker,
|
|
5156
|
-
onCloseWindow: vwControlRuntime.onCloseWindow,
|
|
5157
|
-
onNewWindow: vwMutationRuntime.onNewWindow,
|
|
5158
|
-
onModalWindowToggle: vwMutationRuntime.onModalWindowToggle,
|
|
5159
|
-
onSyncInputBarToggle: vwControlRuntime.onSyncInputBarToggle,
|
|
5160
|
-
onZoomToggle: vwControlRuntime.onZoomToggle,
|
|
5161
|
-
onLastFocusedPane: vwControlRuntime.onLastFocusedPane,
|
|
5162
|
-
onRenameWindow: vwMutationRuntime.onRenameWindow,
|
|
5163
|
-
onRenamePane: vwMutationRuntime.onRenamePane,
|
|
5164
|
-
onSplit: vwSplitRuntime.onSplit,
|
|
5165
|
-
},
|
|
5166
|
-
});
|
|
5167
|
-
// Phase T3b-b1 — install the VW placement adapter. matrix.move()
|
|
5168
|
-
// with kind='vw' now routes through the VW registry's splitFocused
|
|
5169
|
-
// / closePaneAt. Uses the vwSlotBindings map so the slot id (which
|
|
5170
|
-
// the matrix caller chose) resolves back to the real PaneId.
|
|
5171
|
-
const vwPlacementAdapter = new VwPlacementAdapter({
|
|
5172
|
-
matrix: terminalMatrix,
|
|
5173
|
-
sessionRegistry,
|
|
5174
|
-
termSize,
|
|
5175
|
-
installSlot: (windowId, slotId, terminalId) => {
|
|
5176
|
-
// WindowId is a number in the VW registry but the matrix
|
|
5177
|
-
// placement carries it as a string. Convert + guard Naan.
|
|
5178
|
-
const winNum = Number(windowId);
|
|
5179
|
-
const w = Number.isFinite(winNum) ? virtualWindows.registry.get(winNum) : null;
|
|
5180
|
-
if (!w) throw new Error(`window not found: ${windowId}`);
|
|
5181
|
-
const content = createPaneContent({
|
|
5182
|
-
kind: 'terminal-slot',
|
|
5183
|
-
terminalId,
|
|
5184
|
-
title: `term:${terminalId}`,
|
|
5185
|
-
});
|
|
5186
|
-
// Adapter-driven splits default to horizontal. The chord flow
|
|
5187
|
-
// chooses axis itself and bypasses the adapter — see onSplit
|
|
5188
|
-
// above. This default is fine because users who care about the
|
|
5189
|
-
// axis press the chord; users who call `/term move <id> vw:w/s`
|
|
5190
|
-
// typically just want a slot.
|
|
5191
|
-
const newPaneId = w.splitFocused('h', content);
|
|
5192
|
-
vwSlotBindings.set(`${windowId}/${slotId}`, newPaneId);
|
|
5193
|
-
},
|
|
5194
|
-
removeSlot: (windowId, slotId) => {
|
|
5195
|
-
const winNum = Number(windowId);
|
|
5196
|
-
const w = Number.isFinite(winNum) ? virtualWindows.registry.get(winNum) : null;
|
|
5197
|
-
if (!w) return;
|
|
5198
|
-
const key = `${windowId}/${slotId}`;
|
|
5199
|
-
const paneId = vwSlotBindings.get(key) ?? slotId; // fallback: slotId == paneId on chord path
|
|
5200
|
-
suppressedVwPaneKills.add(paneId);
|
|
5201
|
-
try { w.closePaneAt(paneId); } catch { /* already gone */ }
|
|
5202
|
-
vwSlotBindings.delete(key);
|
|
5203
|
-
},
|
|
5204
|
-
});
|
|
5205
|
-
vwPlacementAdapter.install();
|
|
5206
|
-
// Phase T3b-b1 — drop stale bindings when a pane closes externally
|
|
5207
|
-
// (user pressed `x` in the VW, window was destroyed, pane exited).
|
|
5208
|
-
// Matrix placement stays as `vw:<w>/<slot>` until the user moves it
|
|
5209
|
-
// explicitly; drift is annoying but not dangerous. Future phase:
|
|
5210
|
-
// auto-move to background on pane:close.
|
|
5211
|
-
installVwLifecycleHandlers({
|
|
5212
|
-
bus: virtualWindows.bus,
|
|
5213
|
-
terminalMatrix,
|
|
5214
|
-
bindings: vwSlotBindings,
|
|
5215
|
-
suppressedKills: suppressedVwPaneKills,
|
|
5216
|
-
});
|
|
5217
|
-
// Symmetric counterpart — when a VW-placed PTY exits or is killed
|
|
5218
|
-
// (shell `exit`, external kill), auto-close the hosting VW pane so
|
|
5219
|
-
// the user isn't left with a dead shell frame on screen. closePaneAt
|
|
5220
|
-
// emits pane:close → the handler above drops the binding; kill is a
|
|
5221
|
-
// no-op because the terminal already has exitCode !== null.
|
|
5222
|
-
const closeVwPaneForExit = createVwExitPaneCloser({
|
|
5223
|
-
getVirtualWindow: (id) => virtualWindows.registry.get(id),
|
|
5224
|
-
bindings: vwSlotBindings,
|
|
5225
|
-
});
|
|
5226
|
-
// Phase T3b-b3 — auto-tag terminals with `_vw:<windowId>` broadcast
|
|
5227
|
-
// group as they enter / leave a VW placement. This is the per-VW
|
|
5228
|
-
// implicit group that `/term group send _vw:<id> <text>` broadcasts
|
|
5229
|
-
// to — a tmux synchronize-panes at the VW level without the user
|
|
5230
|
-
// having to manually joinGroup each split terminal.
|
|
5231
|
-
terminalMatrix.subscribe((ev) => {
|
|
5232
|
-
if (ev.type !== 'placement') return;
|
|
5233
|
-
const { instance, prev } = ev;
|
|
5234
|
-
if (prev.kind === 'vw') {
|
|
5235
|
-
terminalMatrix.leaveGroup(instance.id, `_vw:${prev.windowId}`);
|
|
5236
|
-
}
|
|
5237
|
-
if (instance.placement.kind === 'vw') {
|
|
5238
|
-
terminalMatrix.joinGroup(instance.id, `_vw:${instance.placement.windowId}`);
|
|
5239
|
-
}
|
|
5240
|
-
});
|
|
5241
|
-
virtualWindows.bus.subscribe({ types: ['window:close'] }, (ev) => {
|
|
5242
|
-
if (ev.type !== 'window:close') return;
|
|
5243
|
-
const ownerId = vwCompanionOwnerId(ev.windowId);
|
|
5244
|
-
const host = companionSurfaceHosts.get(ownerId);
|
|
5245
|
-
if (!host) return;
|
|
5246
|
-
suppressCompanionPopupDispose = true;
|
|
5247
|
-
try {
|
|
5248
|
-
host.disposeHandles();
|
|
5249
|
-
} finally {
|
|
5250
|
-
suppressCompanionPopupDispose = false;
|
|
5251
|
-
}
|
|
5252
|
-
for (const key of ['clipboard', 'memo', 'detail'] as const) {
|
|
5253
|
-
host.close(key);
|
|
5254
|
-
display.workspaceHostAPI().removeMember(ownerId, companionSurfaceId(ownerId, key));
|
|
5255
|
-
}
|
|
5256
|
-
});
|
|
5257
|
-
// TR-P3: pane-modal chord (Ctrl+M <key>) — pops a deferred pane
|
|
5258
|
-
// as a transient modal when the viewport is too narrow to show it
|
|
5259
|
-
// inline. Chord state lives with the dashboard; hint line rendered
|
|
5260
|
-
// by renderPaneModalHint in the frame loop.
|
|
5261
|
-
// FU-1 — pane-modal-chord 상태는 이제 coordinator 의 chordArmed
|
|
5262
|
-
// 필드가 소유. createPaneModalChord 인스턴스는 더 이상 필요 없음.
|
|
5263
|
-
|
|
5264
|
-
// Phase C/D — now that virtualWindows.registry exists, augment the
|
|
5265
|
-
// context.* + control.* deps so ContextWindowsList / WindowDetail /
|
|
5266
|
-
// PaneDetail + ControlWindowResize / ControlPaneLayout see live
|
|
5267
|
-
// windows. Safe to call again — set*RuntimeDeps replaces the
|
|
5268
|
-
// stored record wholesale.
|
|
4597
|
+
// Refresh context runtime deps after the dashboard session registry is ready.
|
|
5269
4598
|
try {
|
|
5270
|
-
const { setContextRuntimeDeps
|
|
5271
|
-
// Surface-unification v2.2 V2.2-5 (2026-05-11) — scheduler store
|
|
5272
|
-
// wire retired (scheduler view + `context.jobs.list` polychord
|
|
5273
|
-
// both gone). Workflows now own scheduled work end-to-end.
|
|
4599
|
+
const { setContextRuntimeDeps } = await import('../tool-runtime/index.js');
|
|
5274
4600
|
bootDashboardContextWindowRuntime({
|
|
5275
|
-
setControlRuntimeDeps,
|
|
5276
4601
|
setContextRuntimeDeps,
|
|
5277
|
-
registry: virtualWindows.registry,
|
|
5278
4602
|
// WD7 — context runtime cwd follows SWD.
|
|
5279
4603
|
cwd: getSessionCwd(),
|
|
5280
4604
|
getTerminalSessions: () => sessionRegistry.list().map((s) => ({
|
|
@@ -5463,7 +4787,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5463
4787
|
wireDashboardSurfaceRegistry({
|
|
5464
4788
|
surfaceRegistry,
|
|
5465
4789
|
widgetHost,
|
|
5466
|
-
windowRegistry: virtualWindows.registry,
|
|
5467
4790
|
});
|
|
5468
4791
|
} catch { /* never break boot */ }
|
|
5469
4792
|
|
|
@@ -5495,8 +4818,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5495
4818
|
try {
|
|
5496
4819
|
registerDashboardScenarioRuntimes({
|
|
5497
4820
|
scenarioCatalog,
|
|
5498
|
-
registry: virtualWindows.registry,
|
|
5499
|
-
createPaneContent,
|
|
5500
4821
|
spawnWidget: (spec) => widgetHost.spawn(spec),
|
|
5501
4822
|
disposeWidget: (id) => { widgetHost.dispose(id); },
|
|
5502
4823
|
getDashboardModals: () => dashboardModals,
|
|
@@ -5523,7 +4844,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5523
4844
|
const artifactStore = createArtifactStore({
|
|
5524
4845
|
legacyProviders: [
|
|
5525
4846
|
createLegacyTimelineProvider({ dir: defaultTimelineBaseDir() }),
|
|
5526
|
-
createLegacyLayoutProvider({ dir: layoutsDir() }),
|
|
5527
4847
|
],
|
|
5528
4848
|
});
|
|
5529
4849
|
try {
|
|
@@ -5960,19 +5280,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5960
5280
|
afterThemeActiveSaved: draw,
|
|
5961
5281
|
});
|
|
5962
5282
|
|
|
5963
|
-
// T6-K6 — wire the SpawnCodingAgentInVW tool. Registry is the
|
|
5964
|
-
// virtual-windows WindowRegistry shared across VW-P1..VW-P11.
|
|
5965
|
-
// paneDeps already flow into VW tool dispatchers via
|
|
5966
|
-
// initVirtualWindowTools so the terminal factory + spawn seam
|
|
5967
|
-
// use the same defaults.
|
|
5968
|
-
bootDashboardAgentSpawnTools({
|
|
5969
|
-
registry: virtualWindows.registry,
|
|
5970
|
-
initSpawnCodingAgentInVW,
|
|
5971
|
-
initSpawnEmbodiedAgentInVW,
|
|
5972
|
-
});
|
|
5973
|
-
// H5 P1 Step E — wire the Embodied Agent Bus spawner + register the
|
|
5974
|
-
// default codex-pty adapter into `defaultAdapterRegistry`. Legacy
|
|
5975
|
-
// `/acp-vw codex` flows through `dispatchSpawnCodingAgentInVW`.
|
|
5976
5283
|
// H5 P2 bootstrap — register the default channel router patterns
|
|
5977
5284
|
// + codex-pty adapter hook, then bind the TTY snapshot LLM tools
|
|
5978
5285
|
// to the live embodied-session registry. Without this wiring:
|
|
@@ -6127,15 +5434,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6127
5434
|
findLiveSessionById,
|
|
6128
5435
|
findLiveSessionByPaneId,
|
|
6129
5436
|
getFocusedConversationSessionId: () => conversationPopupHost.snapshot().focusedSessionId,
|
|
6130
|
-
getFocusedVirtualWindowPane: () => {
|
|
6131
|
-
const vw = virtualWindows?.registry.current();
|
|
6132
|
-
const pane = vw?.getFocusedPane();
|
|
6133
|
-
return {
|
|
6134
|
-
vwId: vw?.id ?? null,
|
|
6135
|
-
paneId: pane?.id ?? null,
|
|
6136
|
-
paneKind: pane?.kind ?? null,
|
|
6137
|
-
};
|
|
6138
|
-
},
|
|
5437
|
+
getFocusedVirtualWindowPane: () => ({ vwId: null, paneId: null, paneKind: null }),
|
|
6139
5438
|
noteUserSubmit: (sessionId, text) => globalAcpEventRouter().noteUserSubmit(sessionId, text),
|
|
6140
5439
|
clientSessionSend: (opts) => globalDualRoleManager().clientSessionSend(opts),
|
|
6141
5440
|
getWorkingFocus: () => workingDir.focus,
|
|
@@ -6200,25 +5499,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6200
5499
|
'../capture/capture-tools.js'
|
|
6201
5500
|
);
|
|
6202
5501
|
pfcScreenshotAttacherRef.current = createPfcScreenshotAttacher({
|
|
6203
|
-
|
|
6204
|
-
// `previewPaneRegistry` and `virtualWindows.registry`. For now
|
|
6205
|
-
// resolve via the registered VW runner label (most common case);
|
|
6206
|
-
// bg / inline shells return null and skip capture.
|
|
6207
|
-
resolveScreenshotTarget: (shellId) => {
|
|
6208
|
-
try {
|
|
6209
|
-
const reg = pfcGetShellRegistry();
|
|
6210
|
-
const label = reg.getVwLabel(shellId);
|
|
6211
|
-
if (!label) return null;
|
|
6212
|
-
const win = virtualWindows.registry.list().find(
|
|
6213
|
-
(w) => virtualWindows.registry.spawnTitleOf(w.id) === label,
|
|
6214
|
-
);
|
|
6215
|
-
if (!win) return null;
|
|
6216
|
-
return {
|
|
6217
|
-
surfaceId: `vw:${win.id}/${label}`,
|
|
6218
|
-
args: { windowId: String(win.id), runnerLabel: label },
|
|
6219
|
-
};
|
|
6220
|
-
} catch { return null; }
|
|
6221
|
-
},
|
|
5502
|
+
resolveScreenshotTarget: () => null,
|
|
6222
5503
|
dispatchScreenshot: async (args) => {
|
|
6223
5504
|
const out = await pfcDispatchScreenshot(args);
|
|
6224
5505
|
return {
|
|
@@ -6620,25 +5901,19 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6620
5901
|
// 페인트를 멈춰 하단 영역의 단일 소유자를 보장(codex mod.rs:1674 · CC
|
|
6621
5902
|
// REPL.tsx:4894 동형). 키는 기존 blocking-modal 라우팅 그대로 뷰가 소비.
|
|
6622
5903
|
const bottomSlotModalActive = (): boolean => topBlockingForegroundModal()?.slot === 'bottom';
|
|
6623
|
-
//
|
|
6624
|
-
// 중앙 플로팅 유지(/ui 왕복 즉시 반영 — 호출 시점 게이트 패턴).
|
|
5904
|
+
// Pickers occupy the composer bottom slot.
|
|
6625
5905
|
const resolveDecisionPickerPlacement = (desired: { height: number }): {
|
|
6626
5906
|
bounds: { row: number; col: number; width: number; height: number };
|
|
6627
5907
|
slot?: 'bottom';
|
|
6628
5908
|
width: number;
|
|
6629
5909
|
} => {
|
|
6630
5910
|
const { cols: tc, rows: tr } = termSize();
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
return { bounds, slot: 'bottom', width: bounds.width };
|
|
6638
|
-
}
|
|
6639
|
-
const width = Math.min(84, Math.max(48, tc - 6));
|
|
6640
|
-
const col = Math.max(2, Math.floor((tc - width) / 2));
|
|
6641
|
-
return { bounds: { row: 3, col, width, height: desired.height }, width };
|
|
5911
|
+
const bounds = resolveBottomSlotBounds({
|
|
5912
|
+
termCols: tc, termRows: tr,
|
|
5913
|
+
promptFrame: currentPromptFrame(tr),
|
|
5914
|
+
height: desired.height,
|
|
5915
|
+
});
|
|
5916
|
+
return { bounds, slot: 'bottom', width: bounds.width };
|
|
6642
5917
|
};
|
|
6643
5918
|
const topBottomAreaFreezeModal = (
|
|
6644
5919
|
termRows = termSize().rows,
|
|
@@ -6688,7 +5963,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6688
5963
|
}
|
|
6689
5964
|
return policy.suppressPromptArea || policy.suppressStatusArea;
|
|
6690
5965
|
};
|
|
6691
|
-
const vwCompanionOwnerId = (windowId: string | number): string => `virtual-window:${windowId}`;
|
|
6692
5966
|
const companionPopupSpec = (
|
|
6693
5967
|
key: CompanionPopupKey,
|
|
6694
5968
|
): {
|
|
@@ -6931,189 +6205,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6931
6205
|
syncCompanionPopups();
|
|
6932
6206
|
return next;
|
|
6933
6207
|
};
|
|
6934
|
-
const computeVirtualWindowCompanionBounds = (
|
|
6935
|
-
windowId: number,
|
|
6936
|
-
slotIndex = 0,
|
|
6937
|
-
totalCount = 1,
|
|
6938
|
-
) => {
|
|
6939
|
-
const bounds = virtualWindows.registry.get(windowId)?.getBounds();
|
|
6940
|
-
if (!bounds) return null;
|
|
6941
|
-
const innerCols = Math.max(24, bounds.width - 2);
|
|
6942
|
-
const innerRows = Math.max(10, bounds.height - 2);
|
|
6943
|
-
const local = computeCompanionPopupBounds({
|
|
6944
|
-
termCols: innerCols,
|
|
6945
|
-
termRows: innerRows,
|
|
6946
|
-
slotIndex,
|
|
6947
|
-
totalCount,
|
|
6948
|
-
hasBlockingForeground: false,
|
|
6949
|
-
});
|
|
6950
|
-
return {
|
|
6951
|
-
row: bounds.row + Math.max(0, local.row - 1),
|
|
6952
|
-
col: bounds.col + Math.max(0, local.col - 1),
|
|
6953
|
-
width: Math.min(local.width, innerCols),
|
|
6954
|
-
height: Math.min(local.height, innerRows),
|
|
6955
|
-
};
|
|
6956
|
-
};
|
|
6957
|
-
const syncVwCompanions = (windowId: number): void => {
|
|
6958
|
-
const ownerId = vwCompanionOwnerId(windowId);
|
|
6959
|
-
const host = companionSurfaceHosts.ensure(ownerId, ['clipboard', 'memo', 'detail']);
|
|
6960
|
-
const workspaceHost = display.workspaceHostAPI();
|
|
6961
|
-
suppressCompanionPopupDispose = true;
|
|
6962
|
-
try {
|
|
6963
|
-
host.disposeHandles();
|
|
6964
|
-
} finally {
|
|
6965
|
-
suppressCompanionPopupDispose = false;
|
|
6966
|
-
}
|
|
6967
|
-
const window = virtualWindows.registry.get(windowId);
|
|
6968
|
-
if (!window) {
|
|
6969
|
-
for (const key of ['clipboard', 'memo', 'detail'] as const) {
|
|
6970
|
-
workspaceHost.removeMember(ownerId, companionSurfaceId(ownerId, key));
|
|
6971
|
-
}
|
|
6972
|
-
return;
|
|
6973
|
-
}
|
|
6974
|
-
workspaceHost.setLayoutMode(ownerId, 'desktop');
|
|
6975
|
-
(['clipboard', 'memo', 'detail'] as const).forEach((key, index) => {
|
|
6976
|
-
const surfaceId = companionSurfaceId(ownerId, key);
|
|
6977
|
-
if (!host.isActive(key)) {
|
|
6978
|
-
workspaceHost.removeMember(ownerId, surfaceId);
|
|
6979
|
-
return;
|
|
6980
|
-
}
|
|
6981
|
-
workspaceHost.upsertMember(ownerId, {
|
|
6982
|
-
surfaceId,
|
|
6983
|
-
kind: 'popup',
|
|
6984
|
-
label: companionPopupSpec(key).title,
|
|
6985
|
-
order: 280 + index,
|
|
6986
|
-
});
|
|
6987
|
-
if (host.isDocked(key)) {
|
|
6988
|
-
workspaceHost.minimizeMember(ownerId, surfaceId, { docked: true });
|
|
6989
|
-
return;
|
|
6990
|
-
}
|
|
6991
|
-
workspaceHost.restoreMember(ownerId, surfaceId);
|
|
6992
|
-
const bounds = computeVirtualWindowCompanionBounds(windowId, index, 3);
|
|
6993
|
-
if (!bounds) return;
|
|
6994
|
-
const spec = companionPopupSpec(key);
|
|
6995
|
-
const columns = spec.columns.map((column) => ({ ...column }));
|
|
6996
|
-
if (key === 'clipboard' && columns[0]) {
|
|
6997
|
-
columns[0].onAfterKey = (action, ev) => {
|
|
6998
|
-
syncClipboardCursorFromWidget();
|
|
6999
|
-
if (action?.type === 'submit' || ev.name === 'enter' || ev.name === 'y' || ev.name === 'ㅛ') {
|
|
7000
|
-
void copyClipboardHistoryEntryAt(clipCursor).then(() => draw());
|
|
7001
|
-
return;
|
|
7002
|
-
}
|
|
7003
|
-
if (ev.name === 'c') {
|
|
7004
|
-
clipHistory.clear();
|
|
7005
|
-
clipCursor = 0;
|
|
7006
|
-
statusFeedbackRuntime.onClipboardHistoryCleared();
|
|
7007
|
-
draw();
|
|
7008
|
-
return;
|
|
7009
|
-
}
|
|
7010
|
-
if (ev.name === 'escape' || ev.name === 'l' || ev.name === 'right') {
|
|
7011
|
-
host.close('clipboard');
|
|
7012
|
-
syncVwCompanions(windowId);
|
|
7013
|
-
draw();
|
|
7014
|
-
}
|
|
7015
|
-
};
|
|
7016
|
-
}
|
|
7017
|
-
if (key === 'memo' && columns[0]) {
|
|
7018
|
-
columns[0].onAfterKey = (_action, ev) => {
|
|
7019
|
-
if (ev.name === 'escape') {
|
|
7020
|
-
closeVwMemoCompanion(windowId);
|
|
7021
|
-
syncVwCompanions(windowId);
|
|
7022
|
-
draw();
|
|
7023
|
-
return;
|
|
7024
|
-
}
|
|
7025
|
-
if ((ev as { ctrl?: boolean }).ctrl && (ev.name === 's' || ev.name === 'ㄴ')) {
|
|
7026
|
-
commitVwMemoCompanion(windowId);
|
|
7027
|
-
syncVwCompanions(windowId);
|
|
7028
|
-
draw();
|
|
7029
|
-
return;
|
|
7030
|
-
}
|
|
7031
|
-
if ((ev as { ctrl?: boolean }).ctrl && ev.name === 'a') {
|
|
7032
|
-
const memo = widgetHost.get('wd-memo') as any;
|
|
7033
|
-
if (memo?.state) memo.state.memoColIdx = 0;
|
|
7034
|
-
requestDashboardRender('memo');
|
|
7035
|
-
return;
|
|
7036
|
-
}
|
|
7037
|
-
if ((ev as { ctrl?: boolean }).ctrl && ev.name === 'e') {
|
|
7038
|
-
const memo = widgetHost.get('wd-memo') as any;
|
|
7039
|
-
if (memo?.state) {
|
|
7040
|
-
const lineIdx = memo.state.memoLineIdx ?? 0;
|
|
7041
|
-
const line = memo.state.memoLines?.[lineIdx] ?? '';
|
|
7042
|
-
memo.state.memoColIdx = line.length;
|
|
7043
|
-
}
|
|
7044
|
-
requestDashboardRender('memo');
|
|
7045
|
-
}
|
|
7046
|
-
};
|
|
7047
|
-
}
|
|
7048
|
-
const handle = showLivePaneMultiModal({
|
|
7049
|
-
id: surfaceId,
|
|
7050
|
-
title: spec.title,
|
|
7051
|
-
columns,
|
|
7052
|
-
widgetHost,
|
|
7053
|
-
coordinator: display,
|
|
7054
|
-
termCols: termSize().cols,
|
|
7055
|
-
termRows: termSize().rows,
|
|
7056
|
-
bounds,
|
|
7057
|
-
ttlMs: 0,
|
|
7058
|
-
group: surfaceId,
|
|
7059
|
-
interactionClass: 'embedded-overlay',
|
|
7060
|
-
windowRole: 'companion',
|
|
7061
|
-
chrome: resolveWindowScopedCompanionPopupChrome({
|
|
7062
|
-
theme: currentThemeTokens(),
|
|
7063
|
-
titleControls: spec.titleControls,
|
|
7064
|
-
bottomStatus: spec.status,
|
|
7065
|
-
windowId,
|
|
7066
|
-
}),
|
|
7067
|
-
onChromeAction: (action) => {
|
|
7068
|
-
if (action.controlId === 'minimize') {
|
|
7069
|
-
host.markDocked(key);
|
|
7070
|
-
workspaceHost.minimizeMember(ownerId, surfaceId, { docked: true });
|
|
7071
|
-
syncVwCompanions(windowId);
|
|
7072
|
-
draw();
|
|
7073
|
-
return;
|
|
7074
|
-
}
|
|
7075
|
-
if (action.controlId === 'close') {
|
|
7076
|
-
host.close(key);
|
|
7077
|
-
workspaceHost.removeMember(ownerId, surfaceId);
|
|
7078
|
-
syncVwCompanions(windowId);
|
|
7079
|
-
draw();
|
|
7080
|
-
}
|
|
7081
|
-
},
|
|
7082
|
-
onDispose: () => {
|
|
7083
|
-
if (suppressCompanionPopupDispose) return;
|
|
7084
|
-
if (host.isDocked(key)) {
|
|
7085
|
-
workspaceHost.minimizeMember(ownerId, surfaceId, { docked: true });
|
|
7086
|
-
draw();
|
|
7087
|
-
return;
|
|
7088
|
-
}
|
|
7089
|
-
host.close(key);
|
|
7090
|
-
workspaceHost.removeMember(ownerId, surfaceId);
|
|
7091
|
-
draw();
|
|
7092
|
-
},
|
|
7093
|
-
});
|
|
7094
|
-
host.setHandle(key, handle);
|
|
7095
|
-
});
|
|
7096
|
-
};
|
|
7097
|
-
const toggleVwCompanion = (
|
|
7098
|
-
windowId: number,
|
|
7099
|
-
key: 'clipboard' | 'memo' | 'detail',
|
|
7100
|
-
): boolean => {
|
|
7101
|
-
const host = companionSurfaceHosts.ensure(vwCompanionOwnerId(windowId), ['clipboard', 'memo', 'detail']);
|
|
7102
|
-
if (key === 'memo' && !host.isActive('memo')) seedMemoWidget(['']);
|
|
7103
|
-
const next = host.toggleOpen(key);
|
|
7104
|
-
syncVwCompanions(windowId);
|
|
7105
|
-
return next;
|
|
7106
|
-
};
|
|
7107
|
-
const setVwCompanionOpen = (
|
|
7108
|
-
windowId: number,
|
|
7109
|
-
key: 'clipboard' | 'memo' | 'detail',
|
|
7110
|
-
next: boolean,
|
|
7111
|
-
): void => {
|
|
7112
|
-
const host = companionSurfaceHosts.ensure(vwCompanionOwnerId(windowId), ['clipboard', 'memo', 'detail']);
|
|
7113
|
-
if (key === 'memo' && next && !host.isActive('memo')) seedMemoWidget(['']);
|
|
7114
|
-
host.setOpen(key, next);
|
|
7115
|
-
syncVwCompanions(windowId);
|
|
7116
|
-
};
|
|
7117
6208
|
const {
|
|
7118
6209
|
syncConversationPopupModals,
|
|
7119
6210
|
setConversationPopupLayoutMode,
|
|
@@ -7144,7 +6235,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7144
6235
|
createAgentSessionProvider,
|
|
7145
6236
|
createBrowserCdpProvider,
|
|
7146
6237
|
registerProvider: (registry, provider) => { registry.registerProvider(provider); },
|
|
7147
|
-
getWindows: () =>
|
|
6238
|
+
getWindows: () => [],
|
|
7148
6239
|
listSessions: () => listLiveEmbodiedSessions(),
|
|
7149
6240
|
// H6 P5 observer-registry landed · threading through enables
|
|
7150
6241
|
// the channel-aware snapshot path (falls back to raw snapshot
|
|
@@ -7167,7 +6258,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7167
6258
|
|
|
7168
6259
|
// ACP follow-up #1 — auto-persist on turn-end. DRM end_turn
|
|
7169
6260
|
// transitions + BG terminal states flow into the H2 #5 persistence
|
|
7170
|
-
// primitive automatically
|
|
6261
|
+
// primitive automatically (always on — off-switch graduated 2026-09-26).
|
|
7171
6262
|
wireAutoPersist({
|
|
7172
6263
|
drm: globalDualRoleManager(),
|
|
7173
6264
|
bg: globalBackgroundManager(),
|
|
@@ -7178,17 +6269,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7178
6269
|
// the in-memory BackgroundManager bounded for long-running elanous
|
|
7179
6270
|
// processes. Auto-persist (#1) already flushed the terminal record
|
|
7180
6271
|
// to disk, so sweeping doesn't lose history · only the live stub.
|
|
7181
|
-
//
|
|
6272
|
+
// Always on (ELANOUS_ACP_BG_SWEEP_MODE off-switch graduated 2026-09-26). Defaults: 24h TTL ·
|
|
7182
6273
|
// 1h tick (matches Warp cloud-agent "stale after a day" heuristic).
|
|
7183
6274
|
bootDashboardAcpBgSweep({
|
|
7184
|
-
enabled:
|
|
6275
|
+
enabled: true,
|
|
7185
6276
|
backgroundManager: globalBackgroundManager(),
|
|
7186
6277
|
});
|
|
7187
6278
|
|
|
7188
|
-
// Phase 3a wiring — register SaveLayout/LoadLayout/ApplyLayoutPreset
|
|
7189
|
-
// LLM tools against the shared WindowRegistry. Plan-only today; actual
|
|
7190
|
-
// restore-to-live-VW lands in a follow-up commit.
|
|
7191
|
-
|
|
7192
6279
|
// T6-K5 — wire widget + pane control tools. Widgets are reported
|
|
7193
6280
|
// from widgetHost; pane focus piggybacks on workingDir.focus. The
|
|
7194
6281
|
// pane name list mirrors the PaneFocus type so the LLM sees valid
|
|
@@ -7268,32 +6355,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7268
6355
|
openSurfaceCatalogPopup();
|
|
7269
6356
|
return true;
|
|
7270
6357
|
},
|
|
7271
|
-
openSurfaceInVw: (
|
|
7272
|
-
if (surface === 'scratch') {
|
|
7273
|
-
spawnScratchVirtualWindow();
|
|
7274
|
-
return true;
|
|
7275
|
-
}
|
|
7276
|
-
if (surface === 'browser') {
|
|
7277
|
-
spawnBrowserVirtualWindow();
|
|
7278
|
-
return true;
|
|
7279
|
-
}
|
|
7280
|
-
if (surface === 'preview') {
|
|
7281
|
-
spawnPreviewVirtualWindow();
|
|
7282
|
-
return true;
|
|
7283
|
-
}
|
|
7284
|
-
if (surface === 'browser-preview') {
|
|
7285
|
-
spawnBrowserPreviewVirtualWindow();
|
|
7286
|
-
return true;
|
|
7287
|
-
}
|
|
7288
|
-
return false;
|
|
7289
|
-
},
|
|
6358
|
+
openSurfaceInVw: () => false,
|
|
7290
6359
|
openCompanionSurface: (surface, target) => {
|
|
7291
|
-
if (target === 'vw')
|
|
7292
|
-
const windowId = virtualWindows.registry.current()?.id ?? null;
|
|
7293
|
-
if (!Number.isInteger(windowId)) return false;
|
|
7294
|
-
setVwCompanionOpen(windowId as number, surface, true);
|
|
7295
|
-
return true;
|
|
7296
|
-
}
|
|
6360
|
+
if (target === 'vw') return false;
|
|
7297
6361
|
setCompanionPopupOpen(surface, true);
|
|
7298
6362
|
return true;
|
|
7299
6363
|
},
|
|
@@ -8096,131 +7160,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
8096
7160
|
const activeBrowserState = (): BrowserPaneModel => (
|
|
8097
7161
|
resolveBrowserStateById(activeBrowserWidgetId()) ?? (workingDir as BrowserPaneModel)
|
|
8098
7162
|
);
|
|
8099
|
-
let vwPaneMountSeq = 0;
|
|
8100
|
-
const nextVwBrowserPaneId = (): string => `vw-browser:${++vwPaneMountSeq}`;
|
|
8101
|
-
const nextVwPreviewPaneId = (): string => `vw-preview:${++vwPaneMountSeq}`;
|
|
8102
|
-
const cloneActiveBrowserIntoVw = (): { browserId: string; state: BrowserPaneModel } => {
|
|
8103
|
-
const browserId = nextVwBrowserPaneId();
|
|
8104
|
-
const state = browserPaneRegistry.cloneInto(activeBrowserWidgetId(), browserId);
|
|
8105
|
-
return { browserId, state };
|
|
8106
|
-
};
|
|
8107
|
-
const cloneDockedPreviewIntoVw = (): { previewId: string } => {
|
|
8108
|
-
const previewId = nextVwPreviewPaneId();
|
|
8109
|
-
previewPaneRegistry.cloneInto('wd-preview', previewId);
|
|
8110
|
-
return { previewId };
|
|
8111
|
-
};
|
|
8112
|
-
const nextTerminalVwSlotId = (terminalId: string): string => `term-slot:${terminalId}`;
|
|
8113
|
-
const spawnScratchVirtualWindow = (title?: string): number => {
|
|
8114
|
-
const reg = virtualWindows.registry;
|
|
8115
|
-
const nextTitle = title?.trim() || `window ${reg.list().length + 1}`;
|
|
8116
|
-
const w = reg.spawn({
|
|
8117
|
-
title: nextTitle,
|
|
8118
|
-
initialContent: { kind: 'scratch', title: nextTitle },
|
|
8119
|
-
});
|
|
8120
|
-
return w.id;
|
|
8121
|
-
};
|
|
8122
|
-
const spawnBrowserVirtualWindow = (title?: string): number => {
|
|
8123
|
-
const reg = virtualWindows.registry;
|
|
8124
|
-
const nextTitle = title?.trim() || `browser ${reg.list().length + 1}`;
|
|
8125
|
-
const { browserId } = cloneActiveBrowserIntoVw();
|
|
8126
|
-
const w = reg.spawn({
|
|
8127
|
-
title: nextTitle,
|
|
8128
|
-
initialContent: { kind: 'vw-browser', browserId, title: 'browser' } as any,
|
|
8129
|
-
});
|
|
8130
|
-
return w.id;
|
|
8131
|
-
};
|
|
8132
|
-
const spawnPreviewVirtualWindow = (title?: string): number => {
|
|
8133
|
-
const reg = virtualWindows.registry;
|
|
8134
|
-
const nextTitle = title?.trim() || `preview ${reg.list().length + 1}`;
|
|
8135
|
-
const { previewId } = cloneDockedPreviewIntoVw();
|
|
8136
|
-
const w = reg.spawn({
|
|
8137
|
-
title: nextTitle,
|
|
8138
|
-
initialContent: { kind: 'vw-preview', previewId, title: 'preview' } as any,
|
|
8139
|
-
});
|
|
8140
|
-
return w.id;
|
|
8141
|
-
};
|
|
8142
|
-
const spawnBrowserPreviewVirtualWindow = (title?: string): number => {
|
|
8143
|
-
const reg = virtualWindows.registry;
|
|
8144
|
-
const nextTitle = title?.trim() || `browser+preview ${reg.list().length + 1}`;
|
|
8145
|
-
const { browserId } = cloneActiveBrowserIntoVw();
|
|
8146
|
-
const { previewId } = cloneDockedPreviewIntoVw();
|
|
8147
|
-
const w = reg.spawn({
|
|
8148
|
-
title: nextTitle,
|
|
8149
|
-
initialContent: { kind: 'vw-browser', browserId, title: 'browser' } as any,
|
|
8150
|
-
});
|
|
8151
|
-
const previewContent = createPaneContent({
|
|
8152
|
-
kind: 'vw-preview',
|
|
8153
|
-
previewId,
|
|
8154
|
-
title: 'preview',
|
|
8155
|
-
} as any, {
|
|
8156
|
-
browserPaneRegistry,
|
|
8157
|
-
previewPaneRegistry,
|
|
8158
|
-
refreshRemoteBrowserPane: async (state: BrowserPaneModel) => {
|
|
8159
|
-
await refreshRemoteWorkingDir(
|
|
8160
|
-
state as WorkingDirState,
|
|
8161
|
-
{},
|
|
8162
|
-
{ previewPath: null, previewLines: [], previewOffset: 0 },
|
|
8163
|
-
);
|
|
8164
|
-
},
|
|
8165
|
-
});
|
|
8166
|
-
w.splitFocused('h', previewContent);
|
|
8167
|
-
return w.id;
|
|
8168
|
-
};
|
|
8169
|
-
const spawnIulVirtualWindow = (title?: string): number => {
|
|
8170
|
-
const reg = virtualWindows.registry;
|
|
8171
|
-
const trimmed = title?.trim() ?? '';
|
|
8172
|
-
if (!trimmed && isIulResidentEnabled(getUserConfig().vw)) {
|
|
8173
|
-
return focusOrSpawnIulResidentWindow(reg);
|
|
8174
|
-
}
|
|
8175
|
-
const nextTitle = trimmed || `IUL UX Lab ${reg.list().length + 1}`;
|
|
8176
|
-
const w = reg.spawn({
|
|
8177
|
-
title: nextTitle,
|
|
8178
|
-
initialContent: { kind: 'iul-shell', title: nextTitle } as any,
|
|
8179
|
-
});
|
|
8180
|
-
return w.id;
|
|
8181
|
-
};
|
|
8182
|
-
const spawnAcpVirtualWindow = (title?: string): number => {
|
|
8183
|
-
const reg = virtualWindows.registry;
|
|
8184
|
-
const trimmed = title?.trim() ?? '';
|
|
8185
|
-
// PLAN-tui-redundancy-cleanup T1 (2026-05-16) — resident-vw 의
|
|
8186
|
-
// focusOrSpawnAcpResidentWindow + isAcpResidentEnabled 의존 제거.
|
|
8187
|
-
// 사용자 slash command 통한 manual spawn 만 유지.
|
|
8188
|
-
const nextTitle = trimmed || `ACP channels ${reg.list().length + 1}`;
|
|
8189
|
-
const w = reg.spawn({
|
|
8190
|
-
title: nextTitle,
|
|
8191
|
-
initialContent: { kind: 'acp-shell', title: 'ACP Channels' } as any,
|
|
8192
|
-
});
|
|
8193
|
-
return w.id;
|
|
8194
|
-
};
|
|
8195
|
-
const spawnSimVirtualWindow = (title?: string): number => {
|
|
8196
|
-
const reg = virtualWindows.registry;
|
|
8197
|
-
const trimmed = title?.trim() ?? '';
|
|
8198
|
-
if (!trimmed && isSimResidentEnabled(getUserConfig().vw)) {
|
|
8199
|
-
return focusOrSpawnSimResidentWindow(reg);
|
|
8200
|
-
}
|
|
8201
|
-
const nextTitle = trimmed || `Simulator ${reg.list().length + 1}`;
|
|
8202
|
-
const w = reg.spawn({
|
|
8203
|
-
title: nextTitle,
|
|
8204
|
-
initialContent: { kind: 'sim-shell', title: 'Test Simulator' } as any,
|
|
8205
|
-
});
|
|
8206
|
-
return w.id;
|
|
8207
|
-
};
|
|
8208
|
-
for (const residentKind of getUserConfig().vw.order) {
|
|
8209
|
-
if (residentKind === 'iul' && isIulResidentEnabled(getUserConfig().vw)) {
|
|
8210
|
-
bootIulResidentWindow(virtualWindows.registry, {
|
|
8211
|
-
foreground: isIulForegroundStartupEnabled(getUserConfig().vw),
|
|
8212
|
-
});
|
|
8213
|
-
continue;
|
|
8214
|
-
}
|
|
8215
|
-
// PLAN-tui-redundancy-cleanup T1 (2026-05-16) — ACP resident window
|
|
8216
|
-
// boot auto-mount 제거. `vw.order` 에 'acp' 가 남아 있어도 noop ·
|
|
8217
|
-
// 사용자 manual slash command (/acp-vw) 통한 spawn 만 유지.
|
|
8218
|
-
if (residentKind === 'acp') continue;
|
|
8219
|
-
if (residentKind === 'sim' && isSimResidentEnabled(getUserConfig().vw)) {
|
|
8220
|
-
bootSimResidentWindow(virtualWindows.registry);
|
|
8221
|
-
}
|
|
8222
|
-
}
|
|
8223
|
-
|
|
8224
7163
|
// T7-N1 — ACP chat bridge. Speaks JSON-RPC to claude-code-acp /
|
|
8225
7164
|
// codex-acp / gemini via the real client in src/acp/*. Subprocess
|
|
8226
7165
|
// spawn is lazy — no cost until the user runs /acp.
|
|
@@ -8255,7 +7194,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
8255
7194
|
// Scratch visibility (Phase S5). When closed, the workingDir
|
|
8256
7195
|
// layouts drop the scratch cell so the remaining panes expand
|
|
8257
7196
|
// to fill the reclaimed columns — useful on narrow terminals.
|
|
8258
|
-
// Reopen via the
|
|
7197
|
+
// Reopen via the ^B ^S chord.
|
|
8259
7198
|
let scratchClosed = false;
|
|
8260
7199
|
const dashboardViewRegistryOptions = () => ({
|
|
8261
7200
|
extraPanes: pluginHost.activeDashboardPanes().map(p => p.paneId),
|
|
@@ -8322,7 +7261,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
8322
7261
|
// chrome rows (input/status/dock), but that does not mean the
|
|
8323
7262
|
// main workspace's chat composer remains an active input owner.
|
|
8324
7263
|
const chatMainAvailable = foregroundWorkspace === null;
|
|
8325
|
-
const vwLocalComposerActive =
|
|
7264
|
+
const vwLocalComposerActive = false;
|
|
8326
7265
|
const overlayInputActive = hasOverlayInputOwner({
|
|
8327
7266
|
focusStack: display.modalStack(),
|
|
8328
7267
|
surfaceAt: (id) => display.surface(id),
|
|
@@ -9579,13 +8518,11 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
9579
8518
|
agentStatusStore.clear(ev.instance.id);
|
|
9580
8519
|
claudeStatusParser.reset(ev.instance.id);
|
|
9581
8520
|
codexStatusParser.reset(ev.instance.id);
|
|
9582
|
-
closeVwPaneForExit(ev.instance.placement, 'exited');
|
|
9583
8521
|
} else if (ev.type === 'killed') {
|
|
9584
8522
|
notificationStore.push(exitToNotification(ev.instance.id, null));
|
|
9585
8523
|
agentStatusStore.clear(ev.instance.id);
|
|
9586
8524
|
claudeStatusParser.reset(ev.instance.id);
|
|
9587
8525
|
codexStatusParser.reset(ev.instance.id);
|
|
9588
|
-
closeVwPaneForExit(ev.instance.placement, 'killed');
|
|
9589
8526
|
} else if (ev.type === 'attention') {
|
|
9590
8527
|
notificationStore.push(attentionToNotification(ev.instance.id, ev.level));
|
|
9591
8528
|
}
|
|
@@ -9620,27 +8557,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
9620
8557
|
try { debug.log('agent-status.mirror.activate-failed', String(err), { level: 'error' }); } catch { /* swallow */ }
|
|
9621
8558
|
}
|
|
9622
8559
|
})();
|
|
9623
|
-
// PLAN-chat-hud-multi-surface-port-2026-05-13 §4 M3 — TUI HUD strip
|
|
9624
|
-
// mirrors to daemon's HudStore via `POST /v1/hud-segment` so PWA
|
|
9625
|
-
// `<ChatHud>` (M4) hydrates from dashboard-only writers (token gauge
|
|
9626
|
-
// · ssh-remote · agent-activity · reasoning level · variant badge).
|
|
9627
|
-
// Same probe-once + fire-and-forget contract as agent-status mirror.
|
|
9628
|
-
void (async () => {
|
|
9629
|
-
try {
|
|
9630
|
-
const { activateHudMirrorIfReachable } = await import('./hud-mirror.js');
|
|
9631
|
-
const handle = await activateHudMirrorIfReachable({
|
|
9632
|
-
hud,
|
|
9633
|
-
log: (m) => { try { debug.log('hud.mirror', m); } catch { /* swallow */ } },
|
|
9634
|
-
});
|
|
9635
|
-
if (handle.active) {
|
|
9636
|
-
process.once('beforeExit', () => {
|
|
9637
|
-
try { handle.deactivate(); } catch { /* ignore */ }
|
|
9638
|
-
});
|
|
9639
|
-
}
|
|
9640
|
-
} catch (err) {
|
|
9641
|
-
try { debug.log('hud.mirror.activate-failed', String(err), { level: 'error' }); } catch { /* swallow */ }
|
|
9642
|
-
}
|
|
9643
|
-
})();
|
|
9644
8560
|
const disposeConversationWidgetLiveBridge = createConversationWidgetLiveBridge({
|
|
9645
8561
|
widgetHost,
|
|
9646
8562
|
listSessions: () => listLiveEmbodiedSessions().map((entry) => ({
|
|
@@ -10888,24 +9804,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
10888
9804
|
});
|
|
10889
9805
|
}
|
|
10890
9806
|
}
|
|
10891
|
-
const scratch = widgetHost.get('wd-scratch') as any;
|
|
10892
|
-
if (scratch) {
|
|
10893
|
-
const displayScratch = display.scratchState();
|
|
10894
|
-
const focused = workingDir.focus === 'scratch';
|
|
10895
|
-
// Arc Z — push dashboard source-of-truth state into the scratch
|
|
10896
|
-
// widget. Native scratch modes (memo / preview) hand their
|
|
10897
|
-
// structured state over.
|
|
10898
|
-
// Surface-unification v2.2 V2.2-5 Part 2 (2026-05-11) — view=4
|
|
10899
|
-
// scheduler scratch projection retired (scheduler view 폐기).
|
|
10900
|
-
scratchWidgetRuntime.projectPreview(
|
|
10901
|
-
scratch,
|
|
10902
|
-
focused,
|
|
10903
|
-
scratchOffset,
|
|
10904
|
-
scratchTitle,
|
|
10905
|
-
scratchLines,
|
|
10906
|
-
displayScratch && displayScratch.mode !== 'agents' ? displayScratch : null,
|
|
10907
|
-
);
|
|
10908
|
-
}
|
|
10909
9807
|
const clipboardWidget = widgetHost.get('wd-clipboard') as any;
|
|
10910
9808
|
companionWidgetRuntime.projectClipboardWidget(
|
|
10911
9809
|
clipboardWidget,
|
|
@@ -11726,18 +10624,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11726
10624
|
getScratchTotalBytes: () => scratchLines.reduce((n, l) => n + l.length, 0),
|
|
11727
10625
|
isCompanionOpen: (key) => companionPopupHost.isActive(key as CompanionPopupKey),
|
|
11728
10626
|
hasClosedPanes: () => paneStateSnapshot().panes.some((pane) => pane.closed),
|
|
11729
|
-
resolveVirtualWindowPaneKind: ({ windowId, paneId }) => {
|
|
11730
|
-
const id = Number.parseInt(windowId, 10);
|
|
11731
|
-
if (!Number.isFinite(id)) return null;
|
|
11732
|
-
return virtualWindows.registry.get(id)?.getPane(paneId)?.kind ?? null;
|
|
11733
|
-
},
|
|
11734
|
-
isVirtualWindowCompanionOpen: ({ windowId }, key) => {
|
|
11735
|
-
const id = Number.parseInt(windowId, 10);
|
|
11736
|
-
if (!Number.isFinite(id)) return false;
|
|
11737
|
-
return companionSurfaceHosts
|
|
11738
|
-
.ensure(vwCompanionOwnerId(id), ['clipboard', 'memo', 'detail'])
|
|
11739
|
-
.isActive(key as 'clipboard' | 'memo' | 'detail');
|
|
11740
|
-
},
|
|
11741
10627
|
getDebugPath: () => debug.path(),
|
|
11742
10628
|
getDebugLevel: () => debug.level(),
|
|
11743
10629
|
});
|
|
@@ -11915,103 +10801,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11915
10801
|
});
|
|
11916
10802
|
return;
|
|
11917
10803
|
}
|
|
11918
|
-
case 'vw.selector': {
|
|
11919
|
-
const payload = result.payload as VirtualWindowTitleMenuPayload | undefined;
|
|
11920
|
-
if (!payload) return;
|
|
11921
|
-
const windowId = Number.parseInt(payload.windowId, 10);
|
|
11922
|
-
if (!Number.isFinite(windowId)) return;
|
|
11923
|
-
openVwSelectorPopup(windowId, _ev.col, _ev.row);
|
|
11924
|
-
return;
|
|
11925
|
-
}
|
|
11926
|
-
case 'vw.clipboard-companion': {
|
|
11927
|
-
const payload = result.payload as VirtualWindowTitleMenuPayload | undefined;
|
|
11928
|
-
if (!payload) return;
|
|
11929
|
-
const windowId = Number.parseInt(payload.windowId, 10);
|
|
11930
|
-
if (!Number.isFinite(windowId)) return;
|
|
11931
|
-
const opened = toggleVwCompanion(windowId, 'clipboard');
|
|
11932
|
-
contextMenuFeedbackRuntime.onVwCompanionToggled(windowId, 'clipboard', opened);
|
|
11933
|
-
return;
|
|
11934
|
-
}
|
|
11935
|
-
case 'vw.memo-companion': {
|
|
11936
|
-
const payload = result.payload as VirtualWindowTitleMenuPayload | undefined;
|
|
11937
|
-
if (!payload) return;
|
|
11938
|
-
const windowId = Number.parseInt(payload.windowId, 10);
|
|
11939
|
-
if (!Number.isFinite(windowId)) return;
|
|
11940
|
-
const opened = toggleVwCompanion(windowId, 'memo');
|
|
11941
|
-
contextMenuFeedbackRuntime.onVwCompanionToggled(windowId, 'memo', opened);
|
|
11942
|
-
return;
|
|
11943
|
-
}
|
|
11944
|
-
case 'vw.detail-companion': {
|
|
11945
|
-
const payload = result.payload as VirtualWindowTitleMenuPayload | undefined;
|
|
11946
|
-
if (!payload) return;
|
|
11947
|
-
const windowId = Number.parseInt(payload.windowId, 10);
|
|
11948
|
-
if (!Number.isFinite(windowId)) return;
|
|
11949
|
-
const opened = toggleVwCompanion(windowId, 'detail');
|
|
11950
|
-
contextMenuFeedbackRuntime.onVwCompanionToggled(windowId, 'detail', opened);
|
|
11951
|
-
return;
|
|
11952
|
-
}
|
|
11953
|
-
case 'vw.return-popup': {
|
|
11954
|
-
const payload = result.payload as VirtualWindowTitleMenuPayload | undefined;
|
|
11955
|
-
if (!payload) return;
|
|
11956
|
-
const windowId = Number.parseInt(payload.windowId, 10);
|
|
11957
|
-
if (!Number.isFinite(windowId)) return;
|
|
11958
|
-
const window = virtualWindows.registry.get(windowId);
|
|
11959
|
-
const pane = window?.getPane(payload.paneId);
|
|
11960
|
-
if (!window || !pane) return;
|
|
11961
|
-
if (pane.kind === 'terminal-slot') {
|
|
11962
|
-
const inst = resolveVwTerminalInstanceForPane(
|
|
11963
|
-
terminalMatrix.list({ includeExited: true }),
|
|
11964
|
-
vwSlotBindings,
|
|
11965
|
-
payload.windowId,
|
|
11966
|
-
payload.paneId,
|
|
11967
|
-
);
|
|
11968
|
-
if (!inst) return;
|
|
11969
|
-
terminalMatrix.move(inst.id, { kind: 'modal', modalId: inst.id });
|
|
11970
|
-
if (inst.legacySessionId) {
|
|
11971
|
-
const session = sessionRegistry.get(inst.legacySessionId);
|
|
11972
|
-
if (session?.modal) {
|
|
11973
|
-
terminalModalRouter.set(session.modal, {
|
|
11974
|
-
onClose: () => { sessionRegistry.detach(session.id); draw(); },
|
|
11975
|
-
});
|
|
11976
|
-
}
|
|
11977
|
-
}
|
|
11978
|
-
draw();
|
|
11979
|
-
return;
|
|
11980
|
-
}
|
|
11981
|
-
if (pane.kind === 'vw-browser') {
|
|
11982
|
-
openBrowserOnlyModal();
|
|
11983
|
-
} else if (pane.kind === 'vw-preview') {
|
|
11984
|
-
openPreviewOnlyModal();
|
|
11985
|
-
} else if (pane.kind === 'scratch') {
|
|
11986
|
-
openDashboardPaneModal('scratch');
|
|
11987
|
-
} else {
|
|
11988
|
-
return;
|
|
11989
|
-
}
|
|
11990
|
-
try { window.closePaneAt(payload.paneId); } catch { /* already gone */ }
|
|
11991
|
-
return;
|
|
11992
|
-
}
|
|
11993
10804
|
case 'dashboard-pane.open-popup': {
|
|
11994
10805
|
const payload = result.payload as DashboardPaneTitleMenuPayload | undefined;
|
|
11995
10806
|
if (!payload) return;
|
|
11996
10807
|
openDashboardPaneModal(payload.pane);
|
|
11997
10808
|
return;
|
|
11998
10809
|
}
|
|
11999
|
-
case 'dashboard-pane.open-vw': {
|
|
12000
|
-
const payload = result.payload as DashboardPaneTitleMenuPayload | undefined;
|
|
12001
|
-
if (!payload) return;
|
|
12002
|
-
if (payload.pane === 'browser') {
|
|
12003
|
-
spawnBrowserVirtualWindow();
|
|
12004
|
-
return;
|
|
12005
|
-
}
|
|
12006
|
-
if (payload.pane === 'preview') {
|
|
12007
|
-
spawnPreviewVirtualWindow();
|
|
12008
|
-
return;
|
|
12009
|
-
}
|
|
12010
|
-
if (payload.pane === 'scratch') {
|
|
12011
|
-
spawnScratchVirtualWindow();
|
|
12012
|
-
}
|
|
12013
|
-
return;
|
|
12014
|
-
}
|
|
12015
10810
|
case 'dashboard-pane.clipboard-companion': {
|
|
12016
10811
|
const opened = toggleCompanionPopup('clipboard');
|
|
12017
10812
|
contextMenuFeedbackRuntime.onDashboardCompanionToggled('clipboard', opened);
|
|
@@ -12071,13 +10866,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12071
10866
|
openBrowserPreviewModal: () => openBrowserPreviewModal(),
|
|
12072
10867
|
openDashboardPaneModal: (pane) => openDashboardPaneModal(pane),
|
|
12073
10868
|
openCompanionPopup: (key) => setCompanionPopupOpen(key as DashboardCompanionSurfaceKey, true),
|
|
12074
|
-
spawnBrowserVirtualWindow: () => spawnBrowserVirtualWindow(),
|
|
12075
|
-
spawnPreviewVirtualWindow: () => spawnPreviewVirtualWindow(),
|
|
12076
|
-
spawnBrowserPreviewVirtualWindow: () => spawnBrowserPreviewVirtualWindow(),
|
|
12077
|
-
spawnScratchVirtualWindow: () => spawnScratchVirtualWindow(),
|
|
12078
|
-
spawnSimVirtualWindow: () => spawnSimVirtualWindow(),
|
|
12079
|
-
currentVirtualWindowId: () => virtualWindows.registry.current()?.id ?? null,
|
|
12080
|
-
openVwCompanion: (windowId, key) => setVwCompanionOpen(windowId, key as DashboardCompanionSurfaceKey, true),
|
|
12081
10869
|
onWarning: (message) => {
|
|
12082
10870
|
pushDebugLine(C.warning(` ${message}`));
|
|
12083
10871
|
chatScrollOffset = -1;
|
|
@@ -12131,20 +10919,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12131
10919
|
pushChatLine: (line) => { chatLines.push(line); },
|
|
12132
10920
|
setChatScrollBottom: () => { chatScrollOffset = -1; },
|
|
12133
10921
|
});
|
|
12134
|
-
const windowSlashRuntime = createDashboardWindowSlashRuntime({
|
|
12135
|
-
accent: C.accent,
|
|
12136
|
-
muted: C.muted,
|
|
12137
|
-
success: C.success,
|
|
12138
|
-
error: C.error,
|
|
12139
|
-
warning: C.warning,
|
|
12140
|
-
});
|
|
12141
|
-
const benchSlashRuntime = createDashboardBenchSlashRuntime({
|
|
12142
|
-
accent: C.accent,
|
|
12143
|
-
muted: C.muted,
|
|
12144
|
-
warning: C.warning,
|
|
12145
|
-
error: C.error,
|
|
12146
|
-
maxPanes: MAX_BENCHMARK_PANES,
|
|
12147
|
-
});
|
|
12148
10922
|
const termSlashRuntime = createDashboardTermSlashRuntime({
|
|
12149
10923
|
accent: C.accent,
|
|
12150
10924
|
muted: C.muted,
|
|
@@ -12182,36 +10956,27 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12182
10956
|
muted: C.muted,
|
|
12183
10957
|
warning: C.warning,
|
|
12184
10958
|
});
|
|
12185
|
-
const
|
|
10959
|
+
const companionSlashRuntime = createDashboardCompanionSlashRuntime({
|
|
12186
10960
|
muted: C.muted,
|
|
12187
10961
|
warning: C.warning,
|
|
12188
10962
|
});
|
|
12189
|
-
const
|
|
10963
|
+
const agentsSlashRuntime = createDashboardAgentsSlashRuntime({
|
|
12190
10964
|
muted: C.muted,
|
|
12191
10965
|
warning: C.warning,
|
|
12192
10966
|
});
|
|
12193
|
-
const
|
|
10967
|
+
const controlSignalSlashRuntime = createDashboardControlSignalSlashRuntime({
|
|
10968
|
+
accent: C.accent,
|
|
12194
10969
|
muted: C.muted,
|
|
12195
10970
|
warning: C.warning,
|
|
10971
|
+
observer: defaultControlSignalObserver(),
|
|
10972
|
+
signalBus: dashboardControlSignals,
|
|
12196
10973
|
});
|
|
12197
|
-
const
|
|
10974
|
+
const browserCdpSlashRuntime = createDashboardBrowserCdpSlashRuntime({
|
|
10975
|
+
accent: C.accent,
|
|
12198
10976
|
muted: C.muted,
|
|
12199
|
-
success: C.success,
|
|
12200
10977
|
warning: C.warning,
|
|
10978
|
+
signalBus: dashboardControlSignals,
|
|
12201
10979
|
});
|
|
12202
|
-
const controlSignalSlashRuntime = createDashboardControlSignalSlashRuntime({
|
|
12203
|
-
accent: C.accent,
|
|
12204
|
-
muted: C.muted,
|
|
12205
|
-
warning: C.warning,
|
|
12206
|
-
observer: defaultControlSignalObserver(),
|
|
12207
|
-
signalBus: dashboardControlSignals,
|
|
12208
|
-
});
|
|
12209
|
-
const browserCdpSlashRuntime = createDashboardBrowserCdpSlashRuntime({
|
|
12210
|
-
accent: C.accent,
|
|
12211
|
-
muted: C.muted,
|
|
12212
|
-
warning: C.warning,
|
|
12213
|
-
signalBus: dashboardControlSignals,
|
|
12214
|
-
});
|
|
12215
10980
|
const simSlashRuntime = createDashboardSimSlashRuntime({
|
|
12216
10981
|
accent: C.accent,
|
|
12217
10982
|
muted: C.muted,
|
|
@@ -12252,27 +11017,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12252
11017
|
muted: C.muted,
|
|
12253
11018
|
warning: C.warning,
|
|
12254
11019
|
});
|
|
12255
|
-
const mouseDockRuntime = createMouseDockRuntime({
|
|
12256
|
-
listDockWindowPanes: () =>
|
|
12257
|
-
panesForDashboardView(activeViewDef()).filter((pane) => pane !== 'input'),
|
|
12258
|
-
paneLabel,
|
|
12259
|
-
openDockWindow: (pane) => openDashboardPaneModal(pane),
|
|
12260
|
-
compactSurfaceHost,
|
|
12261
|
-
listVirtualWindows: () =>
|
|
12262
|
-
virtualWindows.registry.list().map((window) => ({
|
|
12263
|
-
id: window.id,
|
|
12264
|
-
title: window.title,
|
|
12265
|
-
})),
|
|
12266
|
-
getCurrentVirtualWindowId: () => virtualWindows.registry.current()?.id ?? null,
|
|
12267
|
-
switchToVirtualWindow: (windowId) => {
|
|
12268
|
-
virtualWindows.registry.switchTo(windowId);
|
|
12269
|
-
},
|
|
12270
|
-
focusDashboardMain: () => {
|
|
12271
|
-
virtualWindows.registry.backgroundCurrent();
|
|
12272
|
-
setWorkingFocus(firstPaneOfView(workingDir.view), 'dock-vw-mover-main');
|
|
12273
|
-
},
|
|
12274
|
-
redraw: () => { draw(); },
|
|
12275
|
-
});
|
|
12276
11020
|
const mousePickerRuntime = createMousePickerRuntime({
|
|
12277
11021
|
getRotation: () => getUserConfig().llm.rotation ?? [],
|
|
12278
11022
|
getCurrentModelEntry: () => {
|
|
@@ -12290,337 +11034,52 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12290
11034
|
},
|
|
12291
11035
|
getRecentWds: () => [...wdHistory],
|
|
12292
11036
|
applySessionWd: (path) => {
|
|
12293
|
-
setSessionCwd(path, 'user');
|
|
12294
|
-
rememberWd(path);
|
|
12295
|
-
},
|
|
12296
|
-
reportModelSwitchError: (message) => {
|
|
12297
|
-
chatLines.push(C.error(` model switch failed: ${message}`));
|
|
12298
|
-
chatScrollOffset = -1;
|
|
12299
|
-
},
|
|
12300
|
-
reportWdSwitchError: (message) => {
|
|
12301
|
-
chatLines.push(C.error(` cwd switch failed: ${message}`));
|
|
12302
|
-
chatScrollOffset = -1;
|
|
12303
|
-
},
|
|
12304
|
-
});
|
|
12305
|
-
const mouseShellRollupRuntime = createMouseShellRollupRuntime({
|
|
12306
|
-
resolveVwIdByLabel: (
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
},
|
|
12318
|
-
});
|
|
12319
|
-
const
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
// ReferenceError when this deps object is built during boot. Same
|
|
12331
|
-
// pattern as the PR #1111 fix on `applyFocusToInputTransition` /
|
|
12332
|
-
// `draw` for `createDashboardVoiceRuntime`. The arrow defers the
|
|
12333
|
-
// name lookup until the callback actually runs.
|
|
12334
|
-
openDebugWindow: () => openDebugWindow(),
|
|
12335
|
-
openDebugWorkbenchModal: () => { openDebugWorkbenchModal(); },
|
|
12336
|
-
syncCompanionPopups,
|
|
12337
|
-
openConversationModal,
|
|
12338
|
-
redraw: () => { draw(); },
|
|
12339
|
-
});
|
|
12340
|
-
const mouseModeSwitchRuntime = createMouseModeSwitchRuntime({
|
|
12341
|
-
getActiveMode: () => inputCoreActiveMode(),
|
|
12342
|
-
getModeAction: (actionId) => getInputCoreAction(actionId),
|
|
12343
|
-
setMode: (next) => inputCoreSetMode(next),
|
|
12344
|
-
});
|
|
12345
|
-
const mouseHoverRuntime = createMouseHoverRuntime({
|
|
12346
|
-
dispatchHoverToWidget: (paneId, event) => {
|
|
12347
|
-
widgetHost.dispatchHover(
|
|
12348
|
-
paneId,
|
|
12349
|
-
event,
|
|
12350
|
-
);
|
|
12351
|
-
},
|
|
12352
|
-
setConversationHoverLabel: (label) => {
|
|
12353
|
-
setSegment(hud, 'conv-hover', C.muted(label), 4);
|
|
12354
|
-
},
|
|
12355
|
-
clearConversationHoverLabel: () => {
|
|
12356
|
-
clearSegment(hud, 'conv-hover');
|
|
12357
|
-
},
|
|
12358
|
-
conversationHoverHudLabel,
|
|
12359
|
-
});
|
|
12360
|
-
const mouseModalHitRuntime = createMouseModalHitRuntime({
|
|
12361
|
-
getTopSurface: () => {
|
|
12362
|
-
const stack = display.modalStack();
|
|
12363
|
-
const topId = stack[stack.length - 1];
|
|
12364
|
-
if (!topId) return null;
|
|
12365
|
-
return display.surface(topId) as import('../display/modal-stack.js').ModalSurface | null;
|
|
12366
|
-
},
|
|
12367
|
-
});
|
|
12368
|
-
const mouseModalSurfaceRuntime = createMouseModalSurfaceRuntime({
|
|
12369
|
-
openWindowPicker,
|
|
12370
|
-
getFocusStack: () => display.modalStack(),
|
|
12371
|
-
surfaceAt: (id) =>
|
|
12372
|
-
display.surface(id) as import('../display/modal-stack.js').ModalSurface | null | undefined,
|
|
12373
|
-
getTopBlockingModalSurface: topBlockingForegroundModal,
|
|
12374
|
-
routeModalMouse: (surface, ev) => display.routeMouseToSurface(surface, ev),
|
|
12375
|
-
});
|
|
12376
|
-
const mousePillContextRuntime = createMousePillContextRuntime({
|
|
12377
|
-
handleForPill: (name) => {
|
|
12378
|
-
const handle = handleForPill(name as Parameters<typeof handleForPill>[0]);
|
|
12379
|
-
// 2026-05-05 — model pill 만: 우클릭 직전에 menu 의 title 을 활성
|
|
12380
|
-
// rotation entry 라벨로 갱신해 "어떤 모델이 픽 되었는지" 정확히
|
|
12381
|
-
// 보여준다. 라벨도 짧게 (Switch / Remove / Settings…) 해서 메뉴
|
|
12382
|
-
// 폭을 status bar pill 인접 폭에 가깝게 유지.
|
|
12383
|
-
if (handle && name === 'model') {
|
|
12384
|
-
try {
|
|
12385
|
-
const reg = getDashboardContextMenuRegistry();
|
|
12386
|
-
const current = mousePickerRuntime.getCurrentModelEntry?.() ?? null;
|
|
12387
|
-
const activeLabel = current ? rotationEntryLabel(current) : '(none)';
|
|
12388
|
-
reg.updateMenu(handle as never, buildPillMenu({
|
|
12389
|
-
pillName: 'Model',
|
|
12390
|
-
title: `Model · ${activeLabel}`,
|
|
12391
|
-
canSwitch: true,
|
|
12392
|
-
canRemove: true,
|
|
12393
|
-
canOpenSettings: false,
|
|
12394
|
-
switchLabel: 'Switch',
|
|
12395
|
-
removeLabel: 'Remove',
|
|
12396
|
-
}));
|
|
12397
|
-
} catch { /* dynamic update is best-effort */ }
|
|
12398
|
-
}
|
|
12399
|
-
return handle;
|
|
12400
|
-
},
|
|
12401
|
-
showMenu: (handle, pos) =>
|
|
12402
|
-
getDashboardContextMenuRegistry().showMenu(
|
|
12403
|
-
handle as Parameters<ReturnType<typeof getDashboardContextMenuRegistry>['showMenu']>[0],
|
|
12404
|
-
pos,
|
|
12405
|
-
// 2026-05-05 — pill 우클릭 메뉴를 CMX-2 의 일반 context-menu wire
|
|
12406
|
-
// 와 같은 path 로 정렬: singleInstance + ownerWorkspaceId. 이전엔
|
|
12407
|
-
// 옵션 미지정으로 surface 가 dashboard-main workspace 에 attach 만
|
|
12408
|
-
// 됐고 (default), singleInstance 도 false 라 매번 새 surface id.
|
|
12409
|
-
// 키보드 ↑/↓ 가 routeKey 까지 도달하지 못하던 사용자 피드백 대응.
|
|
12410
|
-
{ singleInstance: true, ownerWorkspaceId: 'dashboard-main' },
|
|
12411
|
-
),
|
|
12412
|
-
// 2026-05-05 — pill 우클릭 메뉴 결과 wire. 현재 model pill 만 액션
|
|
12413
|
-
// 매핑되어 있다 (`Switch Model…` · `Remove from rotation`). 좌클릭은
|
|
12414
|
-
// 그대로 cycle (mouse-wiring 의 pill click branch). 다른 pill 은
|
|
12415
|
-
// legacy 동작 — 추후 wire 추가 시 여기 분기 늘리기.
|
|
12416
|
-
onPillMenuPick: async (name, value, pos) => {
|
|
12417
|
-
if (debug.enabled) {
|
|
12418
|
-
debug.log('mouse.pill.context.dispatch', 'enter', { name, value, pos });
|
|
12419
|
-
}
|
|
12420
|
-
if (name !== 'model') return;
|
|
12421
|
-
// Pill 우클릭 위치 → vw picker 의 PopupPlacement. status row 는
|
|
12422
|
-
// pos.y+1 (mouse-pill-context-runtime 가 0-indexed y 로 ev.row-1
|
|
12423
|
-
// 보냈음 — 1-indexed 로 복귀). anchor col 도 동일.
|
|
12424
|
-
const pillPickerPlacement = (origin: { x: number; y: number }): PopupPlacement => {
|
|
12425
|
-
const { rows: termRows, cols: termCols } = termSize();
|
|
12426
|
-
const anchorCol = origin.x + 1;
|
|
12427
|
-
return {
|
|
12428
|
-
anchorStartCol: anchorCol,
|
|
12429
|
-
anchorEndCol: anchorCol,
|
|
12430
|
-
statusRow: origin.y + 1,
|
|
12431
|
-
termCols,
|
|
12432
|
-
termRows,
|
|
12433
|
-
};
|
|
12434
|
-
};
|
|
12435
|
-
if (value === 'pill.switch') {
|
|
12436
|
-
// 좌클릭 cycle 과 동일 — 다음 rotation entry 로 switch.
|
|
12437
|
-
const ring = mousePickerRuntime.getRotation();
|
|
12438
|
-
if (ring.length === 0) {
|
|
12439
|
-
pushModeToast?.('No rotation configured · /provider add', 'warning');
|
|
12440
|
-
return;
|
|
12441
|
-
}
|
|
12442
|
-
const current = mousePickerRuntime.getCurrentModelEntry?.() ?? null;
|
|
12443
|
-
let nextIdx = 0;
|
|
12444
|
-
if (current) {
|
|
12445
|
-
const cIdx = ring.findIndex((e) =>
|
|
12446
|
-
e.provider === current.provider
|
|
12447
|
-
&& (e.model ?? null) === (current.model ?? null),
|
|
12448
|
-
);
|
|
12449
|
-
nextIdx = cIdx < 0 ? 0 : (cIdx + 1) % ring.length;
|
|
12450
|
-
}
|
|
12451
|
-
const nextEntry = ring[nextIdx]!;
|
|
12452
|
-
await Promise.resolve(mousePickerRuntime.setActiveModel(nextEntry));
|
|
12453
|
-
pushModeToast?.(`▸ ${rotationEntryLabel(nextEntry)}`, 'success');
|
|
12454
|
-
draw();
|
|
12455
|
-
return;
|
|
12456
|
-
}
|
|
12457
|
-
if (value === 'pill.remove') {
|
|
12458
|
-
const current = mousePickerRuntime.getCurrentModelEntry?.() ?? null;
|
|
12459
|
-
if (debug.enabled) {
|
|
12460
|
-
debug.log('mouse.pill.context.dispatch', 'remove.start', {
|
|
12461
|
-
hasCurrent: !!current,
|
|
12462
|
-
currentLabel: current ? rotationEntryLabel(current) : null,
|
|
12463
|
-
});
|
|
12464
|
-
}
|
|
12465
|
-
// 2026-05-05 — `currentRotationIndex(cfg)` 사용. 이전 PR 들은
|
|
12466
|
-
// (1) `removeRotationEntry(needle)` — 합성 라벨이 단일 필드와
|
|
12467
|
-
// 매칭 안 됨
|
|
12468
|
-
// (2) 직접 `(provider, model)` 튜플 — 사용자 지적: "디스플레이
|
|
12469
|
-
// 시 provider 이름 생략 루틴" 때문에 cfg.llm.provider/model
|
|
12470
|
-
// 이 entry 와 그대로 매칭 안 됨
|
|
12471
|
-
// currentRotationIndex 는 이미 검증된 active-entry 매칭 로직을
|
|
12472
|
-
// 가짐 — provider 동일 + (양쪽 model 다 있고 다르면 skip · 한쪽
|
|
12473
|
-
// 만 있으면 같은 provider 의 entry 면 OK). cfg.llm 으로부터 직접
|
|
12474
|
-
// 인덱스 산출하므로 derived label 변환 영향 받지 않음.
|
|
12475
|
-
const cfg = getUserConfig();
|
|
12476
|
-
const ring = cfg.llm?.rotation ?? [];
|
|
12477
|
-
const idx = currentRotationIndex(cfg);
|
|
12478
|
-
if (debug.enabled) {
|
|
12479
|
-
debug.log('mouse.pill.context.dispatch', 'remove.result', {
|
|
12480
|
-
matchedIndex: idx,
|
|
12481
|
-
rotationLengthBefore: ring.length,
|
|
12482
|
-
cfgProvider: cfg.llm?.provider ?? null,
|
|
12483
|
-
cfgModel: cfg.llm?.model ?? null,
|
|
12484
|
-
});
|
|
12485
|
-
}
|
|
12486
|
-
if (idx < 0) {
|
|
12487
|
-
pushModeToast?.(
|
|
12488
|
-
`Active model not in rotation: ${current ? rotationEntryLabel(current) : '(none)'}`,
|
|
12489
|
-
'warning',
|
|
12490
|
-
);
|
|
12491
|
-
return;
|
|
12492
|
-
}
|
|
12493
|
-
// 2026-05-05 — Confirm popup (vw picker 스타일). 사용자 요청:
|
|
12494
|
-
// "테마가 vw picker 스타일로 깔끔하게 될것 같은데" — context-
|
|
12495
|
-
// menu widget 대신 createActionPickerRecipe 를 사용해 model
|
|
12496
|
-
// picker / window picker 같은 정돈된 chrome 으로 통일.
|
|
12497
|
-
const targetLabel = rotationEntryLabel(ring[idx]!);
|
|
12498
|
-
const placement = pillPickerPlacement(pos);
|
|
12499
|
-
const confirmValue = await new Promise<string | null>((resolve) => {
|
|
12500
|
-
let resolved = false;
|
|
12501
|
-
let handle: ReturnType<typeof createActionPickerRecipe> | null = null;
|
|
12502
|
-
handle = createActionPickerRecipe<string>({
|
|
12503
|
-
id: 'pill-remove-confirm',
|
|
12504
|
-
title: `Remove from rotation?`,
|
|
12505
|
-
// 단일 preview row — primary CTA 가 이 entry 의 value 로 fire.
|
|
12506
|
-
items: [
|
|
12507
|
-
{ value: 'confirm.remove', label: targetLabel },
|
|
12508
|
-
],
|
|
12509
|
-
placement,
|
|
12510
|
-
// CTA 버튼 명시 (사용자 요청). primary='Remove' · cancel='Cancel'.
|
|
12511
|
-
actionButtons: true,
|
|
12512
|
-
primaryActionLabel: 'Remove',
|
|
12513
|
-
cancelActionLabel: 'Cancel',
|
|
12514
|
-
filterable: false,
|
|
12515
|
-
initialIndex: 0,
|
|
12516
|
-
// 2026-05-06 — dock submenu 와 동일 row look 차용. parent
|
|
12517
|
-
// role = highlight 색상으로 cursor/selected row · 사용자 요청:
|
|
12518
|
-
// "dock area 매뉴 subitem 들의 UI/UX (포커스시와 아닐시 look)
|
|
12519
|
-
// 그것을 차용".
|
|
12520
|
-
theme: deriveSubmenuPopupRoleTheme(currentThemeTokens(), 'parent'),
|
|
12521
|
-
shadow: { theme: currentThemeTokens() },
|
|
12522
|
-
onPick: (value) => {
|
|
12523
|
-
if (resolved) return;
|
|
12524
|
-
resolved = true;
|
|
12525
|
-
try { handle?.dispose(); } catch { /* swallow */ }
|
|
12526
|
-
resolve(value);
|
|
12527
|
-
},
|
|
12528
|
-
onCancel: () => {
|
|
12529
|
-
if (resolved) return;
|
|
12530
|
-
resolved = true;
|
|
12531
|
-
try { handle?.dispose(); } catch { /* swallow */ }
|
|
12532
|
-
resolve(null);
|
|
12533
|
-
},
|
|
12534
|
-
});
|
|
12535
|
-
display.pushModal(handle.surface);
|
|
12536
|
-
draw();
|
|
12537
|
-
});
|
|
12538
|
-
if (debug.enabled) {
|
|
12539
|
-
debug.log('mouse.pill.context.dispatch', 'remove.confirm', {
|
|
12540
|
-
value: confirmValue ?? '(cancelled)',
|
|
12541
|
-
});
|
|
12542
|
-
}
|
|
12543
|
-
if (confirmValue !== 'confirm.remove') {
|
|
12544
|
-
// Cancelled / escaped — toast 으로 회복 신호. 사용자 피드백:
|
|
12545
|
-
// "Remove Confirm 팝업에서 Cancel 을 선택하면 아래 회복 방법
|
|
12546
|
-
// 이 없음" — 액션이 안 됐다는 visible feedback 가 필요.
|
|
12547
|
-
pushModeToast?.(
|
|
12548
|
-
`Cancelled · '${targetLabel}' still in rotation`,
|
|
12549
|
-
'info',
|
|
12550
|
-
);
|
|
12551
|
-
return;
|
|
12552
|
-
}
|
|
12553
|
-
const removed = ring[idx]!;
|
|
12554
|
-
const nextRing = ring.slice(0, idx).concat(ring.slice(idx + 1));
|
|
12555
|
-
const nextCfg = {
|
|
12556
|
-
...cfg,
|
|
12557
|
-
llm: {
|
|
12558
|
-
...cfg.llm,
|
|
12559
|
-
rotation: nextRing.length > 0 ? nextRing : undefined,
|
|
12560
|
-
},
|
|
12561
|
-
};
|
|
12562
|
-
try {
|
|
12563
|
-
saveUserConfig(nextCfg);
|
|
12564
|
-
reloadUserConfig();
|
|
12565
|
-
if (debug.enabled) {
|
|
12566
|
-
debug.log('mouse.pill.context.dispatch', 'remove.persisted', {
|
|
12567
|
-
rotationLength: nextRing.length,
|
|
12568
|
-
});
|
|
12569
|
-
}
|
|
12570
|
-
} catch (err) {
|
|
12571
|
-
if (debug.enabled) {
|
|
12572
|
-
debug.log('mouse.pill.context.dispatch', 'remove.persist-failed', {
|
|
12573
|
-
err: err instanceof Error ? err.message : String(err),
|
|
12574
|
-
}, { level: 'error' });
|
|
12575
|
-
}
|
|
12576
|
-
pushModeToast?.('Save failed', 'warning');
|
|
12577
|
-
return;
|
|
12578
|
-
}
|
|
12579
|
-
// 후속: 새 rotation 의 첫 entry 로 switch (있으면).
|
|
12580
|
-
const liveRing = mousePickerRuntime.getRotation();
|
|
12581
|
-
if (liveRing.length > 0) {
|
|
12582
|
-
await Promise.resolve(mousePickerRuntime.setActiveModel(liveRing[0]!));
|
|
12583
|
-
}
|
|
12584
|
-
pushModeToast?.(
|
|
12585
|
-
`🗑 Removed ${rotationEntryLabel(removed)} · ${liveRing.length} left`,
|
|
12586
|
-
'success',
|
|
12587
|
-
);
|
|
12588
|
-
draw();
|
|
12589
|
-
// 2026-05-05 — 정보 popup (vw picker 스타일). 사용자 요청:
|
|
12590
|
-
// "실제 지웠을때 인포 팝업도 만들어주세요" + "테마 vw picker
|
|
12591
|
-
// 스타일". confirm 과 동일한 createActionPickerRecipe 패턴 ·
|
|
12592
|
-
// 단일 'OK' 항목 (Enter/Esc 로 close).
|
|
12593
|
-
let infoHandle: ReturnType<typeof createActionPickerRecipe> | null = null;
|
|
12594
|
-
const closeInfo = (): void => {
|
|
12595
|
-
try { infoHandle?.dispose(); } catch { /* swallow */ }
|
|
12596
|
-
};
|
|
12597
|
-
infoHandle = createActionPickerRecipe<string>({
|
|
12598
|
-
id: 'pill-remove-info',
|
|
12599
|
-
title: '🗑 Removed from rotation',
|
|
12600
|
-
// 두 정보 row · primary CTA = 'OK'. items value 는 onPick callback
|
|
12601
|
-
// 으로 들어오지만 모두 동일 closeInfo 로 라우팅.
|
|
12602
|
-
items: [
|
|
12603
|
-
{ value: 'info.removed', label: rotationEntryLabel(removed) },
|
|
12604
|
-
{ value: 'info.remaining', label: `${liveRing.length} entries left` },
|
|
12605
|
-
],
|
|
12606
|
-
placement: pillPickerPlacement(pos),
|
|
12607
|
-
// CTA 버튼 명시. info popup 은 primary='OK' · cancel='Close'.
|
|
12608
|
-
actionButtons: true,
|
|
12609
|
-
primaryActionLabel: 'OK',
|
|
12610
|
-
cancelActionLabel: 'Close',
|
|
12611
|
-
filterable: false,
|
|
12612
|
-
initialIndex: 0,
|
|
12613
|
-
theme: currentThemeTokens(),
|
|
12614
|
-
shadow: { theme: currentThemeTokens() },
|
|
12615
|
-
onPick: closeInfo,
|
|
12616
|
-
onCancel: closeInfo,
|
|
12617
|
-
});
|
|
12618
|
-
display.pushModal(infoHandle.surface);
|
|
12619
|
-
draw();
|
|
12620
|
-
return;
|
|
12621
|
-
}
|
|
11037
|
+
setSessionCwd(path, 'user');
|
|
11038
|
+
rememberWd(path);
|
|
11039
|
+
},
|
|
11040
|
+
reportModelSwitchError: (message) => {
|
|
11041
|
+
chatLines.push(C.error(` model switch failed: ${message}`));
|
|
11042
|
+
chatScrollOffset = -1;
|
|
11043
|
+
},
|
|
11044
|
+
reportWdSwitchError: (message) => {
|
|
11045
|
+
chatLines.push(C.error(` cwd switch failed: ${message}`));
|
|
11046
|
+
chatScrollOffset = -1;
|
|
11047
|
+
},
|
|
11048
|
+
});
|
|
11049
|
+
const mouseShellRollupRuntime = createMouseShellRollupRuntime({
|
|
11050
|
+
resolveVwIdByLabel: () => null,
|
|
11051
|
+
switchToVirtualWindow: () => { throw new Error('Virtual windows are unavailable in the essential dashboard'); },
|
|
11052
|
+
onWarning: (message) => {
|
|
11053
|
+
chatLines.push(C.warning(` ${message}`));
|
|
11054
|
+
chatScrollOffset = -1;
|
|
11055
|
+
},
|
|
11056
|
+
});
|
|
11057
|
+
const mouseConversationPopupRuntime = createMouseConversationPopupRuntime({
|
|
11058
|
+
conversationPopupHost,
|
|
11059
|
+
ensureConversationWidgetMounted,
|
|
11060
|
+
syncConversationPopupModals,
|
|
11061
|
+
redraw: () => { draw(); },
|
|
11062
|
+
});
|
|
11063
|
+
const mouseModeSwitchRuntime = createMouseModeSwitchRuntime({
|
|
11064
|
+
getActiveMode: () => inputCoreActiveMode(),
|
|
11065
|
+
getModeAction: (actionId) => getInputCoreAction(actionId),
|
|
11066
|
+
setMode: (next) => inputCoreSetMode(next),
|
|
11067
|
+
});
|
|
11068
|
+
const mouseModalHitRuntime = createMouseModalHitRuntime({
|
|
11069
|
+
getTopSurface: () => {
|
|
11070
|
+
const stack = display.modalStack();
|
|
11071
|
+
const topId = stack[stack.length - 1];
|
|
11072
|
+
if (!topId) return null;
|
|
11073
|
+
return display.surface(topId) as import('../display/modal-stack.js').ModalSurface | null;
|
|
12622
11074
|
},
|
|
12623
11075
|
});
|
|
11076
|
+
const mouseModalSurfaceRuntime = createMouseModalSurfaceRuntime({
|
|
11077
|
+
getFocusStack: () => display.modalStack(),
|
|
11078
|
+
surfaceAt: (id) =>
|
|
11079
|
+
display.surface(id) as import('../display/modal-stack.js').ModalSurface | null | undefined,
|
|
11080
|
+
getTopBlockingModalSurface: topBlockingForegroundModal,
|
|
11081
|
+
routeModalMouse: (surface, ev) => display.routeMouseToSurface(surface, ev),
|
|
11082
|
+
});
|
|
12624
11083
|
const mousePaneHitRuntime = createMousePaneHitRuntime({
|
|
12625
11084
|
getPaneNavRow: () => paneNavRow,
|
|
12626
11085
|
paneAtColumn: (col0) => {
|
|
@@ -12649,29 +11108,16 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12649
11108
|
|
|
12650
11109
|
const mouseWiring = createDashboardMouseWiring({
|
|
12651
11110
|
termSize: () => termSize(),
|
|
12652
|
-
|
|
12653
|
-
// /ui 런타임 전환을 따르도록 predicate 로 배선.
|
|
12654
|
-
hoverPopupsEnabled: () => isDashboardHeavyFeatureEnabled(dashboardUiMode, 'hover-popups'),
|
|
11111
|
+
hoverPopupsEnabled: () => false,
|
|
12655
11112
|
getRotation: mousePickerRuntime.getRotation,
|
|
12656
11113
|
getCurrentModelEntry: mousePickerRuntime.getCurrentModelEntry,
|
|
12657
11114
|
setActiveModel: mousePickerRuntime.setActiveModel,
|
|
12658
11115
|
getRecentWds: mousePickerRuntime.getRecentWds,
|
|
12659
11116
|
setSessionWd: mousePickerRuntime.setSessionWd,
|
|
12660
|
-
getDockMenuWindowTargets: mouseDockRuntime.getDockMenuWindowTargets,
|
|
12661
|
-
onOpenDockWindow: mouseDockRuntime.onOpenDockWindow,
|
|
12662
|
-
getDockMenuSurfaceTargets: mouseDockRuntime.getDockMenuSurfaceTargets,
|
|
12663
|
-
onOpenDockSurface: mouseDockRuntime.onOpenDockSurface,
|
|
12664
|
-
onToggleChatOnly: mouseDockRuntime.onToggleChatOnly,
|
|
12665
11117
|
onExitProgram: async () => {
|
|
12666
11118
|
exitDashboardTui();
|
|
12667
11119
|
setTimeout(() => process.exit(0), 0);
|
|
12668
11120
|
},
|
|
12669
|
-
getDashboardViews: mouseDockRuntime.getDashboardViews,
|
|
12670
|
-
onApplyDashboardView: mouseDockRuntime.onApplyDashboardView,
|
|
12671
|
-
getVirtualWindows: mouseDockRuntime.getVirtualWindows,
|
|
12672
|
-
onSwitchVirtualWindow: mouseDockRuntime.onSwitchVirtualWindow,
|
|
12673
|
-
getVirtualWindowMover: mouseDockRuntime.getVirtualWindowMover,
|
|
12674
|
-
onMoveVirtualWindow: mouseDockRuntime.onMoveVirtualWindow,
|
|
12675
11121
|
pushModalSurface: surface => display.pushModal(surface),
|
|
12676
11122
|
// DS-2b (2026-04-21) — drag-session routing hook. Adapter lives
|
|
12677
11123
|
// in src/display/drag-dispatch.ts (PR #319); this single line is
|
|
@@ -12680,10 +11126,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12680
11126
|
// the existing chain (0 overhead path). See PLAN-drag-session-
|
|
12681
11127
|
// primitive.md §3.3 and PR #319 for the contract.
|
|
12682
11128
|
dragDispatch: (ev) => dragDispatch(ev, display.dragManagerAPI()),
|
|
12683
|
-
// CMX-2 (2026-04-22) — non-pill right-click dispatch.
|
|
12684
|
-
//
|
|
12685
|
-
//
|
|
12686
|
-
// / input / VW right-clicks via MenuProviderRegistry. Unconsumed
|
|
11129
|
+
// CMX-2 (2026-04-22) — non-pill right-click dispatch. This hook
|
|
11130
|
+
// serves pane-body / pane-title / input / VW right-clicks via
|
|
11131
|
+
// MenuProviderRegistry. Unconsumed
|
|
12687
11132
|
// (no provider matches) falls through to modal forwarding.
|
|
12688
11133
|
contextMenuDispatch: (ev) => ctxMenuWire.onMouse(ev),
|
|
12689
11134
|
// DS-3a (2026-04-21) — chat input hit classifier. Routes clicks
|
|
@@ -12703,18 +11148,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12703
11148
|
updateModalBounds: (id, bounds) => display.updateModalBounds(id, bounds),
|
|
12704
11149
|
redraw: () => { draw(); },
|
|
12705
11150
|
requestRender: () => { requestDashboardRender(); },
|
|
12706
|
-
// IDX-F5d Phase 2 (2026-04-22) — pane-body hover dispatcher.
|
|
12707
|
-
// Mouse wiring subscribes to its internal HoverTracker; we bridge
|
|
12708
|
-
// pane-body hover events to `widgetHost.dispatchHover` so each
|
|
12709
|
-
// widget's `onHover` override fires when the pointer enters /
|
|
12710
|
-
// leaves / hovers stable over one of its items. `paneId` matches
|
|
12711
|
-
// `widgetInstanceId` in the current grid (getPaneHitTarget wires
|
|
12712
|
-
// them 1:1 in dashboard.ts:7852).
|
|
12713
|
-
dispatchHoverToWidget: mouseHoverRuntime.dispatchHoverToWidget,
|
|
12714
|
-
onPaneHoverEvent: mouseHoverRuntime.onPaneHoverEvent,
|
|
12715
11151
|
conversationPopupHost,
|
|
12716
11152
|
onConversationPopupPick: mouseConversationPopupRuntime.onConversationPopupPick,
|
|
12717
|
-
onWindowPillClick: mouseModalSurfaceRuntime.onWindowPillClick,
|
|
12718
11153
|
// SRF-4 — shell rollup pill click → popup listing live handles.
|
|
12719
11154
|
// Handles are fetched at click time so the popup always reflects
|
|
12720
11155
|
// the current ShellRegistry state (not a frozen snapshot).
|
|
@@ -12742,13 +11177,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12742
11177
|
getTheme: () => currentThemeTokens(),
|
|
12743
11178
|
suppressHoverHints: true,
|
|
12744
11179
|
workspaceHost: display.workspaceHostAPI(),
|
|
12745
|
-
onWorkspaceRestore: mouseWorkspaceRestoreRuntime.onWorkspaceRestore,
|
|
12746
|
-
// IDX-5 Phase 2 — right-click on a pill → context-menu registry.
|
|
12747
|
-
// Registry is initialised just below (after mouseWiring is built
|
|
12748
|
-
// so the presenter can use `display.pushModal`). The handler is a
|
|
12749
|
-
// closure that resolves the right registry handle at call time so
|
|
12750
|
-
// the one-off bootstrap order works out.
|
|
12751
|
-
onPillRightClick: mousePillContextRuntime.onPillRightClick,
|
|
12752
11180
|
// IDX-5 Phase 3 B-4 — classify clicks outside the status-bar pill
|
|
12753
11181
|
// row into broader pane regions so lastClickHitKind can carry
|
|
12754
11182
|
// 'pane-nav' / 'pane-title' / 'pane-body' values (previously only
|
|
@@ -12781,14 +11209,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12781
11209
|
getTheme: () => currentThemeTokens(),
|
|
12782
11210
|
});
|
|
12783
11211
|
|
|
12784
|
-
//
|
|
12785
|
-
// registration. Both need late boot state now available here:
|
|
12786
|
-
// artifactStore/windowRegistry for Layout* and mouse/context-menu
|
|
12787
|
-
// deps for display-control. Registration is idempotent.
|
|
11212
|
+
// F6 / S1.D — display-control runtime registration needs late-boot mouse/context-menu state.
|
|
12788
11213
|
try {
|
|
12789
11214
|
registerDashboardLayoutDisplayRuntimes({
|
|
12790
|
-
windowRegistry: virtualWindows.registry,
|
|
12791
|
-
artifactStore,
|
|
12792
11215
|
coordinator: display,
|
|
12793
11216
|
mouseDispatch: (ev) => mouseWiring.handleMouse(ev),
|
|
12794
11217
|
menuProviderRegistry: ctxMenuProviders,
|
|
@@ -12815,16 +11238,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12815
11238
|
// values are cheap no-ops (one field comparison per key).
|
|
12816
11239
|
publishFocusContextKeysFromService(workingDir.focus);
|
|
12817
11240
|
|
|
12818
|
-
// TR-P3: refresh the pane-modal hint segment each draw. When the
|
|
12819
|
-
// viewport is at tabletMini/tabletTwo and there are deferred
|
|
12820
|
-
// panes, a "Ctrl+M p=preview l=log" segment appears on the HUD.
|
|
12821
|
-
// Clears on wider viewports so the hint doesn't stick around.
|
|
12822
|
-
{
|
|
12823
|
-
const vis = activePaneVisibility();
|
|
12824
|
-
const hint = renderPaneModalHint(vis, cols, effectiveTabletMode());
|
|
12825
|
-
if (hint) setSegment(hud, 'tr-pane-modal', C.muted(hint), 4);
|
|
12826
|
-
else clearSegment(hud, 'tr-pane-modal');
|
|
12827
|
-
}
|
|
12828
11241
|
|
|
12829
11242
|
// T3-B1: agent-activity HUD segment. Pulsing glyph + running
|
|
12830
11243
|
// count drives awareness that sub-agent work is in flight —
|
|
@@ -12962,9 +11375,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12962
11375
|
}
|
|
12963
11376
|
const suppressPromptArea = hostChromePolicy.suppressPromptArea;
|
|
12964
11377
|
const suppressStatusArea = hostChromePolicy.suppressStatusArea;
|
|
12965
|
-
const suppressHudArea = hostChromePolicy.suppressHudArea;
|
|
12966
11378
|
const suppressDashboardBackground = hostChromePolicy.suppressDashboardBackground;
|
|
12967
|
-
const suppressDockArea = hostChromePolicy.suppressDockArea;
|
|
12968
11379
|
if (suppressPromptArea) display.setCursor(null);
|
|
12969
11380
|
// ── Zone list (top-to-bottom) ──
|
|
12970
11381
|
// Replaces the old inline `termRows - N` arithmetic and hand-rolled
|
|
@@ -13034,18 +11445,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13034
11445
|
});
|
|
13035
11446
|
}
|
|
13036
11447
|
|
|
13037
|
-
//
|
|
13038
|
-
// segments. TUI 부활 T1: essential 모드는 HUD pill 행 자체를 생략
|
|
13039
|
-
// (codex 패리티 — 하단 chrome 은 status line 1줄만). zoneRows 소비처
|
|
13040
|
-
// (`zoneRows.get('hud')` 류)는 missing zone 을 안전 처리하는 설계
|
|
13041
|
-
// (§MX11b 코멘트)라 생략이 안전하다.
|
|
13042
|
-
if (isDashboardHeavyFeatureEnabled(dashboardUiMode, 'hud')) {
|
|
13043
|
-
zones.push({
|
|
13044
|
-
id: 'hud',
|
|
13045
|
-
height: 1,
|
|
13046
|
-
render: (_h, c) => [suppressHudArea ? '' : (renderHud(hud, c) || '')],
|
|
13047
|
-
});
|
|
13048
|
-
}
|
|
11448
|
+
// Essential chrome uses only the status line, not a HUD row.
|
|
13049
11449
|
|
|
13050
11450
|
// Input block.
|
|
13051
11451
|
let promptCaret: CursorState | null = null;
|
|
@@ -13075,24 +11475,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13075
11475
|
render: (_h, c) => [suppressPromptArea ? ' '.repeat(c) : hLine(c)],
|
|
13076
11476
|
});
|
|
13077
11477
|
|
|
13078
|
-
//
|
|
13079
|
-
// TUI 부활 T1: essential 은 status line 1줄만 유지(대표 확정 ①) —
|
|
13080
|
-
// gap-mid·dock 행 생략으로 chat log 가 2행 더 얻는다. dock 클릭
|
|
13081
|
-
// 라우팅은 setDockRow(null) 경로로 자연 비활성.
|
|
11478
|
+
// Essential bottom area: status line only; no dock row.
|
|
13082
11479
|
zones.push({ id: 'status-gap-top', height: 1, render: () => [''] });
|
|
13083
11480
|
zones.push({
|
|
13084
11481
|
id: 'status',
|
|
13085
11482
|
height: 1,
|
|
13086
11483
|
render: () => [suppressStatusArea ? '' : buildStatusLine()],
|
|
13087
11484
|
});
|
|
13088
|
-
if (isDashboardHeavyFeatureEnabled(dashboardUiMode, 'dock')) {
|
|
13089
|
-
zones.push({ id: 'status-gap-mid', height: 1, render: () => [''] });
|
|
13090
|
-
zones.push({
|
|
13091
|
-
id: 'dock',
|
|
13092
|
-
height: 1,
|
|
13093
|
-
render: () => [suppressDockArea ? '' : mouseWiring.buildDockLine()],
|
|
13094
|
-
});
|
|
13095
|
-
}
|
|
13096
11485
|
|
|
13097
11486
|
// Compose.
|
|
13098
11487
|
const composed = composeVertical(zones, { rows: termRows, cols: totalW });
|
|
@@ -13151,11 +11540,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13151
11540
|
// is one of the easiest ways to see a flash under tmux.
|
|
13152
11541
|
let modalFrame = '';
|
|
13153
11542
|
let modalKey = '';
|
|
13154
|
-
// TUI 부활 T3 — essential 은 VW frame 합성 스킵 (rich 에서 스폰된
|
|
13155
|
-
// 윈도우가 남아 있어도 essential 로 전환하면 그리지 않는다).
|
|
13156
|
-
const foregroundWorkspaceFrame = isDashboardHeavyFeatureEnabled(dashboardUiMode, 'workspace-frame')
|
|
13157
|
-
? (virtualWindows.registry.current()?.render() ?? '')
|
|
13158
|
-
: '';
|
|
13159
11543
|
if (effectiveLayout && effectiveLayout.modals.length > 0) {
|
|
13160
11544
|
const m = effectiveLayout.modals[0]!;
|
|
13161
11545
|
modalKey = `${m.id}:${m.widgetInstanceId}:${JSON.stringify(m.position)}:${m.size?.width ?? ''}x${m.size?.height ?? ''}`;
|
|
@@ -13163,15 +11547,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13163
11547
|
termRows, termCols: cols, theme: currentThemeTokens(),
|
|
13164
11548
|
});
|
|
13165
11549
|
}
|
|
13166
|
-
if (foregroundWorkspaceFrame.length > 0) {
|
|
13167
|
-
modalFrame += foregroundWorkspaceFrame;
|
|
13168
|
-
}
|
|
13169
11550
|
if (debug.isKeyTraceEnabled() && blockingForegroundModal) {
|
|
13170
11551
|
debug.log('dashboard.frame-compose', 'blocking-modal', {
|
|
13171
11552
|
modalId: blockingForegroundModal.id,
|
|
13172
11553
|
baseLineCount: baseLines.length,
|
|
13173
11554
|
overlayLen: modalFrame.length,
|
|
13174
|
-
hasForegroundWorkspaceFrame:
|
|
11555
|
+
hasForegroundWorkspaceFrame: false,
|
|
13175
11556
|
});
|
|
13176
11557
|
}
|
|
13177
11558
|
try {
|
|
@@ -13183,15 +11564,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13183
11564
|
// propagated request.force (e.g. popModal / closeSurface on a
|
|
13184
11565
|
// coordinator-owned modal). Before V3 only the layout-modal signal
|
|
13185
11566
|
// was honored, so coordinator modal closes left residual pixels.
|
|
13186
|
-
// ⭐
|
|
11567
|
+
// ⭐ Single flush: resolve the prompt caret after overlays.
|
|
13187
11568
|
const frameCursorDecision = display.cursorDecision();
|
|
13188
11569
|
renderDashboardFrame(baseLines, composeDashboardFrameWithCoordinatorModal(display, {
|
|
13189
11570
|
overlay: modalFrame,
|
|
13190
11571
|
force: forceFromCoordinator || modalKey !== lastModalKey,
|
|
13191
|
-
essential: dashboardUiMode === 'essential',
|
|
13192
11572
|
cursorOwner: frameCursorDecision.owner,
|
|
13193
11573
|
claimedCursor: frameCursorDecision.cursor,
|
|
13194
|
-
// ⛔ rich 는 #6528 까지의 값을 그대로 쓴다 — 이 PR 은 essential 축만 바꾼다.
|
|
13195
11574
|
coordinatorCursor: display.getCursor(),
|
|
13196
11575
|
promptCaret,
|
|
13197
11576
|
suppressPromptArea,
|
|
@@ -14109,42 +12488,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14109
12488
|
when: () => agentSearchModal === null,
|
|
14110
12489
|
});
|
|
14111
12490
|
|
|
14112
|
-
// FU-1 — pane-modal-chord port. Each pane letter from SHORTCUT_TABLE
|
|
14113
|
-
// registers as a chord binding under `Ctrl+M,Ctrl+ㅡ`. The `when`
|
|
14114
|
-
// guard keeps a pane's binding inactive unless it's currently in
|
|
14115
|
-
// the deferred list, so mistyped letters still fall through.
|
|
14116
|
-
const openDeferredPane = (pane: PaneFocus): void => {
|
|
14117
|
-
const { cols: tc, rows: tr } = termSize();
|
|
14118
|
-
const captured = captureDeferredPane(pane);
|
|
14119
|
-
showTransientTerminalModal({
|
|
14120
|
-
title: `${pane} (modal)`,
|
|
14121
|
-
lines: captured.split('\n'),
|
|
14122
|
-
coordinator: display,
|
|
14123
|
-
termCols: tc,
|
|
14124
|
-
termRows: tr,
|
|
14125
|
-
ttlMs: 8000,
|
|
14126
|
-
group: 'pane-modal',
|
|
14127
|
-
});
|
|
14128
|
-
};
|
|
14129
|
-
for (const [pane, letter] of Object.entries(PANE_SHORTCUT_TABLE) as Array<[PaneFocus, string]>) {
|
|
14130
|
-
display.registerKeyBinding({
|
|
14131
|
-
id: `dashboard:pane-modal-chord:${pane}`,
|
|
14132
|
-
chordPrefix: 'C-m',
|
|
14133
|
-
key: letter,
|
|
14134
|
-
chordTimeoutMs: PANE_MODAL_CHORD_TIMEOUT_MS,
|
|
14135
|
-
scope: 'global',
|
|
14136
|
-
handler: () => openDeferredPane(pane),
|
|
14137
|
-
when: () => activePaneVisibility().modalDeferred.includes(pane),
|
|
14138
|
-
});
|
|
14139
|
-
}
|
|
14140
|
-
|
|
14141
|
-
// Task 2 · T-3 / T-4 — `Ctrl+M B` (shift) opens the 2×1 modal with
|
|
14142
|
-
// browser + preview side-by-side. Complementary to the lowercase
|
|
14143
|
-
// single-pane chord above. T-4 saves the pre-modal focus and
|
|
14144
|
-
// restores it on dispose (→ log when tablet mode is active, the
|
|
14145
|
-
// default "keep user where they were" otherwise). narrow terminals
|
|
14146
|
-
// get a 1-column fallback automatically via showPaneMultiModal's
|
|
14147
|
-
// MIN_WIDE_WIDTH gate.
|
|
14148
12491
|
let debugWorkbenchHandle: PaneMultiModalHandle | null = null;
|
|
14149
12492
|
let debugWindowHandle: PaneMultiModalHandle | null = null;
|
|
14150
12493
|
let debugWindowHoverActive = false;
|
|
@@ -14469,14 +12812,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14469
12812
|
onContextMenuMouse: (ev) => ctxMenuWire.onMouse(ev),
|
|
14470
12813
|
});
|
|
14471
12814
|
};
|
|
14472
|
-
display.registerKeyBinding({
|
|
14473
|
-
id: 'dashboard:pane-modal-chord:browser+preview',
|
|
14474
|
-
chordPrefix: 'C-m',
|
|
14475
|
-
key: 'S-b',
|
|
14476
|
-
chordTimeoutMs: PANE_MODAL_CHORD_TIMEOUT_MS,
|
|
14477
|
-
scope: 'global',
|
|
14478
|
-
handler: openBrowserPreviewModal,
|
|
14479
|
-
});
|
|
14480
12815
|
const openBrowserOnlyModal = (): void => {
|
|
14481
12816
|
const { cols: tc, rows: tr } = termSize();
|
|
14482
12817
|
const liveMode = resolveBrowserPreviewModalLiveMode(process.env.ELANOUS_PANE_MODAL_LIVE);
|
|
@@ -14497,14 +12832,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14497
12832
|
onCancel: () => { draw(); },
|
|
14498
12833
|
});
|
|
14499
12834
|
};
|
|
14500
|
-
display.registerKeyBinding({
|
|
14501
|
-
id: 'dashboard:pane-modal-chord:browser-only',
|
|
14502
|
-
chordPrefix: 'C-m',
|
|
14503
|
-
key: 'S-w',
|
|
14504
|
-
chordTimeoutMs: PANE_MODAL_CHORD_TIMEOUT_MS,
|
|
14505
|
-
scope: 'global',
|
|
14506
|
-
handler: openBrowserOnlyModal,
|
|
14507
|
-
});
|
|
14508
12835
|
const openPreviewOnlyModal = (): void => {
|
|
14509
12836
|
const { cols: tc, rows: tr } = termSize();
|
|
14510
12837
|
const liveMode = (process.env.ELANOUS_PANE_MODAL_LIVE ?? 'on').toLowerCase() !== 'off';
|
|
@@ -14522,237 +12849,22 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14522
12849
|
onCancel: () => { draw(); },
|
|
14523
12850
|
});
|
|
14524
12851
|
};
|
|
14525
|
-
display.registerKeyBinding({
|
|
14526
|
-
id: 'dashboard:pane-modal-chord:preview-only',
|
|
14527
|
-
chordPrefix: 'C-m',
|
|
14528
|
-
key: 'S-p',
|
|
14529
|
-
chordTimeoutMs: PANE_MODAL_CHORD_TIMEOUT_MS,
|
|
14530
|
-
scope: 'global',
|
|
14531
|
-
handler: openPreviewOnlyModal,
|
|
14532
|
-
});
|
|
14533
|
-
|
|
14534
|
-
// FU-2 — virtual-window chord port (last remaining hard branch).
|
|
14535
|
-
// Each body key of the Ctrl+B chord registers as its own coordinator
|
|
14536
|
-
// binding; the handler synthesises a KeyEvent and forwards it to
|
|
14537
|
-
// NavigationRouter.dispatchArmed so the actual routing logic stays
|
|
14538
|
-
// in one place (tests still target NavigationRouter directly).
|
|
14539
|
-
const VW_CHORD_PREFIX = 'C-b';
|
|
14540
|
-
// TUI 부활 T3 — essential 은 VW 키 표면 OFF. 모든 ^B chord body 가
|
|
14541
|
-
// 이 단일 깔때기를 지나므로 여기 한 곳 게이트로 비가시 윈도우
|
|
14542
|
-
// 생성/조작(^B c 등)을 차단한다. /ui rich 런타임 전환 즉시 복원.
|
|
14543
|
-
const vwBody = (ev: DisplayKeyEvent): void => {
|
|
14544
|
-
if (dashboardUiMode !== 'rich') {
|
|
14545
|
-
chatLines.push(C.muted(' (virtual workspace 는 rich 모드 전용 — /ui rich 로 전환)'));
|
|
14546
|
-
chatScrollOffset = -1;
|
|
14547
|
-
draw();
|
|
14548
|
-
return;
|
|
14549
|
-
}
|
|
14550
|
-
virtualWindows.router.dispatchArmed(ev);
|
|
14551
|
-
};
|
|
14552
|
-
const vwKey = (name: string, mods: Partial<DisplayKeyEvent> = {}): DisplayKeyEvent => ({
|
|
14553
|
-
name, ctrl: false, shift: false, alt: false, ...mods,
|
|
14554
|
-
});
|
|
14555
|
-
const registerVwChord = (id: string, key: string, ev: DisplayKeyEvent): void => {
|
|
14556
|
-
display.registerKeyBinding({
|
|
14557
|
-
id: `dashboard:vw-chord:${id}`,
|
|
14558
|
-
chordPrefix: VW_CHORD_PREFIX,
|
|
14559
|
-
key,
|
|
14560
|
-
scope: 'global',
|
|
14561
|
-
handler: () => vwBody(ev),
|
|
14562
|
-
});
|
|
14563
|
-
};
|
|
14564
12852
|
registerDashboardGlobalKeys({
|
|
14565
12853
|
enableSupplementalGlobalKeys: getUserConfig().dashboard.enableSupplementalGlobalKeys,
|
|
14566
12854
|
register: (binding) => { display.registerKeyBinding(binding); },
|
|
14567
12855
|
openSurfaceCatalog: () => openSurfaceCatalogPopup(),
|
|
14568
12856
|
surfaceCatalogWhen: () => agentSearchModal === null,
|
|
14569
|
-
dispatchVirtualWindowChord: vwBody,
|
|
14570
|
-
});
|
|
14571
|
-
// 1-9 / C-1..C-9 → switch to Nth window (router
|
|
14572
|
-
|
|
14573
|
-
// does the registry lookup internally).
|
|
14574
|
-
if (getUserConfig().dashboard.enableVirtualWindowSwitchKeys) {
|
|
14575
|
-
for (let n = 1; n <= 9; n++) {
|
|
14576
|
-
// Q4 (substrate Occam): no per-binding pipe alias. Plain digit
|
|
14577
|
-
// and Ctrl+digit are distinct chord bodies — register each.
|
|
14578
|
-
registerVwChord(`digit-${n}`, `${n}`, vwKey(`${n}`));
|
|
14579
|
-
registerVwChord(`ctrl-digit-${n}`, `C-${n}`, vwKey(`${n}`));
|
|
14580
|
-
}
|
|
14581
|
-
// Cycle next / previous — multiple aliases share a body action.
|
|
14582
|
-
registerVwChord('next-n', 'n', vwKey('n'));
|
|
14583
|
-
registerVwChord('next-dot', '.', vwKey('.'));
|
|
14584
|
-
registerVwChord('next-angle', '>', vwKey('>'));
|
|
14585
|
-
registerVwChord('prev-p', 'p', vwKey('p'));
|
|
14586
|
-
registerVwChord('prev-comma', ',', vwKey(','));
|
|
14587
|
-
registerVwChord('prev-angle', '<', vwKey('<'));
|
|
14588
|
-
}
|
|
14589
|
-
// Window lifecycle + toggles + splits + help + sync.
|
|
14590
|
-
registerVwChord('modal-toggle', 't', vwKey('t'));
|
|
14591
|
-
registerVwChord('hsplit-pct', '%', vwKey('%'));
|
|
14592
|
-
registerVwChord('hsplit-s', 's', vwKey('s'));
|
|
14593
|
-
registerVwChord('vsplit-quote', '"', vwKey('"'));
|
|
14594
|
-
registerVwChord('vsplit-v', 'v', vwKey('v'));
|
|
14595
|
-
registerVwChord('help', '?', vwKey('?'));
|
|
14596
|
-
registerVwChord('sync-input-bar', 'i', vwKey('i'));
|
|
14597
|
-
// Focus direction (arrow + vim).
|
|
14598
|
-
registerVwChord('focus-up', 'up|k', vwKey('up'));
|
|
14599
|
-
registerVwChord('focus-down', 'down|j', vwKey('down'));
|
|
14600
|
-
registerVwChord('focus-left', 'left|h', vwKey('left'));
|
|
14601
|
-
registerVwChord('focus-right', 'right|l', vwKey('right'));
|
|
14602
|
-
// VW-U5 — last-focused pane is registered by registerDashboardGlobalKeys.
|
|
14603
|
-
// VW-B1/B2 — rename chord bodies. Shift qualifier is accepted for
|
|
14604
|
-
// muscle-memory (`^B R` = `^B Shift+r` in many layouts).
|
|
14605
|
-
registerVwChord('rename-window', 'r|S-r', vwKey('r'));
|
|
14606
|
-
registerVwChord('rename-pane', 'S-a', vwKey('a', { shift: true }));
|
|
14607
|
-
|
|
14608
|
-
// N2 — `^B S` opens the shell-runner rollup popup (keyboard parity
|
|
14609
|
-
// with the mouse-clickable 🐚 pill). Shift-qualified to avoid
|
|
14610
|
-
// collision with `^B s` (hsplit); this convention matches VW-B1's
|
|
14611
|
-
// `^B R` rename-window.
|
|
14612
|
-
display.registerKeyBinding({
|
|
14613
|
-
id: 'dashboard:vw-chord:shell-rollup',
|
|
14614
|
-
chordPrefix: VW_CHORD_PREFIX,
|
|
14615
|
-
key: 'S-s',
|
|
14616
|
-
scope: 'global',
|
|
14617
|
-
handler: () => { void openShellRollupPopup(); },
|
|
14618
|
-
});
|
|
14619
|
-
|
|
14620
|
-
// Bundle B-9 — `^B h` toggles the focused pane's visibility in the
|
|
14621
|
-
// shared PaneVisualStateStore between `visible` and `hidden`. First
|
|
14622
|
-
// user-writable path into the store (the LLM `SetFocusPolicy` tool
|
|
14623
|
-
// from B-1 was the only writer before this). Alt+N window-skip
|
|
14624
|
-
// (B-7-α) already consumes the store, so hiding every pane in a
|
|
14625
|
-
// window removes it from the cycle. PLAN: PLAN-vw-term-bundle-b9-
|
|
14626
|
-
// visibility-user-toggle.md. Handler factory lives in
|
|
14627
|
-
// src/dashboard-vw-visibility-chord.ts for unit testability.
|
|
14628
|
-
display.registerKeyBinding({
|
|
14629
|
-
id: 'dashboard:vw-chord:visibility-toggle',
|
|
14630
|
-
chordPrefix: VW_CHORD_PREFIX,
|
|
14631
|
-
// `h` is already taken as the vim alias for focus-left
|
|
14632
|
-
// (`registerVwChord('focus-left', 'left|h', ...)`); use Shift+H
|
|
14633
|
-
// instead so the "H for Hide" mnemonic survives without collision.
|
|
14634
|
-
key: 'S-h',
|
|
14635
|
-
scope: 'global',
|
|
14636
|
-
handler: createVisibilityChordHandler({
|
|
14637
|
-
getCurrentWindow: () => {
|
|
14638
|
-
const w = virtualWindows.registry.current();
|
|
14639
|
-
return w ? { id: w.id, focused: w.focused } : null;
|
|
14640
|
-
},
|
|
14641
|
-
store: paneVisualStateStore,
|
|
14642
|
-
showToast: (title, lines) => {
|
|
14643
|
-
const { cols: tc, rows: tr } = termSize();
|
|
14644
|
-
showToast({ title, lines, coordinator: display, termCols: tc, termRows: tr, ttlMs: 1500 });
|
|
14645
|
-
try { draw(); } catch { /* TUI torn down */ }
|
|
14646
|
-
},
|
|
14647
|
-
}),
|
|
14648
|
-
});
|
|
14649
|
-
|
|
14650
|
-
// SP-D — `^B !` toggles the focused pane's focusPolicy between
|
|
14651
|
-
// 'output-only' and 'interactive'. Doesn't go through NavigationRouter
|
|
14652
|
-
// because the operation is pane-local, not window-level. Silent no-op
|
|
14653
|
-
// when the focused pane doesn't advertise a focusPolicy (plain chat/
|
|
14654
|
-
// markdown panes).
|
|
14655
|
-
display.registerKeyBinding({
|
|
14656
|
-
id: 'dashboard:vw-chord:focus-policy-toggle',
|
|
14657
|
-
chordPrefix: VW_CHORD_PREFIX,
|
|
14658
|
-
key: '!',
|
|
14659
|
-
scope: 'global',
|
|
14660
|
-
handler: () => {
|
|
14661
|
-
const { cols: tc, rows: tr } = termSize();
|
|
14662
|
-
const win = virtualWindows.registry.current();
|
|
14663
|
-
if (!win) {
|
|
14664
|
-
showToast({ title: 'focus policy', lines: ['no foreground window'], coordinator: display, termCols: tc, termRows: tr, ttlMs: 1500 });
|
|
14665
|
-
return;
|
|
14666
|
-
}
|
|
14667
|
-
const pane = win.getFocusedPane();
|
|
14668
|
-
type Togglable = {
|
|
14669
|
-
focusPolicy?: 'output-only' | 'interactive';
|
|
14670
|
-
setFocusPolicy?: (p: 'output-only' | 'interactive') => unknown;
|
|
14671
|
-
};
|
|
14672
|
-
const t = (pane ?? {}) as Togglable;
|
|
14673
|
-
if (!t.setFocusPolicy || !t.focusPolicy) {
|
|
14674
|
-
showToast({ title: 'focus policy', lines: ['pane has no focus policy'], coordinator: display, termCols: tc, termRows: tr, ttlMs: 1500 });
|
|
14675
|
-
return;
|
|
14676
|
-
}
|
|
14677
|
-
const next = t.focusPolicy === 'output-only' ? 'interactive' : 'output-only';
|
|
14678
|
-
t.setFocusPolicy(next);
|
|
14679
|
-
const label = pane ? win.getPaneDisplayTitle(pane.id) : '';
|
|
14680
|
-
showToast({
|
|
14681
|
-
title: 'focus policy',
|
|
14682
|
-
lines: [`${label || 'pane'} → ${next}`],
|
|
14683
|
-
coordinator: display,
|
|
14684
|
-
termCols: tc,
|
|
14685
|
-
termRows: tr,
|
|
14686
|
-
ttlMs: 1500,
|
|
14687
|
-
});
|
|
14688
|
-
try { draw(); } catch { /* TUI torn down */ }
|
|
14689
|
-
},
|
|
14690
|
-
});
|
|
14691
|
-
|
|
14692
|
-
// VW-U2 — chord-free Alt+N/P/1..9/0 fast-switch (helper in
|
|
14693
|
-
// src/dashboard-vw-fast-switch.ts so tests can exercise the
|
|
14694
|
-
// bindings without spinning up the whole dashboard).
|
|
14695
|
-
registerVwFastSwitchBindings({
|
|
14696
|
-
display,
|
|
14697
|
-
registry: virtualWindows.registry,
|
|
14698
|
-
openPicker: () => openWindowPicker(),
|
|
14699
|
-
enableWindowSwitchKeys: getUserConfig().dashboard.enableVirtualWindowSwitchKeys,
|
|
14700
|
-
// B-7-δ — expose the same PaneVisualStateStore the chord writer
|
|
14701
|
-
// (B-7-β) and badge reader (B-7-γ) consume, so Alt+o/Alt+O can
|
|
14702
|
-
// skip hidden/dormant panes within the current window.
|
|
14703
|
-
store: paneVisualStateStore,
|
|
14704
12857
|
});
|
|
14705
12858
|
|
|
14706
|
-
/** T2-P4 / T2-P5 — open the VW window picker. Called from the
|
|
14707
|
-
* NavigationRouter onPicker callback (^B 0) and from /window
|
|
14708
|
-
* picker. Empty-list short-circuit writes a hint to chatLines
|
|
14709
|
-
* so the user knows why nothing popped. Uses the same
|
|
14710
|
-
* agentSearchModal routing path as the agent-roster search
|
|
14711
|
-
* modal so the readKey loop forwards keys into it unchanged. */
|
|
14712
|
-
function openWindowPicker(): void {
|
|
14713
|
-
const currentWindow = virtualWindows.registry.current();
|
|
14714
|
-
const ownerWorkspaceId = currentWindow
|
|
14715
|
-
? workspaceOwnerIdForVirtualWindow(currentWindow.id)
|
|
14716
|
-
: DASHBOARD_MAIN_WORKSPACE_ID;
|
|
14717
|
-
openDashboardWindowPickerPopup({
|
|
14718
|
-
registry: virtualWindows.registry,
|
|
14719
|
-
ownerWorkspaceId,
|
|
14720
|
-
termSize,
|
|
14721
|
-
getTheme: () => currentThemeTokens(),
|
|
14722
|
-
pushModalSurface: (surface) => display.pushModal(surface),
|
|
14723
|
-
setAgentSearchModal: (modal) => {
|
|
14724
|
-
agentSearchModal = modal;
|
|
14725
|
-
},
|
|
14726
|
-
onEmptyWindows: () => {
|
|
14727
|
-
pushDebugLine(C.muted('No virtual windows. Use /window new (or WindowCreate tool) first.'));
|
|
14728
|
-
chatScrollOffset = -1;
|
|
14729
|
-
},
|
|
14730
|
-
onAcceptMain: () => {
|
|
14731
|
-
virtualWindows.registry.backgroundCurrent();
|
|
14732
|
-
setWorkingFocus(firstPaneOfView(workingDir.view), 'window-picker-main');
|
|
14733
|
-
},
|
|
14734
|
-
onAcceptWindow: (w) => {
|
|
14735
|
-
virtualWindows.registry.switchTo(w.id);
|
|
14736
|
-
},
|
|
14737
|
-
redraw: draw,
|
|
14738
|
-
});
|
|
14739
|
-
}
|
|
14740
|
-
|
|
14741
12859
|
function currentWorkspaceOwnerId(): string {
|
|
14742
|
-
|
|
14743
|
-
return currentWindow
|
|
14744
|
-
? workspaceOwnerIdForVirtualWindow(currentWindow.id)
|
|
14745
|
-
: DASHBOARD_MAIN_WORKSPACE_ID;
|
|
12860
|
+
return DASHBOARD_MAIN_WORKSPACE_ID;
|
|
14746
12861
|
}
|
|
14747
12862
|
|
|
14748
12863
|
function openSurfaceCatalogPopup(): void {
|
|
14749
|
-
const currentWindow = virtualWindows.registry.current();
|
|
14750
12864
|
void openCompactSurfaceCatalogPopup({
|
|
14751
12865
|
getTargets: () => compactSurfaceRuntime.buildTargets(),
|
|
14752
12866
|
openTarget: (surfaceId) => compactSurfaceRuntime.openTarget(surfaceId),
|
|
14753
|
-
ownerWorkspaceId:
|
|
14754
|
-
? workspaceOwnerIdForVirtualWindow(currentWindow.id)
|
|
14755
|
-
: DASHBOARD_MAIN_WORKSPACE_ID,
|
|
12867
|
+
ownerWorkspaceId: DASHBOARD_MAIN_WORKSPACE_ID,
|
|
14756
12868
|
termSize,
|
|
14757
12869
|
getTheme: () => currentThemeTokens(),
|
|
14758
12870
|
pushModalSurface: (surface) => display.pushModal(surface),
|
|
@@ -14773,24 +12885,15 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14773
12885
|
let shellRollupDispose: (() => void) | null = null;
|
|
14774
12886
|
async function openShellRollupPopup(): Promise<void> {
|
|
14775
12887
|
const { getShellRegistry } = await import('../shell-runner/registry.js');
|
|
14776
|
-
const currentWindow = virtualWindows.registry.current();
|
|
14777
12888
|
await openDashboardShellRollupPopup({
|
|
14778
12889
|
getShellRegistry,
|
|
14779
12890
|
getCurrentDispose: () => shellRollupDispose,
|
|
14780
12891
|
setCurrentDispose: (dispose) => {
|
|
14781
12892
|
shellRollupDispose = dispose;
|
|
14782
12893
|
},
|
|
14783
|
-
resolveVwIdByLabel: (
|
|
14784
|
-
|
|
14785
|
-
|
|
14786
|
-
return hit ? hit.id : null;
|
|
14787
|
-
},
|
|
14788
|
-
switchVirtualWindow: (windowId) => {
|
|
14789
|
-
virtualWindows.registry.switchTo(windowId);
|
|
14790
|
-
},
|
|
14791
|
-
ownerWorkspaceId: currentWindow
|
|
14792
|
-
? workspaceOwnerIdForVirtualWindow(currentWindow.id)
|
|
14793
|
-
: DASHBOARD_MAIN_WORKSPACE_ID,
|
|
12894
|
+
resolveVwIdByLabel: () => null,
|
|
12895
|
+
switchVirtualWindow: () => { throw new Error('Virtual windows are unavailable in the essential dashboard'); },
|
|
12896
|
+
ownerWorkspaceId: DASHBOARD_MAIN_WORKSPACE_ID,
|
|
14794
12897
|
termSize,
|
|
14795
12898
|
getTheme: () => currentThemeTokens(),
|
|
14796
12899
|
pushModalSurface: (surface) => display.pushModal(surface),
|
|
@@ -14806,108 +12909,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14806
12909
|
});
|
|
14807
12910
|
}
|
|
14808
12911
|
|
|
14809
|
-
/** VW-U4 — open the right-click pane/window selector popup. Called
|
|
14810
|
-
* from virtualWindows.registry's onShowSelector bridge. The popup
|
|
14811
|
-
* covers panes of the source VW + every other window; Enter switches,
|
|
14812
|
-
* Esc cancels. Uses the mouseWiring active-popup protocol (setting
|
|
14813
|
-
* `surface.onKey = handle.handleKey`) so coordinator.routeKey feeds
|
|
14814
|
-
* keys straight to the SelectView wrapper. */
|
|
14815
|
-
let vwSelectorDispose: (() => void) | null = null;
|
|
14816
|
-
function openVwSelectorPopup(windowId: number, col: number, row: number): void {
|
|
14817
|
-
// Close any previous popup so rapid right-clicks don't stack.
|
|
14818
|
-
if (vwSelectorDispose) {
|
|
14819
|
-
try { vwSelectorDispose(); } catch { /* ignore */ }
|
|
14820
|
-
vwSelectorDispose = null;
|
|
14821
|
-
}
|
|
14822
|
-
const { cols: tc, rows: tr } = termSize();
|
|
14823
|
-
const handle = createVwSelectorPopup({
|
|
14824
|
-
registry: virtualWindows.registry,
|
|
14825
|
-
sourceWindowId: windowId,
|
|
14826
|
-
col, row,
|
|
14827
|
-
termCols: tc,
|
|
14828
|
-
termRows: tr,
|
|
14829
|
-
onFocusPane: (w, p) => {
|
|
14830
|
-
const win = virtualWindows.registry.get(w);
|
|
14831
|
-
if (win) win.setFocus(p);
|
|
14832
|
-
draw();
|
|
14833
|
-
},
|
|
14834
|
-
onSwitchWindow: (w) => {
|
|
14835
|
-
virtualWindows.registry.switchTo(w);
|
|
14836
|
-
},
|
|
14837
|
-
onCancel: () => { draw(); },
|
|
14838
|
-
});
|
|
14839
|
-
if (!handle) return;
|
|
14840
|
-
handle.surface.onKey = (ev) => handle.handleKey(ev);
|
|
14841
|
-
const modalHandle = display.pushModal(handle.surface);
|
|
14842
|
-
vwSelectorDispose = () => {
|
|
14843
|
-
try { handle.dispose(); } catch { /* ignore */ }
|
|
14844
|
-
try { modalHandle.dispose(); } catch { /* ignore */ }
|
|
14845
|
-
};
|
|
14846
|
-
draw();
|
|
14847
|
-
}
|
|
14848
|
-
|
|
14849
|
-
let vwLocalInputTargetDispose: (() => void) | null = null;
|
|
14850
|
-
const vwLocalInputTargetState = new Map<number, { query: string; cursor: number }>();
|
|
14851
|
-
function openVwLocalInputTargetPopup(windowId: number, seedQuery?: string): void {
|
|
14852
|
-
openVwLocalInputTargetPopupLauncher({
|
|
14853
|
-
registry: virtualWindows.registry,
|
|
14854
|
-
windowId,
|
|
14855
|
-
seedQuery,
|
|
14856
|
-
stateStore: vwLocalInputTargetState,
|
|
14857
|
-
getCurrentDispose: () => vwLocalInputTargetDispose,
|
|
14858
|
-
setCurrentDispose: (dispose) => {
|
|
14859
|
-
vwLocalInputTargetDispose = dispose;
|
|
14860
|
-
},
|
|
14861
|
-
termSize,
|
|
14862
|
-
pushModalSurface: (surface) => {
|
|
14863
|
-
attachSurfaceToWorkspace(surface, currentWorkspaceOwnerId());
|
|
14864
|
-
return display.pushModal(surface);
|
|
14865
|
-
},
|
|
14866
|
-
onTargetPick: (target) => {
|
|
14867
|
-
const win = virtualWindows.registry.get(windowId);
|
|
14868
|
-
if (win) {
|
|
14869
|
-
win.setLocalInputTarget(target);
|
|
14870
|
-
win.consumeLocalComposerMentionTargetToken();
|
|
14871
|
-
}
|
|
14872
|
-
},
|
|
14873
|
-
redraw: draw,
|
|
14874
|
-
});
|
|
14875
|
-
}
|
|
14876
|
-
|
|
14877
|
-
/** VW-B1/B2 — shared helper that pops an input modal for renaming
|
|
14878
|
-
* either a window or a pane. Disposes any previous rename modal so
|
|
14879
|
-
* typing R twice just re-opens with the latest title. */
|
|
14880
|
-
let vwRenameDispose: (() => void) | null = null;
|
|
14881
|
-
function openVwRenameModal(opts: {
|
|
14882
|
-
title: string;
|
|
14883
|
-
current: string;
|
|
14884
|
-
onSubmit: (next: string) => void;
|
|
14885
|
-
onCancel?: () => void;
|
|
14886
|
-
}): void {
|
|
14887
|
-
openVwRenameModalLauncher({
|
|
14888
|
-
title: opts.title,
|
|
14889
|
-
current: opts.current,
|
|
14890
|
-
onSubmit: (next) => {
|
|
14891
|
-
vwRenameDispose = null;
|
|
14892
|
-
opts.onSubmit(next);
|
|
14893
|
-
},
|
|
14894
|
-
onCancel: () => {
|
|
14895
|
-
vwRenameDispose = null;
|
|
14896
|
-
opts.onCancel?.();
|
|
14897
|
-
},
|
|
14898
|
-
getCurrentDispose: () => vwRenameDispose,
|
|
14899
|
-
setCurrentDispose: (dispose) => {
|
|
14900
|
-
vwRenameDispose = dispose;
|
|
14901
|
-
},
|
|
14902
|
-
termSize,
|
|
14903
|
-
pushModalSurface: (surface) => {
|
|
14904
|
-
attachSurfaceToWorkspace(surface, currentWorkspaceOwnerId());
|
|
14905
|
-
return display.pushModal(surface);
|
|
14906
|
-
},
|
|
14907
|
-
redraw: draw,
|
|
14908
|
-
});
|
|
14909
|
-
}
|
|
14910
|
-
|
|
14911
12912
|
// Track which task ID the cursor is currently LOCKED onto across
|
|
14912
12913
|
// draws — prevents the cursor from visually sliding when the roster
|
|
14913
12914
|
// gets re-sorted with a new entry. Empty string = no lock.
|
|
@@ -15041,11 +13042,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15041
13042
|
return memoWidgetRuntime.readLines(widgetHost.get('wd-memo') as any);
|
|
15042
13043
|
};
|
|
15043
13044
|
const publishMemoLines = (lines: string[]): void => {
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
publishScratchSurface('dashboard:memo', 'preview', scratchTitle, scratchLines);
|
|
13045
|
+
scratchTitle = 'Memo';
|
|
13046
|
+
scratchLines = [...lines];
|
|
13047
|
+
scratchOffset = 0;
|
|
13048
|
+
publishScratchSurface('dashboard:memo', 'preview', scratchTitle, scratchLines);
|
|
15049
13049
|
};
|
|
15050
13050
|
const memoCompanionRuntime = createDashboardMemoCompanionRuntime({
|
|
15051
13051
|
readLines: readMemoWidgetLines,
|
|
@@ -15064,26 +13064,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15064
13064
|
memoCompanionRuntime.cancel();
|
|
15065
13065
|
chatScrollOffset = -1;
|
|
15066
13066
|
};
|
|
15067
|
-
const closeVwMemoCompanion = (windowId: number): void => {
|
|
15068
|
-
seedMemoWidget(['']);
|
|
15069
|
-
const host = companionSurfaceHosts.ensure(vwCompanionOwnerId(windowId), ['clipboard', 'memo', 'detail']);
|
|
15070
|
-
host.close('memo');
|
|
15071
|
-
};
|
|
15072
|
-
const commitVwMemoCompanion = (windowId: number): void => {
|
|
15073
|
-
const host = companionSurfaceHosts.ensure(vwCompanionOwnerId(windowId), ['clipboard', 'memo', 'detail']);
|
|
15074
|
-
const runtime = createDashboardMemoCompanionRuntime({
|
|
15075
|
-
readLines: readMemoWidgetLines,
|
|
15076
|
-
resetEditor: () => { seedMemoWidget(['']); },
|
|
15077
|
-
close: () => { host.close('memo'); },
|
|
15078
|
-
publishSaved: publishMemoLines,
|
|
15079
|
-
pushSavedLine: (lineCount) => { chatLines.push(companionFeedbackRuntime.memoSavedLine(lineCount)); },
|
|
15080
|
-
pushDiscardedLine: () => { chatLines.push(companionFeedbackRuntime.memoDiscardedLine()); },
|
|
15081
|
-
pushCancelledLine: () => { chatLines.push(companionFeedbackRuntime.memoCancelledLine()); },
|
|
15082
|
-
});
|
|
15083
|
-
runtime.commit();
|
|
15084
|
-
chatScrollOffset = -1;
|
|
15085
|
-
};
|
|
15086
|
-
|
|
15087
13067
|
// Repaint hook the active textInput populates so external draws
|
|
15088
13068
|
// (scratchpad refresh, async chafa render finishing) can ask the
|
|
15089
13069
|
// prompt to re-paint itself afterwards. While input is idle this
|
|
@@ -15135,8 +13115,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15135
13115
|
requestRender: () => { requestDashboardRender('detail'); },
|
|
15136
13116
|
});
|
|
15137
13117
|
const companionWidgetRuntime = createDashboardCompanionWidgetRuntime();
|
|
15138
|
-
const scratchWidgetRuntime = createDashboardScratchWidgetRuntime();
|
|
15139
|
-
const scratchStateRuntime = createDashboardScratchStateRuntime();
|
|
15140
13118
|
const clipboardHistoryRuntime = createDashboardClipboardHistoryRuntime();
|
|
15141
13119
|
const memoWidgetRuntime = createDashboardMemoWidgetRuntime();
|
|
15142
13120
|
const logWidgetRuntime = createDashboardLogWidgetRuntime();
|
|
@@ -15479,26 +13457,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15479
13457
|
* display coordinator. The coordinator coalesces this with any
|
|
15480
13458
|
* plugin/widget updates and repaints the prompt after the frame. */
|
|
15481
13459
|
const setScratch = (title: string, lines: string[]): void => {
|
|
15482
|
-
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
scratchOffset = next.offset;
|
|
13460
|
+
scratchTitle = title;
|
|
13461
|
+
scratchLines = [...lines];
|
|
13462
|
+
scratchOffset = 0;
|
|
15486
13463
|
publishScratchSurface('dashboard:scratch', 'preview', title, scratchLines);
|
|
15487
13464
|
};
|
|
15488
13465
|
|
|
15489
|
-
const currentScratchForCommand = (): { title: string; lines: string[] } => {
|
|
15490
|
-
return scratchStateRuntime.resolveCommandSnapshot(display.scratchState(), {
|
|
15491
|
-
title: scratchTitle,
|
|
15492
|
-
lines: scratchLines,
|
|
15493
|
-
});
|
|
15494
|
-
};
|
|
15495
|
-
|
|
15496
|
-
const { setScratchImage, setScratchFile } = createRichScratchViewers({
|
|
15497
|
-
setDetailViewer,
|
|
15498
|
-
termSize,
|
|
15499
|
-
fmtBytes,
|
|
15500
|
-
});
|
|
15501
|
-
|
|
15502
13466
|
// ── Execute sync inline (output to log pane) ──
|
|
15503
13467
|
const runSyncInline = async (
|
|
15504
13468
|
sk: string[] = [...sync.selected[0]!],
|
|
@@ -17314,8 +15278,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17314
15278
|
}
|
|
17315
15279
|
|
|
17316
15280
|
// Ctrl+W (no chord armed — chord would have consumed the
|
|
17317
|
-
// key earlier) closes the scratch pane. Reopen via
|
|
17318
|
-
// /scratch open or the ^B ^S chord target.
|
|
15281
|
+
// key earlier) closes the scratch pane. Reopen via the ^B ^S chord.
|
|
17319
15282
|
if (key.ctrl && (key.name === 'w' || key.name === 'ㅈ')) {
|
|
17320
15283
|
scratchClosed = true;
|
|
17321
15284
|
userClosedPanes.add('scratch');
|
|
@@ -17415,8 +15378,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17415
15378
|
).persistToolOutputPreview;
|
|
17416
15379
|
acpPtyAvailable = (await import('../pty-shell/registry.js')).ptyAvailable;
|
|
17417
15380
|
const dashboardAcpBootResult = await bootDashboardAcpSession({
|
|
17418
|
-
...(opts.remote ? {
|
|
17419
|
-
|
|
15381
|
+
...(opts.remote ? {
|
|
15382
|
+
remote: opts.remote,
|
|
15383
|
+
onRemoteDisconnect: () => {
|
|
15384
|
+
pushChatLine(C.warning(' ⚠ 데몬 연결이 끊겼다 · 입력 중인 글은 그대로다 · 다시 붙으려면 TUI 를 다시 띄워라'));
|
|
15385
|
+
draw();
|
|
15386
|
+
},
|
|
15387
|
+
} : {}),
|
|
17420
15388
|
...(opts.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {}),
|
|
17421
15389
|
getCwd: () => getSessionCwd(),
|
|
17422
15390
|
getChatHistory: () => chat.history,
|
|
@@ -17437,7 +15405,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17437
15405
|
pluginTools: pluginHost.activePluginLLMTools(),
|
|
17438
15406
|
optionalTools: acpTurnRef.optionalSpecs,
|
|
17439
15407
|
surface: acpTurnRef.turnProfile?.surface,
|
|
17440
|
-
rich:
|
|
15408
|
+
rich: false,
|
|
17441
15409
|
})
|
|
17442
15410
|
: [];
|
|
17443
15411
|
return buildDashboardTurnPreamble({
|
|
@@ -17451,7 +15419,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17451
15419
|
// codex-only behavioral addendum (fix L-1) inside the
|
|
17452
15420
|
// universal preamble.
|
|
17453
15421
|
modelFamily: getModelFamily(inspectActiveProvider().model),
|
|
17454
|
-
rich:
|
|
15422
|
+
rich: false,
|
|
17455
15423
|
enabledTools: tools.map(t => t.name),
|
|
17456
15424
|
});
|
|
17457
15425
|
},
|
|
@@ -17465,7 +15433,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17465
15433
|
pluginTools: pluginHost.activePluginLLMTools(),
|
|
17466
15434
|
optionalTools: acpTurnRef.optionalSpecs,
|
|
17467
15435
|
surface: acpTurnRef.turnProfile?.surface,
|
|
17468
|
-
rich:
|
|
15436
|
+
rich: false,
|
|
17469
15437
|
});
|
|
17470
15438
|
// ⭐ Remember this turn's catalog so a spawned sub-agent can inherit it.
|
|
17471
15439
|
//
|
|
@@ -17630,18 +15598,16 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17630
15598
|
try { acpSessionIdRef.current = dashboardAcpSession.currentSessionId ?? null; } catch { /* 없으면 넣지 않는다 */ }
|
|
17631
15599
|
pushDebugLine(C.muted('[acp-boot] dashboard ACP session ready'));
|
|
17632
15600
|
// User-visible mode indicator. Without this, a user who set
|
|
17633
|
-
// ELANOUS_REMOTE
|
|
17634
|
-
//
|
|
15601
|
+
// ELANOUS_REMOTE has no way to tell whether the
|
|
15602
|
+
// attach actually succeeded — the attached daemon mode is useful
|
|
17635
15603
|
// chat transcript context, but the local in-process fallback is
|
|
17636
15604
|
// runtime plumbing and belongs in the debug log instead.
|
|
17637
15605
|
if (opts.remote) {
|
|
17638
15606
|
const authNote = opts.remote.token ? 'token' : 'no-auth';
|
|
17639
15607
|
const labelNote = opts.remote.label ? ` · ${opts.remote.label}` : '';
|
|
17640
15608
|
chatLines.push(C.success(` ✓ attached to remote daemon: ${opts.remote.url} (${authNote})${labelNote}`));
|
|
17641
|
-
} else if (opts.localDaemon) {
|
|
17642
|
-
chatLines.push(C.success(` ✓ attached to local daemon: ${opts.localDaemon.socketPath}`));
|
|
17643
15609
|
} else {
|
|
17644
|
-
pushDebugLine(C.muted(' in-process ACP (no daemon attach · set ELANOUS_REMOTE
|
|
15610
|
+
pushDebugLine(C.muted(' in-process ACP (no daemon attach · set ELANOUS_REMOTE to attach)'));
|
|
17645
15611
|
}
|
|
17646
15612
|
// Tier 1 daemon-resume status. Three branches:
|
|
17647
15613
|
// - resumed: attachExisting succeeded · the daemon's prior
|
|
@@ -17655,9 +15621,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17655
15621
|
if (dashboardAcpBootResult.mode === 'resumed' && dashboardAcpBootResult.sessionId) {
|
|
17656
15622
|
const sid = dashboardAcpBootResult.sessionId;
|
|
17657
15623
|
chatLines.push(C.success(` ✓ resumed daemon session: ${sid}`));
|
|
17658
|
-
// Best-effort REST history replay
|
|
17659
|
-
// path has a derivable HTTP base. Local-daemon (unix socket)
|
|
17660
|
-
// can't fetch over REST today; that's a follow-up.
|
|
15624
|
+
// Best-effort REST history replay over the remote HTTP/WS endpoint.
|
|
17661
15625
|
if (opts.remote) {
|
|
17662
15626
|
const httpBase = deriveDaemonHttpBase(opts.remote.url);
|
|
17663
15627
|
if (httpBase) {
|
|
@@ -17693,8 +15657,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17693
15657
|
chatLines.push(C.muted(` no prior turns found for ${sid}.`));
|
|
17694
15658
|
}
|
|
17695
15659
|
}
|
|
17696
|
-
} else {
|
|
17697
|
-
chatLines.push(C.muted(' (history replay over unix socket is a follow-up — REST endpoint required)'));
|
|
17698
15660
|
}
|
|
17699
15661
|
} else if (dashboardAcpBootResult.mode === 'new' && dashboardAcpBootResult.resumeFallbackReason) {
|
|
17700
15662
|
// The user asked to resume but the daemon rejected the id —
|
|
@@ -17704,7 +15666,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17704
15666
|
const reason = dashboardAcpBootResult.resumeFallbackReason;
|
|
17705
15667
|
const newId = dashboardAcpBootResult.sessionId ?? '(unknown)';
|
|
17706
15668
|
chatLines.push(C.warning(` ⚠ resume failed (${reason}); started new session: ${newId}`));
|
|
17707
|
-
} else if (opts.resumeSessionId && !opts.remote
|
|
15669
|
+
} else if (opts.resumeSessionId && !opts.remote) {
|
|
17708
15670
|
// Match `/session load <prefix>` for in-process boot: resolve the
|
|
17709
15671
|
// local prefix, preserve the stock system prompt, and attach the
|
|
17710
15672
|
// restored session for subsequent persistence.
|
|
@@ -17746,6 +15708,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17746
15708
|
const key: import('../tui.js').Key = wdAutoInput
|
|
17747
15709
|
? { name: CHAT_MAIN_AUTO_ENTRY_KEY_NAME, ctrl: false, shift: false }
|
|
17748
15710
|
: await readKey();
|
|
15711
|
+
const helpModal = currentTransientTerminalModal('dashboard-help');
|
|
15712
|
+
if (key.name === 'escape' && helpModal) {
|
|
15713
|
+
helpModal.dispose();
|
|
15714
|
+
draw();
|
|
15715
|
+
continue;
|
|
15716
|
+
}
|
|
17749
15717
|
|
|
17750
15718
|
// U-0 · recompute ViewMode at the top of every key dispatch
|
|
17751
15719
|
// loop iteration. This is the one natural "mode re-evaluation"
|
|
@@ -17823,13 +15791,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17823
15791
|
&& voiceHostFlow.getState().kind === 'idle'
|
|
17824
15792
|
&& workingDir.focus !== 'input'
|
|
17825
15793
|
) {
|
|
17826
|
-
const focusedTerminalPane =
|
|
17827
|
-
try {
|
|
17828
|
-
const vw = virtualWindows?.registry.current();
|
|
17829
|
-
const pane = vw?.getFocusedPane();
|
|
17830
|
-
return pane?.kind === 'terminal' || pane?.kind === 'terminal-slot';
|
|
17831
|
-
} catch { return false; }
|
|
17832
|
-
})();
|
|
15794
|
+
const focusedTerminalPane = false;
|
|
17833
15795
|
|
|
17834
15796
|
// Branch 1 — Ctrl+Shift+D trial chord. TEMP DEBUG (2026-04-29):
|
|
17835
15797
|
// toggle pattern instead of long-press detector. First press
|
|
@@ -18069,23 +16031,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18069
16031
|
if (result === 'closed') draw();
|
|
18070
16032
|
return true;
|
|
18071
16033
|
},
|
|
18072
|
-
routeVwTerminalKey: (routeKey) => {
|
|
18073
|
-
// Claim when the foreground VW's focused pane is a live
|
|
18074
|
-
// terminal — forward the key directly to the pane's PTY
|
|
18075
|
-
// and skip every later step (input-core, chord, global,
|
|
18076
|
-
// layout). The pane's onKey returns an Action; we only
|
|
18077
|
-
// care about triggering a redraw on 'refresh'.
|
|
18078
|
-
const vw = virtualWindows.registry.current();
|
|
18079
|
-
if (!vw) return false;
|
|
18080
|
-
const focusedPane = vw.getFocusedPane();
|
|
18081
|
-
if (!focusedPane) return false;
|
|
18082
|
-
const isTerminalKind = focusedPane.kind === 'terminal' || focusedPane.kind === 'terminal-slot';
|
|
18083
|
-
if (!isTerminalKind) return false;
|
|
18084
|
-
const ev = toDashboardKeyEvent(routeKey);
|
|
18085
|
-
const action = focusedPane.onKey(ev);
|
|
18086
|
-
if (action.type === 'refresh') draw();
|
|
18087
|
-
return true;
|
|
18088
|
-
},
|
|
18089
16034
|
routeArmedChordKey: async (routeKey) => {
|
|
18090
16035
|
if (!isChordArmed(chord)) return false;
|
|
18091
16036
|
disarmChordHud();
|
|
@@ -18134,44 +16079,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18134
16079
|
if (routeKey.name === 'ㅃ') return true;
|
|
18135
16080
|
return false;
|
|
18136
16081
|
},
|
|
18137
|
-
// Step 0a — Alt+W close. Replaces the removed Ctrl+Shift+T close
|
|
18138
|
-
// chord (which collided with shell-level Ctrl+T finders). Fires
|
|
18139
|
-
// from popup terminal modal AND VW with terminal pane focused.
|
|
18140
|
-
// Korean ㅈ is the W-position jamo on 2-bul, included for IME
|
|
18141
|
-
// parity. Does nothing when neither a popup nor a VW-terminal
|
|
18142
|
-
// is active — the chord is targeted at popup-style surfaces.
|
|
18143
|
-
routePopupCloseChord: (routeKey) => {
|
|
18144
|
-
if (!routeKey.alt) return false;
|
|
18145
|
-
const isW = routeKey.name === 'w' || routeKey.name === 'W' || routeKey.name === 'ㅈ';
|
|
18146
|
-
if (!isW) return false;
|
|
18147
|
-
// Popup terminal modal close
|
|
18148
|
-
if (terminalModalRouter.current() !== null) {
|
|
18149
|
-
if (debug.enabled) {
|
|
18150
|
-
debug.log('window.terminalModalRouter.handleKey.close', 'alt-w', {
|
|
18151
|
-
id: terminalModalRouter.current()?.id,
|
|
18152
|
-
});
|
|
18153
|
-
}
|
|
18154
|
-
terminalModalRouter.close();
|
|
18155
|
-
draw();
|
|
18156
|
-
return true;
|
|
18157
|
-
}
|
|
18158
|
-
// VW with terminal pane focused — close the VW
|
|
18159
|
-
const vwForClose = virtualWindows.registry.current();
|
|
18160
|
-
if (vwForClose) {
|
|
18161
|
-
const focusedPane = vwForClose.getFocusedPane();
|
|
18162
|
-
if (focusedPane && (focusedPane.kind === 'terminal' || focusedPane.kind === 'terminal-slot')) {
|
|
18163
|
-
if (debug.enabled) {
|
|
18164
|
-
debug.log('window.vw.close', 'alt-w', {
|
|
18165
|
-
windowId: vwForClose.id, paneKind: focusedPane.kind,
|
|
18166
|
-
});
|
|
18167
|
-
}
|
|
18168
|
-
virtualWindows.registry.close(vwForClose.id);
|
|
18169
|
-
draw();
|
|
18170
|
-
return true;
|
|
18171
|
-
}
|
|
18172
|
-
}
|
|
18173
|
-
return false;
|
|
18174
|
-
},
|
|
18175
16082
|
// PR-S1V.4-wiring · Step 0x — voice mode entry chord.
|
|
18176
16083
|
// Fires only when voice mode is currently `idle`; once active
|
|
18177
16084
|
// the next step (routeVoiceModeKey) takes over. Skipping when
|
|
@@ -18206,7 +16113,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18206
16113
|
// experiment/voice-chat-realtime-rebind · Step 0s — modal-A
|
|
18207
16114
|
// swallow while voice-chat is active. Returns true when the
|
|
18208
16115
|
// controller is non-idle so any key not already claimed above
|
|
18209
|
-
// (force-quit · Alt+W ·
|
|
16116
|
+
// (force-quit · Alt+W · chord toggle) is consumed
|
|
18210
16117
|
// — typing doesn't leak into chat input, Space doesn't toggle
|
|
18211
16118
|
// pickers, etc. ESC explicitly exits. Idle controller returns
|
|
18212
16119
|
// false so legacy dispatch is reachable.
|
|
@@ -18322,36 +16229,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18322
16229
|
})();
|
|
18323
16230
|
return true;
|
|
18324
16231
|
},
|
|
18325
|
-
// Step 0b — Alt+digit VW switch. Single-keystroke window
|
|
18326
|
-
// navigation that survives the popup-terminal / VW-terminal
|
|
18327
|
-
// priority forwarding. Alt+1 → 1st VW (sorted ascending by
|
|
18328
|
-
// numeric id), Alt+2 → 2nd, …, Alt+9 → 9th. Alt+0 is
|
|
18329
|
-
// intentionally omitted (digit-argument convention conflict
|
|
18330
|
-
// is rare; reserve for future use).
|
|
18331
|
-
routeVwSwitchChord: (routeKey) => {
|
|
18332
|
-
if (!routeKey.alt) return false;
|
|
18333
|
-
if (routeKey.name.length !== 1) return false;
|
|
18334
|
-
const digit = routeKey.name.charCodeAt(0);
|
|
18335
|
-
if (digit < 0x31 || digit > 0x39) return false; // '1' .. '9'
|
|
18336
|
-
const ordinal = digit - 0x30; // 1..9
|
|
18337
|
-
const windows = virtualWindows.registry.list().sort((a, b) => a.id - b.id);
|
|
18338
|
-
const target = windows[ordinal - 1];
|
|
18339
|
-
if (!target) {
|
|
18340
|
-
if (debug.enabled) {
|
|
18341
|
-
debug.log('window.vw.switch.miss', `alt-${ordinal}`, {
|
|
18342
|
-
ordinal, windowCount: windows.length,
|
|
18343
|
-
});
|
|
18344
|
-
}
|
|
18345
|
-
return true; // claim anyway so it doesn't leak to the child
|
|
18346
|
-
}
|
|
18347
|
-
if (debug.enabled) {
|
|
18348
|
-
debug.log('window.vw.switch', `alt-${ordinal}`, {
|
|
18349
|
-
ordinal, targetId: target.id,
|
|
18350
|
-
});
|
|
18351
|
-
}
|
|
18352
|
-
virtualWindows.registry.switchTo(target.id);
|
|
18353
|
-
return true;
|
|
18354
|
-
},
|
|
18355
16232
|
// Step 6 hard-quit — only reached when no popup terminal is
|
|
18356
16233
|
// active. Plain Ctrl+Q stays as the dashboard-mode shortcut
|
|
18357
16234
|
// so muscle memory survives outside the popup. Inside the
|
|
@@ -18359,12 +16236,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18359
16236
|
// to force-quit instead).
|
|
18360
16237
|
isHardQuitKey: (routeKey) => routeKey.ctrl && !routeKey.shift && (routeKey.name === 'q' || routeKey.name === 'ㅂ'),
|
|
18361
16238
|
matchGlobalAction: (routeKey) => matchTextInputGlobalAction(routeKey, {
|
|
18362
|
-
allowSpawnTerminalModal:
|
|
18363
|
-
|
|
18364
|
-
&& (previewTerminal as PreviewTerminal).isAlive),
|
|
18365
|
-
allowToggleLogZoom: !(workingDir.focus === 'preview'
|
|
18366
|
-
&& previewTerminal
|
|
18367
|
-
&& (previewTerminal as PreviewTerminal).isAlive),
|
|
16239
|
+
allowSpawnTerminalModal: false,
|
|
16240
|
+
allowToggleLogZoom: false,
|
|
18368
16241
|
}),
|
|
18369
16242
|
runGlobalAction: async (action) => {
|
|
18370
16243
|
await runChatMainGlobalAction(action);
|
|
@@ -18828,8 +16701,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18828
16701
|
initialText: inputEntry?.initialText ?? null,
|
|
18829
16702
|
visibility: chatMainInputVisibilityState(),
|
|
18830
16703
|
topBlockingForegroundModal: topBlockingForegroundModal()?.id ?? null,
|
|
18831
|
-
currentVwId:
|
|
18832
|
-
currentVwHostChromeProfile:
|
|
16704
|
+
currentVwId: null,
|
|
16705
|
+
currentVwHostChromeProfile: null,
|
|
18833
16706
|
});
|
|
18834
16707
|
}
|
|
18835
16708
|
if (inputEntry) {
|
|
@@ -18910,10 +16783,20 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18910
16783
|
: '/quit /clear (run `elanous setup` — no LLM provider available)',
|
|
18911
16784
|
debugLog: debug.enabled ? (event, label, payload) => debug.log(event, label, payload) : undefined,
|
|
18912
16785
|
textInputOpts: {
|
|
16786
|
+
onScrollKey: (name) => {
|
|
16787
|
+
const { rows } = termSize();
|
|
16788
|
+
const viewport = computePromptFrameLogViewportBounds(
|
|
16789
|
+
rows, computePaneH(rows), getLayoutPromptFrame(rows),
|
|
16790
|
+
);
|
|
16791
|
+
chatScrollOffset = nextChatScrollOffset(
|
|
16792
|
+
chatScrollOffset, name, Math.max(1, viewport.height),
|
|
16793
|
+
Math.max(0, chatLines.length - viewport.height),
|
|
16794
|
+
);
|
|
16795
|
+
draw();
|
|
16796
|
+
},
|
|
18913
16797
|
// TUI 부활 후속 — Esc·Esc = /rewind 픽커 (codex backtrack
|
|
18914
16798
|
// 제스처 · resolveEscEscRewind 순수 판정). 빈 버퍼에서만
|
|
18915
|
-
// prime · 1.5s
|
|
18916
|
-
// 하므로 사실상 essential 전용(의도). 힌트는 세션 1회.
|
|
16799
|
+
// prime · 1.5s 창. 힌트는 세션 1회.
|
|
18917
16800
|
onEscape: (bufferText) => {
|
|
18918
16801
|
const decision = resolveEscEscRewind({
|
|
18919
16802
|
bufferText: bufferText ?? '',
|
|
@@ -19216,6 +17099,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19216
17099
|
hasActiveStatusPopup: () => mouseWiring.hasActivePopup(),
|
|
19217
17100
|
hasTerminalModal: () => terminalModalRouter.current() !== null,
|
|
19218
17101
|
shouldRouteForegroundModalKey: (key) => {
|
|
17102
|
+
if (key.name === 'escape' && currentTransientTerminalModal('dashboard-help')) return true;
|
|
19219
17103
|
const topModalId = display.modalStack().at(-1) ?? null;
|
|
19220
17104
|
const topModal = topModalId ? display.surface(topModalId) : null;
|
|
19221
17105
|
const topModalSurface =
|
|
@@ -19242,7 +17126,17 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19242
17126
|
toKeyEvent: toDashboardKeyEvent,
|
|
19243
17127
|
routeStatusPopupKey: key => mouseWiring.routeKey(key as never),
|
|
19244
17128
|
handleTerminalModalKey: keyEvent => terminalModalRouter.handleKey(keyEvent),
|
|
19245
|
-
tryRouteForegroundModalKey: keyEvent =>
|
|
17129
|
+
tryRouteForegroundModalKey: async keyEvent => {
|
|
17130
|
+
if (keyEvent.name === 'escape') {
|
|
17131
|
+
const helpModal = currentTransientTerminalModal('dashboard-help');
|
|
17132
|
+
if (helpModal) {
|
|
17133
|
+
helpModal.dispose();
|
|
17134
|
+
draw();
|
|
17135
|
+
return 'consumed';
|
|
17136
|
+
}
|
|
17137
|
+
}
|
|
17138
|
+
return display.tryRouteKeyToTopModalAsync(keyEvent);
|
|
17139
|
+
},
|
|
19246
17140
|
redraw: draw,
|
|
19247
17141
|
dispatchMouse: runTextInputOnMouseUnifiedDispatch,
|
|
19248
17142
|
}),
|
|
@@ -19604,6 +17498,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19604
17498
|
closeTui,
|
|
19605
17499
|
exitTui: exitDashboardTui,
|
|
19606
17500
|
showHelp,
|
|
17501
|
+
showHelpModal: ({ title, lines }) => {
|
|
17502
|
+
const { cols, rows } = termSize();
|
|
17503
|
+
showTransientTerminalModal({ title, lines: [...lines], coordinator: display, termCols: cols, termRows: rows, ttlMs: 0, group: 'dashboard-help' });
|
|
17504
|
+
},
|
|
19607
17505
|
clearLogSearch,
|
|
19608
17506
|
clearLogFilter,
|
|
19609
17507
|
forkAttachedSessionFromChatHistory,
|
|
@@ -19628,6 +17526,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19628
17526
|
controlSignalSlashRuntime,
|
|
19629
17527
|
browserCdpSlashRuntime,
|
|
19630
17528
|
widgetHost,
|
|
17529
|
+
backgroundTasksTextOnly: true,
|
|
19631
17530
|
widgetModalPopup: {
|
|
19632
17531
|
open: (s) => {
|
|
19633
17532
|
// Wave P4b-1 — bridge slash → widget-modal-popup.
|
|
@@ -19684,10 +17583,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19684
17583
|
attachClipboardImage,
|
|
19685
17584
|
setNextInitial: (token) => { nextInitial = token; },
|
|
19686
17585
|
},
|
|
19687
|
-
uiModeSlash: {
|
|
19688
|
-
getMode: () => dashboardUiMode,
|
|
19689
|
-
setMode: (mode) => { applyDashboardUiMode(mode, { persist: true, announce: true }); },
|
|
19690
|
-
},
|
|
19691
17586
|
sessionResume: {
|
|
19692
17587
|
openPicker: () => { openSessionResumePicker(); },
|
|
19693
17588
|
},
|
|
@@ -19709,23 +17604,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19709
17604
|
refresh: refreshInputHistory,
|
|
19710
17605
|
openDetailViewer: (title, lines) => { setDetailViewer(title, lines); },
|
|
19711
17606
|
},
|
|
19712
|
-
terminal: {
|
|
19713
|
-
fullscreenMissingLine: () => termSlashRuntime.fullscreenMissingLine(),
|
|
19714
|
-
showFullscreenToast: (opts) => {
|
|
19715
|
-
const { cols: tc, rows: tr } = termSize();
|
|
19716
|
-
showToast({ title: opts.title, lines: opts.lines, coordinator: display, termCols: tc, termRows: tr });
|
|
19717
|
-
},
|
|
19718
|
-
},
|
|
19719
17607
|
undo: {
|
|
19720
17608
|
refreshGitDirty: () => { refreshGitDirty(getSessionCwd(), { force: true }); },
|
|
19721
17609
|
bold: C.bold,
|
|
19722
17610
|
},
|
|
19723
|
-
ptyPane: {
|
|
19724
|
-
spawnPtyTailWindow: (opts) => virtualWindows.registry.spawn({
|
|
19725
|
-
title: opts.title,
|
|
19726
|
-
initialContent: { kind: 'pty-tail', ptyId: opts.ptyId },
|
|
19727
|
-
}),
|
|
19728
|
-
},
|
|
19729
17611
|
delta: {
|
|
19730
17612
|
openBrowserPopup: (scope, limit, browserMode) =>
|
|
19731
17613
|
openSourceDeltaBrowserPopup(scope, limit, browserMode),
|
|
@@ -19800,24 +17682,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19800
17682
|
},
|
|
19801
17683
|
compact: {
|
|
19802
17684
|
getHistory: () => chat.history as unknown as { role: string; [k: string]: unknown }[],
|
|
19803
|
-
compactBoundaryEnabled: () => getUserConfig().chat.rendering.compactBoundary.enabled,
|
|
19804
17685
|
},
|
|
19805
17686
|
skill: {
|
|
19806
17687
|
triggersSlashRuntime: skillTriggersSlashRuntime,
|
|
19807
17688
|
runSlashRuntime: runSkillSlashRuntime,
|
|
19808
17689
|
runByName: (name, skillArgs) => runSkillByName(name, skillArgs),
|
|
19809
17690
|
},
|
|
19810
|
-
bench: {
|
|
19811
|
-
slashRuntime: benchSlashRuntime,
|
|
19812
|
-
spawn: (spec) => spawnLLMBenchmark(
|
|
19813
|
-
{ prompt: spec.prompt, providers: [...spec.providers] },
|
|
19814
|
-
{
|
|
19815
|
-
registry: virtualWindows.registry,
|
|
19816
|
-
eventBus: virtualWindows.bus,
|
|
19817
|
-
addressBook: virtualWindows.book,
|
|
19818
|
-
},
|
|
19819
|
-
),
|
|
19820
|
-
},
|
|
19821
17691
|
setup: {
|
|
19822
17692
|
launchPopup: (cmd) => {
|
|
19823
17693
|
const session = TerminalPopup.shell()
|
|
@@ -19902,40 +17772,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19902
17772
|
focusPopup: (direction) => focusConversationPopup(direction),
|
|
19903
17773
|
openModal: (sessionId) => openConversationModal(sessionId),
|
|
19904
17774
|
},
|
|
19905
|
-
scratch: {
|
|
19906
|
-
slashRuntime: scratchSlashRuntime,
|
|
19907
|
-
isClosed: () => scratchClosed,
|
|
19908
|
-
open: () => {
|
|
19909
|
-
scratchClosed = false;
|
|
19910
|
-
userClosedPanes.delete('scratch');
|
|
19911
|
-
setWorkingFocus('scratch', 'slash-scratch-open');
|
|
19912
|
-
},
|
|
19913
|
-
close: () => {
|
|
19914
|
-
scratchClosed = true;
|
|
19915
|
-
userClosedPanes.add('scratch');
|
|
19916
|
-
if (workingDir.focus === 'scratch') {
|
|
19917
|
-
applyFocusToPaneTransition(resolveFocusToPaneTransition({
|
|
19918
|
-
targetPane: 'log',
|
|
19919
|
-
reason: 'slash-scratch-close',
|
|
19920
|
-
}));
|
|
19921
|
-
}
|
|
19922
|
-
},
|
|
19923
|
-
clear: () => { setScratch('', []); },
|
|
19924
|
-
currentForCommand: () => currentScratchForCommand(),
|
|
19925
|
-
snapshotForAppend: () => ({ title: scratchTitle, lines: scratchLines }),
|
|
19926
|
-
setText: (title, lines) => { setScratch(title, [...lines]); },
|
|
19927
|
-
buildDumpLines: (lines) => buildDashboardScratchDumpLines([...lines]),
|
|
19928
|
-
popup: {
|
|
19929
|
-
open: () => { setCompanionPopupOpen('scratch', true); },
|
|
19930
|
-
close: () => { setCompanionPopupOpen('scratch', false); },
|
|
19931
|
-
toggle: () => toggleCompanionPopup('scratch'),
|
|
19932
|
-
promote: () => { promoteCompanionPopup('scratch'); },
|
|
19933
|
-
},
|
|
19934
|
-
openMemo: () => { openMemoCompanion(); },
|
|
19935
|
-
},
|
|
19936
17775
|
sim: {
|
|
19937
17776
|
slashRuntime: simSlashRuntime,
|
|
19938
|
-
spawnVirtualWindow: () => spawnSimVirtualWindow(),
|
|
19939
17777
|
openWebCockpit: () => openDashboardSimulationWebCockpit(),
|
|
19940
17778
|
listScenarios: () => listDashboardSimulationScenarios(),
|
|
19941
17779
|
runById: (scenarioId) => runDashboardSimulationById(scenarioId as Parameters<typeof runDashboardSimulationById>[0]),
|
|
@@ -19959,39 +17797,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19959
17797
|
return aliases.get(target) ?? null;
|
|
19960
17798
|
},
|
|
19961
17799
|
},
|
|
19962
|
-
view: {
|
|
19963
|
-
slashRuntime: viewSlashRuntime,
|
|
19964
|
-
buildListItems: () => viewRegistry.allViews.map((v) => ({
|
|
19965
|
-
active: activeViewId === v.id,
|
|
19966
|
-
id: v.id,
|
|
19967
|
-
label: v.label,
|
|
19968
|
-
enabled: v.enabled,
|
|
19969
|
-
shortcut: v.shortcut,
|
|
19970
|
-
// List-entry contract types baseView as a display string;
|
|
19971
|
-
// the registry holds it as a WorkingDirView number.
|
|
19972
|
-
baseView: String(v.baseView),
|
|
19973
|
-
})),
|
|
19974
|
-
closedPaneLabels: () => closedStarterPanes().map((pane) => paneLabel(pane)),
|
|
19975
|
-
next: () => { setActiveDashboardView(nextDashboardView(viewRegistry, activeViewId, 1)); },
|
|
19976
|
-
prev: () => { setActiveDashboardView(nextDashboardView(viewRegistry, activeViewId, -1)); },
|
|
19977
|
-
reload: () => {
|
|
19978
|
-
reloadUserConfig();
|
|
19979
|
-
reloadDashboardViews();
|
|
19980
|
-
},
|
|
19981
|
-
save: () => { saveDashboardViewsConfig(); },
|
|
19982
|
-
restoreAllClosed: () => { restoreAllClosedDashboardPanes(); },
|
|
19983
|
-
reset: () => { resetDashboardViewsConfig(); },
|
|
19984
|
-
exportConfigJson: () => JSON.stringify(serializeDashboardViewsConfig(viewRegistry), null, 2),
|
|
19985
|
-
openByQuery: (query) => {
|
|
19986
|
-
const def = findDashboardView(viewRegistry, query);
|
|
19987
|
-
if (def) {
|
|
19988
|
-
setActiveDashboardView(def);
|
|
19989
|
-
return true;
|
|
19990
|
-
}
|
|
19991
|
-
return false;
|
|
19992
|
-
},
|
|
19993
|
-
openDetailViewer: (title, lines) => { setDetailViewer(title, lines); },
|
|
19994
|
-
},
|
|
19995
17800
|
intake: {
|
|
19996
17801
|
runSlash: async (intakeArgs) => {
|
|
19997
17802
|
try {
|
|
@@ -20019,7 +17824,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20019
17824
|
},
|
|
20020
17825
|
};
|
|
20021
17826
|
const r = await resolveIntakeSlash([...intakeArgs], {
|
|
20022
|
-
getScratchSnapshot:
|
|
17827
|
+
getScratchSnapshot: () => {
|
|
17828
|
+
const snapshot = display.scratchState();
|
|
17829
|
+
return snapshot && snapshot.mode !== 'agents'
|
|
17830
|
+
? { title: snapshot.title, lines: [...snapshot.lines] }
|
|
17831
|
+
: { title: scratchTitle, lines: [...scratchLines] };
|
|
17832
|
+
},
|
|
20023
17833
|
});
|
|
20024
17834
|
if (shouldOpenDashboardIntakeSessionPicker([...intakeArgs], r)) {
|
|
20025
17835
|
openDashboardIntakeSessionPicker(r.sessions, intakeUiDeps);
|
|
@@ -20263,44 +18073,22 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20263
18073
|
remoteDaemon: () => opts.remote
|
|
20264
18074
|
? { url: opts.remote.url, token: opts.remote.token }
|
|
20265
18075
|
: null,
|
|
20266
|
-
localDaemon: () => opts.localDaemon
|
|
20267
|
-
? { socketPath: opts.localDaemon.socketPath }
|
|
20268
|
-
: null,
|
|
20269
18076
|
acpSwapTo: (sessionId, cwd) => dashboardAcpSession.swapTo(sessionId, cwd),
|
|
20270
18077
|
},
|
|
20271
18078
|
shellSlash: {
|
|
20272
18079
|
slashRuntime: shellSlashRuntime,
|
|
20273
18080
|
openRollupPopup: () => openShellRollupPopup(),
|
|
20274
|
-
virtualWindowsSwitchTo: (
|
|
20275
|
-
resolveVwIdByLabel: (
|
|
20276
|
-
const all = virtualWindows.registry.list();
|
|
20277
|
-
const hit = all.find(w => virtualWindows.registry.spawnTitleOf(w.id) === label);
|
|
20278
|
-
return hit ? hit.id : null;
|
|
20279
|
-
},
|
|
20280
|
-
},
|
|
20281
|
-
workspaceSlash: {
|
|
20282
|
-
slashRuntime: windowSlashRuntime,
|
|
20283
|
-
registry: virtualWindows.registry as unknown as DashboardSlashContext['workspaceSlash']['registry'],
|
|
20284
|
-
spawnScratchVirtualWindow,
|
|
20285
|
-
spawnBrowserVirtualWindow,
|
|
20286
|
-
spawnPreviewVirtualWindow,
|
|
20287
|
-
spawnBrowserPreviewVirtualWindow,
|
|
20288
|
-
spawnIulVirtualWindow,
|
|
20289
|
-
spawnAcpVirtualWindow,
|
|
20290
|
-
spawnSimVirtualWindow,
|
|
20291
|
-
openWindowPicker: () => openWindowPicker(),
|
|
20292
|
-
toggleVwCompanion: (windowId, key) => toggleVwCompanion(windowId, key as Parameters<typeof toggleVwCompanion>[1]),
|
|
20293
|
-
setVwCompanionOpen: (windowId, key, open) => setVwCompanionOpen(windowId, key as Parameters<typeof setVwCompanionOpen>[1], open),
|
|
20294
|
-
},
|
|
20295
|
-
acpVwSlash: {
|
|
20296
|
-
cwd: () => workingDir.cwd,
|
|
20297
|
-
vwRegistry: virtualWindows.registry,
|
|
18081
|
+
virtualWindowsSwitchTo: () => { throw new Error('Virtual windows are unavailable in the essential dashboard'); },
|
|
18082
|
+
resolveVwIdByLabel: () => null,
|
|
20298
18083
|
},
|
|
20299
18084
|
termSlash: {
|
|
20300
18085
|
slashRuntime: termSlashRuntime,
|
|
20301
18086
|
sessionRegistry: sessionRegistry as unknown as DashboardSlashContext['termSlash']['sessionRegistry'],
|
|
20302
18087
|
terminalMatrix: terminalMatrix as unknown as DashboardSlashContext['termSlash']['terminalMatrix'],
|
|
20303
|
-
vwRegistry:
|
|
18088
|
+
vwRegistry: {
|
|
18089
|
+
current: () => null,
|
|
18090
|
+
get: () => null,
|
|
18091
|
+
},
|
|
20304
18092
|
broadcastBus: broadcastBus as unknown as DashboardSlashContext['termSlash']['broadcastBus'],
|
|
20305
18093
|
channelBus: channelBus as unknown as DashboardSlashContext['termSlash']['channelBus'],
|
|
20306
18094
|
openSessionPicker: () => {
|
|
@@ -20563,15 +18351,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20563
18351
|
}
|
|
20564
18352
|
continue;
|
|
20565
18353
|
}
|
|
20566
|
-
// T7-N2 — spawn coding-agent CLI in a new VW pane.
|
|
20567
|
-
// /acp-vw [claude|codex] — legacy, brand via sub-arg
|
|
20568
|
-
// /claude-vw — direct alias (default brand claude-code)
|
|
20569
|
-
// /codex-vw — direct alias (brand codex)
|
|
20570
|
-
//
|
|
20571
|
-
// Sprint 5B (2026-04-28) removed the `/acp-vw cxn` path
|
|
20572
|
-
// (codex-native via Embodied Agent Bus) — codex-native
|
|
20573
|
-
// source is gone, codex-app-server is canonical.
|
|
20574
|
-
// B-3.d migrated: /codex-vw /acp-vw /claude-vw → registry handlers.
|
|
20575
18354
|
// B-2.w migrated: /conv → registry handler.
|
|
20576
18355
|
// H5 P3 · /handoff <fromId> <toBrand> [--channels reasoning,plan]
|
|
20577
18356
|
// Cross-agent snapshot-based context transfer.
|
|
@@ -20585,7 +18364,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20585
18364
|
// B-2.l migrated: /agents /agent /ag → registry handler.
|
|
20586
18365
|
// B-1.f migrated: /clipboard /clip /cb · /memo /note /me ·
|
|
20587
18366
|
// /detail /report /dv → registry handlers (companion ctx field).
|
|
20588
|
-
// B-2.v migrated: /scratch /sc → registry handler.
|
|
20589
18367
|
// B-2.o migrated: /intake → registry handler.
|
|
20590
18368
|
// B-1.g migrated: /signals /signal → registry handler (controlSignalSlashRuntime ctx field).
|
|
20591
18369
|
case 'media':
|
|
@@ -20727,17 +18505,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20727
18505
|
const handled = await pluginHost.dispatchSlash(cmdLower, args);
|
|
20728
18506
|
if (handled) { chatScrollOffset = -1; continue; }
|
|
20729
18507
|
}
|
|
20730
|
-
const
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
implement: '/harness implement <feature>',
|
|
20734
|
-
dev: '/harness dev <무엇을 왜 고칠지 한 문장>',
|
|
20735
|
-
} as Record<string, string>)[cmdLower];
|
|
20736
|
-
if (retiredHarnessCommand) {
|
|
20737
|
-
chatLines.push(C.warning(`/${cmdLower} has moved; use ${retiredHarnessCommand}`));
|
|
20738
|
-
} else {
|
|
20739
|
-
chatLines.push(C.warning(`Unknown command: /${cmdLower}`));
|
|
20740
|
-
chatLines.push(C.muted('Available: /view /preview /scratch /intake /run-skill /skill-triggers /skill-reload /provider /context /paste /sync /widget /plugin /chat /clear /help /quit /research'));
|
|
18508
|
+
const replyLines = unknownSlashReply(cmdLower, dashboardSlashRegistry.names());
|
|
18509
|
+
for (const [index, line] of replyLines.entries()) {
|
|
18510
|
+
chatLines.push(index === 0 ? C.warning(line) : C.muted(line));
|
|
20741
18511
|
}
|
|
20742
18512
|
chatScrollOffset = -1;
|
|
20743
18513
|
continue; // stay in input mode
|
|
@@ -20749,7 +18519,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20749
18519
|
|
|
20750
18520
|
// ── Q&A chat — requires at least one LLM provider ──
|
|
20751
18521
|
if (!anyProviderAvailable()) {
|
|
20752
|
-
|
|
18522
|
+
const reply = noProviderReply(input.text);
|
|
18523
|
+
for (const line of reply.lines) {
|
|
18524
|
+
chatLines.push(line.tone === 'warning' ? C.warning(line.text) : C.muted(line.text));
|
|
18525
|
+
}
|
|
18526
|
+
inputPrefixState.set(reply.prefill);
|
|
18527
|
+
nextInitial = inputPrefixState.consumeInitialText('plain');
|
|
20753
18528
|
continue; // stay in input mode
|
|
20754
18529
|
}
|
|
20755
18530
|
|
|
@@ -21052,8 +18827,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21052
18827
|
contextRegistry,
|
|
21053
18828
|
loadAttachments: (reg) => loadAllAttachments(reg as Parameters<typeof loadAllAttachments>[0]),
|
|
21054
18829
|
sessionRegistry,
|
|
21055
|
-
virtualWindowBook: virtualWindows.book,
|
|
21056
|
-
virtualWindowRegistry: virtualWindows.registry,
|
|
21057
18830
|
sync,
|
|
21058
18831
|
chatFooterLine,
|
|
21059
18832
|
routeFooter: () => {
|
|
@@ -21091,8 +18864,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21091
18864
|
contextText: args.contextText,
|
|
21092
18865
|
contextRegistry: args.contextRegistry as typeof contextRegistry,
|
|
21093
18866
|
terminalRegistry: args.terminalRegistry as typeof sessionRegistry,
|
|
21094
|
-
addressBook: args.addressBook as typeof virtualWindows.book,
|
|
21095
|
-
windowRegistry: args.windowRegistry as typeof virtualWindows.registry,
|
|
21096
18867
|
blockAttach: args.blockAttach,
|
|
21097
18868
|
pushChatLine: args.pushChatLine,
|
|
21098
18869
|
}),
|
|
@@ -21119,7 +18890,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21119
18890
|
pluginTools: pluginHost.activePluginLLMTools(),
|
|
21120
18891
|
optionalTools: acpTurnRef.optionalSpecs,
|
|
21121
18892
|
surface: acpTurnRef.turnProfile?.surface,
|
|
21122
|
-
rich:
|
|
18893
|
+
rich: false,
|
|
21123
18894
|
})
|
|
21124
18895
|
: [];
|
|
21125
18896
|
return buildDashboardTurnPreamble({
|
|
@@ -21127,7 +18898,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21127
18898
|
cwd: args.cwd,
|
|
21128
18899
|
turnProfile: args.turnProfile as SessionTurnProfile,
|
|
21129
18900
|
userConfig: args.userConfig,
|
|
21130
|
-
rich:
|
|
18901
|
+
rich: false,
|
|
21131
18902
|
enabledTools: tools.map(t => t.name),
|
|
21132
18903
|
});
|
|
21133
18904
|
},
|
|
@@ -21151,7 +18922,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21151
18922
|
userMsg: userMsg as ChatMessage,
|
|
21152
18923
|
model: inspectActiveProvider().model,
|
|
21153
18924
|
autoCompactConfig: userConfig.chat.autoCompact,
|
|
21154
|
-
compactBoundaryEnabled: userConfig.chat.rendering.compactBoundary.enabled,
|
|
21155
18925
|
shouldAutoCompact,
|
|
21156
18926
|
compactConversation: async (history) => compactConversation(history),
|
|
21157
18927
|
compactConversationPartial: async (history, opts) => compactConversationPartial(history, opts),
|
|
@@ -21190,7 +18960,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21190
18960
|
createDashboardTurnStreamRuntimeEscBoundary(escAbortToolState);
|
|
21191
18961
|
const toolRendering = {
|
|
21192
18962
|
...getUserConfig().chat.rendering.tool,
|
|
21193
|
-
expandHint:
|
|
18963
|
+
expandHint: false,
|
|
21194
18964
|
};
|
|
21195
18965
|
const renderedToolRuntime = createDashboardRenderedToolRuntime({
|
|
21196
18966
|
chatLines,
|
|
@@ -21314,7 +19084,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21314
19084
|
},
|
|
21315
19085
|
runCodeEditPostTurn: async () => {
|
|
21316
19086
|
await runDashboardCodeEditPostTurn({
|
|
21317
|
-
turnSummaryEnabled: getUserConfig().chat.rendering.diff.turnSummary,
|
|
21318
19087
|
pushChatLine: (line) => { chatLines.push(line); },
|
|
21319
19088
|
setChatScrollBottom: () => { chatScrollOffset = -1; },
|
|
21320
19089
|
importCodeEdit: () => import('../code-edit/index.js'),
|