elanous 0.2.0 → 0.2.4
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 +16 -14
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1191-7b13a24117a689fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2375-3fcae5186c64fe6b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +25 -0
- package/apps/pwa/out/_next/static/chunks/{2a79f15a-2013e4d421d6df88.js → 2ea96958-e8c7e112de50b067.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/319-d37df1b6e0cbeff4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +1 -0
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6804.8ed6ab492bc5fc0a.js → 4323.c5dfb6f503304775.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4836-3c93795ab834381e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{320-d7013ec072863e5e.js → 5080-1613752891fcadb4.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6062-73e68343a9814f6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6090-1bd6077591603947.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7457-f5cb1cc8db9f7453.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8046cadf-211ca3c0e00f2b72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8067-f74bf14d67ad98f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8142-011e1f474efb8b33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8519-0059d82bdb4812bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9740-52467f244755917f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-21c3261af6ab377c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1991445b8ea86274.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-4ebfaee2369fe248.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-9fa879ebf5959096.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ca7c3cc305c3285a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9951930add3d2051.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-4472ddf1e2458e69.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-4de08d4b766f134b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7a975e2b9db1dfb7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-49270714ef35bb96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-33fbdf353e2a5982.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-259f122e2dd64317.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-65b82726753658e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4b8df3748dc06285.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-112f7e477bda77fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-542a5c0006da637c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-63ffb347831262ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-98e4e359d97263b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-97e24ac675ce576e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ac6391f26391d89d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f45c9d45ffc43bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-36995b9cb5d98218.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0c795b577988d63f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b4311e2f71c6735a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-eb2381074df20dba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-b01336e64eba01ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-7af7f21c1f2858ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-a98ecd364586c89b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-57f0502dfbfa089b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-3467d2e1abd8a14a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-7842ca23d53ba682.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-ae9ac882912b0198.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-3a0d72e3f783bcef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-f3b39fe8358c2a97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-5a22af3181ac2afb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-1457627bb302a22c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +1 -0
- package/apps/pwa/out/_next/static/css/e66b7f5efc8df3f3.css +1 -0
- package/apps/pwa/out/_next/static/zoQX5iTvXOsIvCjxCe1Ji/_buildManifest.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -0
- package/apps/pwa/out/approvals/index.txt +30 -0
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +27 -26
- package/apps/pwa/out/board/index.html +1 -0
- package/apps/pwa/out/board/index.txt +30 -0
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +24 -23
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +24 -23
- package/apps/pwa/out/chat/index.html +1 -2
- package/apps/pwa/out/chat/index.txt +24 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +27 -26
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +27 -26
- package/apps/pwa/out/editor/index.html +1 -0
- package/apps/pwa/out/editor/index.txt +31 -0
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +24 -23
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +27 -26
- package/apps/pwa/out/live/index.html +1 -0
- package/apps/pwa/out/live/index.txt +30 -0
- package/apps/pwa/out/market/index.html +1 -0
- package/apps/pwa/out/market/index.txt +27 -0
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +24 -23
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +27 -26
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +27 -26
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +25 -24
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +27 -26
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +24 -23
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +27 -26
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +27 -26
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +27 -26
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +27 -26
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +27 -26
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +24 -23
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +27 -26
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +27 -26
- package/apps/pwa/out/trace/index.html +1 -0
- package/apps/pwa/out/trace/index.txt +30 -0
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +27 -26
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +27 -26
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +27 -27
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +27 -26
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +27 -26
- package/catalog/resources.yaml +8 -11
- 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 +44 -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 +38 -0
- package/graphs/release/release-loop.yaml +40 -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/broll-line.yaml +54 -0
- package/package.json +7 -5
- package/plugins/job-coach/.agents/plugins/marketplace.json +12 -0
- package/plugins/job-coach/.codex-plugin/plugin.json +6 -0
- package/plugins/job-coach/.mcp.json +9 -0
- package/plugins/job-coach/README.md +20 -0
- package/plugins/job-coach/connectors/ncs/server.ts +89 -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/recipes.yaml +18 -0
- package/plugins/job-coach/graphs/report.yaml +20 -0
- package/plugins/job-coach/graphs/run-step.ts +108 -0
- package/plugins/job-coach/plugin.json +13 -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/interview-to-profile/SKILL.md +6 -0
- package/plugins/job-coach/skills/run-report/SKILL.md +15 -0
- package/scripts/backup/elanous-backup.sh +139 -13
- package/scripts/backup/elanous-restore.sh +122 -0
- 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 +5 -5
- package/scripts/coord-tracks.json +5 -4
- 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/fleet/node-setup.sh +38 -4
- 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 +37 -0
- package/scripts/landing-heal/run-mission.ts +101 -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/market/db-check.ts +212 -0
- package/scripts/market-posture-cycle.ts +63 -4
- 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-leak-baseline.txt +0 -7
- package/scripts/publish-internal-dist.ts +119 -0
- package/scripts/pwa-scenarios.ts +106 -0
- package/scripts/rebrand-elanous.ts +1 -1
- 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 +353 -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 +57 -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 +102 -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 +25 -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-deterministic.ts +2 -1
- package/scripts/uninstall.sh +10 -3
- 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/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/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 +821 -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 +19 -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 +187 -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/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/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/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 +16 -2
- 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/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 +21 -45
- package/src/chat/input-text-key.ts +2 -2
- 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/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 +721 -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/docs-cli.ts +38 -0
- package/src/cli/doctor-cli.ts +225 -26
- 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 +8 -5
- 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 +43 -13
- package/src/cli/mcp-gateway-cli.ts +90 -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 +103 -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/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 +99 -27
- package/src/cli/pwa-test.ts +201 -96
- package/src/cli/release-cli.ts +90 -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 +98 -10
- 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 +221 -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 +11 -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 +278 -2558
- 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/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/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/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 +16 -4
- 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/element-registry/address.ts +1 -3
- 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/plugin-nodes.ts +60 -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 +457 -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 +115 -0
- package/src/harness/harness-cli-command.ts +352 -19
- package/src/harness/harness-pod-dispatch.ts +110 -0
- package/src/harness/harness-stop.ts +131 -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 +224 -0
- package/src/harness/shell-relay.ts +5 -0
- 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 +666 -3406
- 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 +40 -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 +86 -0
- package/src/intake-plane/digest.ts +102 -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 +175 -0
- package/src/llm/provider-detect.ts +247 -0
- package/src/llm/provider-probe.ts +57 -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 +174 -0
- package/src/market/official-keys.ts +5 -0
- package/src/market/publish.ts +273 -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 +64 -343
- 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-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 +274 -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 +33 -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 +30 -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 +306 -0
- package/src/nexus/api/meta-api.ts +4 -0
- package/src/nexus/api/next-fluent-wiring.ts +7 -9
- package/src/nexus/api/plugins-market.ts +125 -0
- package/src/nexus/api/pod-credential-api.ts +133 -0
- package/src/nexus/api/public-routes.ts +80 -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 +354 -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 +38 -4
- package/src/nexus/daemon-endpoint.ts +85 -0
- package/src/nexus/default-port.ts +1 -0
- package/src/nexus/index.ts +329 -111
- package/src/nexus/onboarding/pwa-share-prompt.ts +31 -8
- package/src/nexus/onboarding/tailscale-probe.ts +9 -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 +2 -2
- 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 +94 -4
- package/src/plugins/core/manifest.ts +104 -7
- package/src/plugins/install/market-fetch.ts +249 -0
- package/src/plugins/install/plugin-install.ts +387 -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/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/manifest.ts +65 -0
- package/src/release-loop/release-note.ts +174 -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 +250 -139
- package/src/self-dev/dev-pipeline.ts +80 -8
- 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 +32 -1
- 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 +23 -2
- 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 +240 -0
- package/src/self-implement/non-git-consent.ts +23 -0
- package/src/self-implement/orchestrator.ts +481 -132
- 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 +203 -38
- 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 +3 -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/triage.ts +203 -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 +136 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +348 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +177 -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 +132 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +91 -0
- package/src/task-orchestrator/surfaces/pod-source-spec.ts +77 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +782 -41
- 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 +2 -1
- 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/headless-core-guard.ts +0 -1
- package/src/tui.ts +8 -5
- package/src/typecheck-ratchet.ts +15 -0
- package/src/ui/hover-presenter.ts +3 -7
- package/src/user-config.ts +427 -190
- package/src/version/code-revision.ts +33 -8
- 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/index.ts +5 -5
- package/src/web-terminal/preview-tap-registry.ts +152 -43
- 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 +138 -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 +74 -4
- 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/2598.814f64e3268634e7.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/5927.8378481a12cc8044.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 → zoQX5iTvXOsIvCjxCe1Ji}/_ssgManifest.js +0 -0
- /package/src/dashboard/{companion-slash-runtime.ts → companion-messages-runtime.ts} +0 -0
package/src/dashboard/index.ts
CHANGED
|
@@ -295,24 +295,10 @@ export interface RegisterDashboardGlobalKeysDeps {
|
|
|
295
295
|
register: (binding: DashboardGlobalKeyRegistration) => void;
|
|
296
296
|
openSurfaceCatalog: () => void;
|
|
297
297
|
surfaceCatalogWhen?: () => boolean;
|
|
298
|
-
dispatchVirtualWindowChord: (event: DisplayKeyEvent) => void;
|
|
299
298
|
}
|
|
300
299
|
|
|
301
|
-
/** Registers optional dashboard controls
|
|
300
|
+
/** Registers optional dashboard controls. */
|
|
302
301
|
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
302
|
if (deps.enableSupplementalGlobalKeys) {
|
|
317
303
|
deps.register({
|
|
318
304
|
id: 'dashboard:open-surface-catalog',
|
|
@@ -321,14 +307,7 @@ export function registerDashboardGlobalKeys(deps: RegisterDashboardGlobalKeysDep
|
|
|
321
307
|
handler: deps.openSurfaceCatalog,
|
|
322
308
|
when: deps.surfaceCatalogWhen,
|
|
323
309
|
});
|
|
324
|
-
registerVwChord('picker', '0', vwKey('0'));
|
|
325
|
-
registerVwChord('close-window', 'S-x', vwKey('x', { shift: true }));
|
|
326
|
-
registerVwChord('last-pane', 'tab', vwKey('tab'));
|
|
327
310
|
}
|
|
328
|
-
|
|
329
|
-
registerVwChord('new-window', 'c', vwKey('c'));
|
|
330
|
-
registerVwChord('close-pane', 'x', vwKey('x'));
|
|
331
|
-
registerVwChord('zoom-toggle', 'z', vwKey('z'));
|
|
332
311
|
}
|
|
333
312
|
|
|
334
313
|
export type ForkableSessionTurn = {
|
|
@@ -509,13 +488,10 @@ import {
|
|
|
509
488
|
} from '../primitives/damage-region/index.js';
|
|
510
489
|
import {
|
|
511
490
|
createArtifactStore,
|
|
512
|
-
createLegacyLayoutProvider,
|
|
513
491
|
createLegacyTimelineProvider,
|
|
514
492
|
} from '../artifact/index.js';
|
|
515
493
|
import { defaultTimelineBaseDir } from '../tool-runtime/recording-runtimes-paths.js';
|
|
516
|
-
import { layoutsDir } from '../virtual-windows/layout/persistence.js';
|
|
517
494
|
import { createVisualStateStore } from '../panes/visual-state.js';
|
|
518
|
-
import { skipWindowWhenStorePredicate } from '../panes/alt-skip-predicate.js';
|
|
519
495
|
import { composeIdentityHooks } from '../display/modal-identity-wiring.js';
|
|
520
496
|
import { composeWorkspaceHostHooks } from '../display/workspace-host-wiring.js';
|
|
521
497
|
import {
|
|
@@ -650,7 +626,6 @@ import {
|
|
|
650
626
|
matchDashboardChordAction,
|
|
651
627
|
} from './input/dashboard-chord-actions.js';
|
|
652
628
|
import { createDashboardChordRuntime } from './input/dashboard-chord-runtime.js';
|
|
653
|
-
import { createMouseDockRuntime } from './input/mouse-dock-runtime.js';
|
|
654
629
|
import { handleDashboardDisplayKeyRoute } from './input/dashboard-display-key-route.js';
|
|
655
630
|
import { routeDashboardPriorityKey } from './input/dashboard-priority-key-route.js';
|
|
656
631
|
import { shouldPassthroughDashboardHostOwnedInputCoreAction } from './input/input-core-host-action.js';
|
|
@@ -915,15 +890,12 @@ import {
|
|
|
915
890
|
import { globalVoiceCostTracker } from '../voice/cost-tracker.js';
|
|
916
891
|
import { createDashboardMouseWiring } from './input/mouse-wiring.js';
|
|
917
892
|
import { createMouseConversationPopupRuntime } from './input/mouse-conversation-popup-runtime.js';
|
|
918
|
-
import { createMouseHoverRuntime } from './input/mouse-hover-runtime.js';
|
|
919
893
|
import { createMouseModalHitRuntime } from './input/mouse-modal-hit-runtime.js';
|
|
920
894
|
import { createMouseModalSurfaceRuntime } from './input/mouse-modal-surface-runtime.js';
|
|
921
895
|
import { createMouseModeSwitchRuntime } from './input/mouse-mode-switch-runtime.js';
|
|
922
896
|
import { createMousePaneHitRuntime } from './input/mouse-pane-hit-runtime.js';
|
|
923
897
|
import { createMousePickerRuntime } from './input/mouse-picker-runtime.js';
|
|
924
|
-
import { createMousePillContextRuntime } from './input/mouse-pill-context-runtime.js';
|
|
925
898
|
import { createMouseShellRollupRuntime } from './input/mouse-shell-rollup-runtime.js';
|
|
926
|
-
import { createMouseWorkspaceRestoreRuntime } from './input/mouse-workspace-restore-runtime.js';
|
|
927
899
|
import { createDashboardPluginBaseRuntime } from './plugin-base-runtime.js';
|
|
928
900
|
import { createDashboardPluginExecutionRuntime } from './plugin-execution-runtime.js';
|
|
929
901
|
import { createDashboardPluginPaneRuntime } from './plugin-pane-runtime.js';
|
|
@@ -987,7 +959,6 @@ import { runDashboardSkillByName } from './skill-runtime.js';
|
|
|
987
959
|
import { createDashboardClipboardActions } from './clipboard-actions.js';
|
|
988
960
|
import {
|
|
989
961
|
buildDashboardEditorOpenPayload,
|
|
990
|
-
buildDashboardScratchDumpLines,
|
|
991
962
|
} from './clipboard-message-runtime.js';
|
|
992
963
|
import { createDashboardCopyRuntime } from './copy-runtime.js';
|
|
993
964
|
import { createDashboardMediaRuntime } from './media-runtime.js';
|
|
@@ -998,18 +969,14 @@ import { createDashboardContextMenuFeedbackRuntime } from './context-menu-feedba
|
|
|
998
969
|
import { createDashboardStatusFeedbackRuntime } from './status-feedback-runtime.js';
|
|
999
970
|
import { createDashboardTransferFeedbackRuntime } from './transfer-feedback-runtime.js';
|
|
1000
971
|
import { createDashboardFinderFeedbackRuntime } from './finder-feedback-runtime.js';
|
|
1001
|
-
import { createDashboardWindowSlashRuntime } from './window-slash-runtime.js';
|
|
1002
|
-
import { createDashboardBenchSlashRuntime } from './bench-slash-runtime.js';
|
|
1003
972
|
import { createDashboardTermSlashRuntime } from './term-slash-runtime.js';
|
|
1004
973
|
import { createDashboardShellSlashRuntime } from './shell-slash-runtime.js';
|
|
1005
974
|
import { createDashboardRunSkillSlashRuntime } from './run-skill-slash-runtime.js';
|
|
1006
975
|
import { createDashboardSkillTriggersSlashRuntime } from './skill-triggers-slash-runtime.js';
|
|
1007
976
|
import { createDashboardProviderSlashRuntime } from './provider-slash-runtime.js';
|
|
1008
977
|
import { createDashboardPreviewSlashRuntime } from './preview-slash-runtime.js';
|
|
1009
|
-
import {
|
|
1010
|
-
import { createDashboardCompanionSlashRuntime } from './companion-slash-runtime.js';
|
|
978
|
+
import { createDashboardCompanionSlashRuntime } from './companion-messages-runtime.js';
|
|
1011
979
|
import { createDashboardAgentsSlashRuntime } from './agents-slash-runtime.js';
|
|
1012
|
-
import { createDashboardViewSlashRuntime } from './view-slash-runtime.js';
|
|
1013
980
|
import { createDashboardControlSignalSlashRuntime } from './control-signal-slash-runtime.js';
|
|
1014
981
|
import { createDashboardBrowserCdpSlashRuntime } from './browser-cdp-slash-runtime.js';
|
|
1015
982
|
import { collectGroundingFactsViaCdp } from '../product-grounding/cdp-collect.js';
|
|
@@ -1025,9 +992,6 @@ import { resolveDashboardMediaSlash } from './media-slash-runtime.js';
|
|
|
1025
992
|
import { createDashboardMemoCompanionRuntime } from './memo-companion-runtime.js';
|
|
1026
993
|
import { createDashboardDetailViewerRuntime } from './detail-viewer-runtime.js';
|
|
1027
994
|
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
995
|
import { createDashboardClipboardHistoryRuntime } from './clipboard-history-runtime.js';
|
|
1032
996
|
import { createDashboardClipboardCompanionRuntime } from './clipboard-companion-runtime.js';
|
|
1033
997
|
import { createDashboardMemoWidgetRuntime } from './memo-widget-runtime.js';
|
|
@@ -1082,7 +1046,6 @@ import {
|
|
|
1082
1046
|
import { createDashboardTerminalPopupRuntime } from './terminal-popup-runtime.js';
|
|
1083
1047
|
import { toggleDashboardAssistantRenderState } from './assistant-render-state-runtime.js';
|
|
1084
1048
|
import { bootDashboardAcpBgSweep } from './acp-bg-sweep-boot.js';
|
|
1085
|
-
import { bootDashboardAgentSpawnTools } from './agent-spawn-tools-boot.js';
|
|
1086
1049
|
import { bootDashboardConfigTools } from './config-tools-boot.js';
|
|
1087
1050
|
import { bootDashboardConversationPopupRuntime } from './conversation-popup-boot.js';
|
|
1088
1051
|
import { bootDashboardTerminalRuntime } from './terminal-runtime-boot.js';
|
|
@@ -1108,15 +1071,10 @@ import type { SurfaceUx } from '../agent/surface-ux/types.js';
|
|
|
1108
1071
|
import { getDefaultQuestionChannels, type QuestionChannel } from '../hitl/question.js';
|
|
1109
1072
|
import { getDefaultCompactProvider, scheduleArchiveRetentionOnce } from '../compact/index.js';
|
|
1110
1073
|
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
1074
|
import { createBrowserHelpRuntime } from './browser-help-runtime.js';
|
|
1114
1075
|
import { createBrowserChordRuntime } from './browser-chord-runtime.js';
|
|
1115
1076
|
import { summarizeFileWithLLM } from './browser-llm-summary.js';
|
|
1116
|
-
import { createDashboardVirtualWindowInputRuntime } from './virtual-window-input-runtime.js';
|
|
1117
1077
|
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
1078
|
import {
|
|
1121
1079
|
bootDashboardPlanModeRuntime,
|
|
1122
1080
|
cleanupDashboardWorktreeSessions,
|
|
@@ -1152,11 +1110,7 @@ import {
|
|
|
1152
1110
|
import {
|
|
1153
1111
|
type DashboardPaneTitleMenuPayload,
|
|
1154
1112
|
} from '../dashboard-pane-context-menu.js';
|
|
1155
|
-
import {
|
|
1156
|
-
type VirtualWindowTitleMenuPayload,
|
|
1157
|
-
} from '../virtual-window-context-menu.js';
|
|
1158
1113
|
// writeClipboard imported below with other clipboard helpers (line ~185).
|
|
1159
|
-
import { registerVwFastSwitchBindings } from './windowing/fast-switch.js';
|
|
1160
1114
|
import {
|
|
1161
1115
|
renderPaneNav, paneAtColumn, paneNavLabel,
|
|
1162
1116
|
type PaneNavHitArea,
|
|
@@ -1204,15 +1158,9 @@ import { createInteractiveTerminalModal } from '../interactive-terminal-modal.js
|
|
|
1204
1158
|
import { showToast } from './render/toast.js';
|
|
1205
1159
|
import {
|
|
1206
1160
|
browserWidgetInstanceIdForView,
|
|
1207
|
-
renderPaneModalHint,
|
|
1208
1161
|
shortcutFor,
|
|
1209
|
-
SHORTCUT_TABLE as PANE_SHORTCUT_TABLE,
|
|
1210
|
-
PANE_MODAL_CHORD_TIMEOUT_MS,
|
|
1211
1162
|
} from './modals/pane.js';
|
|
1212
|
-
|
|
1213
|
-
// 의 registerKeyBinding chord 경로로 이전. imperative 호출용 파일은
|
|
1214
|
-
// dashboard-virtual-window-key-router.ts 에 그대로 유지.
|
|
1215
|
-
import { showTransientTerminalModal } from './modals/transient.js';
|
|
1163
|
+
import { showTransientTerminalModal, currentTransientTerminalModal } from './modals/transient.js';
|
|
1216
1164
|
import { showPaneMultiModal, showLivePaneMultiModal, currentPaneMultiModal, type PaneMultiModalHandle } from './modals/pane-multi.js';
|
|
1217
1165
|
import {
|
|
1218
1166
|
resolveCompanionPopupChrome,
|
|
@@ -1234,26 +1182,10 @@ import {
|
|
|
1234
1182
|
TerminalRegistry,
|
|
1235
1183
|
BroadcastBus,
|
|
1236
1184
|
PreviewSlotAdapter,
|
|
1237
|
-
VwPlacementAdapter,
|
|
1238
1185
|
getChannelBus,
|
|
1239
1186
|
type TerminalPlacement,
|
|
1240
1187
|
} 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';
|
|
1188
|
+
import { resolveTerminalMoveDestination } from '../terminal-matrix/mobility.js';
|
|
1257
1189
|
import { initElementObservability } from '../element-registry/index.js';
|
|
1258
1190
|
import {
|
|
1259
1191
|
armSessionQuickControl,
|
|
@@ -1278,8 +1210,6 @@ import {
|
|
|
1278
1210
|
import {
|
|
1279
1211
|
initDashboardApprovers,
|
|
1280
1212
|
createInjectApprover,
|
|
1281
|
-
createPaneInjectApprover,
|
|
1282
|
-
createBroadcastApprover,
|
|
1283
1213
|
createConfigSetApprover,
|
|
1284
1214
|
createAcpPermissionApprover,
|
|
1285
1215
|
openGenericApproval,
|
|
@@ -1303,7 +1233,6 @@ import { createDashboardCompactSurfaceAssembly } from './compact-surface-assembl
|
|
|
1303
1233
|
import { openCompactSurfaceCatalogPopup } from './compact-surface-popup.js';
|
|
1304
1234
|
import { approvalModalRouter, type ApprovalModalRouter } from '../approval-modal.js';
|
|
1305
1235
|
import { routeApprovalModalKey } from './input/approval-key-router.js';
|
|
1306
|
-
import { createWindowPickerModal } from '../window-picker-modal.js';
|
|
1307
1236
|
|
|
1308
1237
|
export function routeStreamingApprovalModalKey(
|
|
1309
1238
|
key: Parameters<typeof routeApprovalModalKey>[0],
|
|
@@ -1320,21 +1249,9 @@ export function routeStreamingApprovalModalKey(
|
|
|
1320
1249
|
import {
|
|
1321
1250
|
attachSurfaceToWorkspace,
|
|
1322
1251
|
DASHBOARD_MAIN_WORKSPACE_ID,
|
|
1323
|
-
workspaceOwnerIdForVirtualWindow,
|
|
1324
1252
|
} 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
1253
|
import { initDashboardHitl, stopDashboardHitl } from './runtime/hitl.js';
|
|
1331
|
-
import { openDashboardWindowPickerPopup } from './window-picker-popup.js';
|
|
1332
|
-
import { createIulSidebarShellPaneContent } from '../iul/sidebar-shell.js';
|
|
1333
1254
|
import { openDashboardShellRollupPopup } from './shell-rollup-popup.js';
|
|
1334
|
-
import {
|
|
1335
|
-
openVwLocalInputTargetPopupLauncher,
|
|
1336
|
-
openVwRenameModalLauncher,
|
|
1337
|
-
} from './vw-popup-openers.js';
|
|
1338
1255
|
import { expandPromptReferences } from '../prompt/references.js';
|
|
1339
1256
|
import { spawnCodingAgent, CodingAgentBinaryMissing } from '../terminal/coding-agent.js';
|
|
1340
1257
|
import type { TerminalSession } from '../terminal/session-registry.js';
|
|
@@ -1367,7 +1284,7 @@ import { enqueuePendingUserInput } from '../session/pending-input.js';
|
|
|
1367
1284
|
import { createAttachmentRowMap } from '../log-pane/attachment-row-map.js';
|
|
1368
1285
|
import { createAttachmentPopup, type AttachmentPopupAction } from '../log-pane/attachment-popup.js';
|
|
1369
1286
|
import { findLogMatches, type LogSearchResult } from '../log-pane/search.js';
|
|
1370
|
-
import { createLogSearchModal } from '../log-pane/search-modal.js';
|
|
1287
|
+
import { createLogSearchModal, type LogSearchModalOpts } from '../log-pane/search-modal.js';
|
|
1371
1288
|
// U-4.3 · direct imports of tryAttachmentHitAtBodyRow /
|
|
1372
1289
|
// tryHandleLogAreaClick are gone · wd-log.onMouse owns the hit-test.
|
|
1373
1290
|
// LogClickDispatchDeps type still needed for buildLogClickDeps +
|
|
@@ -1379,7 +1296,7 @@ import {
|
|
|
1379
1296
|
import { fileColor, fileIcon, sizeStr, dirColor } from '../panes/file-icons.js';
|
|
1380
1297
|
import { canPreview } from '../panes/preview-pane.js';
|
|
1381
1298
|
import { colorLine } from '../panes/syntax-color.js';
|
|
1382
|
-
import { createHud, setSegment, clearSegment
|
|
1299
|
+
import { createHud, setSegment, clearSegment } from '../panes/hud.js';
|
|
1383
1300
|
import {
|
|
1384
1301
|
paneHeightBeforeTargetRow,
|
|
1385
1302
|
paneHeightForTargetRows,
|
|
@@ -1429,11 +1346,9 @@ import { initWidgetInspectorTools } from '../skills/tools/widget-inspector.js';
|
|
|
1429
1346
|
import {
|
|
1430
1347
|
initDashboardViewTools,
|
|
1431
1348
|
} from '../skills/tools/dashboard-view.js';
|
|
1432
|
-
import { initSpawnCodingAgentInVW } from '../skills/tools/spawn-coding-agent-vw.js';
|
|
1433
1349
|
import {
|
|
1434
1350
|
findLiveSessionById,
|
|
1435
1351
|
findLiveSessionByPaneId,
|
|
1436
|
-
initSpawnEmbodiedAgentInVW,
|
|
1437
1352
|
listLiveEmbodiedSessions,
|
|
1438
1353
|
} from '../agent/spawn-embodied-agent-in-vw.js';
|
|
1439
1354
|
import { findSessionObserver } from '../agent/observer-registry.js';
|
|
@@ -1496,7 +1411,7 @@ import { buildAstGrepHostTool } from '../skills/tools/ast-grep.js';
|
|
|
1496
1411
|
import { buildLspHostTool } from '../skills/tools/lsp/index.js';
|
|
1497
1412
|
import { PluginHost } from '../plugins/core/host.js';
|
|
1498
1413
|
import { registerDashboardPaneHostTools } from './panes/host-tools.js';
|
|
1499
|
-
import { DEFAULT_THEME_TOKENS, mergeThemeTokens, resolveThemeTokens, type ThemeTokenInput } from '../theme/tokens.js';
|
|
1414
|
+
import { DEFAULT_THEME_TOKENS, mergeThemeTokens, resolveThemeTokens, type ThemeTokenInput, type ThemeTokens } from '../theme/tokens.js';
|
|
1500
1415
|
import { resolveActiveTheme, setActivePresetInConfig } from './render/theme-resolver.js';
|
|
1501
1416
|
import { getTheme, listThemes } from '../themes/index.js';
|
|
1502
1417
|
import type { PaneFocus, PreviewSource, WorkingDirView } from '../workspace-types.js';
|
|
@@ -1525,9 +1440,8 @@ import {
|
|
|
1525
1440
|
resolveBrowserActionContextFromHit,
|
|
1526
1441
|
} from '../browser-pane/actions.js';
|
|
1527
1442
|
import { resolveBrowserTransferCapability } from '../browser-pane/capabilities.js';
|
|
1528
|
-
import {
|
|
1443
|
+
import { openBrowserPaneModal } from '../browser-pane/mount.js';
|
|
1529
1444
|
import { openPreviewPaneModal } from '../preview-pane/mount.js';
|
|
1530
|
-
import { createPreviewPaneContent } from '../preview-pane/mount.js';
|
|
1531
1445
|
import {
|
|
1532
1446
|
cyclePreviewSourceForView,
|
|
1533
1447
|
formatPreviewSourceLabel,
|
|
@@ -1558,7 +1472,6 @@ import {
|
|
|
1558
1472
|
pruneSurfaceCatalogForCompactMode,
|
|
1559
1473
|
productCompactModeForViewport,
|
|
1560
1474
|
} from '../views/product-compact-mode.js';
|
|
1561
|
-
import { isDashboardHeavyFeatureEnabled, resolveDashboardUiMode, type DashboardUiMode } from '../views/ui-mode.js';
|
|
1562
1475
|
import { readScopedRenderLogs, resolveRenderSuppressed, readScopedDebugLevel, resolveStartupDebugLevel, hotPathGateOpen } from '../mss/logging/scoped-level.js';
|
|
1563
1476
|
import { resolveCurrentInstance } from '../instance/current.js';
|
|
1564
1477
|
import { createPushLog } from '../push-log.js';
|
|
@@ -1658,34 +1571,16 @@ import {
|
|
|
1658
1571
|
TERMINAL_BACKGROUND_STATES,
|
|
1659
1572
|
withBgApprovalSignals,
|
|
1660
1573
|
} 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';
|
|
1574
|
+
import { dispatchAcpSessionJoin } from '../skills/tools/acp-session.js';
|
|
1669
1575
|
import {
|
|
1670
1576
|
listDashboardSimulationScenarios,
|
|
1671
1577
|
runDashboardSimulationScenario,
|
|
1672
1578
|
} 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
1579
|
import { preservesHostChromeInput } from '../display/host-chrome-profile.js';
|
|
1685
1580
|
// H3 #6 follow-up #1 — auto-persist on turn-end. Subscribes DRM +
|
|
1686
1581
|
// BG managers to the H2 #5 persistence primitive so
|
|
1687
1582
|
// `AcpSessionList` returns real records instead of empty arrays.
|
|
1688
|
-
// Mode
|
|
1583
|
+
// Mode is always 'auto' (the ELANOUS_ACP_PERSIST_MODE off-switch was graduated 2026-09-26).
|
|
1689
1584
|
import { wireAutoPersist } from '../acp/auto-persist.js';
|
|
1690
1585
|
import { globalAcpSessionPersistence } from '../acp/session-persistence.js';
|
|
1691
1586
|
import { AgentStatusStore } from '../agent-status/store.js';
|
|
@@ -1752,10 +1647,6 @@ export interface ShowDashboardOptions {
|
|
|
1752
1647
|
* input). Useful on tablets where the 3-pane grid is too narrow
|
|
1753
1648
|
* to read. Toggle at runtime with /chat or the chord in the HUD. */
|
|
1754
1649
|
chatOnly?: boolean;
|
|
1755
|
-
/** TUI 부활 T0 — CLI `--rich`. 이번 실행만 uiMode 를 rich 로 강제
|
|
1756
|
-
* (config 무변). essential 이 기본이 된 뒤 기존 full dashboard 로
|
|
1757
|
-
* 들어가는 탈출구. 해석은 views/ui-mode.ts resolveDashboardUiMode. */
|
|
1758
|
-
rich?: boolean;
|
|
1759
1650
|
/** Flip code-edit policy to unsupervised at boot — every Edit/Write
|
|
1760
1651
|
* from the LLM applies without an approval modal. Equivalent to
|
|
1761
1652
|
* typing `/code-edit policy unsupervised` right after launch.
|
|
@@ -1771,15 +1662,8 @@ export interface ShowDashboardOptions {
|
|
|
1771
1662
|
* (resolved in `main()`). Tool dispatch + history live on the
|
|
1772
1663
|
* daemon side; the local TUI is a thin client. */
|
|
1773
1664
|
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
|
|
1665
|
+
/** Tier 1 daemon-resume — when set together with `remote`,
|
|
1666
|
+
* the dashboard attaches to this existing
|
|
1783
1667
|
* daemon-side sessionId instead of minting a new one. The boot
|
|
1784
1668
|
* also fetches the session's prior turns via REST (when an HTTP
|
|
1785
1669
|
* endpoint is reachable, derived from `remote.url`) and replays
|
|
@@ -1901,18 +1785,16 @@ export function renderDashboardCoordinatorModalOverlay(display: Pick<DisplayCoor
|
|
|
1901
1785
|
* ⭐⭐⭐ **essential 은 커서 값을 Z축에 묻지 않는다**(2026-08-02 · RFC essential-z-axis-off).
|
|
1902
1786
|
* 입력 루프가 끝나면 `setCursor(null)` 로 소유가 비므로 물어보면 빈손이고, 그래서 턴이 도는
|
|
1903
1787
|
* 동안 커서가 사라졌다(라이브 14 표본 전부 `visible false`). ⇒ 모달이 **실제로 claim** 했으면
|
|
1904
|
-
* 그 값을 쓰고, 아니면 **프롬프트 caret** 을 쓴다. 프롬프트가 감춰졌으면 숨긴다.
|
|
1905
|
-
* ⚠️ rich 는 Z축을 실제로 쓰므로 종전 동작(조율자가 정한 값)을 그대로 둔다. */
|
|
1788
|
+
* 그 값을 쓰고, 아니면 **프롬프트 caret** 을 쓴다. 프롬프트가 감춰졌으면 숨긴다. */
|
|
1906
1789
|
export interface DashboardFrameInput {
|
|
1907
1790
|
overlay: string;
|
|
1908
1791
|
force: boolean;
|
|
1909
|
-
essential: boolean;
|
|
1910
1792
|
/** ⭐ Z축이 **실제로 누구에게** 커서를 준 결정. essential 은 `modal`·`terminal` 일 때만
|
|
1911
1793
|
* 그 값에 양보한다 — `coordinator` fallback 은 소유자가 없다는 뜻이지 claim 이 아니다. */
|
|
1912
1794
|
cursorOwner: CursorDecision['owner'];
|
|
1913
1795
|
claimedCursor: CursorState | null;
|
|
1914
|
-
/**
|
|
1915
|
-
coordinatorCursor
|
|
1796
|
+
/** essential 결정이 커서를 안 낼 때(null)의 폴백 — 조율자가 emit 하던 값(종전 동작 보존). */
|
|
1797
|
+
coordinatorCursor?: CursorState | null;
|
|
1916
1798
|
promptCaret: CursorState | null;
|
|
1917
1799
|
suppressPromptArea: boolean;
|
|
1918
1800
|
onEssentialFrameCursorDecision?: (observation: EssentialFrameCursorObservation) => void;
|
|
@@ -1948,31 +1830,27 @@ export function createDashboardEssentialCursorObserver(deps: DashboardEssentialC
|
|
|
1948
1830
|
|
|
1949
1831
|
export function renderDashboardFrame(
|
|
1950
1832
|
lines: string[],
|
|
1951
|
-
input: DashboardFrameInput
|
|
1833
|
+
input: DashboardFrameInput,
|
|
1952
1834
|
renderFrame: DashboardFrameRenderer = render,
|
|
1953
1835
|
): void {
|
|
1954
1836
|
const cursorDecisionExists = input.cursorOwner !== 'none';
|
|
1955
|
-
const essentialDecision =
|
|
1956
|
-
?
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
})
|
|
1961
|
-
: null;
|
|
1837
|
+
const essentialDecision = resolveEssentialFrameCursorDecision({
|
|
1838
|
+
claimedCursor: cursorDecisionExists ? input.claimedCursor : null,
|
|
1839
|
+
promptCaret: input.promptCaret,
|
|
1840
|
+
suppressPromptArea: input.suppressPromptArea,
|
|
1841
|
+
});
|
|
1962
1842
|
renderFrame(lines, {
|
|
1963
1843
|
overlay: input.overlay,
|
|
1964
1844
|
force: input.force,
|
|
1965
|
-
cursor: paintCursor(essentialDecision
|
|
1845
|
+
cursor: paintCursor(essentialDecision.cursor ?? input.coordinatorCursor ?? null),
|
|
1846
|
+
});
|
|
1847
|
+
input.onEssentialFrameCursorDecision?.({
|
|
1848
|
+
caret: essentialDecision.cursor,
|
|
1849
|
+
cursorOwner: input.cursorOwner,
|
|
1850
|
+
reason: essentialDecision.reason,
|
|
1851
|
+
source: essentialDecision.source,
|
|
1852
|
+
suppressPromptArea: input.suppressPromptArea,
|
|
1966
1853
|
});
|
|
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
1854
|
}
|
|
1977
1855
|
|
|
1978
1856
|
/** Production frame input: append coordinator modals after every dashboard-owned overlay. */
|
|
@@ -2175,6 +2053,47 @@ export async function dispatchDashboardAdSlash(
|
|
|
2175
2053
|
afterRun();
|
|
2176
2054
|
}
|
|
2177
2055
|
|
|
2056
|
+
export function createDashboardLogSearchOpener(deps: {
|
|
2057
|
+
display: () => DisplayCoordinator;
|
|
2058
|
+
linesGetter: LogSearchModalOpts['linesGetter'];
|
|
2059
|
+
initialQuery: () => string;
|
|
2060
|
+
termSize: () => { cols: number; rows: number };
|
|
2061
|
+
computePaneH: (rows: number) => number;
|
|
2062
|
+
currentThemeTokens: () => ThemeTokens;
|
|
2063
|
+
currentWorkspaceOwnerId: () => string;
|
|
2064
|
+
draw: () => void;
|
|
2065
|
+
onJump: LogSearchModalOpts['onJump'];
|
|
2066
|
+
onCancel: NonNullable<LogSearchModalOpts['onCancel']>;
|
|
2067
|
+
}): () => void {
|
|
2068
|
+
return () => {
|
|
2069
|
+
let modalHandle: { dispose(): void } | null = null;
|
|
2070
|
+
const closeLogSearchModal = (): void => { modalHandle?.dispose(); modalHandle = null; };
|
|
2071
|
+
const { cols: tc, rows: tr } = deps.termSize();
|
|
2072
|
+
const anchorRow = Math.max(1, deps.computePaneH(tr) + 2);
|
|
2073
|
+
const anchorCol = Math.max(2, Math.floor(tc / 4));
|
|
2074
|
+
const popup = createLogSearchModal({
|
|
2075
|
+
linesGetter: deps.linesGetter,
|
|
2076
|
+
initialQuery: deps.initialQuery(),
|
|
2077
|
+
termCols: tc,
|
|
2078
|
+
termRows: tr,
|
|
2079
|
+
anchorRow,
|
|
2080
|
+
anchorCol,
|
|
2081
|
+
theme: deps.currentThemeTokens(),
|
|
2082
|
+
onJump: (result, query) => {
|
|
2083
|
+
closeLogSearchModal();
|
|
2084
|
+
deps.onJump(result, query);
|
|
2085
|
+
},
|
|
2086
|
+
onCancel: query => {
|
|
2087
|
+
closeLogSearchModal();
|
|
2088
|
+
deps.onCancel(query);
|
|
2089
|
+
},
|
|
2090
|
+
});
|
|
2091
|
+
attachSurfaceToWorkspace(popup.surface, deps.currentWorkspaceOwnerId());
|
|
2092
|
+
modalHandle = deps.display().pushModal(popup.surface);
|
|
2093
|
+
deps.draw();
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2178
2097
|
export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<DashboardAction> {
|
|
2179
2098
|
const dashboardQuitConfirmationState = createQuitConfirmationState();
|
|
2180
2099
|
const signalQuitConfirmationState = createQuitConfirmationState();
|
|
@@ -2196,7 +2115,6 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2196
2115
|
forceQuit: true,
|
|
2197
2116
|
});
|
|
2198
2117
|
});
|
|
2199
|
-
let virtualWindows!: DashboardVirtualWindows;
|
|
2200
2118
|
// E3 (§7.4 TS baseline reduction · 2026-05-17) — forward declarations
|
|
2201
2119
|
// for handler functions that get assigned later via destructure from
|
|
2202
2120
|
// createDashboardCopyRuntime / createDashboardMediaRuntime (lines
|
|
@@ -2404,10 +2322,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2404
2322
|
* same file isn't re-loading twice. Repeats inside the same call
|
|
2405
2323
|
* (same id appearing twice in `added`) are also collapsed.
|
|
2406
2324
|
*
|
|
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. */
|
|
2325
|
+
* Image attachments stay in the chat log without a scratch preview. */
|
|
2411
2326
|
const renderAttachmentSummary = (added: { attachment: Attachment; isNew: boolean }[]): void => {
|
|
2412
2327
|
renderDashboardAttachmentSummary(added, {
|
|
2413
2328
|
formatNewLine: (attachment) =>
|
|
@@ -2419,16 +2334,6 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2419
2334
|
return chatLines.length - 1;
|
|
2420
2335
|
},
|
|
2421
2336
|
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
2337
|
});
|
|
2433
2338
|
};
|
|
2434
2339
|
|
|
@@ -2572,7 +2477,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2572
2477
|
});
|
|
2573
2478
|
},
|
|
2574
2479
|
foldMode: logFoldMode,
|
|
2575
|
-
expandHint:
|
|
2480
|
+
expandHint: false,
|
|
2576
2481
|
});
|
|
2577
2482
|
|
|
2578
2483
|
// Session-scoped skill decline memory (session 21). When the user
|
|
@@ -2633,32 +2538,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2633
2538
|
pushDebugLine(C.muted(` \u251c\u2500 `) + C.text(att.token) + ' ' + C.subtext('(already attached)'));
|
|
2634
2539
|
}
|
|
2635
2540
|
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
|
-
}
|
|
2541
|
+
// The attachment summary confirms the paste without a scratch preview or modal.
|
|
2662
2542
|
return `${att.token} `;
|
|
2663
2543
|
} catch (err: any) {
|
|
2664
2544
|
// grabClipboardImage now throws with the osascript diagnostic
|
|
@@ -2675,19 +2555,21 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2675
2555
|
}
|
|
2676
2556
|
};
|
|
2677
2557
|
|
|
2678
|
-
const renderContextList = ():
|
|
2558
|
+
const renderContextList = (): string[] => {
|
|
2679
2559
|
const items = ctxList(contextRegistry);
|
|
2560
|
+
const lines: string[] = [];
|
|
2561
|
+
const output = (line: string): void => { pushDebugLine(line); lines.push(line); };
|
|
2680
2562
|
pushDebugBlank();
|
|
2681
|
-
|
|
2563
|
+
output(C.accent('\u276f /context'));
|
|
2682
2564
|
if (!items.length) {
|
|
2683
|
-
|
|
2684
|
-
return;
|
|
2565
|
+
output(C.muted(' (empty)'));
|
|
2566
|
+
return lines;
|
|
2685
2567
|
}
|
|
2686
2568
|
const totalBytes = ctxTotalBytes(contextRegistry);
|
|
2687
2569
|
const total = fmtBytes(totalBytes);
|
|
2688
|
-
|
|
2570
|
+
output(C.muted(` ${items.length} items, ${total} total`));
|
|
2689
2571
|
if (totalBytes > CTX_WARN_BYTES) {
|
|
2690
|
-
|
|
2572
|
+
output(C.warning(` ⚠ ${total} exceeds 10MB — consider /context clear big`));
|
|
2691
2573
|
}
|
|
2692
2574
|
|
|
2693
2575
|
// Table columns: ✓ id kind filename(trunc) size [source-tail]
|
|
@@ -2695,7 +2577,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2695
2577
|
// left indent; filename gets the slack column so long paths just clip.
|
|
2696
2578
|
const { cols } = termSize();
|
|
2697
2579
|
const filenameMax = Math.max(18, cols - 36);
|
|
2698
|
-
|
|
2580
|
+
output(C.muted(
|
|
2699
2581
|
` ${' '}${'id'.padEnd(4)}${'kind'.padEnd(7)}${'file'.padEnd(filenameMax)}${'size'.padStart(8)}`
|
|
2700
2582
|
));
|
|
2701
2583
|
for (const a of items) {
|
|
@@ -2704,8 +2586,9 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
|
|
|
2704
2586
|
const kindCol = (KIND_DISPLAY[a.kind] ?? a.kind).padEnd(7);
|
|
2705
2587
|
const file = ellipsize(a.filename, filenameMax).padEnd(filenameMax);
|
|
2706
2588
|
const size = fmtBytes(a.sizeBytes).padStart(8);
|
|
2707
|
-
|
|
2589
|
+
output(` ${mark} ${C.muted(idCol)}${C.muted(kindCol)}${C.text(file)}${C.subtext(size)}`);
|
|
2708
2590
|
}
|
|
2591
|
+
return lines;
|
|
2709
2592
|
};
|
|
2710
2593
|
|
|
2711
2594
|
const chat = createChatState(
|
|
@@ -2863,40 +2746,30 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2863
2746
|
const target = logSearchResults[logSearchCursor]!;
|
|
2864
2747
|
scrollToSearchResult(target);
|
|
2865
2748
|
};
|
|
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
|
-
};
|
|
2749
|
+
const openLogSearchModal = createDashboardLogSearchOpener({
|
|
2750
|
+
display: () => display,
|
|
2751
|
+
linesGetter: () => chatLines,
|
|
2752
|
+
initialQuery: () => logSearchQuery,
|
|
2753
|
+
termSize,
|
|
2754
|
+
computePaneH: rows => computePaneH(rows),
|
|
2755
|
+
currentThemeTokens: () => currentThemeTokens(),
|
|
2756
|
+
currentWorkspaceOwnerId: () => currentWorkspaceOwnerId(),
|
|
2757
|
+
draw: () => draw(),
|
|
2758
|
+
onJump: (result, query) => {
|
|
2759
|
+
applyLogSearch(query);
|
|
2760
|
+
// Position cursor on the picked result. applyLogSearch reset
|
|
2761
|
+
// it to 0; advance it to the result the user actually picked.
|
|
2762
|
+
const idx = logSearchResults.findIndex(r => r.lineIdx === result.lineIdx);
|
|
2763
|
+
logSearchCursor = idx >= 0 ? idx : 0;
|
|
2764
|
+
scrollToSearchResult(result);
|
|
2765
|
+
draw();
|
|
2766
|
+
},
|
|
2767
|
+
onCancel: query => {
|
|
2768
|
+
// Keep the query so n/N still works after cancel — tmux convention.
|
|
2769
|
+
if (query.trim()) applyLogSearch(query);
|
|
2770
|
+
draw();
|
|
2771
|
+
},
|
|
2772
|
+
});
|
|
2900
2773
|
|
|
2901
2774
|
// TUI 부활 S-a — /resume 세션 픽커 (codex 패리티). chat 세션 스토어를
|
|
2902
2775
|
// 필터형 모달로 띄우고, 선택 시 기존 `/session load <id>` slash 를
|
|
@@ -2920,7 +2793,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2920
2793
|
draw();
|
|
2921
2794
|
return;
|
|
2922
2795
|
}
|
|
2923
|
-
//
|
|
2796
|
+
// Pickers share the composer bottom slot.
|
|
2924
2797
|
const placement = resolveDecisionPickerPlacement({ height: 16 });
|
|
2925
2798
|
const modalWidth = placement.width;
|
|
2926
2799
|
const fmtRow = (m: (typeof rows)[number]): string => {
|
|
@@ -2979,12 +2852,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
2979
2852
|
browserMode?: 'all' | 'files' | 'turns',
|
|
2980
2853
|
): Promise<boolean> => {
|
|
2981
2854
|
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
2855
|
const { getSourceDeltaManager, createSourceDeltaBrowserPopup } = await import('../code-edit/index.js');
|
|
2989
2856
|
const turns = mode === 'latest'
|
|
2990
2857
|
? getSourceDeltaManager().recentTurns(1)
|
|
@@ -3284,7 +3151,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3284
3151
|
})
|
|
3285
3152
|
.reverse(); // 최신 턴 먼저
|
|
3286
3153
|
const items: SearchItem[] = turnItems;
|
|
3287
|
-
//
|
|
3154
|
+
// Pickers share the composer bottom slot.
|
|
3288
3155
|
const placement = resolveDecisionPickerPlacement({ height: 16 });
|
|
3289
3156
|
const modalWidth = placement.width;
|
|
3290
3157
|
const handle = createSearchModal({
|
|
@@ -3350,7 +3217,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3350
3217
|
...HITL_REVISE_PRESETS.map((p): SearchItem => ({ label: `${p.label} — 재분해`, payload: `preset:${p.action}` })),
|
|
3351
3218
|
{ label: '✏️ 직접입력 — 정정 코멘트 작성', payload: 'custom' },
|
|
3352
3219
|
];
|
|
3353
|
-
//
|
|
3220
|
+
// Pickers share the composer bottom slot.
|
|
3354
3221
|
const placement = resolveDecisionPickerPlacement({ height: 14 });
|
|
3355
3222
|
const modalWidth = placement.width;
|
|
3356
3223
|
const handle = createSearchModal({
|
|
@@ -3681,33 +3548,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3681
3548
|
let lastAssistantRaw: string | null = null;
|
|
3682
3549
|
let lastAssistantRange: { start: number; end: number } | null = null;
|
|
3683
3550
|
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.
|
|
3551
|
+
// Log-pane resize remains available when chatOnlyMode is toggled off.
|
|
3687
3552
|
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
3553
|
// Chat-only mode: 3-pane grid collapses, log pane owns all space above
|
|
3700
3554
|
// the input. Toggled by /chat or /dashboard. Input loop stays alive
|
|
3701
3555
|
// 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';
|
|
3556
|
+
// Essential layout starts chat-only; /chat and /dashboard still toggle it.
|
|
3557
|
+
let chatOnlyMode = true;
|
|
3711
3558
|
|
|
3712
3559
|
// Debug log — auto-start forensic file capture so every run has a
|
|
3713
3560
|
// tail-able JSONL trail without the user thinking about it. Default
|
|
@@ -3739,12 +3586,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3739
3586
|
debug.setFileEnabled(dbgCfg.file);
|
|
3740
3587
|
// OH9 — 렌더 로그 무음 시드(레벨과 직교). 우선순위:
|
|
3741
3588
|
// level.json.render(명시) > config.debug.renderLogs(true=override) >
|
|
3742
|
-
//
|
|
3589
|
+
// essential 기본 억제. 부팅 시 렌더 노이즈를 자동으로
|
|
3743
3590
|
// 끄고, 대표가 diag 로 올려도 진단은 그대로 흐른다.
|
|
3744
3591
|
debug.setRenderSuppressed(resolveRenderSuppressed({
|
|
3745
3592
|
scopedRender: readScopedRenderLogs(),
|
|
3746
3593
|
configRenderLogs: dbgCfg.renderLogs,
|
|
3747
|
-
|
|
3594
|
+
defaultSuppressed: true,
|
|
3748
3595
|
}));
|
|
3749
3596
|
// Announce the path so the user knows where to tail. Prefixed
|
|
3750
3597
|
// with (muted) so it doesn't compete with real chat output.
|
|
@@ -3771,9 +3618,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3771
3618
|
debugScrollOffset = -1;
|
|
3772
3619
|
mirrorDrawThrottle.request();
|
|
3773
3620
|
});
|
|
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.
|
|
3621
|
+
// --debug launch flag: force both sinks ON and announce it in the log pane.
|
|
3777
3622
|
if (opts.debug) {
|
|
3778
3623
|
debug.setFileEnabled(true);
|
|
3779
3624
|
debug.enable();
|
|
@@ -3837,14 +3682,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3837
3682
|
// ── Plugin host (Phase 2) ──
|
|
3838
3683
|
const hud = createHud();
|
|
3839
3684
|
|
|
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
3685
|
// Reasoning HUD segment — provider-agnostic emoji + label that
|
|
3849
3686
|
// sits in the top transient HUD row (next to voice / streaming
|
|
3850
3687
|
// indicators), NOT the bottom status bar. Capability-driven: pill
|
|
@@ -3929,42 +3766,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3929
3766
|
const toggleChatOnlyLayout = (opts: { announce?: boolean } = {}): void => {
|
|
3930
3767
|
setChatOnlyLayout(!chatOnlyMode, opts);
|
|
3931
3768
|
};
|
|
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
3769
|
// Mirror chatOnly launch flag into the HUD pill (same style /chat
|
|
3969
3770
|
// toggle uses) so the user sees "mode: chat" from the first frame.
|
|
3970
3771
|
if (chatOnlyMode) setSegment(hud, 'mode', C.info('mode: chat'), 10);
|
|
@@ -4004,25 +3805,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4004
3805
|
}
|
|
4005
3806
|
: {};
|
|
4006
3807
|
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
3808
|
pruneConversationPopupHost();
|
|
4027
3809
|
const conversationSnapshot = conversationPopupHost.snapshot();
|
|
4028
3810
|
const metrics = getSessionMetrics();
|
|
@@ -4039,7 +3821,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4039
3821
|
controller: process.env.ELANOUS_CONTROLLER?.trim() || undefined,
|
|
4040
3822
|
shellCount: liveShells,
|
|
4041
3823
|
shellRollup: latestShellRollup ?? undefined,
|
|
4042
|
-
vw:
|
|
3824
|
+
vw: null,
|
|
4043
3825
|
conversationPopups: {
|
|
4044
3826
|
liveCount: conversationSnapshot.live.length,
|
|
4045
3827
|
minimizedCount: conversationSnapshot.minimized.length,
|
|
@@ -4368,9 +4150,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4368
4150
|
cols: termSize().cols,
|
|
4369
4151
|
syntax: true,
|
|
4370
4152
|
colorTier: diffRendering.colorTier,
|
|
4371
|
-
adaptiveBg: diffRendering.adaptiveBg,
|
|
4372
|
-
syntaxPerHunk: diffRendering.syntaxPerHunk,
|
|
4373
|
-
cache: diffRendering.cache,
|
|
4374
4153
|
headerStyle: diffRendering.headerStyle,
|
|
4375
4154
|
})
|
|
4376
4155
|
.then((rows) => {
|
|
@@ -4471,13 +4250,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4471
4250
|
// tools) has one place to fan keys + clipboard across groups.
|
|
4472
4251
|
// Phase T5 — terminal IPC channel bus. Fetched via getChannelBus()
|
|
4473
4252
|
// 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
4253
|
// P16 — mirror session metadata to
|
|
4482
4254
|
// ~/.config/monad-agent/terminal-sessions.json on each lifecycle
|
|
4483
4255
|
// change (debounced 250ms). /term resume later re-spawns from this.
|
|
@@ -4508,22 +4280,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4508
4280
|
// dispatch so browser Ctrl+W / /wd retargets Bash immediately.
|
|
4509
4281
|
setBashRuntimeDeps({});
|
|
4510
4282
|
|
|
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.
|
|
4283
|
+
// ShellRunner registry tracks handles; file capture runs inline/bg commands.
|
|
4519
4284
|
{
|
|
4520
4285
|
const { initShellRegistry } = await import('../shell-runner/registry.js');
|
|
4521
4286
|
const { createFileCaptureEngine } = await import('../shell-runner/file-engine.js');
|
|
4522
4287
|
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
4288
|
const { createBackgroundSurface } = await import('../shell-runner/background-surface.js');
|
|
4526
|
-
const { registerPaneContentKind } = await import('../virtual-windows/pane-content.js');
|
|
4527
4289
|
// The boot seam types the registry as the opaque `ShellRegistryLike`
|
|
4528
4290
|
// stub (decoupling), while the real `wireShellRunnerSurface` takes a
|
|
4529
4291
|
// concrete `ShellRegistry`. At runtime `initShellRegistry` returns the
|
|
@@ -4538,161 +4300,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4538
4300
|
deps: { shellRegistry: unknown },
|
|
4539
4301
|
) => void;
|
|
4540
4302
|
} 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
4303
|
bootDashboardShellRunner({
|
|
4638
4304
|
createBackgroundSurface,
|
|
4639
4305
|
initShellRegistry,
|
|
4640
4306
|
wireShellRunnerSurface,
|
|
4641
|
-
registerPaneContentKind,
|
|
4642
|
-
createExternalTerminalPaneContent,
|
|
4643
|
-
createRunnerHostFactory,
|
|
4644
4307
|
createFileCaptureEngine,
|
|
4645
4308
|
setShellRunnerDeps,
|
|
4646
|
-
getSessionCwd: () => getSessionCwd(),
|
|
4647
|
-
termSize: () => termSize(),
|
|
4648
4309
|
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
4310
|
});
|
|
4697
4311
|
}
|
|
4698
4312
|
const { setShellApprover } = await import('../shell-primitive/index.js');
|
|
@@ -4819,9 +4433,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4819
4433
|
} catch { return []; }
|
|
4820
4434
|
});
|
|
4821
4435
|
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).
|
|
4436
|
+
// Phase C — wire context.* tools without virtual-window state.
|
|
4825
4437
|
const { setContextRuntimeDeps } = await import('../tool-runtime/index.js');
|
|
4826
4438
|
// Surface-unification v2.2 V2.2-5 (2026-05-11) — scheduler store
|
|
4827
4439
|
// wire retired together with `context.jobs.list` LLM tool.
|
|
@@ -4924,103 +4536,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
4924
4536
|
debug.log(scope, area, details);
|
|
4925
4537
|
},
|
|
4926
4538
|
});
|
|
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.
|
|
4539
|
+
// PaneVisualStateStore serves dashboard pane tools.
|
|
4934
4540
|
const paneVisualStateStore = createVisualStateStore();
|
|
4935
4541
|
let browserPaneRegistry!: BrowserPaneRegistry;
|
|
4936
4542
|
let previewPaneRegistry!: PreviewPaneRegistry;
|
|
4937
4543
|
|
|
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.
|
|
4544
|
+
// Browser-pane help (`~`) uses the transient modal primitive.
|
|
5024
4545
|
const browserHelpRuntime = createBrowserHelpRuntime({
|
|
5025
4546
|
termSize,
|
|
5026
4547
|
keyLabel: (key, desc) => ` ${C.key(pad(key, 14))} ${C.text(desc)}`,
|
|
@@ -5038,243 +4559,11 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5038
4559
|
});
|
|
5039
4560
|
},
|
|
5040
4561
|
});
|
|
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.
|
|
4562
|
+
// Refresh context runtime deps after the dashboard session registry is ready.
|
|
5269
4563
|
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.
|
|
4564
|
+
const { setContextRuntimeDeps } = await import('../tool-runtime/index.js');
|
|
5274
4565
|
bootDashboardContextWindowRuntime({
|
|
5275
|
-
setControlRuntimeDeps,
|
|
5276
4566
|
setContextRuntimeDeps,
|
|
5277
|
-
registry: virtualWindows.registry,
|
|
5278
4567
|
// WD7 — context runtime cwd follows SWD.
|
|
5279
4568
|
cwd: getSessionCwd(),
|
|
5280
4569
|
getTerminalSessions: () => sessionRegistry.list().map((s) => ({
|
|
@@ -5463,7 +4752,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5463
4752
|
wireDashboardSurfaceRegistry({
|
|
5464
4753
|
surfaceRegistry,
|
|
5465
4754
|
widgetHost,
|
|
5466
|
-
windowRegistry: virtualWindows.registry,
|
|
5467
4755
|
});
|
|
5468
4756
|
} catch { /* never break boot */ }
|
|
5469
4757
|
|
|
@@ -5495,8 +4783,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5495
4783
|
try {
|
|
5496
4784
|
registerDashboardScenarioRuntimes({
|
|
5497
4785
|
scenarioCatalog,
|
|
5498
|
-
registry: virtualWindows.registry,
|
|
5499
|
-
createPaneContent,
|
|
5500
4786
|
spawnWidget: (spec) => widgetHost.spawn(spec),
|
|
5501
4787
|
disposeWidget: (id) => { widgetHost.dispose(id); },
|
|
5502
4788
|
getDashboardModals: () => dashboardModals,
|
|
@@ -5523,7 +4809,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5523
4809
|
const artifactStore = createArtifactStore({
|
|
5524
4810
|
legacyProviders: [
|
|
5525
4811
|
createLegacyTimelineProvider({ dir: defaultTimelineBaseDir() }),
|
|
5526
|
-
createLegacyLayoutProvider({ dir: layoutsDir() }),
|
|
5527
4812
|
],
|
|
5528
4813
|
});
|
|
5529
4814
|
try {
|
|
@@ -5960,19 +5245,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
5960
5245
|
afterThemeActiveSaved: draw,
|
|
5961
5246
|
});
|
|
5962
5247
|
|
|
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
5248
|
// H5 P2 bootstrap — register the default channel router patterns
|
|
5977
5249
|
// + codex-pty adapter hook, then bind the TTY snapshot LLM tools
|
|
5978
5250
|
// to the live embodied-session registry. Without this wiring:
|
|
@@ -6127,15 +5399,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6127
5399
|
findLiveSessionById,
|
|
6128
5400
|
findLiveSessionByPaneId,
|
|
6129
5401
|
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
|
-
},
|
|
5402
|
+
getFocusedVirtualWindowPane: () => ({ vwId: null, paneId: null, paneKind: null }),
|
|
6139
5403
|
noteUserSubmit: (sessionId, text) => globalAcpEventRouter().noteUserSubmit(sessionId, text),
|
|
6140
5404
|
clientSessionSend: (opts) => globalDualRoleManager().clientSessionSend(opts),
|
|
6141
5405
|
getWorkingFocus: () => workingDir.focus,
|
|
@@ -6200,25 +5464,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6200
5464
|
'../capture/capture-tools.js'
|
|
6201
5465
|
);
|
|
6202
5466
|
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
|
-
},
|
|
5467
|
+
resolveScreenshotTarget: () => null,
|
|
6222
5468
|
dispatchScreenshot: async (args) => {
|
|
6223
5469
|
const out = await pfcDispatchScreenshot(args);
|
|
6224
5470
|
return {
|
|
@@ -6620,25 +5866,19 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6620
5866
|
// 페인트를 멈춰 하단 영역의 단일 소유자를 보장(codex mod.rs:1674 · CC
|
|
6621
5867
|
// REPL.tsx:4894 동형). 키는 기존 blocking-modal 라우팅 그대로 뷰가 소비.
|
|
6622
5868
|
const bottomSlotModalActive = (): boolean => topBlockingForegroundModal()?.slot === 'bottom';
|
|
6623
|
-
//
|
|
6624
|
-
// 중앙 플로팅 유지(/ui 왕복 즉시 반영 — 호출 시점 게이트 패턴).
|
|
5869
|
+
// Pickers occupy the composer bottom slot.
|
|
6625
5870
|
const resolveDecisionPickerPlacement = (desired: { height: number }): {
|
|
6626
5871
|
bounds: { row: number; col: number; width: number; height: number };
|
|
6627
5872
|
slot?: 'bottom';
|
|
6628
5873
|
width: number;
|
|
6629
5874
|
} => {
|
|
6630
5875
|
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 };
|
|
5876
|
+
const bounds = resolveBottomSlotBounds({
|
|
5877
|
+
termCols: tc, termRows: tr,
|
|
5878
|
+
promptFrame: currentPromptFrame(tr),
|
|
5879
|
+
height: desired.height,
|
|
5880
|
+
});
|
|
5881
|
+
return { bounds, slot: 'bottom', width: bounds.width };
|
|
6642
5882
|
};
|
|
6643
5883
|
const topBottomAreaFreezeModal = (
|
|
6644
5884
|
termRows = termSize().rows,
|
|
@@ -6688,7 +5928,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6688
5928
|
}
|
|
6689
5929
|
return policy.suppressPromptArea || policy.suppressStatusArea;
|
|
6690
5930
|
};
|
|
6691
|
-
const vwCompanionOwnerId = (windowId: string | number): string => `virtual-window:${windowId}`;
|
|
6692
5931
|
const companionPopupSpec = (
|
|
6693
5932
|
key: CompanionPopupKey,
|
|
6694
5933
|
): {
|
|
@@ -6931,189 +6170,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6931
6170
|
syncCompanionPopups();
|
|
6932
6171
|
return next;
|
|
6933
6172
|
};
|
|
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
6173
|
const {
|
|
7118
6174
|
syncConversationPopupModals,
|
|
7119
6175
|
setConversationPopupLayoutMode,
|
|
@@ -7144,7 +6200,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7144
6200
|
createAgentSessionProvider,
|
|
7145
6201
|
createBrowserCdpProvider,
|
|
7146
6202
|
registerProvider: (registry, provider) => { registry.registerProvider(provider); },
|
|
7147
|
-
getWindows: () =>
|
|
6203
|
+
getWindows: () => [],
|
|
7148
6204
|
listSessions: () => listLiveEmbodiedSessions(),
|
|
7149
6205
|
// H6 P5 observer-registry landed · threading through enables
|
|
7150
6206
|
// the channel-aware snapshot path (falls back to raw snapshot
|
|
@@ -7167,7 +6223,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7167
6223
|
|
|
7168
6224
|
// ACP follow-up #1 — auto-persist on turn-end. DRM end_turn
|
|
7169
6225
|
// transitions + BG terminal states flow into the H2 #5 persistence
|
|
7170
|
-
// primitive automatically
|
|
6226
|
+
// primitive automatically (always on — off-switch graduated 2026-09-26).
|
|
7171
6227
|
wireAutoPersist({
|
|
7172
6228
|
drm: globalDualRoleManager(),
|
|
7173
6229
|
bg: globalBackgroundManager(),
|
|
@@ -7178,17 +6234,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7178
6234
|
// the in-memory BackgroundManager bounded for long-running elanous
|
|
7179
6235
|
// processes. Auto-persist (#1) already flushed the terminal record
|
|
7180
6236
|
// to disk, so sweeping doesn't lose history · only the live stub.
|
|
7181
|
-
//
|
|
6237
|
+
// Always on (ELANOUS_ACP_BG_SWEEP_MODE off-switch graduated 2026-09-26). Defaults: 24h TTL ·
|
|
7182
6238
|
// 1h tick (matches Warp cloud-agent "stale after a day" heuristic).
|
|
7183
6239
|
bootDashboardAcpBgSweep({
|
|
7184
|
-
enabled:
|
|
6240
|
+
enabled: true,
|
|
7185
6241
|
backgroundManager: globalBackgroundManager(),
|
|
7186
6242
|
});
|
|
7187
6243
|
|
|
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
6244
|
// T6-K5 — wire widget + pane control tools. Widgets are reported
|
|
7193
6245
|
// from widgetHost; pane focus piggybacks on workingDir.focus. The
|
|
7194
6246
|
// pane name list mirrors the PaneFocus type so the LLM sees valid
|
|
@@ -7268,32 +6320,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
7268
6320
|
openSurfaceCatalogPopup();
|
|
7269
6321
|
return true;
|
|
7270
6322
|
},
|
|
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
|
-
},
|
|
6323
|
+
openSurfaceInVw: () => false,
|
|
7290
6324
|
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
|
-
}
|
|
6325
|
+
if (target === 'vw') return false;
|
|
7297
6326
|
setCompanionPopupOpen(surface, true);
|
|
7298
6327
|
return true;
|
|
7299
6328
|
},
|
|
@@ -8096,131 +7125,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
8096
7125
|
const activeBrowserState = (): BrowserPaneModel => (
|
|
8097
7126
|
resolveBrowserStateById(activeBrowserWidgetId()) ?? (workingDir as BrowserPaneModel)
|
|
8098
7127
|
);
|
|
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
7128
|
// T7-N1 — ACP chat bridge. Speaks JSON-RPC to claude-code-acp /
|
|
8225
7129
|
// codex-acp / gemini via the real client in src/acp/*. Subprocess
|
|
8226
7130
|
// spawn is lazy — no cost until the user runs /acp.
|
|
@@ -8255,7 +7159,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
8255
7159
|
// Scratch visibility (Phase S5). When closed, the workingDir
|
|
8256
7160
|
// layouts drop the scratch cell so the remaining panes expand
|
|
8257
7161
|
// to fill the reclaimed columns — useful on narrow terminals.
|
|
8258
|
-
// Reopen via the
|
|
7162
|
+
// Reopen via the ^B ^S chord.
|
|
8259
7163
|
let scratchClosed = false;
|
|
8260
7164
|
const dashboardViewRegistryOptions = () => ({
|
|
8261
7165
|
extraPanes: pluginHost.activeDashboardPanes().map(p => p.paneId),
|
|
@@ -8322,7 +7226,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
8322
7226
|
// chrome rows (input/status/dock), but that does not mean the
|
|
8323
7227
|
// main workspace's chat composer remains an active input owner.
|
|
8324
7228
|
const chatMainAvailable = foregroundWorkspace === null;
|
|
8325
|
-
const vwLocalComposerActive =
|
|
7229
|
+
const vwLocalComposerActive = false;
|
|
8326
7230
|
const overlayInputActive = hasOverlayInputOwner({
|
|
8327
7231
|
focusStack: display.modalStack(),
|
|
8328
7232
|
surfaceAt: (id) => display.surface(id),
|
|
@@ -9579,13 +8483,11 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
9579
8483
|
agentStatusStore.clear(ev.instance.id);
|
|
9580
8484
|
claudeStatusParser.reset(ev.instance.id);
|
|
9581
8485
|
codexStatusParser.reset(ev.instance.id);
|
|
9582
|
-
closeVwPaneForExit(ev.instance.placement, 'exited');
|
|
9583
8486
|
} else if (ev.type === 'killed') {
|
|
9584
8487
|
notificationStore.push(exitToNotification(ev.instance.id, null));
|
|
9585
8488
|
agentStatusStore.clear(ev.instance.id);
|
|
9586
8489
|
claudeStatusParser.reset(ev.instance.id);
|
|
9587
8490
|
codexStatusParser.reset(ev.instance.id);
|
|
9588
|
-
closeVwPaneForExit(ev.instance.placement, 'killed');
|
|
9589
8491
|
} else if (ev.type === 'attention') {
|
|
9590
8492
|
notificationStore.push(attentionToNotification(ev.instance.id, ev.level));
|
|
9591
8493
|
}
|
|
@@ -9620,27 +8522,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
9620
8522
|
try { debug.log('agent-status.mirror.activate-failed', String(err), { level: 'error' }); } catch { /* swallow */ }
|
|
9621
8523
|
}
|
|
9622
8524
|
})();
|
|
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
8525
|
const disposeConversationWidgetLiveBridge = createConversationWidgetLiveBridge({
|
|
9645
8526
|
widgetHost,
|
|
9646
8527
|
listSessions: () => listLiveEmbodiedSessions().map((entry) => ({
|
|
@@ -10888,24 +9769,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
10888
9769
|
});
|
|
10889
9770
|
}
|
|
10890
9771
|
}
|
|
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
9772
|
const clipboardWidget = widgetHost.get('wd-clipboard') as any;
|
|
10910
9773
|
companionWidgetRuntime.projectClipboardWidget(
|
|
10911
9774
|
clipboardWidget,
|
|
@@ -11726,18 +10589,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11726
10589
|
getScratchTotalBytes: () => scratchLines.reduce((n, l) => n + l.length, 0),
|
|
11727
10590
|
isCompanionOpen: (key) => companionPopupHost.isActive(key as CompanionPopupKey),
|
|
11728
10591
|
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
10592
|
getDebugPath: () => debug.path(),
|
|
11742
10593
|
getDebugLevel: () => debug.level(),
|
|
11743
10594
|
});
|
|
@@ -11915,103 +10766,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
11915
10766
|
});
|
|
11916
10767
|
return;
|
|
11917
10768
|
}
|
|
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
10769
|
case 'dashboard-pane.open-popup': {
|
|
11994
10770
|
const payload = result.payload as DashboardPaneTitleMenuPayload | undefined;
|
|
11995
10771
|
if (!payload) return;
|
|
11996
10772
|
openDashboardPaneModal(payload.pane);
|
|
11997
10773
|
return;
|
|
11998
10774
|
}
|
|
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
10775
|
case 'dashboard-pane.clipboard-companion': {
|
|
12016
10776
|
const opened = toggleCompanionPopup('clipboard');
|
|
12017
10777
|
contextMenuFeedbackRuntime.onDashboardCompanionToggled('clipboard', opened);
|
|
@@ -12071,13 +10831,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12071
10831
|
openBrowserPreviewModal: () => openBrowserPreviewModal(),
|
|
12072
10832
|
openDashboardPaneModal: (pane) => openDashboardPaneModal(pane),
|
|
12073
10833
|
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
10834
|
onWarning: (message) => {
|
|
12082
10835
|
pushDebugLine(C.warning(` ${message}`));
|
|
12083
10836
|
chatScrollOffset = -1;
|
|
@@ -12131,20 +10884,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12131
10884
|
pushChatLine: (line) => { chatLines.push(line); },
|
|
12132
10885
|
setChatScrollBottom: () => { chatScrollOffset = -1; },
|
|
12133
10886
|
});
|
|
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
10887
|
const termSlashRuntime = createDashboardTermSlashRuntime({
|
|
12149
10888
|
accent: C.accent,
|
|
12150
10889
|
muted: C.muted,
|
|
@@ -12182,36 +10921,27 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12182
10921
|
muted: C.muted,
|
|
12183
10922
|
warning: C.warning,
|
|
12184
10923
|
});
|
|
12185
|
-
const
|
|
10924
|
+
const companionSlashRuntime = createDashboardCompanionSlashRuntime({
|
|
12186
10925
|
muted: C.muted,
|
|
12187
10926
|
warning: C.warning,
|
|
12188
10927
|
});
|
|
12189
|
-
const
|
|
10928
|
+
const agentsSlashRuntime = createDashboardAgentsSlashRuntime({
|
|
12190
10929
|
muted: C.muted,
|
|
12191
10930
|
warning: C.warning,
|
|
12192
10931
|
});
|
|
12193
|
-
const
|
|
10932
|
+
const controlSignalSlashRuntime = createDashboardControlSignalSlashRuntime({
|
|
10933
|
+
accent: C.accent,
|
|
12194
10934
|
muted: C.muted,
|
|
12195
10935
|
warning: C.warning,
|
|
10936
|
+
observer: defaultControlSignalObserver(),
|
|
10937
|
+
signalBus: dashboardControlSignals,
|
|
12196
10938
|
});
|
|
12197
|
-
const
|
|
10939
|
+
const browserCdpSlashRuntime = createDashboardBrowserCdpSlashRuntime({
|
|
10940
|
+
accent: C.accent,
|
|
12198
10941
|
muted: C.muted,
|
|
12199
|
-
success: C.success,
|
|
12200
10942
|
warning: C.warning,
|
|
10943
|
+
signalBus: dashboardControlSignals,
|
|
12201
10944
|
});
|
|
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
10945
|
const simSlashRuntime = createDashboardSimSlashRuntime({
|
|
12216
10946
|
accent: C.accent,
|
|
12217
10947
|
muted: C.muted,
|
|
@@ -12252,27 +10982,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12252
10982
|
muted: C.muted,
|
|
12253
10983
|
warning: C.warning,
|
|
12254
10984
|
});
|
|
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
10985
|
const mousePickerRuntime = createMousePickerRuntime({
|
|
12277
10986
|
getRotation: () => getUserConfig().llm.rotation ?? [],
|
|
12278
10987
|
getCurrentModelEntry: () => {
|
|
@@ -12283,343 +10992,58 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12283
10992
|
...(llm.model !== undefined ? { model: llm.model } : {}),
|
|
12284
10993
|
};
|
|
12285
10994
|
},
|
|
12286
|
-
applyActiveModel: (entry) => {
|
|
12287
|
-
const nextCfg = applyRotationEntry(getUserConfig(), entry);
|
|
12288
|
-
saveUserConfig(nextCfg);
|
|
12289
|
-
reloadUserConfig();
|
|
12290
|
-
},
|
|
12291
|
-
getRecentWds: () => [...wdHistory],
|
|
12292
|
-
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
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
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
|
-
}
|
|
12622
|
-
},
|
|
10995
|
+
applyActiveModel: (entry) => {
|
|
10996
|
+
const nextCfg = applyRotationEntry(getUserConfig(), entry);
|
|
10997
|
+
saveUserConfig(nextCfg);
|
|
10998
|
+
reloadUserConfig();
|
|
10999
|
+
},
|
|
11000
|
+
getRecentWds: () => [...wdHistory],
|
|
11001
|
+
applySessionWd: (path) => {
|
|
11002
|
+
setSessionCwd(path, 'user');
|
|
11003
|
+
rememberWd(path);
|
|
11004
|
+
},
|
|
11005
|
+
reportModelSwitchError: (message) => {
|
|
11006
|
+
chatLines.push(C.error(` model switch failed: ${message}`));
|
|
11007
|
+
chatScrollOffset = -1;
|
|
11008
|
+
},
|
|
11009
|
+
reportWdSwitchError: (message) => {
|
|
11010
|
+
chatLines.push(C.error(` cwd switch failed: ${message}`));
|
|
11011
|
+
chatScrollOffset = -1;
|
|
11012
|
+
},
|
|
11013
|
+
});
|
|
11014
|
+
const mouseShellRollupRuntime = createMouseShellRollupRuntime({
|
|
11015
|
+
resolveVwIdByLabel: () => null,
|
|
11016
|
+
switchToVirtualWindow: () => { throw new Error('Virtual windows are unavailable in the essential dashboard'); },
|
|
11017
|
+
onWarning: (message) => {
|
|
11018
|
+
chatLines.push(C.warning(` ${message}`));
|
|
11019
|
+
chatScrollOffset = -1;
|
|
11020
|
+
},
|
|
11021
|
+
});
|
|
11022
|
+
const mouseConversationPopupRuntime = createMouseConversationPopupRuntime({
|
|
11023
|
+
conversationPopupHost,
|
|
11024
|
+
ensureConversationWidgetMounted,
|
|
11025
|
+
syncConversationPopupModals,
|
|
11026
|
+
redraw: () => { draw(); },
|
|
11027
|
+
});
|
|
11028
|
+
const mouseModeSwitchRuntime = createMouseModeSwitchRuntime({
|
|
11029
|
+
getActiveMode: () => inputCoreActiveMode(),
|
|
11030
|
+
getModeAction: (actionId) => getInputCoreAction(actionId),
|
|
11031
|
+
setMode: (next) => inputCoreSetMode(next),
|
|
11032
|
+
});
|
|
11033
|
+
const mouseModalHitRuntime = createMouseModalHitRuntime({
|
|
11034
|
+
getTopSurface: () => {
|
|
11035
|
+
const stack = display.modalStack();
|
|
11036
|
+
const topId = stack[stack.length - 1];
|
|
11037
|
+
if (!topId) return null;
|
|
11038
|
+
return display.surface(topId) as import('../display/modal-stack.js').ModalSurface | null;
|
|
11039
|
+
},
|
|
11040
|
+
});
|
|
11041
|
+
const mouseModalSurfaceRuntime = createMouseModalSurfaceRuntime({
|
|
11042
|
+
getFocusStack: () => display.modalStack(),
|
|
11043
|
+
surfaceAt: (id) =>
|
|
11044
|
+
display.surface(id) as import('../display/modal-stack.js').ModalSurface | null | undefined,
|
|
11045
|
+
getTopBlockingModalSurface: topBlockingForegroundModal,
|
|
11046
|
+
routeModalMouse: (surface, ev) => display.routeMouseToSurface(surface, ev),
|
|
12623
11047
|
});
|
|
12624
11048
|
const mousePaneHitRuntime = createMousePaneHitRuntime({
|
|
12625
11049
|
getPaneNavRow: () => paneNavRow,
|
|
@@ -12649,29 +11073,16 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12649
11073
|
|
|
12650
11074
|
const mouseWiring = createDashboardMouseWiring({
|
|
12651
11075
|
termSize: () => termSize(),
|
|
12652
|
-
|
|
12653
|
-
// /ui 런타임 전환을 따르도록 predicate 로 배선.
|
|
12654
|
-
hoverPopupsEnabled: () => isDashboardHeavyFeatureEnabled(dashboardUiMode, 'hover-popups'),
|
|
11076
|
+
hoverPopupsEnabled: () => false,
|
|
12655
11077
|
getRotation: mousePickerRuntime.getRotation,
|
|
12656
11078
|
getCurrentModelEntry: mousePickerRuntime.getCurrentModelEntry,
|
|
12657
11079
|
setActiveModel: mousePickerRuntime.setActiveModel,
|
|
12658
11080
|
getRecentWds: mousePickerRuntime.getRecentWds,
|
|
12659
11081
|
setSessionWd: mousePickerRuntime.setSessionWd,
|
|
12660
|
-
getDockMenuWindowTargets: mouseDockRuntime.getDockMenuWindowTargets,
|
|
12661
|
-
onOpenDockWindow: mouseDockRuntime.onOpenDockWindow,
|
|
12662
|
-
getDockMenuSurfaceTargets: mouseDockRuntime.getDockMenuSurfaceTargets,
|
|
12663
|
-
onOpenDockSurface: mouseDockRuntime.onOpenDockSurface,
|
|
12664
|
-
onToggleChatOnly: mouseDockRuntime.onToggleChatOnly,
|
|
12665
11082
|
onExitProgram: async () => {
|
|
12666
11083
|
exitDashboardTui();
|
|
12667
11084
|
setTimeout(() => process.exit(0), 0);
|
|
12668
11085
|
},
|
|
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
11086
|
pushModalSurface: surface => display.pushModal(surface),
|
|
12676
11087
|
// DS-2b (2026-04-21) — drag-session routing hook. Adapter lives
|
|
12677
11088
|
// in src/display/drag-dispatch.ts (PR #319); this single line is
|
|
@@ -12680,10 +11091,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12680
11091
|
// the existing chain (0 overhead path). See PLAN-drag-session-
|
|
12681
11092
|
// primitive.md §3.3 and PR #319 for the contract.
|
|
12682
11093
|
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
|
|
11094
|
+
// CMX-2 (2026-04-22) — non-pill right-click dispatch. This hook
|
|
11095
|
+
// serves pane-body / pane-title / input / VW right-clicks via
|
|
11096
|
+
// MenuProviderRegistry. Unconsumed
|
|
12687
11097
|
// (no provider matches) falls through to modal forwarding.
|
|
12688
11098
|
contextMenuDispatch: (ev) => ctxMenuWire.onMouse(ev),
|
|
12689
11099
|
// DS-3a (2026-04-21) — chat input hit classifier. Routes clicks
|
|
@@ -12703,18 +11113,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12703
11113
|
updateModalBounds: (id, bounds) => display.updateModalBounds(id, bounds),
|
|
12704
11114
|
redraw: () => { draw(); },
|
|
12705
11115
|
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
11116
|
conversationPopupHost,
|
|
12716
11117
|
onConversationPopupPick: mouseConversationPopupRuntime.onConversationPopupPick,
|
|
12717
|
-
onWindowPillClick: mouseModalSurfaceRuntime.onWindowPillClick,
|
|
12718
11118
|
// SRF-4 — shell rollup pill click → popup listing live handles.
|
|
12719
11119
|
// Handles are fetched at click time so the popup always reflects
|
|
12720
11120
|
// the current ShellRegistry state (not a frozen snapshot).
|
|
@@ -12742,13 +11142,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12742
11142
|
getTheme: () => currentThemeTokens(),
|
|
12743
11143
|
suppressHoverHints: true,
|
|
12744
11144
|
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
11145
|
// IDX-5 Phase 3 B-4 — classify clicks outside the status-bar pill
|
|
12753
11146
|
// row into broader pane regions so lastClickHitKind can carry
|
|
12754
11147
|
// 'pane-nav' / 'pane-title' / 'pane-body' values (previously only
|
|
@@ -12781,14 +11174,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12781
11174
|
getTheme: () => currentThemeTokens(),
|
|
12782
11175
|
});
|
|
12783
11176
|
|
|
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.
|
|
11177
|
+
// F6 / S1.D — display-control runtime registration needs late-boot mouse/context-menu state.
|
|
12788
11178
|
try {
|
|
12789
11179
|
registerDashboardLayoutDisplayRuntimes({
|
|
12790
|
-
windowRegistry: virtualWindows.registry,
|
|
12791
|
-
artifactStore,
|
|
12792
11180
|
coordinator: display,
|
|
12793
11181
|
mouseDispatch: (ev) => mouseWiring.handleMouse(ev),
|
|
12794
11182
|
menuProviderRegistry: ctxMenuProviders,
|
|
@@ -12815,16 +11203,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12815
11203
|
// values are cheap no-ops (one field comparison per key).
|
|
12816
11204
|
publishFocusContextKeysFromService(workingDir.focus);
|
|
12817
11205
|
|
|
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
11206
|
|
|
12829
11207
|
// T3-B1: agent-activity HUD segment. Pulsing glyph + running
|
|
12830
11208
|
// count drives awareness that sub-agent work is in flight —
|
|
@@ -12962,9 +11340,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
12962
11340
|
}
|
|
12963
11341
|
const suppressPromptArea = hostChromePolicy.suppressPromptArea;
|
|
12964
11342
|
const suppressStatusArea = hostChromePolicy.suppressStatusArea;
|
|
12965
|
-
const suppressHudArea = hostChromePolicy.suppressHudArea;
|
|
12966
11343
|
const suppressDashboardBackground = hostChromePolicy.suppressDashboardBackground;
|
|
12967
|
-
const suppressDockArea = hostChromePolicy.suppressDockArea;
|
|
12968
11344
|
if (suppressPromptArea) display.setCursor(null);
|
|
12969
11345
|
// ── Zone list (top-to-bottom) ──
|
|
12970
11346
|
// Replaces the old inline `termRows - N` arithmetic and hand-rolled
|
|
@@ -13034,18 +11410,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13034
11410
|
});
|
|
13035
11411
|
}
|
|
13036
11412
|
|
|
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
|
-
}
|
|
11413
|
+
// Essential chrome uses only the status line, not a HUD row.
|
|
13049
11414
|
|
|
13050
11415
|
// Input block.
|
|
13051
11416
|
let promptCaret: CursorState | null = null;
|
|
@@ -13075,24 +11440,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13075
11440
|
render: (_h, c) => [suppressPromptArea ? ' '.repeat(c) : hLine(c)],
|
|
13076
11441
|
});
|
|
13077
11442
|
|
|
13078
|
-
//
|
|
13079
|
-
// TUI 부활 T1: essential 은 status line 1줄만 유지(대표 확정 ①) —
|
|
13080
|
-
// gap-mid·dock 행 생략으로 chat log 가 2행 더 얻는다. dock 클릭
|
|
13081
|
-
// 라우팅은 setDockRow(null) 경로로 자연 비활성.
|
|
11443
|
+
// Essential bottom area: status line only; no dock row.
|
|
13082
11444
|
zones.push({ id: 'status-gap-top', height: 1, render: () => [''] });
|
|
13083
11445
|
zones.push({
|
|
13084
11446
|
id: 'status',
|
|
13085
11447
|
height: 1,
|
|
13086
11448
|
render: () => [suppressStatusArea ? '' : buildStatusLine()],
|
|
13087
11449
|
});
|
|
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
11450
|
|
|
13097
11451
|
// Compose.
|
|
13098
11452
|
const composed = composeVertical(zones, { rows: termRows, cols: totalW });
|
|
@@ -13151,11 +11505,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13151
11505
|
// is one of the easiest ways to see a flash under tmux.
|
|
13152
11506
|
let modalFrame = '';
|
|
13153
11507
|
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
11508
|
if (effectiveLayout && effectiveLayout.modals.length > 0) {
|
|
13160
11509
|
const m = effectiveLayout.modals[0]!;
|
|
13161
11510
|
modalKey = `${m.id}:${m.widgetInstanceId}:${JSON.stringify(m.position)}:${m.size?.width ?? ''}x${m.size?.height ?? ''}`;
|
|
@@ -13163,15 +11512,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13163
11512
|
termRows, termCols: cols, theme: currentThemeTokens(),
|
|
13164
11513
|
});
|
|
13165
11514
|
}
|
|
13166
|
-
if (foregroundWorkspaceFrame.length > 0) {
|
|
13167
|
-
modalFrame += foregroundWorkspaceFrame;
|
|
13168
|
-
}
|
|
13169
11515
|
if (debug.isKeyTraceEnabled() && blockingForegroundModal) {
|
|
13170
11516
|
debug.log('dashboard.frame-compose', 'blocking-modal', {
|
|
13171
11517
|
modalId: blockingForegroundModal.id,
|
|
13172
11518
|
baseLineCount: baseLines.length,
|
|
13173
11519
|
overlayLen: modalFrame.length,
|
|
13174
|
-
hasForegroundWorkspaceFrame:
|
|
11520
|
+
hasForegroundWorkspaceFrame: false,
|
|
13175
11521
|
});
|
|
13176
11522
|
}
|
|
13177
11523
|
try {
|
|
@@ -13183,15 +11529,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
13183
11529
|
// propagated request.force (e.g. popModal / closeSurface on a
|
|
13184
11530
|
// coordinator-owned modal). Before V3 only the layout-modal signal
|
|
13185
11531
|
// was honored, so coordinator modal closes left residual pixels.
|
|
13186
|
-
// ⭐
|
|
11532
|
+
// ⭐ Single flush: resolve the prompt caret after overlays.
|
|
13187
11533
|
const frameCursorDecision = display.cursorDecision();
|
|
13188
11534
|
renderDashboardFrame(baseLines, composeDashboardFrameWithCoordinatorModal(display, {
|
|
13189
11535
|
overlay: modalFrame,
|
|
13190
11536
|
force: forceFromCoordinator || modalKey !== lastModalKey,
|
|
13191
|
-
essential: dashboardUiMode === 'essential',
|
|
13192
11537
|
cursorOwner: frameCursorDecision.owner,
|
|
13193
11538
|
claimedCursor: frameCursorDecision.cursor,
|
|
13194
|
-
// ⛔ rich 는 #6528 까지의 값을 그대로 쓴다 — 이 PR 은 essential 축만 바꾼다.
|
|
13195
11539
|
coordinatorCursor: display.getCursor(),
|
|
13196
11540
|
promptCaret,
|
|
13197
11541
|
suppressPromptArea,
|
|
@@ -14109,42 +12453,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14109
12453
|
when: () => agentSearchModal === null,
|
|
14110
12454
|
});
|
|
14111
12455
|
|
|
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
12456
|
let debugWorkbenchHandle: PaneMultiModalHandle | null = null;
|
|
14149
12457
|
let debugWindowHandle: PaneMultiModalHandle | null = null;
|
|
14150
12458
|
let debugWindowHoverActive = false;
|
|
@@ -14469,14 +12777,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14469
12777
|
onContextMenuMouse: (ev) => ctxMenuWire.onMouse(ev),
|
|
14470
12778
|
});
|
|
14471
12779
|
};
|
|
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
12780
|
const openBrowserOnlyModal = (): void => {
|
|
14481
12781
|
const { cols: tc, rows: tr } = termSize();
|
|
14482
12782
|
const liveMode = resolveBrowserPreviewModalLiveMode(process.env.ELANOUS_PANE_MODAL_LIVE);
|
|
@@ -14497,14 +12797,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14497
12797
|
onCancel: () => { draw(); },
|
|
14498
12798
|
});
|
|
14499
12799
|
};
|
|
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
12800
|
const openPreviewOnlyModal = (): void => {
|
|
14509
12801
|
const { cols: tc, rows: tr } = termSize();
|
|
14510
12802
|
const liveMode = (process.env.ELANOUS_PANE_MODAL_LIVE ?? 'on').toLowerCase() !== 'off';
|
|
@@ -14522,237 +12814,22 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14522
12814
|
onCancel: () => { draw(); },
|
|
14523
12815
|
});
|
|
14524
12816
|
};
|
|
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
12817
|
registerDashboardGlobalKeys({
|
|
14565
12818
|
enableSupplementalGlobalKeys: getUserConfig().dashboard.enableSupplementalGlobalKeys,
|
|
14566
12819
|
register: (binding) => { display.registerKeyBinding(binding); },
|
|
14567
12820
|
openSurfaceCatalog: () => openSurfaceCatalogPopup(),
|
|
14568
12821
|
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
12822
|
});
|
|
14705
12823
|
|
|
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
12824
|
function currentWorkspaceOwnerId(): string {
|
|
14742
|
-
|
|
14743
|
-
return currentWindow
|
|
14744
|
-
? workspaceOwnerIdForVirtualWindow(currentWindow.id)
|
|
14745
|
-
: DASHBOARD_MAIN_WORKSPACE_ID;
|
|
12825
|
+
return DASHBOARD_MAIN_WORKSPACE_ID;
|
|
14746
12826
|
}
|
|
14747
12827
|
|
|
14748
12828
|
function openSurfaceCatalogPopup(): void {
|
|
14749
|
-
const currentWindow = virtualWindows.registry.current();
|
|
14750
12829
|
void openCompactSurfaceCatalogPopup({
|
|
14751
12830
|
getTargets: () => compactSurfaceRuntime.buildTargets(),
|
|
14752
12831
|
openTarget: (surfaceId) => compactSurfaceRuntime.openTarget(surfaceId),
|
|
14753
|
-
ownerWorkspaceId:
|
|
14754
|
-
? workspaceOwnerIdForVirtualWindow(currentWindow.id)
|
|
14755
|
-
: DASHBOARD_MAIN_WORKSPACE_ID,
|
|
12832
|
+
ownerWorkspaceId: DASHBOARD_MAIN_WORKSPACE_ID,
|
|
14756
12833
|
termSize,
|
|
14757
12834
|
getTheme: () => currentThemeTokens(),
|
|
14758
12835
|
pushModalSurface: (surface) => display.pushModal(surface),
|
|
@@ -14773,24 +12850,15 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14773
12850
|
let shellRollupDispose: (() => void) | null = null;
|
|
14774
12851
|
async function openShellRollupPopup(): Promise<void> {
|
|
14775
12852
|
const { getShellRegistry } = await import('../shell-runner/registry.js');
|
|
14776
|
-
const currentWindow = virtualWindows.registry.current();
|
|
14777
12853
|
await openDashboardShellRollupPopup({
|
|
14778
12854
|
getShellRegistry,
|
|
14779
12855
|
getCurrentDispose: () => shellRollupDispose,
|
|
14780
12856
|
setCurrentDispose: (dispose) => {
|
|
14781
12857
|
shellRollupDispose = dispose;
|
|
14782
12858
|
},
|
|
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,
|
|
12859
|
+
resolveVwIdByLabel: () => null,
|
|
12860
|
+
switchVirtualWindow: () => { throw new Error('Virtual windows are unavailable in the essential dashboard'); },
|
|
12861
|
+
ownerWorkspaceId: DASHBOARD_MAIN_WORKSPACE_ID,
|
|
14794
12862
|
termSize,
|
|
14795
12863
|
getTheme: () => currentThemeTokens(),
|
|
14796
12864
|
pushModalSurface: (surface) => display.pushModal(surface),
|
|
@@ -14806,108 +12874,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
14806
12874
|
});
|
|
14807
12875
|
}
|
|
14808
12876
|
|
|
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
12877
|
// Track which task ID the cursor is currently LOCKED onto across
|
|
14912
12878
|
// draws — prevents the cursor from visually sliding when the roster
|
|
14913
12879
|
// gets re-sorted with a new entry. Empty string = no lock.
|
|
@@ -15041,11 +13007,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15041
13007
|
return memoWidgetRuntime.readLines(widgetHost.get('wd-memo') as any);
|
|
15042
13008
|
};
|
|
15043
13009
|
const publishMemoLines = (lines: string[]): void => {
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
publishScratchSurface('dashboard:memo', 'preview', scratchTitle, scratchLines);
|
|
13010
|
+
scratchTitle = 'Memo';
|
|
13011
|
+
scratchLines = [...lines];
|
|
13012
|
+
scratchOffset = 0;
|
|
13013
|
+
publishScratchSurface('dashboard:memo', 'preview', scratchTitle, scratchLines);
|
|
15049
13014
|
};
|
|
15050
13015
|
const memoCompanionRuntime = createDashboardMemoCompanionRuntime({
|
|
15051
13016
|
readLines: readMemoWidgetLines,
|
|
@@ -15064,26 +13029,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15064
13029
|
memoCompanionRuntime.cancel();
|
|
15065
13030
|
chatScrollOffset = -1;
|
|
15066
13031
|
};
|
|
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
13032
|
// Repaint hook the active textInput populates so external draws
|
|
15088
13033
|
// (scratchpad refresh, async chafa render finishing) can ask the
|
|
15089
13034
|
// prompt to re-paint itself afterwards. While input is idle this
|
|
@@ -15135,8 +13080,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15135
13080
|
requestRender: () => { requestDashboardRender('detail'); },
|
|
15136
13081
|
});
|
|
15137
13082
|
const companionWidgetRuntime = createDashboardCompanionWidgetRuntime();
|
|
15138
|
-
const scratchWidgetRuntime = createDashboardScratchWidgetRuntime();
|
|
15139
|
-
const scratchStateRuntime = createDashboardScratchStateRuntime();
|
|
15140
13083
|
const clipboardHistoryRuntime = createDashboardClipboardHistoryRuntime();
|
|
15141
13084
|
const memoWidgetRuntime = createDashboardMemoWidgetRuntime();
|
|
15142
13085
|
const logWidgetRuntime = createDashboardLogWidgetRuntime();
|
|
@@ -15479,26 +13422,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15479
13422
|
* display coordinator. The coordinator coalesces this with any
|
|
15480
13423
|
* plugin/widget updates and repaints the prompt after the frame. */
|
|
15481
13424
|
const setScratch = (title: string, lines: string[]): void => {
|
|
15482
|
-
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
scratchOffset = next.offset;
|
|
13425
|
+
scratchTitle = title;
|
|
13426
|
+
scratchLines = [...lines];
|
|
13427
|
+
scratchOffset = 0;
|
|
15486
13428
|
publishScratchSurface('dashboard:scratch', 'preview', title, scratchLines);
|
|
15487
13429
|
};
|
|
15488
13430
|
|
|
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
13431
|
// ── Execute sync inline (output to log pane) ──
|
|
15503
13432
|
const runSyncInline = async (
|
|
15504
13433
|
sk: string[] = [...sync.selected[0]!],
|
|
@@ -17314,8 +15243,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17314
15243
|
}
|
|
17315
15244
|
|
|
17316
15245
|
// 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.
|
|
15246
|
+
// key earlier) closes the scratch pane. Reopen via the ^B ^S chord.
|
|
17319
15247
|
if (key.ctrl && (key.name === 'w' || key.name === 'ㅈ')) {
|
|
17320
15248
|
scratchClosed = true;
|
|
17321
15249
|
userClosedPanes.add('scratch');
|
|
@@ -17416,7 +15344,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17416
15344
|
acpPtyAvailable = (await import('../pty-shell/registry.js')).ptyAvailable;
|
|
17417
15345
|
const dashboardAcpBootResult = await bootDashboardAcpSession({
|
|
17418
15346
|
...(opts.remote ? { remote: opts.remote } : {}),
|
|
17419
|
-
...(opts.localDaemon ? { localDaemon: opts.localDaemon } : {}),
|
|
17420
15347
|
...(opts.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {}),
|
|
17421
15348
|
getCwd: () => getSessionCwd(),
|
|
17422
15349
|
getChatHistory: () => chat.history,
|
|
@@ -17437,7 +15364,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17437
15364
|
pluginTools: pluginHost.activePluginLLMTools(),
|
|
17438
15365
|
optionalTools: acpTurnRef.optionalSpecs,
|
|
17439
15366
|
surface: acpTurnRef.turnProfile?.surface,
|
|
17440
|
-
rich:
|
|
15367
|
+
rich: false,
|
|
17441
15368
|
})
|
|
17442
15369
|
: [];
|
|
17443
15370
|
return buildDashboardTurnPreamble({
|
|
@@ -17451,7 +15378,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17451
15378
|
// codex-only behavioral addendum (fix L-1) inside the
|
|
17452
15379
|
// universal preamble.
|
|
17453
15380
|
modelFamily: getModelFamily(inspectActiveProvider().model),
|
|
17454
|
-
rich:
|
|
15381
|
+
rich: false,
|
|
17455
15382
|
enabledTools: tools.map(t => t.name),
|
|
17456
15383
|
});
|
|
17457
15384
|
},
|
|
@@ -17465,7 +15392,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17465
15392
|
pluginTools: pluginHost.activePluginLLMTools(),
|
|
17466
15393
|
optionalTools: acpTurnRef.optionalSpecs,
|
|
17467
15394
|
surface: acpTurnRef.turnProfile?.surface,
|
|
17468
|
-
rich:
|
|
15395
|
+
rich: false,
|
|
17469
15396
|
});
|
|
17470
15397
|
// ⭐ Remember this turn's catalog so a spawned sub-agent can inherit it.
|
|
17471
15398
|
//
|
|
@@ -17630,18 +15557,16 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17630
15557
|
try { acpSessionIdRef.current = dashboardAcpSession.currentSessionId ?? null; } catch { /* 없으면 넣지 않는다 */ }
|
|
17631
15558
|
pushDebugLine(C.muted('[acp-boot] dashboard ACP session ready'));
|
|
17632
15559
|
// User-visible mode indicator. Without this, a user who set
|
|
17633
|
-
// ELANOUS_REMOTE
|
|
17634
|
-
//
|
|
15560
|
+
// ELANOUS_REMOTE has no way to tell whether the
|
|
15561
|
+
// attach actually succeeded — the attached daemon mode is useful
|
|
17635
15562
|
// chat transcript context, but the local in-process fallback is
|
|
17636
15563
|
// runtime plumbing and belongs in the debug log instead.
|
|
17637
15564
|
if (opts.remote) {
|
|
17638
15565
|
const authNote = opts.remote.token ? 'token' : 'no-auth';
|
|
17639
15566
|
const labelNote = opts.remote.label ? ` · ${opts.remote.label}` : '';
|
|
17640
15567
|
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
15568
|
} else {
|
|
17644
|
-
pushDebugLine(C.muted(' in-process ACP (no daemon attach · set ELANOUS_REMOTE
|
|
15569
|
+
pushDebugLine(C.muted(' in-process ACP (no daemon attach · set ELANOUS_REMOTE to attach)'));
|
|
17645
15570
|
}
|
|
17646
15571
|
// Tier 1 daemon-resume status. Three branches:
|
|
17647
15572
|
// - resumed: attachExisting succeeded · the daemon's prior
|
|
@@ -17655,9 +15580,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17655
15580
|
if (dashboardAcpBootResult.mode === 'resumed' && dashboardAcpBootResult.sessionId) {
|
|
17656
15581
|
const sid = dashboardAcpBootResult.sessionId;
|
|
17657
15582
|
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.
|
|
15583
|
+
// Best-effort REST history replay over the remote HTTP/WS endpoint.
|
|
17661
15584
|
if (opts.remote) {
|
|
17662
15585
|
const httpBase = deriveDaemonHttpBase(opts.remote.url);
|
|
17663
15586
|
if (httpBase) {
|
|
@@ -17693,8 +15616,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17693
15616
|
chatLines.push(C.muted(` no prior turns found for ${sid}.`));
|
|
17694
15617
|
}
|
|
17695
15618
|
}
|
|
17696
|
-
} else {
|
|
17697
|
-
chatLines.push(C.muted(' (history replay over unix socket is a follow-up — REST endpoint required)'));
|
|
17698
15619
|
}
|
|
17699
15620
|
} else if (dashboardAcpBootResult.mode === 'new' && dashboardAcpBootResult.resumeFallbackReason) {
|
|
17700
15621
|
// The user asked to resume but the daemon rejected the id —
|
|
@@ -17704,7 +15625,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17704
15625
|
const reason = dashboardAcpBootResult.resumeFallbackReason;
|
|
17705
15626
|
const newId = dashboardAcpBootResult.sessionId ?? '(unknown)';
|
|
17706
15627
|
chatLines.push(C.warning(` ⚠ resume failed (${reason}); started new session: ${newId}`));
|
|
17707
|
-
} else if (opts.resumeSessionId && !opts.remote
|
|
15628
|
+
} else if (opts.resumeSessionId && !opts.remote) {
|
|
17708
15629
|
// Match `/session load <prefix>` for in-process boot: resolve the
|
|
17709
15630
|
// local prefix, preserve the stock system prompt, and attach the
|
|
17710
15631
|
// restored session for subsequent persistence.
|
|
@@ -17746,6 +15667,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17746
15667
|
const key: import('../tui.js').Key = wdAutoInput
|
|
17747
15668
|
? { name: CHAT_MAIN_AUTO_ENTRY_KEY_NAME, ctrl: false, shift: false }
|
|
17748
15669
|
: await readKey();
|
|
15670
|
+
const helpModal = currentTransientTerminalModal('dashboard-help');
|
|
15671
|
+
if (key.name === 'escape' && helpModal) {
|
|
15672
|
+
helpModal.dispose();
|
|
15673
|
+
draw();
|
|
15674
|
+
continue;
|
|
15675
|
+
}
|
|
17749
15676
|
|
|
17750
15677
|
// U-0 · recompute ViewMode at the top of every key dispatch
|
|
17751
15678
|
// loop iteration. This is the one natural "mode re-evaluation"
|
|
@@ -17823,13 +15750,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17823
15750
|
&& voiceHostFlow.getState().kind === 'idle'
|
|
17824
15751
|
&& workingDir.focus !== 'input'
|
|
17825
15752
|
) {
|
|
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
|
-
})();
|
|
15753
|
+
const focusedTerminalPane = false;
|
|
17833
15754
|
|
|
17834
15755
|
// Branch 1 — Ctrl+Shift+D trial chord. TEMP DEBUG (2026-04-29):
|
|
17835
15756
|
// toggle pattern instead of long-press detector. First press
|
|
@@ -18069,23 +15990,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18069
15990
|
if (result === 'closed') draw();
|
|
18070
15991
|
return true;
|
|
18071
15992
|
},
|
|
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
15993
|
routeArmedChordKey: async (routeKey) => {
|
|
18090
15994
|
if (!isChordArmed(chord)) return false;
|
|
18091
15995
|
disarmChordHud();
|
|
@@ -18134,44 +16038,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18134
16038
|
if (routeKey.name === 'ㅃ') return true;
|
|
18135
16039
|
return false;
|
|
18136
16040
|
},
|
|
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
16041
|
// PR-S1V.4-wiring · Step 0x — voice mode entry chord.
|
|
18176
16042
|
// Fires only when voice mode is currently `idle`; once active
|
|
18177
16043
|
// the next step (routeVoiceModeKey) takes over. Skipping when
|
|
@@ -18206,7 +16072,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18206
16072
|
// experiment/voice-chat-realtime-rebind · Step 0s — modal-A
|
|
18207
16073
|
// swallow while voice-chat is active. Returns true when the
|
|
18208
16074
|
// controller is non-idle so any key not already claimed above
|
|
18209
|
-
// (force-quit · Alt+W ·
|
|
16075
|
+
// (force-quit · Alt+W · chord toggle) is consumed
|
|
18210
16076
|
// — typing doesn't leak into chat input, Space doesn't toggle
|
|
18211
16077
|
// pickers, etc. ESC explicitly exits. Idle controller returns
|
|
18212
16078
|
// false so legacy dispatch is reachable.
|
|
@@ -18322,36 +16188,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18322
16188
|
})();
|
|
18323
16189
|
return true;
|
|
18324
16190
|
},
|
|
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
16191
|
// Step 6 hard-quit — only reached when no popup terminal is
|
|
18356
16192
|
// active. Plain Ctrl+Q stays as the dashboard-mode shortcut
|
|
18357
16193
|
// so muscle memory survives outside the popup. Inside the
|
|
@@ -18359,12 +16195,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18359
16195
|
// to force-quit instead).
|
|
18360
16196
|
isHardQuitKey: (routeKey) => routeKey.ctrl && !routeKey.shift && (routeKey.name === 'q' || routeKey.name === 'ㅂ'),
|
|
18361
16197
|
matchGlobalAction: (routeKey) => matchTextInputGlobalAction(routeKey, {
|
|
18362
|
-
allowSpawnTerminalModal:
|
|
18363
|
-
|
|
18364
|
-
&& (previewTerminal as PreviewTerminal).isAlive),
|
|
18365
|
-
allowToggleLogZoom: !(workingDir.focus === 'preview'
|
|
18366
|
-
&& previewTerminal
|
|
18367
|
-
&& (previewTerminal as PreviewTerminal).isAlive),
|
|
16198
|
+
allowSpawnTerminalModal: false,
|
|
16199
|
+
allowToggleLogZoom: false,
|
|
18368
16200
|
}),
|
|
18369
16201
|
runGlobalAction: async (action) => {
|
|
18370
16202
|
await runChatMainGlobalAction(action);
|
|
@@ -18828,8 +16660,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18828
16660
|
initialText: inputEntry?.initialText ?? null,
|
|
18829
16661
|
visibility: chatMainInputVisibilityState(),
|
|
18830
16662
|
topBlockingForegroundModal: topBlockingForegroundModal()?.id ?? null,
|
|
18831
|
-
currentVwId:
|
|
18832
|
-
currentVwHostChromeProfile:
|
|
16663
|
+
currentVwId: null,
|
|
16664
|
+
currentVwHostChromeProfile: null,
|
|
18833
16665
|
});
|
|
18834
16666
|
}
|
|
18835
16667
|
if (inputEntry) {
|
|
@@ -18912,8 +16744,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18912
16744
|
textInputOpts: {
|
|
18913
16745
|
// TUI 부활 후속 — Esc·Esc = /rewind 픽커 (codex backtrack
|
|
18914
16746
|
// 제스처 · resolveEscEscRewind 순수 판정). 빈 버퍼에서만
|
|
18915
|
-
// prime · 1.5s
|
|
18916
|
-
// 하므로 사실상 essential 전용(의도). 힌트는 세션 1회.
|
|
16747
|
+
// prime · 1.5s 창. 힌트는 세션 1회.
|
|
18917
16748
|
onEscape: (bufferText) => {
|
|
18918
16749
|
const decision = resolveEscEscRewind({
|
|
18919
16750
|
bufferText: bufferText ?? '',
|
|
@@ -19216,6 +17047,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19216
17047
|
hasActiveStatusPopup: () => mouseWiring.hasActivePopup(),
|
|
19217
17048
|
hasTerminalModal: () => terminalModalRouter.current() !== null,
|
|
19218
17049
|
shouldRouteForegroundModalKey: (key) => {
|
|
17050
|
+
if (key.name === 'escape' && currentTransientTerminalModal('dashboard-help')) return true;
|
|
19219
17051
|
const topModalId = display.modalStack().at(-1) ?? null;
|
|
19220
17052
|
const topModal = topModalId ? display.surface(topModalId) : null;
|
|
19221
17053
|
const topModalSurface =
|
|
@@ -19242,7 +17074,17 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19242
17074
|
toKeyEvent: toDashboardKeyEvent,
|
|
19243
17075
|
routeStatusPopupKey: key => mouseWiring.routeKey(key as never),
|
|
19244
17076
|
handleTerminalModalKey: keyEvent => terminalModalRouter.handleKey(keyEvent),
|
|
19245
|
-
tryRouteForegroundModalKey: keyEvent =>
|
|
17077
|
+
tryRouteForegroundModalKey: async keyEvent => {
|
|
17078
|
+
if (keyEvent.name === 'escape') {
|
|
17079
|
+
const helpModal = currentTransientTerminalModal('dashboard-help');
|
|
17080
|
+
if (helpModal) {
|
|
17081
|
+
helpModal.dispose();
|
|
17082
|
+
draw();
|
|
17083
|
+
return 'consumed';
|
|
17084
|
+
}
|
|
17085
|
+
}
|
|
17086
|
+
return display.tryRouteKeyToTopModalAsync(keyEvent);
|
|
17087
|
+
},
|
|
19246
17088
|
redraw: draw,
|
|
19247
17089
|
dispatchMouse: runTextInputOnMouseUnifiedDispatch,
|
|
19248
17090
|
}),
|
|
@@ -19604,6 +17446,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19604
17446
|
closeTui,
|
|
19605
17447
|
exitTui: exitDashboardTui,
|
|
19606
17448
|
showHelp,
|
|
17449
|
+
showHelpModal: ({ title, lines }) => {
|
|
17450
|
+
const { cols, rows } = termSize();
|
|
17451
|
+
showTransientTerminalModal({ title, lines: [...lines], coordinator: display, termCols: cols, termRows: rows, ttlMs: 0, group: 'dashboard-help' });
|
|
17452
|
+
},
|
|
19607
17453
|
clearLogSearch,
|
|
19608
17454
|
clearLogFilter,
|
|
19609
17455
|
forkAttachedSessionFromChatHistory,
|
|
@@ -19628,6 +17474,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19628
17474
|
controlSignalSlashRuntime,
|
|
19629
17475
|
browserCdpSlashRuntime,
|
|
19630
17476
|
widgetHost,
|
|
17477
|
+
backgroundTasksTextOnly: true,
|
|
19631
17478
|
widgetModalPopup: {
|
|
19632
17479
|
open: (s) => {
|
|
19633
17480
|
// Wave P4b-1 — bridge slash → widget-modal-popup.
|
|
@@ -19684,10 +17531,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19684
17531
|
attachClipboardImage,
|
|
19685
17532
|
setNextInitial: (token) => { nextInitial = token; },
|
|
19686
17533
|
},
|
|
19687
|
-
uiModeSlash: {
|
|
19688
|
-
getMode: () => dashboardUiMode,
|
|
19689
|
-
setMode: (mode) => { applyDashboardUiMode(mode, { persist: true, announce: true }); },
|
|
19690
|
-
},
|
|
19691
17534
|
sessionResume: {
|
|
19692
17535
|
openPicker: () => { openSessionResumePicker(); },
|
|
19693
17536
|
},
|
|
@@ -19709,23 +17552,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19709
17552
|
refresh: refreshInputHistory,
|
|
19710
17553
|
openDetailViewer: (title, lines) => { setDetailViewer(title, lines); },
|
|
19711
17554
|
},
|
|
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
17555
|
undo: {
|
|
19720
17556
|
refreshGitDirty: () => { refreshGitDirty(getSessionCwd(), { force: true }); },
|
|
19721
17557
|
bold: C.bold,
|
|
19722
17558
|
},
|
|
19723
|
-
ptyPane: {
|
|
19724
|
-
spawnPtyTailWindow: (opts) => virtualWindows.registry.spawn({
|
|
19725
|
-
title: opts.title,
|
|
19726
|
-
initialContent: { kind: 'pty-tail', ptyId: opts.ptyId },
|
|
19727
|
-
}),
|
|
19728
|
-
},
|
|
19729
17559
|
delta: {
|
|
19730
17560
|
openBrowserPopup: (scope, limit, browserMode) =>
|
|
19731
17561
|
openSourceDeltaBrowserPopup(scope, limit, browserMode),
|
|
@@ -19800,24 +17630,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19800
17630
|
},
|
|
19801
17631
|
compact: {
|
|
19802
17632
|
getHistory: () => chat.history as unknown as { role: string; [k: string]: unknown }[],
|
|
19803
|
-
compactBoundaryEnabled: () => getUserConfig().chat.rendering.compactBoundary.enabled,
|
|
19804
17633
|
},
|
|
19805
17634
|
skill: {
|
|
19806
17635
|
triggersSlashRuntime: skillTriggersSlashRuntime,
|
|
19807
17636
|
runSlashRuntime: runSkillSlashRuntime,
|
|
19808
17637
|
runByName: (name, skillArgs) => runSkillByName(name, skillArgs),
|
|
19809
17638
|
},
|
|
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
17639
|
setup: {
|
|
19822
17640
|
launchPopup: (cmd) => {
|
|
19823
17641
|
const session = TerminalPopup.shell()
|
|
@@ -19902,40 +17720,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19902
17720
|
focusPopup: (direction) => focusConversationPopup(direction),
|
|
19903
17721
|
openModal: (sessionId) => openConversationModal(sessionId),
|
|
19904
17722
|
},
|
|
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
17723
|
sim: {
|
|
19937
17724
|
slashRuntime: simSlashRuntime,
|
|
19938
|
-
spawnVirtualWindow: () => spawnSimVirtualWindow(),
|
|
19939
17725
|
openWebCockpit: () => openDashboardSimulationWebCockpit(),
|
|
19940
17726
|
listScenarios: () => listDashboardSimulationScenarios(),
|
|
19941
17727
|
runById: (scenarioId) => runDashboardSimulationById(scenarioId as Parameters<typeof runDashboardSimulationById>[0]),
|
|
@@ -19959,39 +17745,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19959
17745
|
return aliases.get(target) ?? null;
|
|
19960
17746
|
},
|
|
19961
17747
|
},
|
|
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
17748
|
intake: {
|
|
19996
17749
|
runSlash: async (intakeArgs) => {
|
|
19997
17750
|
try {
|
|
@@ -20019,7 +17772,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20019
17772
|
},
|
|
20020
17773
|
};
|
|
20021
17774
|
const r = await resolveIntakeSlash([...intakeArgs], {
|
|
20022
|
-
getScratchSnapshot:
|
|
17775
|
+
getScratchSnapshot: () => {
|
|
17776
|
+
const snapshot = display.scratchState();
|
|
17777
|
+
return snapshot && snapshot.mode !== 'agents'
|
|
17778
|
+
? { title: snapshot.title, lines: [...snapshot.lines] }
|
|
17779
|
+
: { title: scratchTitle, lines: [...scratchLines] };
|
|
17780
|
+
},
|
|
20023
17781
|
});
|
|
20024
17782
|
if (shouldOpenDashboardIntakeSessionPicker([...intakeArgs], r)) {
|
|
20025
17783
|
openDashboardIntakeSessionPicker(r.sessions, intakeUiDeps);
|
|
@@ -20263,44 +18021,22 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20263
18021
|
remoteDaemon: () => opts.remote
|
|
20264
18022
|
? { url: opts.remote.url, token: opts.remote.token }
|
|
20265
18023
|
: null,
|
|
20266
|
-
localDaemon: () => opts.localDaemon
|
|
20267
|
-
? { socketPath: opts.localDaemon.socketPath }
|
|
20268
|
-
: null,
|
|
20269
18024
|
acpSwapTo: (sessionId, cwd) => dashboardAcpSession.swapTo(sessionId, cwd),
|
|
20270
18025
|
},
|
|
20271
18026
|
shellSlash: {
|
|
20272
18027
|
slashRuntime: shellSlashRuntime,
|
|
20273
18028
|
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,
|
|
18029
|
+
virtualWindowsSwitchTo: () => { throw new Error('Virtual windows are unavailable in the essential dashboard'); },
|
|
18030
|
+
resolveVwIdByLabel: () => null,
|
|
20298
18031
|
},
|
|
20299
18032
|
termSlash: {
|
|
20300
18033
|
slashRuntime: termSlashRuntime,
|
|
20301
18034
|
sessionRegistry: sessionRegistry as unknown as DashboardSlashContext['termSlash']['sessionRegistry'],
|
|
20302
18035
|
terminalMatrix: terminalMatrix as unknown as DashboardSlashContext['termSlash']['terminalMatrix'],
|
|
20303
|
-
vwRegistry:
|
|
18036
|
+
vwRegistry: {
|
|
18037
|
+
current: () => null,
|
|
18038
|
+
get: () => null,
|
|
18039
|
+
},
|
|
20304
18040
|
broadcastBus: broadcastBus as unknown as DashboardSlashContext['termSlash']['broadcastBus'],
|
|
20305
18041
|
channelBus: channelBus as unknown as DashboardSlashContext['termSlash']['channelBus'],
|
|
20306
18042
|
openSessionPicker: () => {
|
|
@@ -20563,15 +18299,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20563
18299
|
}
|
|
20564
18300
|
continue;
|
|
20565
18301
|
}
|
|
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
18302
|
// B-2.w migrated: /conv → registry handler.
|
|
20576
18303
|
// H5 P3 · /handoff <fromId> <toBrand> [--channels reasoning,plan]
|
|
20577
18304
|
// Cross-agent snapshot-based context transfer.
|
|
@@ -20585,7 +18312,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20585
18312
|
// B-2.l migrated: /agents /agent /ag → registry handler.
|
|
20586
18313
|
// B-1.f migrated: /clipboard /clip /cb · /memo /note /me ·
|
|
20587
18314
|
// /detail /report /dv → registry handlers (companion ctx field).
|
|
20588
|
-
// B-2.v migrated: /scratch /sc → registry handler.
|
|
20589
18315
|
// B-2.o migrated: /intake → registry handler.
|
|
20590
18316
|
// B-1.g migrated: /signals /signal → registry handler (controlSignalSlashRuntime ctx field).
|
|
20591
18317
|
case 'media':
|
|
@@ -20737,7 +18463,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
20737
18463
|
chatLines.push(C.warning(`/${cmdLower} has moved; use ${retiredHarnessCommand}`));
|
|
20738
18464
|
} else {
|
|
20739
18465
|
chatLines.push(C.warning(`Unknown command: /${cmdLower}`));
|
|
20740
|
-
chatLines.push(C.muted('
|
|
18466
|
+
chatLines.push(C.muted('Type /help for the list of commands.'));
|
|
20741
18467
|
}
|
|
20742
18468
|
chatScrollOffset = -1;
|
|
20743
18469
|
continue; // stay in input mode
|
|
@@ -21052,8 +18778,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21052
18778
|
contextRegistry,
|
|
21053
18779
|
loadAttachments: (reg) => loadAllAttachments(reg as Parameters<typeof loadAllAttachments>[0]),
|
|
21054
18780
|
sessionRegistry,
|
|
21055
|
-
virtualWindowBook: virtualWindows.book,
|
|
21056
|
-
virtualWindowRegistry: virtualWindows.registry,
|
|
21057
18781
|
sync,
|
|
21058
18782
|
chatFooterLine,
|
|
21059
18783
|
routeFooter: () => {
|
|
@@ -21091,8 +18815,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21091
18815
|
contextText: args.contextText,
|
|
21092
18816
|
contextRegistry: args.contextRegistry as typeof contextRegistry,
|
|
21093
18817
|
terminalRegistry: args.terminalRegistry as typeof sessionRegistry,
|
|
21094
|
-
addressBook: args.addressBook as typeof virtualWindows.book,
|
|
21095
|
-
windowRegistry: args.windowRegistry as typeof virtualWindows.registry,
|
|
21096
18818
|
blockAttach: args.blockAttach,
|
|
21097
18819
|
pushChatLine: args.pushChatLine,
|
|
21098
18820
|
}),
|
|
@@ -21119,7 +18841,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21119
18841
|
pluginTools: pluginHost.activePluginLLMTools(),
|
|
21120
18842
|
optionalTools: acpTurnRef.optionalSpecs,
|
|
21121
18843
|
surface: acpTurnRef.turnProfile?.surface,
|
|
21122
|
-
rich:
|
|
18844
|
+
rich: false,
|
|
21123
18845
|
})
|
|
21124
18846
|
: [];
|
|
21125
18847
|
return buildDashboardTurnPreamble({
|
|
@@ -21127,7 +18849,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21127
18849
|
cwd: args.cwd,
|
|
21128
18850
|
turnProfile: args.turnProfile as SessionTurnProfile,
|
|
21129
18851
|
userConfig: args.userConfig,
|
|
21130
|
-
rich:
|
|
18852
|
+
rich: false,
|
|
21131
18853
|
enabledTools: tools.map(t => t.name),
|
|
21132
18854
|
});
|
|
21133
18855
|
},
|
|
@@ -21151,7 +18873,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21151
18873
|
userMsg: userMsg as ChatMessage,
|
|
21152
18874
|
model: inspectActiveProvider().model,
|
|
21153
18875
|
autoCompactConfig: userConfig.chat.autoCompact,
|
|
21154
|
-
compactBoundaryEnabled: userConfig.chat.rendering.compactBoundary.enabled,
|
|
21155
18876
|
shouldAutoCompact,
|
|
21156
18877
|
compactConversation: async (history) => compactConversation(history),
|
|
21157
18878
|
compactConversationPartial: async (history, opts) => compactConversationPartial(history, opts),
|
|
@@ -21190,7 +18911,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21190
18911
|
createDashboardTurnStreamRuntimeEscBoundary(escAbortToolState);
|
|
21191
18912
|
const toolRendering = {
|
|
21192
18913
|
...getUserConfig().chat.rendering.tool,
|
|
21193
|
-
expandHint:
|
|
18914
|
+
expandHint: false,
|
|
21194
18915
|
};
|
|
21195
18916
|
const renderedToolRuntime = createDashboardRenderedToolRuntime({
|
|
21196
18917
|
chatLines,
|
|
@@ -21314,7 +19035,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
21314
19035
|
},
|
|
21315
19036
|
runCodeEditPostTurn: async () => {
|
|
21316
19037
|
await runDashboardCodeEditPostTurn({
|
|
21317
|
-
turnSummaryEnabled: getUserConfig().chat.rendering.diff.turnSummary,
|
|
21318
19038
|
pushChatLine: (line) => { chatLines.push(line); },
|
|
21319
19039
|
setChatScrollBottom: () => { chatScrollOffset = -1; },
|
|
21320
19040
|
importCodeEdit: () => import('../code-edit/index.js'),
|