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
|
@@ -1,1301 +0,0 @@
|
|
|
1
|
-
// VirtualWindow — VW-P4.
|
|
2
|
-
//
|
|
3
|
-
// A VirtualWindow owns a layout tree of panes (LayoutNode) plus a
|
|
4
|
-
// map of paneId → PaneContent. It renders as a single ModalSurface
|
|
5
|
-
// that covers the coordinator's grid (exactly one is foreground at
|
|
6
|
-
// a time; others are detached — see WindowRegistry, VW-P5).
|
|
7
|
-
//
|
|
8
|
-
// Key routing:
|
|
9
|
-
// • The dashboard-level prefix chord (Ctrl+B + sequence) is
|
|
10
|
-
// intercepted BEFORE this class sees a key. When a key reaches
|
|
11
|
-
// VirtualWindow.onKey, it's destined for the focused pane.
|
|
12
|
-
// • Pane-content delegates return the standard Action shape so
|
|
13
|
-
// tests + plugin hooks stay uniform.
|
|
14
|
-
|
|
15
|
-
import { ansi, C, visibleWidth, stripAnsi } from '../tui.js';
|
|
16
|
-
import { debug } from '../debug/log.js';
|
|
17
|
-
import { DEFAULT_HOST_CHROME_PROFILE } from '../display/host-chrome-profile.js';
|
|
18
|
-
import {
|
|
19
|
-
allPaneIds,
|
|
20
|
-
closePane,
|
|
21
|
-
dividerAt,
|
|
22
|
-
focusNeighbor,
|
|
23
|
-
layoutRects,
|
|
24
|
-
leaf,
|
|
25
|
-
paneAt,
|
|
26
|
-
resizePane,
|
|
27
|
-
splitPane,
|
|
28
|
-
SplitRejectedError,
|
|
29
|
-
type Axis,
|
|
30
|
-
type Direction,
|
|
31
|
-
type DividerHit,
|
|
32
|
-
type LayoutNode,
|
|
33
|
-
type Rect,
|
|
34
|
-
type SplitLimits,
|
|
35
|
-
} from './layout-tree.js';
|
|
36
|
-
import type { PaneRect } from './layout-tree.js';
|
|
37
|
-
import type { PaneBroadcast, PaneContent } from './pane-content.js';
|
|
38
|
-
import type { ModalBounds, ModalSurface } from '../display/modal-stack.js';
|
|
39
|
-
import {
|
|
40
|
-
isCaptureSessionEndMouseEventType,
|
|
41
|
-
isCaptureSessionMouseEventType,
|
|
42
|
-
isPrimaryDiscreteClickMouseEventType,
|
|
43
|
-
isSecondaryClickMouseEventType,
|
|
44
|
-
type Action,
|
|
45
|
-
type DisplayMouseEvent,
|
|
46
|
-
type KeyEvent,
|
|
47
|
-
type SurfaceId,
|
|
48
|
-
} from '../display/types.js';
|
|
49
|
-
import type { CursorState } from '../display/cursor-state.js';
|
|
50
|
-
import type { WindowId, PaneId } from './addressing.js';
|
|
51
|
-
import { composeVisibilityBadge, badgeVisibleWidth } from '../panes/visibility-badge.js';
|
|
52
|
-
import type { PaneVisibility } from '../panes/visual-state.js';
|
|
53
|
-
import { secondaryActionTargetAt } from './secondary-action.js';
|
|
54
|
-
import { paneBorderTitle } from '../panes/pane-title.js';
|
|
55
|
-
import { pulsePhase } from '../agent-activity-hud.js';
|
|
56
|
-
import {
|
|
57
|
-
inlineEditorClear,
|
|
58
|
-
type InlineEditorState,
|
|
59
|
-
} from '../input-core/inline-editor.js';
|
|
60
|
-
import { applyInlineEditorKey } from '../input-core/inline-editor-key.js';
|
|
61
|
-
|
|
62
|
-
export interface VirtualWindowSpec {
|
|
63
|
-
id: WindowId;
|
|
64
|
-
title: string;
|
|
65
|
-
rootContent: PaneContent;
|
|
66
|
-
/** Override bounds — defaults to fullscreen over the dashboard. */
|
|
67
|
-
bounds?: ModalBounds;
|
|
68
|
-
/** Per-window split limits — defaults to layout-tree DEFAULT_LIMITS. */
|
|
69
|
-
limits?: SplitLimits;
|
|
70
|
-
/** Bundle B-7-γ — resolver for the focused pane's PaneVisualState
|
|
71
|
-
* `visibility` axis. When set, paintPane appends a short badge
|
|
72
|
-
* (`·H·` / `·D·` / `·ᴸ·`) to the focused pane's label for any
|
|
73
|
-
* non-default state. Omit to keep labels unchanged (default). */
|
|
74
|
-
visibilityResolver?: (paneId: PaneId) => PaneVisibility;
|
|
75
|
-
/** Deterministic clock for chrome motion. Omit in prod. */
|
|
76
|
-
now?: () => number;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface VirtualWindowRenderCtx {
|
|
80
|
-
termCols: number;
|
|
81
|
-
termRows: number;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export type LocalInputTarget =
|
|
85
|
-
| { kind: 'focused' }
|
|
86
|
-
| { kind: 'all' }
|
|
87
|
-
| { kind: 'pane'; paneId: PaneId };
|
|
88
|
-
|
|
89
|
-
export interface LocalInputSubmitRequest {
|
|
90
|
-
broadcast: PaneBroadcast;
|
|
91
|
-
target: LocalInputTarget;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface LocalInputTargetPickerRequest {
|
|
95
|
-
windowId: WindowId;
|
|
96
|
-
seedQuery?: string;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface VirtualWindowEvents {
|
|
100
|
-
onPaneCreate?: (paneId: PaneId) => void;
|
|
101
|
-
onPaneClose?: (paneId: PaneId) => void;
|
|
102
|
-
onPaneFocus?: (paneId: PaneId) => void;
|
|
103
|
-
onClose?: () => void;
|
|
104
|
-
/** Fires when the user submits this window's local composer.
|
|
105
|
-
* The host decides how to route it: focused pane, target picker,
|
|
106
|
-
* or a legacy broadcast path. VW owns only the local input state. */
|
|
107
|
-
onLocalInputSubmit?: (windowId: WindowId, req: LocalInputSubmitRequest) => void;
|
|
108
|
-
/** Backward-compat path for the original per-VW sync bar contract.
|
|
109
|
-
* New consumers should prefer `onLocalInputSubmit`. */
|
|
110
|
-
onSyncInputSubmit?: (windowId: WindowId, text: string) => void;
|
|
111
|
-
/** VW-U4 — fires when the user right-clicks a pane body region
|
|
112
|
-
* (or the border). Host typically opens a pane/window selector
|
|
113
|
-
* popup anchored at (col, row). `paneId` is null on border hits. */
|
|
114
|
-
onShowSelector?: (windowId: WindowId, paneId: PaneId | null, col: number, row: number) => void;
|
|
115
|
-
/** R6 — pane title right-click is distinct from pane body:
|
|
116
|
-
* title goes through the menu-provider path while body keeps the
|
|
117
|
-
* selector popup path. */
|
|
118
|
-
onShowContextMenu?: (windowId: WindowId, paneId: PaneId, col: number, row: number) => void;
|
|
119
|
-
/** Request a target-picker popup for the local composer. Host owns
|
|
120
|
-
* the popup lifecycle; VW only exposes candidate targets/state. */
|
|
121
|
-
onOpenLocalInputTargetPicker?: (req: LocalInputTargetPickerRequest) => void;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** State for the per-window local composer. When active, the window
|
|
125
|
-
* reserves rows at the bottom for a prompt-style input surface.
|
|
126
|
-
* Keys captured there accumulate in `composed` until Enter emits a
|
|
127
|
-
* host-routed submit event. */
|
|
128
|
-
export interface WindowLocalComposerState {
|
|
129
|
-
active: boolean;
|
|
130
|
-
composed: string;
|
|
131
|
-
/** Horizontal scroll offset so the cursor stays visible when the
|
|
132
|
-
* composed buffer overflows the bar width. Recomputed each
|
|
133
|
-
* render; stored so consecutive frames stay consistent. */
|
|
134
|
-
scrollCol: number;
|
|
135
|
-
/** U1 — caret position within `composed` (0..composed.length).
|
|
136
|
-
* Inserts happen at this index, Backspace deletes the char
|
|
137
|
-
* immediately before it, Delete deletes the char at the index.
|
|
138
|
-
* Arrow keys / Home / End mutate this. */
|
|
139
|
-
cursorPos: number;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/** Backward-compat alias while callers migrate off the old name. */
|
|
143
|
-
export type SyncInputBarState = WindowLocalComposerState;
|
|
144
|
-
|
|
145
|
-
/** U2 — upper bound on rows the per-window local composer can claim.
|
|
146
|
-
* Panes keep at least (window_height - 2 - this_value - 1) rows so
|
|
147
|
-
* they stay visible while the user composes a long broadcast. */
|
|
148
|
-
export const WINDOW_LOCAL_COMPOSER_MAX_ROWS = 6;
|
|
149
|
-
/** Backward-compat alias. */
|
|
150
|
-
export const SYNC_BAR_MAX_ROWS = WINDOW_LOCAL_COMPOSER_MAX_ROWS;
|
|
151
|
-
|
|
152
|
-
export class VirtualWindow {
|
|
153
|
-
readonly id: WindowId;
|
|
154
|
-
title: string;
|
|
155
|
-
private tree: LayoutNode;
|
|
156
|
-
private panes = new Map<PaneId, PaneContent>();
|
|
157
|
-
private focusedPaneId: PaneId;
|
|
158
|
-
private bounds: ModalBounds;
|
|
159
|
-
private state: 'foreground' | 'background' | 'closed' = 'background';
|
|
160
|
-
private limits?: SplitLimits;
|
|
161
|
-
/** VW-U1 — when foreground, the top border + corners paint in accent
|
|
162
|
-
* tone instead of muted so the user can spot the active window at
|
|
163
|
-
* a glance. WindowRegistry.switchTo() flips this on the new
|
|
164
|
-
* foreground and off on the previous one. */
|
|
165
|
-
private borderAccent = false;
|
|
166
|
-
/** VW-U5 — when non-null, only this pane renders, filling the full
|
|
167
|
-
* inner rect. Other panes skip their paint pass. The layout tree
|
|
168
|
-
* itself is unchanged — exiting zoom restores the previous view
|
|
169
|
-
* exactly. Cleared automatically when the zoomed pane is closed. */
|
|
170
|
-
private zoomedPaneId: PaneId | null = null;
|
|
171
|
-
/** VW-U5 — swap target for `^B Tab`. Holds the pane that was focused
|
|
172
|
-
* BEFORE the current focus. Updated in setFocus(); flipping between
|
|
173
|
-
* two panes produces A → B → A → B… */
|
|
174
|
-
private previousFocusedPaneId: PaneId | null = null;
|
|
175
|
-
/** VW-B2 — per-pane display title overrides. When set, paintPane
|
|
176
|
-
* renders `[abc123] custom-name` instead of the canonical
|
|
177
|
-
* `content.title`. Map entries are cleaned up in closePaneAt. */
|
|
178
|
-
private paneTitleOverrides = new Map<PaneId, string>();
|
|
179
|
-
/** VW-A3 — active divider drag state. Set on click→drag start when
|
|
180
|
-
* the initial click lands on a split boundary; cleared on release
|
|
181
|
-
* or when the pointer leaves the modal. */
|
|
182
|
-
private dragDivider: {
|
|
183
|
-
hit: DividerHit;
|
|
184
|
-
lastPointer: number;
|
|
185
|
-
} | null = null;
|
|
186
|
-
private readonly events: VirtualWindowEvents;
|
|
187
|
-
/** Window-local composer state. Not persisted across sessions. */
|
|
188
|
-
private syncBar: WindowLocalComposerState = { active: false, composed: '', scrollCol: 0, cursorPos: 0 };
|
|
189
|
-
/** Target for the local composer. Null means "follow focused pane". */
|
|
190
|
-
private localInputTarget: LocalInputTarget = { kind: 'focused' };
|
|
191
|
-
/** Bundle B-7-γ — paneId → PaneVisibility resolver, populated from
|
|
192
|
-
* VirtualWindowSpec. Null when the host didn't wire a store; in
|
|
193
|
-
* that case paintPane treats every pane as 'visible' (no badge). */
|
|
194
|
-
private readonly visibilityResolver: ((paneId: PaneId) => PaneVisibility) | null;
|
|
195
|
-
private readonly now: () => number;
|
|
196
|
-
|
|
197
|
-
constructor(spec: VirtualWindowSpec, events: VirtualWindowEvents = {}) {
|
|
198
|
-
this.id = spec.id;
|
|
199
|
-
this.title = spec.title;
|
|
200
|
-
this.panes.set(spec.rootContent.id, spec.rootContent);
|
|
201
|
-
this.tree = leaf(spec.rootContent.id);
|
|
202
|
-
this.focusedPaneId = spec.rootContent.id;
|
|
203
|
-
this.bounds = spec.bounds ?? { row: 1, col: 1, width: 80, height: 24 };
|
|
204
|
-
this.limits = spec.limits;
|
|
205
|
-
this.events = events;
|
|
206
|
-
this.visibilityResolver = spec.visibilityResolver ?? null;
|
|
207
|
-
this.now = spec.now ?? Date.now;
|
|
208
|
-
spec.rootContent.start();
|
|
209
|
-
this.events.onPaneCreate?.(spec.rootContent.id);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
get focused(): PaneId { return this.focusedPaneId; }
|
|
213
|
-
get isClosed(): boolean { return this.state === 'closed'; }
|
|
214
|
-
|
|
215
|
-
setBounds(bounds: ModalBounds): void {
|
|
216
|
-
this.bounds = bounds;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
getBounds(): ModalBounds {
|
|
220
|
-
return { ...this.bounds };
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/** VW-U1 — called by WindowRegistry.switchTo. Idempotent. */
|
|
224
|
-
setBorderAccent(active: boolean): void {
|
|
225
|
-
this.borderAccent = active;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/** VW-B1 — rename the window. Registry fires a 'window:rename' event
|
|
229
|
-
* via its wrapper so subscribers (pickers, element-registry) can
|
|
230
|
-
* pick up the new title without re-polling. */
|
|
231
|
-
setTitle(next: string): void {
|
|
232
|
-
this.title = next;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/** VW-B2 — per-pane display title override. Stored on the VW so
|
|
236
|
-
* PaneContent.title stays canonical; getPaneDisplayTitle prefers
|
|
237
|
-
* the override when present. Passing empty string clears the
|
|
238
|
-
* override (reverts to PaneContent.title). */
|
|
239
|
-
setPaneTitle(paneId: PaneId, next: string): boolean {
|
|
240
|
-
if (!this.panes.has(paneId)) return false;
|
|
241
|
-
const trimmed = next.trim();
|
|
242
|
-
if (!trimmed) { this.paneTitleOverrides.delete(paneId); return true; }
|
|
243
|
-
this.paneTitleOverrides.set(paneId, trimmed);
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/** VW-B2 — canonical display title. Override wins when present. */
|
|
248
|
-
getPaneDisplayTitle(paneId: PaneId): string {
|
|
249
|
-
const override = this.paneTitleOverrides.get(paneId);
|
|
250
|
-
if (override) return override;
|
|
251
|
-
return this.panes.get(paneId)?.title ?? '';
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
getHostChromeProfile() {
|
|
255
|
-
return this.getFocusedPane()?.hostChromeProfile ?? DEFAULT_HOST_CHROME_PROFILE;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/** VW-B2 — clear on pane close; kept as an internal helper. */
|
|
259
|
-
private clearPaneTitleOverride(paneId: PaneId): void {
|
|
260
|
-
this.paneTitleOverrides.delete(paneId);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
isBorderAccent(): boolean {
|
|
265
|
-
return this.borderAccent;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
listPanes(): Array<{ id: PaneId; content: PaneContent }> {
|
|
269
|
-
return [...this.panes.entries()].map(([id, content]) => ({ id, content }));
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/** Phase 3a · save path — read-only accessor to the current layout
|
|
273
|
-
* binary tree. Consumed by `snapshotWindow()` in layout/tree.ts to
|
|
274
|
-
* produce a serializable LayoutSpec. Returned reference is the live
|
|
275
|
-
* tree (caller must not mutate); see `layout/restore-planner.ts`
|
|
276
|
-
* for the adapter that round-trips through LayoutSpec. */
|
|
277
|
-
getLayoutTree(): LayoutNode {
|
|
278
|
-
return this.tree;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
getPane(id: PaneId): PaneContent | null {
|
|
282
|
-
return this.panes.get(id) ?? null;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/** SP-D — expose the focused pane content to chord handlers that
|
|
286
|
-
* need to probe/mutate focus-policy without poking panes Map. */
|
|
287
|
-
getFocusedPane(): PaneContent | null {
|
|
288
|
-
return this.panes.get(this.focusedPaneId) ?? null;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/** SP-A / A.3 — true iff the focused pane's declared focus policy
|
|
292
|
-
* is not `output-only`. Used by window cycling to skip windows
|
|
293
|
-
* whose focused pane is intentionally read-mostly. */
|
|
294
|
-
hasInteractableFocus(): boolean {
|
|
295
|
-
const pane = this.panes.get(this.focusedPaneId);
|
|
296
|
-
if (!pane) return true;
|
|
297
|
-
return pane.focusPolicy !== 'output-only';
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
getLayout(): LayoutNode {
|
|
301
|
-
return this.tree;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
paneRects(): PaneRect[] {
|
|
305
|
-
return layoutRects(this.tree, this.innerRect());
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// ─── Mutations ──────────────────────────────────────────────────
|
|
309
|
-
|
|
310
|
-
/** Resize the split enclosing `paneId` along `axis` by `delta` cells.
|
|
311
|
-
* Delegates to layout-tree's resizePane which enforces SplitLimits.
|
|
312
|
-
* Returns true when the tree changed, false when delta rounded to
|
|
313
|
-
* a no-op or no matching-axis split was found. */
|
|
314
|
-
resizePaneAt(paneId: PaneId, axis: Axis, delta: number): boolean {
|
|
315
|
-
if (!this.panes.has(paneId) || delta === 0) return false;
|
|
316
|
-
const next = resizePane(this.tree, paneId, axis, delta, this.innerRect());
|
|
317
|
-
if (next === this.tree) return false;
|
|
318
|
-
this.tree = next;
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
splitFocused(axis: Axis, newContent: PaneContent, ratio = 0.5): PaneId {
|
|
323
|
-
return this.splitPaneAt(this.focusedPaneId, axis, newContent, ratio);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
splitPaneAt(paneId: PaneId, axis: Axis, newContent: PaneContent, ratio = 0.5): PaneId {
|
|
327
|
-
const next = splitPane({
|
|
328
|
-
tree: this.tree,
|
|
329
|
-
paneId,
|
|
330
|
-
axis,
|
|
331
|
-
newPaneId: newContent.id,
|
|
332
|
-
ratio,
|
|
333
|
-
bounds: this.innerRect(),
|
|
334
|
-
limits: this.limits,
|
|
335
|
-
});
|
|
336
|
-
this.tree = next;
|
|
337
|
-
this.panes.set(newContent.id, newContent);
|
|
338
|
-
newContent.start();
|
|
339
|
-
this.events.onPaneCreate?.(newContent.id);
|
|
340
|
-
// Focus the new pane (tmux default).
|
|
341
|
-
this.setFocus(newContent.id);
|
|
342
|
-
return newContent.id;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
closeFocused(): boolean {
|
|
346
|
-
return this.closePaneAt(this.focusedPaneId);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
closePaneAt(paneId: PaneId): boolean {
|
|
350
|
-
if (!this.panes.has(paneId)) return false;
|
|
351
|
-
const next = closePane(this.tree, paneId);
|
|
352
|
-
const content = this.panes.get(paneId);
|
|
353
|
-
if (content) {
|
|
354
|
-
try { content.dispose(); } catch { /* ignore */ }
|
|
355
|
-
}
|
|
356
|
-
this.panes.delete(paneId);
|
|
357
|
-
this.clearPaneTitleOverride(paneId); // VW-B2
|
|
358
|
-
this.events.onPaneClose?.(paneId);
|
|
359
|
-
// VW-U5 — if the closed pane was zoomed, clear the zoom flag so
|
|
360
|
-
// the remaining panes paint normally.
|
|
361
|
-
if (this.zoomedPaneId === paneId) this.zoomedPaneId = null;
|
|
362
|
-
// VW-U5 — forget the closed pane from the alt-tab slot.
|
|
363
|
-
if (this.previousFocusedPaneId === paneId) this.previousFocusedPaneId = null;
|
|
364
|
-
if (next === null) {
|
|
365
|
-
this.state = 'closed';
|
|
366
|
-
this.events.onClose?.();
|
|
367
|
-
return true;
|
|
368
|
-
}
|
|
369
|
-
this.tree = next;
|
|
370
|
-
// Focus the first remaining leaf if the focused pane was closed.
|
|
371
|
-
if (this.focusedPaneId === paneId) {
|
|
372
|
-
const remaining = allPaneIds(this.tree);
|
|
373
|
-
if (remaining.length > 0) this.setFocus(remaining[0]!);
|
|
374
|
-
}
|
|
375
|
-
return true;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
setFocus(paneId: PaneId): boolean {
|
|
379
|
-
if (!this.panes.has(paneId)) return false;
|
|
380
|
-
if (this.focusedPaneId === paneId) return true;
|
|
381
|
-
this.previousFocusedPaneId = this.focusedPaneId; // VW-U5
|
|
382
|
-
this.focusedPaneId = paneId;
|
|
383
|
-
this.events.onPaneFocus?.(paneId);
|
|
384
|
-
return true;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/** VW-U5 — toggle zoom on the currently focused pane. When zoomed,
|
|
388
|
-
* render() paints only the focused pane across the inner rect;
|
|
389
|
-
* other panes retain their state but are hidden. Calling again
|
|
390
|
-
* with the same focus clears zoom. Returns the new zoom state. */
|
|
391
|
-
toggleZoom(): boolean {
|
|
392
|
-
if (this.zoomedPaneId === this.focusedPaneId) {
|
|
393
|
-
this.zoomedPaneId = null;
|
|
394
|
-
} else {
|
|
395
|
-
this.zoomedPaneId = this.focusedPaneId;
|
|
396
|
-
}
|
|
397
|
-
return this.zoomedPaneId !== null;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/** VW-U5 — whether a pane is currently zoomed. */
|
|
401
|
-
isZoomed(): boolean {
|
|
402
|
-
return this.zoomedPaneId !== null;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/** VW-U5 — jump focus to the pane that was focused right before the
|
|
406
|
-
* current one. Returns the pane that ended up focused, or null when
|
|
407
|
-
* there is no recorded previous pane (first-ever focus).
|
|
408
|
-
*
|
|
409
|
-
* SRF-5 — when the remembered previous pane is output-only (e.g.
|
|
410
|
-
* a runner pane that swallows keys), we skip to the next
|
|
411
|
-
* interactive pane if one exists. Mirrors the SP-A window-level
|
|
412
|
-
* skip so pane-level cycling behaves consistently. Falls through
|
|
413
|
-
* to the naive target when every alternative is also output-only
|
|
414
|
-
* (no deadlock). */
|
|
415
|
-
focusLastPane(): PaneId | null {
|
|
416
|
-
const prev = this.previousFocusedPaneId;
|
|
417
|
-
if (!prev || !this.panes.has(prev)) return null;
|
|
418
|
-
if (prev === this.focusedPaneId) return this.focusedPaneId;
|
|
419
|
-
const prevPane = this.panes.get(prev);
|
|
420
|
-
const isOutputOnly = (p: PaneContent | undefined): boolean => p?.focusPolicy === 'output-only';
|
|
421
|
-
if (isOutputOnly(prevPane)) {
|
|
422
|
-
// Find another interactive pane (not current, not prev) before
|
|
423
|
-
// falling back to the naive target.
|
|
424
|
-
for (const [id, content] of this.panes) {
|
|
425
|
-
if (id === this.focusedPaneId) continue;
|
|
426
|
-
if (id === prev) continue;
|
|
427
|
-
if (!isOutputOnly(content)) {
|
|
428
|
-
this.setFocus(id);
|
|
429
|
-
return this.focusedPaneId;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
// No interactive alternative — fall through to naive behavior.
|
|
433
|
-
}
|
|
434
|
-
// setFocus() rotates previousFocusedPaneId → current, so the next
|
|
435
|
-
// call to focusLastPane() swaps back. That's the "alt-tab" feel.
|
|
436
|
-
this.setFocus(prev);
|
|
437
|
-
return this.focusedPaneId;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
focusDirection(dir: Direction): boolean {
|
|
441
|
-
const next = focusNeighbor(this.tree, this.focusedPaneId, dir, this.innerRect());
|
|
442
|
-
if (!next) return false;
|
|
443
|
-
return this.setFocus(next);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// ─── Key routing ────────────────────────────────────────────────
|
|
447
|
-
|
|
448
|
-
onKey(ev: KeyEvent): Action {
|
|
449
|
-
// T3b-c — sync input bar wins when active. Returns passthrough
|
|
450
|
-
// for keys it doesn't recognise (e.g. mouse, unknown ctrl combos)
|
|
451
|
-
// so they can still reach the focused pane as a fallback.
|
|
452
|
-
if (this.syncBar.active) {
|
|
453
|
-
const result = this.handleSyncBarKey(ev);
|
|
454
|
-
if (result === 'consumed') return { type: 'refresh' };
|
|
455
|
-
}
|
|
456
|
-
const content = this.panes.get(this.focusedPaneId);
|
|
457
|
-
if (!content) return { type: 'none' };
|
|
458
|
-
return content.onKey(ev);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/** VW-U3 — mouse dispatch.
|
|
462
|
-
*
|
|
463
|
-
* Left click: if the click lands inside a pane rect, focus that
|
|
464
|
-
* pane. Border / title clicks are a no-op (current focus kept).
|
|
465
|
-
*
|
|
466
|
-
* Right click: pane title emits `onShowContextMenu` so the host
|
|
467
|
-
* can route through MenuProvider; pane body/border emits
|
|
468
|
-
* `onShowSelector` so the host can open the pane/window picker
|
|
469
|
-
* popup. This is the R6 coexistence rule.
|
|
470
|
-
*
|
|
471
|
-
* Scroll-up / scroll-down are reserved for future pane scrollback
|
|
472
|
-
* routing — currently forwarded as-is to the focused pane via
|
|
473
|
-
* content.onKey-like plumbing if the pane supports it (not wired
|
|
474
|
-
* in VW-U3). */
|
|
475
|
-
onMouse(ev: DisplayMouseEvent): Action {
|
|
476
|
-
const rect = this.innerRect();
|
|
477
|
-
const insideInner =
|
|
478
|
-
ev.col >= rect.col && ev.col < rect.col + rect.width
|
|
479
|
-
&& ev.row >= rect.row && ev.row < rect.row + rect.height;
|
|
480
|
-
const paneId = insideInner ? paneAt(this.tree, rect, ev.col, ev.row) : null;
|
|
481
|
-
if (debug.enabled && ev.type !== 'motion') {
|
|
482
|
-
debug.log('vw.mouse', 'dispatch', {
|
|
483
|
-
windowId: this.id,
|
|
484
|
-
type: ev.type,
|
|
485
|
-
row: ev.row,
|
|
486
|
-
col: ev.col,
|
|
487
|
-
insideInner,
|
|
488
|
-
paneId,
|
|
489
|
-
focusedPaneId: this.focusedPaneId,
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
if (isPrimaryDiscreteClickMouseEventType(ev.type)) {
|
|
493
|
-
// VW-A2 — × close-button click takes precedence over pane focus.
|
|
494
|
-
// Geometry lives in closeButtonAt so tests can assert it without
|
|
495
|
-
// mutating state.
|
|
496
|
-
const closeTarget = this.closeButtonAt(ev.col, ev.row);
|
|
497
|
-
if (closeTarget) {
|
|
498
|
-
this.closePaneAt(closeTarget);
|
|
499
|
-
return { type: 'refresh' };
|
|
500
|
-
}
|
|
501
|
-
// VW-A3 — divider hit: arm drag state. The same click also
|
|
502
|
-
// cancels any previous drag so stale state can't persist.
|
|
503
|
-
const divider = insideInner && !this.zoomedPaneId
|
|
504
|
-
? dividerAt(this.tree, rect, ev.col, ev.row)
|
|
505
|
-
: null;
|
|
506
|
-
if (divider) {
|
|
507
|
-
this.dragDivider = {
|
|
508
|
-
hit: divider,
|
|
509
|
-
lastPointer: divider.axis === 'h' ? ev.col : ev.row,
|
|
510
|
-
};
|
|
511
|
-
return { type: 'none' };
|
|
512
|
-
}
|
|
513
|
-
this.dragDivider = null;
|
|
514
|
-
if (paneId && paneId !== this.focusedPaneId) {
|
|
515
|
-
this.setFocus(paneId);
|
|
516
|
-
const routed = this.routeMouseToPane(paneId, ev);
|
|
517
|
-
if (debug.enabled) {
|
|
518
|
-
debug.log('vw.mouse', 'click.focus-route', {
|
|
519
|
-
windowId: this.id,
|
|
520
|
-
paneId,
|
|
521
|
-
routed: routed.type,
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
return routed.type === 'none' ? { type: 'refresh' } : routed;
|
|
525
|
-
}
|
|
526
|
-
if (!paneId) return { type: 'none' };
|
|
527
|
-
const routed = this.routeMouseToPane(paneId, ev);
|
|
528
|
-
if (debug.enabled) {
|
|
529
|
-
debug.log('vw.mouse', 'click.route', {
|
|
530
|
-
windowId: this.id,
|
|
531
|
-
paneId,
|
|
532
|
-
routed: routed.type,
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
return routed;
|
|
536
|
-
}
|
|
537
|
-
// VW-A3 — drag motion: while a divider is armed, convert pointer
|
|
538
|
-
// delta into a layout-tree resizePane call. Wheel clicks / releases
|
|
539
|
-
// outside the loop simply clear the state.
|
|
540
|
-
if (isCaptureSessionMouseEventType(ev.type)) {
|
|
541
|
-
if (!this.dragDivider) {
|
|
542
|
-
const target = paneId ?? this.focusedPaneId;
|
|
543
|
-
if (!target) return { type: 'none' };
|
|
544
|
-
return this.routeMouseToPane(target, ev);
|
|
545
|
-
}
|
|
546
|
-
if (isCaptureSessionEndMouseEventType(ev.type)) {
|
|
547
|
-
this.dragDivider = null;
|
|
548
|
-
return { type: 'none' };
|
|
549
|
-
}
|
|
550
|
-
const { hit, lastPointer } = this.dragDivider;
|
|
551
|
-
const pointer = hit.axis === 'h' ? ev.col : ev.row;
|
|
552
|
-
const delta = pointer - lastPointer;
|
|
553
|
-
if (delta === 0) return { type: 'none' };
|
|
554
|
-
const next = resizePane(this.tree, hit.aPaneId, hit.axis, delta, this.innerRect());
|
|
555
|
-
if (next !== this.tree) {
|
|
556
|
-
this.tree = next;
|
|
557
|
-
this.dragDivider = { hit, lastPointer: pointer };
|
|
558
|
-
return { type: 'refresh' };
|
|
559
|
-
}
|
|
560
|
-
// resize refused (MIN size guard) — keep pointer anchor so the
|
|
561
|
-
// user can drag back the other way without a jump.
|
|
562
|
-
return { type: 'none' };
|
|
563
|
-
}
|
|
564
|
-
if (isSecondaryClickMouseEventType(ev.type)) {
|
|
565
|
-
const secondary = secondaryActionTargetAt(this.paneRects(), ev.col, ev.row);
|
|
566
|
-
if (secondary.kind === 'pane-title') {
|
|
567
|
-
this.events.onShowContextMenu?.(this.id, secondary.paneId, ev.col, ev.row);
|
|
568
|
-
return { type: 'none' };
|
|
569
|
-
}
|
|
570
|
-
if (secondary.paneId) {
|
|
571
|
-
const routed = this.routeMouseToPane(secondary.paneId, ev);
|
|
572
|
-
if (routed.type !== 'none') return routed;
|
|
573
|
-
}
|
|
574
|
-
this.events.onShowSelector?.(this.id, secondary.paneId, ev.col, ev.row);
|
|
575
|
-
return { type: 'none' };
|
|
576
|
-
}
|
|
577
|
-
// VW-A1 — scroll-up/down forwards to the pane under the cursor (or
|
|
578
|
-
// the focused pane when the cursor is outside the inner rect). The
|
|
579
|
-
// target pane's PaneContent.onMouse decides what to do with it; static
|
|
580
|
-
// content types (markdown, scratch) omit onMouse entirely and the
|
|
581
|
-
// wheel becomes a no-op. Returning 'refresh' so the dashboard redraws
|
|
582
|
-
// in case the pane updated its own scroll state.
|
|
583
|
-
if (ev.type === 'scroll-up' || ev.type === 'scroll-down') {
|
|
584
|
-
const target = paneId ?? this.focusedPaneId;
|
|
585
|
-
const content = target ? this.panes.get(target) : null;
|
|
586
|
-
if (!content?.onMouse) return { type: 'none' };
|
|
587
|
-
this.routeMouseToPane(target, ev);
|
|
588
|
-
return { type: 'refresh' };
|
|
589
|
-
}
|
|
590
|
-
return { type: 'none' };
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
private routeMouseToPane(paneId: PaneId, ev: DisplayMouseEvent): Action {
|
|
594
|
-
const content = this.panes.get(paneId);
|
|
595
|
-
if (!content?.onMouse) return { type: 'none' };
|
|
596
|
-
const paneRect = this.paneRects().find((entry) => entry.paneId === paneId)?.rect;
|
|
597
|
-
if (!paneRect) return { type: 'none' };
|
|
598
|
-
const localEv: DisplayMouseEvent = {
|
|
599
|
-
...ev,
|
|
600
|
-
row: ev.row - paneRect.row + 1,
|
|
601
|
-
col: ev.col - paneRect.col + 1,
|
|
602
|
-
};
|
|
603
|
-
try {
|
|
604
|
-
const result = content.onMouse(localEv);
|
|
605
|
-
if (debug.enabled && ev.type !== 'motion') {
|
|
606
|
-
debug.log('vw.mouse', 'pane-forward', {
|
|
607
|
-
windowId: this.id,
|
|
608
|
-
paneId,
|
|
609
|
-
absRow: ev.row,
|
|
610
|
-
absCol: ev.col,
|
|
611
|
-
localRow: localEv.row,
|
|
612
|
-
localCol: localEv.col,
|
|
613
|
-
result: result.type,
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
return result;
|
|
617
|
-
} catch {
|
|
618
|
-
if (debug.enabled) {
|
|
619
|
-
debug.log('vw.mouse', 'pane-forward-error', {
|
|
620
|
-
windowId: this.id,
|
|
621
|
-
paneId,
|
|
622
|
-
absRow: ev.row,
|
|
623
|
-
absCol: ev.col,
|
|
624
|
-
}, { level: 'error' });
|
|
625
|
-
}
|
|
626
|
-
return { type: 'none' };
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
deliverBroadcastToFocused(input: PaneBroadcast): number {
|
|
631
|
-
return this.deliverBroadcastToPane(this.focusedPaneId, input);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
deliverBroadcastToPane(paneId: PaneId, input: PaneBroadcast): number {
|
|
635
|
-
const pane = this.panes.get(paneId);
|
|
636
|
-
if (!pane) return 0;
|
|
637
|
-
if (pane.acceptBroadcast) pane.acceptBroadcast(input);
|
|
638
|
-
else pane.write(input.text);
|
|
639
|
-
return 1;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
deliverBroadcastToAll(input: PaneBroadcast): number {
|
|
643
|
-
let delivered = 0;
|
|
644
|
-
for (const paneId of this.panes.keys()) {
|
|
645
|
-
delivered += this.deliverBroadcastToPane(paneId, input);
|
|
646
|
-
}
|
|
647
|
-
return delivered;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// ─── Rendering ──────────────────────────────────────────────────
|
|
651
|
-
|
|
652
|
-
render(): string {
|
|
653
|
-
const out: string[] = [];
|
|
654
|
-
out.push(this.paintBorder());
|
|
655
|
-
out.push(this.paintInteriorBackground());
|
|
656
|
-
// VW-U5 — zoom path: only the zoomed pane paints, across the full
|
|
657
|
-
// inner rect. Other panes retain their state in the tree so exit
|
|
658
|
-
// is a no-op teardown.
|
|
659
|
-
if (this.zoomedPaneId && this.panes.has(this.zoomedPaneId)) {
|
|
660
|
-
const content = this.panes.get(this.zoomedPaneId)!;
|
|
661
|
-
const rect = this.innerRect();
|
|
662
|
-
try {
|
|
663
|
-
const grid = content.render({
|
|
664
|
-
cols: Math.max(2, rect.width),
|
|
665
|
-
rows: Math.max(2, rect.height),
|
|
666
|
-
focused: true,
|
|
667
|
-
});
|
|
668
|
-
out.push(this.paintPane(rect, grid, this.zoomedPaneId));
|
|
669
|
-
} catch { /* broken pane; skip */ }
|
|
670
|
-
} else {
|
|
671
|
-
const rects = this.paneRects();
|
|
672
|
-
for (const { paneId, rect } of rects) {
|
|
673
|
-
const content = this.panes.get(paneId);
|
|
674
|
-
if (!content) continue;
|
|
675
|
-
try {
|
|
676
|
-
const grid = content.render({
|
|
677
|
-
cols: Math.max(2, rect.width),
|
|
678
|
-
rows: Math.max(2, rect.height),
|
|
679
|
-
focused: paneId === this.focusedPaneId,
|
|
680
|
-
});
|
|
681
|
-
out.push(this.paintPane(rect, grid, paneId));
|
|
682
|
-
} catch { /* broken pane; skip */ }
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
if (this.syncBar.active) {
|
|
686
|
-
out.push(this.paintSyncInputBar());
|
|
687
|
-
}
|
|
688
|
-
return out.join('');
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
private paintInteriorBackground(): string {
|
|
692
|
-
const rect = this.innerRect();
|
|
693
|
-
if (rect.width < 1 || rect.height < 1) return '';
|
|
694
|
-
const out: string[] = [];
|
|
695
|
-
for (let i = 0; i < rect.height; i++) {
|
|
696
|
-
out.push(
|
|
697
|
-
ansi.moveTo(rect.row + i, rect.col)
|
|
698
|
-
+ '\x1b[0m'
|
|
699
|
-
+ ' '.repeat(rect.width),
|
|
700
|
-
);
|
|
701
|
-
}
|
|
702
|
-
return out.join('');
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/** Build the ModalSurface representation for the coordinator. */
|
|
706
|
-
asModalSurface(owner: string = 'dashboard'): ModalSurface {
|
|
707
|
-
const surfaceId: SurfaceId = `virtual-window:${this.id}`;
|
|
708
|
-
const self = this;
|
|
709
|
-
return {
|
|
710
|
-
id: surfaceId,
|
|
711
|
-
owner: owner as ModalSurface['owner'],
|
|
712
|
-
kind: 'modal',
|
|
713
|
-
focus: 'owns',
|
|
714
|
-
priority: 500,
|
|
715
|
-
hostChromeProfile: self.getHostChromeProfile(),
|
|
716
|
-
interactionClass: 'workspace',
|
|
717
|
-
backgroundInteractionPolicy: 'block',
|
|
718
|
-
windowRole: 'foreground',
|
|
719
|
-
// IDX-F4 — virtual-window host surfaces sit at the lowest tier;
|
|
720
|
-
// their own child modals (pickers / popups / dialogs) stack
|
|
721
|
-
// above via the normal TIER_ORDER ordering.
|
|
722
|
-
tier: 'vw',
|
|
723
|
-
// VW-U3 — bounds getter now returns THIS window's actual bounds
|
|
724
|
-
// (setBounds still updates `this.bounds`; previous hardcoded
|
|
725
|
-
// `{1,1,80,24}` snapshot was a placeholder that broke any
|
|
726
|
-
// bounds-aware dispatch like hit-testing mouse clicks).
|
|
727
|
-
get bounds() {
|
|
728
|
-
return { ...self.bounds };
|
|
729
|
-
},
|
|
730
|
-
render: () => [],
|
|
731
|
-
paint: () => this.render(),
|
|
732
|
-
cursor: () => this.cursorState(),
|
|
733
|
-
// KX4b — VW is keyboard-exclusive while foregrounded. Any key
|
|
734
|
-
// reaches the focused pane; the pane's Action return is
|
|
735
|
-
// intentionally discarded (the hard-branch router did the same
|
|
736
|
-
// before KX4) so dashboard.ts's displayRoute switch doesn't
|
|
737
|
-
// double-dispatch refresh/focus actions the pane already owns
|
|
738
|
-
// through its direct writes.
|
|
739
|
-
//
|
|
740
|
-
// VW-U2 — **except** Alt-modified keys without Ctrl: those are
|
|
741
|
-
// reserved for dashboard-global VW navigation (Alt+N/P/1..9 fast
|
|
742
|
-
// switch). We let them bubble past the modal surface so the
|
|
743
|
-
// coordinator can match them against registered bindings. The
|
|
744
|
-
// trade-off is that shell users inside a VW lose Alt-only meta
|
|
745
|
-
// shortcuts (e.g. Alt+M in some readline configs); in exchange
|
|
746
|
-
// the user gets a one-keystroke window switcher even while a
|
|
747
|
-
// shell pane holds focus.
|
|
748
|
-
onKey: (ev) => {
|
|
749
|
-
if (ev.alt && !ev.ctrl) return 'passthrough';
|
|
750
|
-
try { this.onKey(ev); } catch { /* isolate pane error */ }
|
|
751
|
-
return 'consumed';
|
|
752
|
-
},
|
|
753
|
-
// VW-U3 — route mouse clicks into the VW. Left click focuses the
|
|
754
|
-
// clicked pane; right-click fires onShowSelector for VW-U4. Errors
|
|
755
|
-
// are isolated just like onKey — a buggy pane shouldn't crash
|
|
756
|
-
// the coordinator.
|
|
757
|
-
onMouse: (ev) => {
|
|
758
|
-
try { return this.onMouse(ev); }
|
|
759
|
-
catch { return { type: 'none' }; }
|
|
760
|
-
},
|
|
761
|
-
dispose: () => { /* close is triggered externally via WindowRegistry */ },
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
dispose(): void {
|
|
766
|
-
if (this.state === 'closed') return;
|
|
767
|
-
this.state = 'closed';
|
|
768
|
-
for (const pane of this.panes.values()) {
|
|
769
|
-
try { pane.dispose(); } catch { /* ignore */ }
|
|
770
|
-
}
|
|
771
|
-
this.panes.clear();
|
|
772
|
-
this.events.onClose?.();
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
// ─── Internals ──────────────────────────────────────────────────
|
|
776
|
-
|
|
777
|
-
private innerRect(): Rect {
|
|
778
|
-
// Reserve 1 cell on each side for the border + 1 row for title.
|
|
779
|
-
// When the sync input bar is active, shrink the content area by
|
|
780
|
-
// the bar's row count — one per composed line, capped at
|
|
781
|
-
// SYNC_BAR_MAX_ROWS so the bar never eats more than ~a quarter
|
|
782
|
-
// of the window. Pane content clips normally when the bar grows.
|
|
783
|
-
const barRows = this.syncBar.active ? this.syncBarRowCount() : 0;
|
|
784
|
-
return {
|
|
785
|
-
row: this.bounds.row + 1,
|
|
786
|
-
col: this.bounds.col + 1,
|
|
787
|
-
width: Math.max(2, this.bounds.width - 2),
|
|
788
|
-
height: Math.max(2, this.bounds.height - 2 - barRows),
|
|
789
|
-
};
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
/** U2 — how many rows the local composer occupies. 1 for a single-line
|
|
793
|
-
* buffer; lineCount(composed) for multi-line, capped at
|
|
794
|
-
* WINDOW_LOCAL_COMPOSER_MAX_ROWS so panes keep at least part of the viewport. */
|
|
795
|
-
private localComposerRowCount(): number {
|
|
796
|
-
return this.syncBarRowCount();
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
/** Backward-compat internal name kept while older call sites
|
|
800
|
-
* migrate to the local-composer terminology. */
|
|
801
|
-
private syncBarRowCount(): number {
|
|
802
|
-
const lines = this.syncBar.composed.split('\n').length;
|
|
803
|
-
return Math.min(WINDOW_LOCAL_COMPOSER_MAX_ROWS, Math.max(1, lines));
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
// ─── Window-local composer ──────────────────────────────────────
|
|
807
|
-
|
|
808
|
-
/** Toggle or set the window-local composer. */
|
|
809
|
-
setLocalComposerActive(active: boolean): void {
|
|
810
|
-
this.setSyncInputBar(active);
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
isLocalComposerActive(): boolean {
|
|
814
|
-
return this.isSyncInputBarActive();
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
getLocalComposerBuffer(): string {
|
|
818
|
-
return this.getSyncInputBuffer();
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
clearLocalComposer(): void {
|
|
822
|
-
this.clearSyncInput();
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
getLocalComposerCursor(): number {
|
|
826
|
-
return this.getSyncInputCursor();
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
getLocalInputTarget(): LocalInputTarget {
|
|
830
|
-
return this.localInputTarget.kind === 'pane'
|
|
831
|
-
? { kind: 'pane', paneId: this.localInputTarget.paneId }
|
|
832
|
-
: { kind: this.localInputTarget.kind };
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
setLocalInputTarget(target: LocalInputTarget): boolean {
|
|
836
|
-
if (target.kind === 'pane' && !this.panes.has(target.paneId)) return false;
|
|
837
|
-
this.localInputTarget = target.kind === 'pane'
|
|
838
|
-
? { kind: 'pane', paneId: target.paneId }
|
|
839
|
-
: { kind: target.kind };
|
|
840
|
-
return true;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
consumeLocalComposerMentionTargetToken(): boolean {
|
|
844
|
-
const range = this.localComposerMentionRangeAtCursor();
|
|
845
|
-
if (!range) return false;
|
|
846
|
-
const s = this.syncBar;
|
|
847
|
-
let start = range.start;
|
|
848
|
-
let end = range.end;
|
|
849
|
-
if (s.composed[end] === ' ') end += 1;
|
|
850
|
-
else if (start > 0 && s.composed[start - 1] === ' ') start -= 1;
|
|
851
|
-
s.composed = s.composed.slice(0, start) + s.composed.slice(end);
|
|
852
|
-
s.cursorPos = Math.min(start, s.composed.length);
|
|
853
|
-
s.scrollCol = 0;
|
|
854
|
-
return true;
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
listLocalInputTargets(): Array<{ target: LocalInputTarget; label: string; active: boolean }> {
|
|
858
|
-
const out: Array<{ target: LocalInputTarget; label: string; active: boolean }> = [];
|
|
859
|
-
out.push({
|
|
860
|
-
target: { kind: 'focused' },
|
|
861
|
-
label: 'focused pane',
|
|
862
|
-
active: this.localInputTarget.kind === 'focused',
|
|
863
|
-
});
|
|
864
|
-
out.push({
|
|
865
|
-
target: { kind: 'all' },
|
|
866
|
-
label: 'all panes',
|
|
867
|
-
active: this.localInputTarget.kind === 'all',
|
|
868
|
-
});
|
|
869
|
-
for (const [paneId] of this.panes) {
|
|
870
|
-
out.push({
|
|
871
|
-
target: { kind: 'pane', paneId },
|
|
872
|
-
label: this.getPaneDisplayTitle(paneId) || `[${paneId.slice(0, 6)}]`,
|
|
873
|
-
active: this.localInputTarget.kind === 'pane' && this.localInputTarget.paneId === paneId,
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
return out;
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
/** Toggle or set the sync input bar. When turning ON, the window
|
|
880
|
-
* reserves a row for the bar and key events flow into it instead
|
|
881
|
-
* of the focused pane. When turning OFF, keys return to normal
|
|
882
|
-
* pane routing. Idempotent. */
|
|
883
|
-
setSyncInputBar(active: boolean): void {
|
|
884
|
-
if (this.syncBar.active === active) return;
|
|
885
|
-
this.syncBar = { active, composed: '', scrollCol: 0, cursorPos: 0 };
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
isSyncInputBarActive(): boolean {
|
|
889
|
-
return this.syncBar.active;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
getSyncInputBuffer(): string {
|
|
893
|
-
return this.syncBar.composed;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
/** Drop the current composed buffer without submitting. Used by the
|
|
897
|
-
* Escape handler inside handleSyncBarKey. */
|
|
898
|
-
clearSyncInput(): void {
|
|
899
|
-
this.applySyncBarEditor(inlineEditorClear(this.syncBarEditorState()));
|
|
900
|
-
this.syncBar.scrollCol = 0;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
/** U1 — expose cursor position for tests + potential external UIs
|
|
904
|
-
* that want to draw an out-of-band indicator. */
|
|
905
|
-
getSyncInputCursor(): number {
|
|
906
|
-
return this.syncBar.cursorPos;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
/** Internal key handler for the sync input bar — returns
|
|
910
|
-
* 'consumed' when the key was handled (prevents fallthrough to
|
|
911
|
-
* the focused pane). Invoked from onKey() when syncBar.active. */
|
|
912
|
-
private handleSyncBarKey(ev: KeyEvent): 'consumed' | 'passthrough' {
|
|
913
|
-
const name = (ev.name ?? '').toLowerCase();
|
|
914
|
-
const s = this.syncBar;
|
|
915
|
-
if (!ev.ctrl && !ev.alt && name === '@') {
|
|
916
|
-
this.events.onOpenLocalInputTargetPicker?.({
|
|
917
|
-
windowId: this.id,
|
|
918
|
-
seedQuery: this.localComposerMentionRangeAtCursor()?.query ?? undefined,
|
|
919
|
-
});
|
|
920
|
-
return 'consumed';
|
|
921
|
-
}
|
|
922
|
-
// Ctrl+G / Escape → drop the bar entirely (return to pane focus).
|
|
923
|
-
if (name === 'escape' || (ev.ctrl && (name === 'g' || name === 'ㅎ'))) {
|
|
924
|
-
this.setSyncInputBar(false);
|
|
925
|
-
return 'consumed';
|
|
926
|
-
}
|
|
927
|
-
// U2 — Shift+Enter inserts a newline at the cursor (multi-line
|
|
928
|
-
// compose); plain Enter submits the buffer. VW emits submit
|
|
929
|
-
// intent here; pane-specific terminal/newline semantics are
|
|
930
|
-
// handled by PaneContent.acceptBroadcast.
|
|
931
|
-
if (name === 'enter' || name === 'return') {
|
|
932
|
-
if (ev.shift) {
|
|
933
|
-
const next = applyInlineEditorKey(this.syncBarEditorState(), ev, { shiftEnter: 'newline' });
|
|
934
|
-
if (next) this.applySyncBarEditor(next);
|
|
935
|
-
return 'consumed';
|
|
936
|
-
}
|
|
937
|
-
const text = s.composed;
|
|
938
|
-
if (text.length > 0) {
|
|
939
|
-
try {
|
|
940
|
-
const inline = this.resolveInlineLocalInputTarget(text);
|
|
941
|
-
const submitText = inline ? inline.text : text;
|
|
942
|
-
const submitTarget = inline ? inline.target : this.getLocalInputTarget();
|
|
943
|
-
if (inline) this.setLocalInputTarget(inline.target);
|
|
944
|
-
if (this.events.onLocalInputSubmit) {
|
|
945
|
-
if (submitText.length > 0) {
|
|
946
|
-
this.events.onLocalInputSubmit(this.id, {
|
|
947
|
-
broadcast: { mode: 'submit', text: submitText },
|
|
948
|
-
target: submitTarget,
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
else if (submitText.length > 0) this.events.onSyncInputSubmit?.(this.id, submitText + '\r');
|
|
953
|
-
}
|
|
954
|
-
catch { /* host-side submit errors don't crash the VW */ }
|
|
955
|
-
}
|
|
956
|
-
s.composed = '';
|
|
957
|
-
s.cursorPos = 0;
|
|
958
|
-
s.scrollCol = 0;
|
|
959
|
-
return 'consumed';
|
|
960
|
-
}
|
|
961
|
-
const next = applyInlineEditorKey(this.syncBarEditorState(), ev);
|
|
962
|
-
if (next !== null) {
|
|
963
|
-
this.applySyncBarEditor(next);
|
|
964
|
-
if (ev.ctrl && name === 'u') s.scrollCol = 0;
|
|
965
|
-
return 'consumed';
|
|
966
|
-
}
|
|
967
|
-
return 'passthrough';
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
private syncBarEditorState(): InlineEditorState {
|
|
971
|
-
return {
|
|
972
|
-
text: this.syncBar.composed,
|
|
973
|
-
cursor: this.syncBar.cursorPos,
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
private applySyncBarEditor(next: InlineEditorState): void {
|
|
978
|
-
this.syncBar.composed = next.text;
|
|
979
|
-
this.syncBar.cursorPos = next.cursor;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
private localComposerMentionRangeAtCursor():
|
|
983
|
-
| { start: number; end: number; query: string }
|
|
984
|
-
| null {
|
|
985
|
-
const { composed, cursorPos } = this.syncBar;
|
|
986
|
-
if (!composed) return null;
|
|
987
|
-
let start = cursorPos;
|
|
988
|
-
while (start > 0 && !/\s/.test(composed[start - 1]!)) start--;
|
|
989
|
-
let end = cursorPos;
|
|
990
|
-
while (end < composed.length && !/\s/.test(composed[end]!)) end++;
|
|
991
|
-
if (start >= end) return null;
|
|
992
|
-
const token = composed.slice(start, end);
|
|
993
|
-
if (!token.startsWith('@')) return null;
|
|
994
|
-
return { start, end, query: token.slice(1) };
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
private resolveInlineLocalInputTarget(text: string):
|
|
998
|
-
| { target: LocalInputTarget; text: string }
|
|
999
|
-
| null {
|
|
1000
|
-
const match = text.match(/^\s*@(\S+)(?:\s+([\s\S]*))?$/);
|
|
1001
|
-
if (!match) return null;
|
|
1002
|
-
const target = this.localInputTargetFromToken(match[1] ?? '');
|
|
1003
|
-
if (!target) return null;
|
|
1004
|
-
return {
|
|
1005
|
-
target,
|
|
1006
|
-
text: (match[2] ?? '').trimStart(),
|
|
1007
|
-
};
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
private localInputTargetFromToken(tokenRaw: string): LocalInputTarget | null {
|
|
1011
|
-
const token = tokenRaw.trim().toLowerCase();
|
|
1012
|
-
if (!token) return null;
|
|
1013
|
-
if (token === 'focused') return { kind: 'focused' };
|
|
1014
|
-
if (token === 'all') return { kind: 'all' };
|
|
1015
|
-
for (const [paneId] of this.panes) {
|
|
1016
|
-
const title = this.getPaneDisplayTitle(paneId);
|
|
1017
|
-
if (title && title.trim().toLowerCase() === token) {
|
|
1018
|
-
return { kind: 'pane', paneId };
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
return null;
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
private paintBorder(): string {
|
|
1025
|
-
const { row, col, width, height } = this.bounds;
|
|
1026
|
-
if (width < 4 || height < 3) return '';
|
|
1027
|
-
const innerWidth = width - 2;
|
|
1028
|
-
const titleRaw = this.title.length > innerWidth - 6
|
|
1029
|
-
? this.title.slice(0, innerWidth - 7) + '…'
|
|
1030
|
-
: this.title;
|
|
1031
|
-
const windowLabel = ` ${C.accent(`win:${this.id}`)} ${C.text(titleRaw)} `;
|
|
1032
|
-
const vw = visibleWidth(stripAnsi(windowLabel));
|
|
1033
|
-
const leftPad = Math.max(1, Math.floor((innerWidth - vw) / 2));
|
|
1034
|
-
const rightPad = Math.max(1, innerWidth - vw - leftPad);
|
|
1035
|
-
// VW-U1 — when foreground, top border + corners render in accent
|
|
1036
|
-
// (blue) so the user can see at a glance which window is active.
|
|
1037
|
-
// Sides + bottom stay muted to avoid loud framing.
|
|
1038
|
-
const top = this.borderAccent ? C.accent : C.muted;
|
|
1039
|
-
const side = C.muted;
|
|
1040
|
-
const out: string[] = [];
|
|
1041
|
-
out.push(
|
|
1042
|
-
ansi.moveTo(row, col) +
|
|
1043
|
-
top('╭') +
|
|
1044
|
-
top('─'.repeat(leftPad)) +
|
|
1045
|
-
windowLabel +
|
|
1046
|
-
top('─'.repeat(rightPad)) +
|
|
1047
|
-
top('╮'),
|
|
1048
|
-
);
|
|
1049
|
-
for (let i = 0; i < height - 2; i++) {
|
|
1050
|
-
const r = row + 1 + i;
|
|
1051
|
-
out.push(ansi.moveTo(r, col) + side('│'));
|
|
1052
|
-
out.push(ansi.moveTo(r, col + width - 1) + side('│'));
|
|
1053
|
-
}
|
|
1054
|
-
out.push(
|
|
1055
|
-
ansi.moveTo(row + height - 1, col) +
|
|
1056
|
-
side('╰') +
|
|
1057
|
-
side('─'.repeat(innerWidth)) +
|
|
1058
|
-
side('╯'),
|
|
1059
|
-
);
|
|
1060
|
-
return out.join('');
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
private paintSyncInputBar(): string {
|
|
1064
|
-
// U2 — the bar spans syncBarRowCount() rows just above the bottom
|
|
1065
|
-
// border. The first row gets the ▶ vw:N prompt; continuation rows
|
|
1066
|
-
// use an aligned indent so the composed body stays readable.
|
|
1067
|
-
const rowCount = this.syncBarRowCount();
|
|
1068
|
-
const topRow = this.bounds.row + this.bounds.height - 1 - rowCount;
|
|
1069
|
-
const col = this.bounds.col + 1;
|
|
1070
|
-
const width = Math.max(2, this.bounds.width - 2);
|
|
1071
|
-
const prompt = C.accent(`▶ vw:${this.id}`) + C.muted(` ${this.localInputTargetLabel()} ▸ `);
|
|
1072
|
-
const promptVw = visibleWidth(stripAnsi(prompt));
|
|
1073
|
-
const contRaw = ' '.repeat(Math.max(0, promptVw - 2)) + '↪ ';
|
|
1074
|
-
const cont = C.muted(contRaw);
|
|
1075
|
-
const contVw = visibleWidth(stripAnsi(cont));
|
|
1076
|
-
const bodyBudget = Math.max(1, width - promptVw);
|
|
1077
|
-
const s = this.syncBar;
|
|
1078
|
-
|
|
1079
|
-
// Compute (line, col) for cursorPos so the rendered caret lands
|
|
1080
|
-
// on the right row when composed has embedded newlines.
|
|
1081
|
-
const { line: cursorLine, col: cursorColInLine } = positionToLineCol(s.composed, s.cursorPos);
|
|
1082
|
-
// Horizontal scroll tracks the current cursor line only. Each
|
|
1083
|
-
// line paints independently; only the focused line's content
|
|
1084
|
-
// shifts left when needed.
|
|
1085
|
-
const lines = s.composed.split('\n');
|
|
1086
|
-
|
|
1087
|
-
const out: string[] = [];
|
|
1088
|
-
// Clear every row we're about to paint (prevents stale glyphs
|
|
1089
|
-
// when the bar grows/shrinks between frames).
|
|
1090
|
-
for (let r = 0; r < rowCount; r++) {
|
|
1091
|
-
out.push(ansi.moveTo(topRow + r, col) + ' '.repeat(width) + '\x1b[0m');
|
|
1092
|
-
}
|
|
1093
|
-
// Window-shift the visible line slice so the cursor stays in view.
|
|
1094
|
-
for (let r = 0; r < rowCount; r++) {
|
|
1095
|
-
const lineIdx = r < lines.length ? r : -1;
|
|
1096
|
-
if (lineIdx < 0) continue;
|
|
1097
|
-
const lineText = lines[lineIdx]!;
|
|
1098
|
-
const promptPrefix = lineIdx === 0 ? prompt : cont;
|
|
1099
|
-
const promptCols = lineIdx === 0 ? promptVw : contVw;
|
|
1100
|
-
const budget = Math.max(1, width - promptCols);
|
|
1101
|
-
// Only scroll the cursor line; the others render from column 0.
|
|
1102
|
-
let start = 0;
|
|
1103
|
-
if (lineIdx === cursorLine) {
|
|
1104
|
-
start = s.scrollCol;
|
|
1105
|
-
if (cursorColInLine < start) start = cursorColInLine;
|
|
1106
|
-
if (cursorColInLine >= start + budget) start = cursorColInLine - budget + 1;
|
|
1107
|
-
start = Math.max(0, start);
|
|
1108
|
-
s.scrollCol = start;
|
|
1109
|
-
}
|
|
1110
|
-
const slice = lineText.slice(start, start + budget);
|
|
1111
|
-
const padded = slice + ' '.repeat(Math.max(0, budget - slice.length));
|
|
1112
|
-
out.push(ansi.moveTo(topRow + r, col) + promptPrefix + padded);
|
|
1113
|
-
}
|
|
1114
|
-
// Paint the cursor cell LAST so it wins over the body paint.
|
|
1115
|
-
const cursorRowAbs = topRow + Math.min(rowCount - 1, cursorLine);
|
|
1116
|
-
const cursorPrompt = cursorLine === 0 ? promptVw : contVw;
|
|
1117
|
-
const cursorCol = col + cursorPrompt + (cursorColInLine - s.scrollCol);
|
|
1118
|
-
const underCh = (lines[cursorLine] ?? '')[cursorColInLine] ?? ' ';
|
|
1119
|
-
out.push(ansi.moveTo(cursorRowAbs, cursorCol) + '\x1b[7m' + underCh + '\x1b[27m');
|
|
1120
|
-
return out.join('');
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
private cursorState(): CursorState | null {
|
|
1124
|
-
if (this.syncBar.active) return this.localComposerCursorState();
|
|
1125
|
-
const rect = this.zoomedPaneCursorRect();
|
|
1126
|
-
if (!rect) return null;
|
|
1127
|
-
const pane = this.panes.get(rect.paneId);
|
|
1128
|
-
if (!pane || typeof pane.cursor !== 'function') return null;
|
|
1129
|
-
try {
|
|
1130
|
-
return pane.cursor({
|
|
1131
|
-
cols: Math.max(2, rect.rect.width),
|
|
1132
|
-
rows: Math.max(2, rect.rect.height),
|
|
1133
|
-
focused: true,
|
|
1134
|
-
row: rect.rect.row,
|
|
1135
|
-
col: rect.rect.col,
|
|
1136
|
-
});
|
|
1137
|
-
} catch {
|
|
1138
|
-
return null;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
private zoomedPaneCursorRect():
|
|
1143
|
-
| { paneId: PaneId; rect: Rect }
|
|
1144
|
-
| null {
|
|
1145
|
-
if (this.zoomedPaneId && this.panes.has(this.zoomedPaneId)) {
|
|
1146
|
-
return { paneId: this.zoomedPaneId, rect: this.innerRect() };
|
|
1147
|
-
}
|
|
1148
|
-
const match = this.paneRects().find((it) => it.paneId === this.focusedPaneId);
|
|
1149
|
-
return match ? { paneId: match.paneId, rect: match.rect } : null;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
private localComposerCursorState(): CursorState {
|
|
1153
|
-
const rowCount = this.syncBarRowCount();
|
|
1154
|
-
const topRow = this.bounds.row + this.bounds.height - 1 - rowCount;
|
|
1155
|
-
const col = this.bounds.col + 1;
|
|
1156
|
-
const width = Math.max(2, this.bounds.width - 2);
|
|
1157
|
-
const prompt = C.accent(`▶ vw:${this.id}`) + C.muted(` ${this.localInputTargetLabel()} ▸ `);
|
|
1158
|
-
const promptVw = visibleWidth(stripAnsi(prompt));
|
|
1159
|
-
const contRaw = ' '.repeat(Math.max(0, promptVw - 2)) + '↪ ';
|
|
1160
|
-
const contVw = visibleWidth(contRaw);
|
|
1161
|
-
const s = this.syncBar;
|
|
1162
|
-
const { line: cursorLine, col: cursorColInLine } = positionToLineCol(s.composed, s.cursorPos);
|
|
1163
|
-
const cursorRowAbs = topRow + Math.min(rowCount - 1, cursorLine);
|
|
1164
|
-
const cursorPrompt = cursorLine === 0 ? promptVw : contVw;
|
|
1165
|
-
const cursorLineText = s.composed.split('\n')[cursorLine] ?? '';
|
|
1166
|
-
const visibleBodyCol = visibleWidth(cursorLineText.slice(s.scrollCol, cursorColInLine));
|
|
1167
|
-
const cursorCol = col + cursorPrompt + visibleBodyCol;
|
|
1168
|
-
return {
|
|
1169
|
-
row: cursorRowAbs,
|
|
1170
|
-
col: Math.max(col, Math.min(cursorCol, col + width - 1)),
|
|
1171
|
-
visible: true,
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
private localInputTargetLabel(): string {
|
|
1176
|
-
if (this.localInputTarget.kind === 'all') return '@all';
|
|
1177
|
-
if (this.localInputTarget.kind === 'focused') return '@focused';
|
|
1178
|
-
return `@${this.getPaneDisplayTitle(this.localInputTarget.paneId) || this.localInputTarget.paneId.slice(0, 6)}`;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
private paintPane(rect: Rect, grid: string, paneId: PaneId): string {
|
|
1182
|
-
const out: string[] = [];
|
|
1183
|
-
const pane = this.panes.get(paneId) ?? null;
|
|
1184
|
-
const focused = paneId === this.focusedPaneId;
|
|
1185
|
-
const pulseActive = focused && (pane?.isAlive ?? false);
|
|
1186
|
-
const pulse = pulseActive ? pulsePhase(this.now()) : null;
|
|
1187
|
-
const lines = grid.split('\n');
|
|
1188
|
-
for (let i = 0; i < rect.height; i++) {
|
|
1189
|
-
const line = lines[i] ?? '';
|
|
1190
|
-
// F2 (2026-04-21) — each row ends with CSI K (erase-to-EOL)
|
|
1191
|
-
// before moving to the next row, so rows that are narrower than
|
|
1192
|
-
// `rect.width` don't leave trailing cells holding residue from
|
|
1193
|
-
// the previous foreground (dashboard, another VW). SGR reset
|
|
1194
|
-
// before EL ensures the erased cells pick up the default bg.
|
|
1195
|
-
out.push(
|
|
1196
|
-
ansi.moveTo(rect.row + i, rect.col)
|
|
1197
|
-
+ line
|
|
1198
|
-
+ '\x1b[0m\x1b[K',
|
|
1199
|
-
);
|
|
1200
|
-
}
|
|
1201
|
-
// Pane divider: draw a thin horizontal/vertical line separating
|
|
1202
|
-
// this pane from its neighbors. Skip when adjacent to window
|
|
1203
|
-
// border (border already paints).
|
|
1204
|
-
const innerRight = this.bounds.col + this.bounds.width - 2;
|
|
1205
|
-
const innerBottom = this.bounds.row + this.bounds.height - 2;
|
|
1206
|
-
if (rect.col + rect.width - 1 < innerRight) {
|
|
1207
|
-
for (let i = 0; i < rect.height; i++) {
|
|
1208
|
-
out.push(ansi.moveTo(rect.row + i, rect.col + rect.width - 1) + C.muted('│'));
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
if (rect.row + rect.height - 1 < innerBottom) {
|
|
1212
|
-
out.push(
|
|
1213
|
-
ansi.moveTo(rect.row + rect.height - 1, rect.col) +
|
|
1214
|
-
C.muted('─'.repeat(rect.width)),
|
|
1215
|
-
);
|
|
1216
|
-
}
|
|
1217
|
-
// Pane label on the top border for every pane.
|
|
1218
|
-
// Focus changes the chrome treatment, but the pane title itself
|
|
1219
|
-
// remains visible for all panes so split layouts (showroom,
|
|
1220
|
-
// 2x2, 4x4) preserve local identity without requiring focus.
|
|
1221
|
-
{
|
|
1222
|
-
const override = this.paneTitleOverrides.get(paneId);
|
|
1223
|
-
const displayTitle = this.getPaneDisplayTitle(paneId);
|
|
1224
|
-
const baseTitle = override ?? (displayTitle || `[${paneId.slice(0, 6)}]`);
|
|
1225
|
-
const vis: PaneVisibility = this.visibilityResolver?.(paneId) ?? 'visible';
|
|
1226
|
-
const pulseGlyph = pulseActive ? (pulse === 'A' ? '●' : '○') : '';
|
|
1227
|
-
const badge = focused ? composeVisibilityBadge(vis) : '';
|
|
1228
|
-
const badgeW = focused ? badgeVisibleWidth(vis) : 0;
|
|
1229
|
-
const closeReserve = focused && this.panes.size > 1 && !this.zoomedPaneId && rect.width >= 4 ? 2 : 0;
|
|
1230
|
-
const pulseW = pulseGlyph ? 2 : 0;
|
|
1231
|
-
const titleBudget = Math.max(0, rect.width - closeReserve - pulseW - (badge ? badgeW + 1 : 0));
|
|
1232
|
-
const titleState =
|
|
1233
|
-
pulseActive && pulse === 'B'
|
|
1234
|
-
? 'pulse-b'
|
|
1235
|
-
: pulseActive
|
|
1236
|
-
? 'pulse-a'
|
|
1237
|
-
: focused
|
|
1238
|
-
? 'active'
|
|
1239
|
-
: 'inactive';
|
|
1240
|
-
const labelCore = paneBorderTitle(baseTitle, titleState, titleBudget);
|
|
1241
|
-
const labelWithPulse = pulseGlyph && labelCore ? `${labelCore} ${pulseGlyph}` : labelCore;
|
|
1242
|
-
const label = badge && labelWithPulse ? `${labelWithPulse} ${badge}` : labelWithPulse;
|
|
1243
|
-
const labelW = Math.min(visibleWidth(label), Math.max(0, rect.width - closeReserve));
|
|
1244
|
-
if (labelW > 0) {
|
|
1245
|
-
out.push(ansi.moveTo(rect.row, rect.col) + '\x1b[0m' + ' '.repeat(labelW));
|
|
1246
|
-
out.push(ansi.moveTo(rect.row, rect.col) + label);
|
|
1247
|
-
}
|
|
1248
|
-
if (debug.enabled) {
|
|
1249
|
-
debug.log('vw.pane.label.paint', paneId.slice(0, 6), {
|
|
1250
|
-
paneId, focused, pulse,
|
|
1251
|
-
labelWidth: labelW, rectRow: rect.row, rectCol: rect.col,
|
|
1252
|
-
baseTitle,
|
|
1253
|
-
visibility: vis, badgeW,
|
|
1254
|
-
});
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
// VW-A2 — close `×` glyph on the focused pane's top-right corner.
|
|
1258
|
-
// Hidden for solo panes (use `^B X` to close the whole window) and
|
|
1259
|
-
// whenever the pane is zoomed — the × would overlap the zoomed
|
|
1260
|
-
// label and users rarely want to close a pane they're focused on
|
|
1261
|
-
// in zoom mode anyway.
|
|
1262
|
-
if (
|
|
1263
|
-
paneId === this.focusedPaneId
|
|
1264
|
-
&& this.panes.size > 1
|
|
1265
|
-
&& !this.zoomedPaneId
|
|
1266
|
-
&& rect.width >= 4
|
|
1267
|
-
) {
|
|
1268
|
-
const closeCol = rect.col + rect.width - 2;
|
|
1269
|
-
out.push(ansi.moveTo(rect.row, closeCol) + C.error('×'));
|
|
1270
|
-
}
|
|
1271
|
-
return out.join('');
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
/** VW-A2 — hit-test for the per-pane `×` close button. Returns the
|
|
1275
|
-
* pane id whose close button covers (col, row), or null. Kept
|
|
1276
|
-
* separate from onMouse so tests can validate the geometry without
|
|
1277
|
-
* side-effecting focus / close. */
|
|
1278
|
-
closeButtonAt(col: number, row: number): PaneId | null {
|
|
1279
|
-
if (this.panes.size < 2) return null;
|
|
1280
|
-
if (this.zoomedPaneId) return null;
|
|
1281
|
-
for (const { paneId, rect } of this.paneRects()) {
|
|
1282
|
-
if (paneId !== this.focusedPaneId) continue;
|
|
1283
|
-
if (rect.width < 4) continue;
|
|
1284
|
-
const closeCol = rect.col + rect.width - 2;
|
|
1285
|
-
if (row === rect.row && col === closeCol) return paneId;
|
|
1286
|
-
}
|
|
1287
|
-
return null;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
/** U2 — convert an absolute cursor offset into (line, col) given
|
|
1292
|
-
* newline-separated composed buffer. Used by the multi-line paint
|
|
1293
|
-
* path to place the caret in the right row. */
|
|
1294
|
-
function positionToLineCol(text: string, pos: number): { line: number; col: number } {
|
|
1295
|
-
let line = 0;
|
|
1296
|
-
let lineStart = 0;
|
|
1297
|
-
for (let i = 0; i < pos && i < text.length; i++) {
|
|
1298
|
-
if (text[i] === '\n') { line += 1; lineStart = i + 1; }
|
|
1299
|
-
}
|
|
1300
|
-
return { line, col: pos - lineStart };
|
|
1301
|
-
}
|