elanous 0.2.0 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +6 -0
- package/README.md +17 -15
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1751.50b96ea9c37b49b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +25 -0
- package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +5 -0
- package/apps/pwa/out/_next/static/chunks/4440-18bb160d95819f4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2a79f15a-2013e4d421d6df88.js → 4daa2798-1363d725c79f3593.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5348-bbf838e119661eee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5391-8793f88b03b30161.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5927.8378481a12cc8044.js → 7527.943753b6ed829f09.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6804.8ed6ab492bc5fc0a.js → 8617.465ca22a319c95b3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{320-d7013ec072863e5e.js → 8918-482b30ce2a8ebf4c.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2598.814f64e3268634e7.js → 9238.2cd5f47f4bf7a2c3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9704-3221c102623c8d73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f89e9a303515a033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-4f403cd060442c95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-0ac5d053f0444d21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-72bd384898d88955.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-bccce0babceae30f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f6f3850d-7f324c6566002113.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-2bf59c720fe9542c.js +1 -0
- package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +1 -0
- package/apps/pwa/out/_next/static/ktMqfrBbf8BMGac0jqLrb/_buildManifest.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -0
- package/apps/pwa/out/approvals/index.txt +32 -0
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +29 -26
- package/apps/pwa/out/board/index.html +1 -0
- package/apps/pwa/out/board/index.txt +32 -0
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +26 -23
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +26 -23
- package/apps/pwa/out/chat/index.html +1 -2
- package/apps/pwa/out/chat/index.txt +26 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +29 -26
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +29 -26
- package/apps/pwa/out/editor/index.html +1 -0
- package/apps/pwa/out/editor/index.txt +33 -0
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/icons/elanous-16.png +0 -0
- package/apps/pwa/out/icons/elanous-180.png +0 -0
- package/apps/pwa/out/icons/elanous-192.png +0 -0
- package/apps/pwa/out/icons/elanous-32.png +0 -0
- package/apps/pwa/out/icons/elanous-512.png +0 -0
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +26 -23
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +29 -26
- package/apps/pwa/out/live/index.html +1 -0
- package/apps/pwa/out/live/index.txt +32 -0
- package/apps/pwa/out/manifest.webmanifest +5 -2
- package/apps/pwa/out/market/index.html +1 -0
- package/apps/pwa/out/market/index.txt +29 -0
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +26 -23
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +29 -26
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +29 -26
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +27 -24
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +29 -26
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +26 -23
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +29 -26
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +29 -26
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +29 -26
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +29 -26
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +29 -26
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +26 -23
- package/apps/pwa/out/sw-strategies.js +44 -0
- package/apps/pwa/out/sw.js +6 -44
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +29 -26
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +29 -26
- package/apps/pwa/out/trace/index.html +1 -0
- package/apps/pwa/out/trace/index.txt +32 -0
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +29 -26
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +29 -26
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +29 -27
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +29 -26
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +29 -26
- package/catalog/resources.yaml +14 -17
- package/docs/design/systems/LICENSE +201 -0
- package/docs/design/systems/NOTICE.md +29 -0
- package/docs/design/systems/SOURCE.json +291 -0
- package/docs/design/systems/application/DESIGN.md +71 -0
- package/docs/design/systems/application/manifest.json +54 -0
- package/docs/design/systems/application/tokens.css +63 -0
- package/docs/design/systems/artistic/DESIGN.md +71 -0
- package/docs/design/systems/artistic/manifest.json +54 -0
- package/docs/design/systems/artistic/tokens.css +63 -0
- package/docs/design/systems/bento/DESIGN.md +71 -0
- package/docs/design/systems/bento/manifest.json +54 -0
- package/docs/design/systems/bento/tokens.css +63 -0
- package/docs/design/systems/bold/DESIGN.md +71 -0
- package/docs/design/systems/bold/manifest.json +54 -0
- package/docs/design/systems/bold/tokens.css +63 -0
- package/docs/design/systems/brutalism/DESIGN.md +71 -0
- package/docs/design/systems/brutalism/manifest.json +54 -0
- package/docs/design/systems/brutalism/tokens.css +63 -0
- package/docs/design/systems/cafe/DESIGN.md +71 -0
- package/docs/design/systems/cafe/manifest.json +54 -0
- package/docs/design/systems/cafe/tokens.css +63 -0
- package/docs/design/systems/claymorphism/DESIGN.md +71 -0
- package/docs/design/systems/claymorphism/manifest.json +54 -0
- package/docs/design/systems/claymorphism/tokens.css +63 -0
- package/docs/design/systems/clean/DESIGN.md +71 -0
- package/docs/design/systems/clean/manifest.json +54 -0
- package/docs/design/systems/clean/tokens.css +63 -0
- package/docs/design/systems/colorful/DESIGN.md +71 -0
- package/docs/design/systems/colorful/manifest.json +54 -0
- package/docs/design/systems/colorful/tokens.css +63 -0
- package/docs/design/systems/contemporary/DESIGN.md +71 -0
- package/docs/design/systems/contemporary/manifest.json +54 -0
- package/docs/design/systems/contemporary/tokens.css +63 -0
- package/docs/design/systems/corporate/DESIGN.md +71 -0
- package/docs/design/systems/corporate/manifest.json +54 -0
- package/docs/design/systems/corporate/tokens.css +63 -0
- package/docs/design/systems/cosmic/DESIGN.md +71 -0
- package/docs/design/systems/cosmic/manifest.json +54 -0
- package/docs/design/systems/cosmic/tokens.css +63 -0
- package/docs/design/systems/creative/DESIGN.md +71 -0
- package/docs/design/systems/creative/manifest.json +54 -0
- package/docs/design/systems/creative/tokens.css +63 -0
- package/docs/design/systems/dashboard/DESIGN.md +71 -0
- package/docs/design/systems/dashboard/manifest.json +54 -0
- package/docs/design/systems/dashboard/tokens.css +63 -0
- package/docs/design/systems/default/DESIGN.md +62 -0
- package/docs/design/systems/default/manifest.json +69 -0
- package/docs/design/systems/default/tokens.css +200 -0
- package/docs/design/systems/dithered/DESIGN.md +71 -0
- package/docs/design/systems/dithered/manifest.json +54 -0
- package/docs/design/systems/dithered/tokens.css +63 -0
- package/docs/design/systems/doodle/DESIGN.md +71 -0
- package/docs/design/systems/doodle/manifest.json +54 -0
- package/docs/design/systems/doodle/tokens.css +63 -0
- package/docs/design/systems/dramatic/DESIGN.md +71 -0
- package/docs/design/systems/dramatic/manifest.json +54 -0
- package/docs/design/systems/dramatic/tokens.css +63 -0
- package/docs/design/systems/editorial/DESIGN.md +71 -0
- package/docs/design/systems/editorial/manifest.json +54 -0
- package/docs/design/systems/editorial/tokens.css +63 -0
- package/docs/design/systems/elegant/DESIGN.md +71 -0
- package/docs/design/systems/elegant/manifest.json +54 -0
- package/docs/design/systems/elegant/tokens.css +63 -0
- package/docs/design/systems/energetic/DESIGN.md +72 -0
- package/docs/design/systems/energetic/manifest.json +54 -0
- package/docs/design/systems/energetic/tokens.css +63 -0
- package/docs/design/systems/enterprise/DESIGN.md +71 -0
- package/docs/design/systems/enterprise/manifest.json +54 -0
- package/docs/design/systems/enterprise/tokens.css +63 -0
- package/docs/design/systems/expressive/DESIGN.md +71 -0
- package/docs/design/systems/expressive/manifest.json +54 -0
- package/docs/design/systems/expressive/tokens.css +63 -0
- package/docs/design/systems/fantasy/DESIGN.md +71 -0
- package/docs/design/systems/fantasy/manifest.json +54 -0
- package/docs/design/systems/fantasy/tokens.css +63 -0
- package/docs/design/systems/flat/DESIGN.md +71 -0
- package/docs/design/systems/flat/manifest.json +54 -0
- package/docs/design/systems/flat/tokens.css +63 -0
- package/docs/design/systems/friendly/DESIGN.md +71 -0
- package/docs/design/systems/friendly/manifest.json +54 -0
- package/docs/design/systems/friendly/tokens.css +63 -0
- package/docs/design/systems/glassmorphism/DESIGN.md +71 -0
- package/docs/design/systems/glassmorphism/manifest.json +54 -0
- package/docs/design/systems/glassmorphism/tokens.css +63 -0
- package/docs/design/systems/gradient/DESIGN.md +71 -0
- package/docs/design/systems/gradient/manifest.json +54 -0
- package/docs/design/systems/gradient/tokens.css +63 -0
- package/docs/design/systems/luxury/DESIGN.md +71 -0
- package/docs/design/systems/luxury/manifest.json +54 -0
- package/docs/design/systems/luxury/tokens.css +63 -0
- package/docs/design/systems/minimal/DESIGN.md +71 -0
- package/docs/design/systems/minimal/manifest.json +54 -0
- package/docs/design/systems/minimal/tokens.css +63 -0
- package/docs/design/systems/modern/DESIGN.md +71 -0
- package/docs/design/systems/modern/manifest.json +54 -0
- package/docs/design/systems/modern/tokens.css +63 -0
- package/docs/design/systems/mono/DESIGN.md +71 -0
- package/docs/design/systems/mono/manifest.json +54 -0
- package/docs/design/systems/mono/tokens.css +63 -0
- package/docs/design/systems/neobrutalism/DESIGN.md +71 -0
- package/docs/design/systems/neobrutalism/manifest.json +54 -0
- package/docs/design/systems/neobrutalism/tokens.css +63 -0
- package/docs/design/systems/neon/DESIGN.md +71 -0
- package/docs/design/systems/neon/manifest.json +54 -0
- package/docs/design/systems/neon/tokens.css +63 -0
- package/docs/design/systems/neumorphism/DESIGN.md +71 -0
- package/docs/design/systems/neumorphism/manifest.json +54 -0
- package/docs/design/systems/neumorphism/tokens.css +63 -0
- package/docs/design/systems/paper/DESIGN.md +71 -0
- package/docs/design/systems/paper/manifest.json +54 -0
- package/docs/design/systems/paper/tokens.css +63 -0
- package/docs/design/systems/perspective/DESIGN.md +71 -0
- package/docs/design/systems/perspective/manifest.json +54 -0
- package/docs/design/systems/perspective/tokens.css +63 -0
- package/docs/design/systems/premium/DESIGN.md +71 -0
- package/docs/design/systems/premium/manifest.json +54 -0
- package/docs/design/systems/premium/tokens.css +63 -0
- package/docs/design/systems/professional/DESIGN.md +71 -0
- package/docs/design/systems/professional/manifest.json +54 -0
- package/docs/design/systems/professional/tokens.css +63 -0
- package/docs/design/systems/publication/DESIGN.md +71 -0
- package/docs/design/systems/publication/manifest.json +54 -0
- package/docs/design/systems/publication/tokens.css +63 -0
- package/docs/design/systems/refined/DESIGN.md +71 -0
- package/docs/design/systems/refined/manifest.json +54 -0
- package/docs/design/systems/refined/tokens.css +63 -0
- package/docs/design/systems/retro/DESIGN.md +71 -0
- package/docs/design/systems/retro/manifest.json +54 -0
- package/docs/design/systems/retro/tokens.css +63 -0
- package/docs/design/systems/shadcn/DESIGN.md +71 -0
- package/docs/design/systems/shadcn/manifest.json +54 -0
- package/docs/design/systems/shadcn/tokens.css +255 -0
- package/docs/design/systems/simple/DESIGN.md +71 -0
- package/docs/design/systems/simple/manifest.json +54 -0
- package/docs/design/systems/simple/tokens.css +63 -0
- package/docs/design/systems/skeumorphism/DESIGN.md +71 -0
- package/docs/design/systems/skeumorphism/manifest.json +54 -0
- package/docs/design/systems/skeumorphism/tokens.css +63 -0
- package/docs/design/systems/sleek/DESIGN.md +71 -0
- package/docs/design/systems/sleek/manifest.json +54 -0
- package/docs/design/systems/sleek/tokens.css +63 -0
- package/docs/design/systems/spacious/DESIGN.md +71 -0
- package/docs/design/systems/spacious/manifest.json +54 -0
- package/docs/design/systems/spacious/tokens.css +63 -0
- package/docs/design/systems/storytelling/DESIGN.md +71 -0
- package/docs/design/systems/storytelling/manifest.json +54 -0
- package/docs/design/systems/storytelling/tokens.css +63 -0
- package/docs/design/systems/tom-modern/DESIGN.md +361 -0
- package/docs/design/systems/tom-modern/manifest.json +16 -0
- package/docs/design/systems/tom-modern/tokens.css +99 -0
- package/docs/design/systems/vibrant/DESIGN.md +71 -0
- package/docs/design/systems/vibrant/manifest.json +54 -0
- package/docs/design/systems/vibrant/tokens.css +63 -0
- package/docs/design/systems/vintage/DESIGN.md +71 -0
- package/docs/design/systems/vintage/manifest.json +54 -0
- package/docs/design/systems/vintage/tokens.css +63 -0
- package/docs/design/systems/warm-editorial/DESIGN.md +65 -0
- package/docs/design/systems/warm-editorial/manifest.json +54 -0
- package/docs/design/systems/warm-editorial/tokens.css +63 -0
- package/docs/goal-context/01-goal-authoring-checks.md +18 -0
- package/docs/goal-context/steward-directives-2026-09-28.md +42 -0
- package/graphs/catalog/catalog.yaml +615 -0
- package/graphs/default-loop.yaml +1 -1
- package/graphs/document-loop.yaml +1 -1
- package/graphs/examples/stale-draft-digest/digest.ts +26 -0
- package/graphs/examples/stale-draft-digest/recipes.yaml +8 -0
- package/graphs/examples/stale-draft-digest/stale-draft-digest.yaml +22 -0
- package/graphs/heal/heal-loop.yaml +155 -0
- package/graphs/heal/recipes.yaml +19 -0
- package/graphs/implement-loop.yaml +2 -2
- package/graphs/intake/intake-daily.yaml +55 -0
- package/graphs/intake/recipes.yaml +16 -0
- package/graphs/landing/landing-heal.yaml +22 -0
- package/graphs/landing/recipes.yaml +8 -0
- package/graphs/launch/launch-head.yaml +66 -0
- package/graphs/launch/recipes.yaml +8 -0
- package/graphs/operate-loop.yaml +1 -1
- package/graphs/ops/docs-publish.yaml +31 -0
- package/graphs/ops/recipes.yaml +8 -0
- package/graphs/release/recipes.yaml +45 -0
- package/graphs/release/release-loop.yaml +45 -0
- package/graphs/research-loop.yaml +1 -1
- package/graphs/steward/recipes.yaml +12 -0
- package/graphs/steward/steward.yaml +45 -0
- package/graphs/video/README.md +1 -0
- package/graphs/video/broll-line.yaml +54 -0
- package/graphs/video/explainer-line.yaml +58 -0
- package/package.json +9 -5
- package/plugins/job-coach/.agents/plugins/marketplace.json +12 -0
- package/plugins/job-coach/.codex-plugin/plugin.json +23 -0
- package/plugins/job-coach/.mcp.json +9 -0
- package/plugins/job-coach/README.md +32 -0
- package/plugins/job-coach/connectors/ncs/server.ts +90 -0
- package/plugins/job-coach/examples/interview-sample.md +11 -0
- package/plugins/job-coach/graphs/course-links.ts +46 -0
- package/plugins/job-coach/graphs/gap-judge.ts +44 -0
- package/plugins/job-coach/graphs/recipes.yaml +45 -0
- package/plugins/job-coach/graphs/report-enterprise.yaml +28 -0
- package/plugins/job-coach/graphs/report.yaml +20 -0
- package/plugins/job-coach/graphs/run-step.ts +302 -0
- package/plugins/job-coach/plugin.json +26 -0
- package/plugins/job-coach/plugin.ts +6 -0
- package/plugins/job-coach/skills/career-report/SKILL.md +6 -0
- package/plugins/job-coach/skills/enterprise-ai-fit/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-competency/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-needs/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-roadmap/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-task-analysis/SKILL.md +8 -0
- package/plugins/job-coach/skills/interview-to-profile/SKILL.md +23 -0
- package/plugins/job-coach/skills/run-report/SKILL.md +15 -0
- package/scripts/backup/elanous-backup.sh +143 -14
- package/scripts/backup/elanous-restore.sh +122 -0
- package/scripts/build-docs-site.ts +4 -3
- package/scripts/ci-daemon-port-gate.ts +164 -0
- package/scripts/ci-typecheck-changed.ts +15 -1
- package/scripts/cli-json-exit-scan.ts +126 -0
- package/scripts/codex-quota-alert-format.ts +52 -0
- package/scripts/codex-quota-alert.ts +63 -13
- package/scripts/continuation-dogfood.ts +2 -1
- package/scripts/coord-channel-watch.sh +28 -9
- package/scripts/coord-post.sh +49 -12
- package/scripts/coord-tracks.json +6 -5
- package/scripts/cron-run.ts +37 -16
- package/scripts/daemon-port-baseline.txt +9 -0
- package/scripts/design/extract-corpus-bench.ts +469 -0
- package/scripts/design/extract-corpus-score.ts +510 -0
- package/scripts/design/vendor-open-design-systems.ts +100 -0
- package/scripts/docs-lint.ts +1 -1
- package/scripts/eval-bot-vs-grok.ts +79 -0
- package/scripts/eval-grok-live-baseline.ts +36 -0
- package/scripts/fixtures/front-route-corpus.sample.json +17 -0
- package/scripts/fleet/node-setup.sh +80 -7
- package/scripts/heal/run-role.ts +328 -0
- package/scripts/install-role-watch.sh +95 -0
- package/scripts/install.ps1 +11 -1
- package/scripts/install.sh +81 -9
- package/scripts/isolation-hardcode-baseline.txt +1 -1
- package/scripts/landing-heal/must-fix-match.ts +63 -0
- package/scripts/landing-heal/run-mission.ts +195 -0
- package/scripts/lib/front-route-measurement.ts +131 -0
- package/scripts/lib/pwa-scenarios/acp-replay.ts +79 -0
- package/scripts/lib/pwa-scenarios/cdp-driver.ts +67 -0
- package/scripts/lib/pwa-scenarios/runner.ts +200 -0
- package/scripts/lib/pwa-scenarios/scenarios.ts +202 -0
- package/scripts/lib/tui-sim-keys.ts +42 -0
- package/scripts/market/db-check.ts +212 -0
- package/scripts/market-posture-cycle.ts +63 -4
- package/scripts/measure-front-route-classifier.ts +56 -0
- package/scripts/media/ocr-leak-scan.sh +21 -0
- package/scripts/nightly-docops.ts +1 -1
- package/scripts/ops/channel-bot-token-migrate.ts +146 -0
- package/scripts/ops-health-check.ts +15 -3
- package/scripts/pty-scenarios/run.ts +272 -0
- package/scripts/public-export.ts +2 -3
- package/scripts/public-import-pr.ts +80 -6
- package/scripts/public-leak-baseline.txt +0 -7
- package/scripts/publish-internal-dist.ts +118 -0
- package/scripts/pwa-scenarios.ts +106 -0
- package/scripts/rebrand-elanous.ts +1 -1
- package/scripts/red-sweep-diff.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +72 -0
- package/scripts/release-loop/cutoff.ts +139 -0
- package/scripts/release-loop/docs-land-node.ts +65 -0
- package/scripts/release-loop/docs-node.ts +172 -0
- package/scripts/release-loop/gate-diff.ts +29 -0
- package/scripts/release-loop/gate-node.ts +641 -0
- package/scripts/release-loop/node-verdict.ts +85 -0
- package/scripts/release-loop/prepare-node.ts +31 -0
- package/scripts/release-loop/publish-node.ts +61 -0
- package/scripts/release-loop/pwa-node-verdict.ts +45 -0
- package/scripts/release-loop/pwa-scenarios-node.ts +140 -0
- package/scripts/release-loop/release-docs.ts +109 -0
- package/scripts/release-loop/test-durations.ts +63 -0
- package/scripts/release-loop/tui-node-checks.ts +29 -0
- package/scripts/release-loop/tui-sim-node.ts +113 -0
- package/scripts/release-loop/upgrade-node.ts +26 -0
- package/scripts/release-loop/verify-node.ts +21 -0
- package/scripts/release-loop/version-node.ts +147 -0
- package/scripts/release-upgrade-check.sh +53 -0
- package/scripts/se-mission-prepare.ts +9 -15
- package/scripts/test-audit-coverage-per-file.sh +16 -0
- package/scripts/test-audit-meaningless.ts +88 -0
- package/scripts/test-audit-overlap-and-weak.ts +73 -0
- package/scripts/test-deterministic.ts +29 -6
- package/scripts/tui-sim.ts +59 -14
- package/scripts/uninstall.sh +10 -3
- package/scripts/ux/bump-installed.sh +20 -0
- package/scripts/ux/lib/cdp.ts +72 -0
- package/scripts/ux/record-page.ts +50 -0
- package/scripts/video-broll-line.ts +89 -0
- package/scripts/waitlist-daily-digest.ts +108 -0
- package/scripts/window-landings.sh +1 -1
- package/skills/explainer-video/SKILL.md +99 -0
- package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -0
- package/skills/explainer-video/engine/build.mjs +431 -0
- package/skills/explainer-video/engine/vo.ts +37 -0
- package/skills/explainer-video/examples/elanous-0.2.5/script.json +155 -0
- package/skills/motion-broll/LICENSE +25 -0
- package/skills/motion-broll/SKILL.md +150 -0
- package/skills/motion-broll/SOURCE.md +6 -0
- package/skills/motion-broll/engine/base.css +19 -0
- package/skills/motion-broll/engine/beats.js +11 -0
- package/skills/motion-broll/engine/build.py +21 -0
- package/skills/motion-broll/engine/fonts/Geist-Variable.woff2 +0 -0
- package/skills/motion-broll/engine/fonts/GeistMono-Medium.woff2 +0 -0
- package/skills/motion-broll/engine/fonts/OFL-Geist.txt +92 -0
- package/skills/motion-broll/engine/motion.js +146 -0
- package/skills/motion-broll/engine/render.js +22 -0
- package/skills/motion-broll/examples/opus-aoe2/01-opus-drop.html +41 -0
- package/skills/motion-broll/examples/opus-aoe2/02-pip-builds.html +110 -0
- package/skills/motion-broll/examples/opus-aoe2/03-effort-slider.html +38 -0
- package/skills/motion-broll/examples/opus-aoe2/04-master-prompt.html +56 -0
- package/skills/motion-broll/examples/opus-aoe2/05-low-vs-max.html +49 -0
- package/skills/motion-broll/examples/opus-aoe2/06-chapter.html +18 -0
- package/skills/motion-broll/examples/opus-aoe2/plan.json +14 -0
- package/skills/motion-broll/reference/engine-api.md +106 -0
- package/skills/motion-broll/scripts/composite.py +14 -0
- package/skills/motion-broll/scripts/inspect_video.py +34 -0
- package/skills/motion-broll/scripts/make_pages.py +34 -0
- package/skills/motion-broll/scripts/setup.sh +16 -0
- package/skills/motion-broll/scripts/words.py +13 -0
- package/skills/motion-broll/templates/compare.html +135 -0
- package/skills/motion-broll/templates/viewer.html +97 -0
- package/skills/omni-digest/SKILL.md +260 -0
- package/skills/omni-digest/digest.md +197 -0
- package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +32 -0
- package/skills/omni-digest/package-lock.json +558 -0
- package/skills/omni-digest/package.json +13 -0
- package/skills/omni-digest/scripts/main.ts +404 -0
- package/skills/omni-digest/src/delegate.ts +34 -0
- package/skills/omni-digest/src/detect.ts +46 -0
- package/skills/omni-digest/src/diagram.ts +72 -0
- package/skills/omni-digest/src/domain-staging.ts +50 -0
- package/skills/omni-digest/src/env.ts +38 -0
- package/skills/omni-digest/src/fetch.ts +237 -0
- package/skills/omni-digest/src/media.ts +180 -0
- package/skills/omni-digest/src/obsidian.ts +69 -0
- package/skills/omni-digest/src/ocr.ts +149 -0
- package/skills/omni-digest/src/router.ts +60 -0
- package/skills/omni-digest/src/summarize.ts +87 -0
- package/skills/omni-digest/src/types.ts +124 -0
- package/skills/omni-digest/src/util.ts +34 -0
- package/skills/omni-digest/src/visual.ts +129 -0
- package/skills/omni-digest/src/x-api.ts +151 -0
- package/skills/omni-digest/tsconfig.json +13 -0
- package/src/a2a/agent-card.ts +29 -0
- package/src/a2a/server.ts +173 -0
- package/src/acp/auto-persist.ts +3 -6
- package/src/acp/backend-registry.ts +6 -10
- package/src/acp/channel-browser-shell.ts +1 -535
- package/src/acp/client.ts +106 -36
- package/src/acp/fs-roots.ts +20 -4
- package/src/acp/obsidian-tags.ts +6 -3
- package/src/acp/server.ts +189 -32
- package/src/agent/nested-agent-env.ts +1 -0
- package/src/agent/pty-binding.ts +1 -1
- package/src/agent/spawn-embodied-agent-in-vw.ts +5 -336
- package/src/agent/subagent-callable.ts +39 -1
- package/src/agent-mission/browser-login.ts +241 -0
- package/src/agent-mission/capabilities-cli.ts +33 -0
- package/src/agent-mission/capability-matrix.ts +31 -0
- package/src/agent-mission/capability-readers.ts +79 -0
- package/src/agent-mission/capability-types.ts +15 -0
- package/src/agent-mission/claude-headless.ts +131 -0
- package/src/agent-mission/claude-subscription.ts +57 -0
- package/src/agent-mission/doc-guided-install.ts +185 -0
- package/src/agent-mission/driver.ts +900 -69
- package/src/agent-mission/env-profile.ts +68 -0
- package/src/agent-mission/handoff.ts +128 -0
- package/src/agent-mission/in-agent-plugin.ts +311 -0
- package/src/agent-mission/mission-cli.ts +25 -1
- package/src/agent-mission/parse.ts +9 -4
- package/src/agent-mission/pr-review-watch.ts +62 -13
- package/src/agent-mission/resource-ladder.ts +235 -0
- package/src/agent-mission/tool-install.ts +249 -0
- package/src/agent-mission/tool-ladder.ts +37 -0
- package/src/agent-room/room-builder.ts +6 -600
- package/src/agent-substrate/review-intent.ts +43 -1
- package/src/auth/acp-token.ts +16 -0
- package/src/auth/github-app-token.ts +112 -0
- package/src/auth/scope.ts +8 -4
- package/src/auth/temp-tokens.ts +131 -0
- package/src/auto-research/obsidian-bridge.ts +2 -0
- package/src/autopilot/build/integrity-gate.ts +27 -4
- package/src/autopilot/build/isolated-instance.ts +2 -1
- package/src/autopilot/build/llm-conflict-merge.ts +27 -0
- package/src/autopilot/gh-rest-fallback.ts +177 -0
- package/src/autopilot/llm-control-brain.ts +54 -12
- package/src/autopilot/mission-engine.ts +15 -1
- package/src/autopilot/mission-notify.ts +4 -2
- package/src/autopilot/mission-origin.ts +5 -5
- package/src/autopilot/mission-phase-track.ts +52 -0
- package/src/autopilot/mission-tool.ts +1 -1
- package/src/autopilot/pr-manager.ts +51 -4
- package/src/autopilot/pty-control-loop.ts +94 -2
- package/src/autopilot/track-agent.ts +138 -0
- package/src/autopilot/track-courier.ts +153 -0
- package/src/boot/acp-server.ts +18 -18
- package/src/boot/check-same-origin.ts +19 -5
- package/src/boot/daemon-multi-llm-runtime.ts +14 -8
- package/src/boot/daemon-prompt-turn.ts +2 -0
- package/src/boot/daemon-runtime.ts +36 -14
- package/src/boot/daemon-tools/index.ts +16 -0
- package/src/boot/daemon-tools/self-implement.ts +4 -0
- package/src/boot/daemon-tools/types.ts +3 -0
- package/src/boot/daemon-tools/web-search.ts +2 -1
- package/src/boot/ws-bridge.ts +11 -0
- package/src/browser-cdp/chrome-flags.ts +7 -0
- package/src/browser-cdp/client.ts +2 -0
- package/src/browser-pane/mount.ts +1 -246
- package/src/budget/codex-reset-credit-state.ts +15 -0
- package/src/budget/fetchers/codex.ts +2 -1
- package/src/budget/run-usage-rollup.ts +11 -4
- package/src/budget/unified-usage.ts +2 -1
- package/src/capture/tui-self-report.ts +10 -0
- package/src/channel-bot-token.ts +126 -0
- package/src/chat/index.ts +57 -52
- package/src/chat/input-text-key.ts +2 -2
- package/src/chat/log-scroll-key.ts +12 -0
- package/src/chat/mode/manual.ts +2 -4
- package/src/chat/pickers/state.ts +10 -27
- package/src/chat/search/modal.ts +14 -2
- package/src/chat/submit-trace.ts +30 -0
- package/src/chat/tool-render/types.ts +1 -1
- package/src/chat/turn-typeahead.ts +2 -1
- package/src/chat/wrap.ts +6 -8
- package/src/cli/__fixtures__/agent-help-before/agent.txt +18 -0
- package/src/cli/__fixtures__/agent-help-before/registry.txt +13 -0
- package/src/cli/__fixtures__/agent-help-before/root.txt +100 -0
- package/src/cli/__fixtures__/agent-help-before/tier.txt +15 -0
- package/src/cli/a2a-cli.ts +52 -0
- package/src/cli/agent-cli.ts +726 -0
- package/src/cli/autopilot-cli.ts +739 -0
- package/src/cli/bg-launch.ts +20 -4
- package/src/cli/claude-plugin-setup.ts +199 -0
- package/src/cli/config-test-sync.ts +94 -10
- package/src/cli/connector-cli.ts +204 -0
- package/src/cli/control-cli.ts +220 -0
- package/src/cli/control-join-cli.ts +142 -0
- package/src/cli/decisions-cli.ts +94 -0
- package/src/cli/docs-cli.ts +38 -0
- package/src/cli/doctor-cli.ts +262 -77
- package/src/cli/doctor-distro.ts +17 -1
- package/src/cli/doctor-fix.ts +145 -17
- package/src/cli/doctor-llm-assist.ts +71 -0
- package/src/cli/doctor-private-files.ts +66 -0
- package/src/cli/doctor-readiness.ts +23 -28
- package/src/cli/fleet-cli.ts +63 -0
- package/src/cli/g6a-registration-probe.ts +16 -0
- package/src/cli/git-install-plan.ts +51 -0
- package/src/cli/hooks-cli.ts +44 -0
- package/src/cli/ingest-token-cli.ts +21 -0
- package/src/cli/intake-cli.ts +416 -0
- package/src/cli/labels-cli.ts +74 -0
- package/src/cli/leader-cli.ts +10 -159
- package/src/cli/live-cli.ts +48 -0
- package/src/cli/llm-detect-cli.ts +130 -0
- package/src/cli/logs-cli.ts +231 -7
- package/src/cli/machine-cli.ts +38 -0
- package/src/cli/mcp-call.ts +52 -13
- package/src/cli/mcp-gateway-cli.ts +94 -0
- package/src/cli/mcp-login.ts +116 -8
- package/src/cli/mcp-reload.ts +20 -3
- package/src/cli/nexus-dist.ts +18 -13
- package/src/cli/nexus-ios-bind.ts +20 -7
- package/src/cli/ops-cli.ts +225 -0
- package/src/cli/plugin-cli.ts +201 -0
- package/src/cli/pod-cli.ts +83 -0
- package/src/cli/port-lease-local.ts +124 -0
- package/src/cli/pr-cli.ts +12 -1
- package/src/cli/pr-lineage.ts +2 -1
- package/src/cli/provider-cli.ts +720 -0
- package/src/cli/pty-record-cli.ts +63 -0
- package/src/cli/pty-takeover-cli.ts +57 -40
- package/src/cli/pty-web-address.ts +52 -0
- package/src/cli/publish-cli.ts +44 -0
- package/src/cli/pwa-build.ts +18 -12
- package/src/cli/pwa-dev.ts +13 -8
- package/src/cli/pwa-registry.ts +6 -0
- package/src/cli/pwa-share.ts +65 -22
- package/src/cli/pwa-show.ts +20 -4
- package/src/cli/pwa-start.ts +102 -27
- package/src/cli/pwa-test.ts +201 -96
- package/src/cli/release-cli.ts +177 -7
- package/src/cli/remotes-cli.ts +20 -1
- package/src/cli/remotes.ts +2 -1
- package/src/cli/repo-cli.ts +315 -36
- package/src/cli/research-cli.ts +66 -0
- package/src/cli/role-cli.ts +320 -0
- package/src/cli/schedule-cli.ts +246 -0
- package/src/cli/self-update.ts +103 -12
- package/src/cli/setup-cli.ts +64 -2
- package/src/cli/shadow-cli.ts +188 -0
- package/src/cli/share-auto-mount.ts +12 -8
- package/src/cli/start-cli.ts +240 -0
- package/src/cli/stdout-flush.ts +8 -0
- package/src/cli/storage-cli.ts +334 -0
- package/src/cli/tailscale-serve.ts +34 -19
- package/src/cli/tasks-cli.ts +176 -0
- package/src/cli/test-state-dir-flag.ts +1 -1
- package/src/cli/usage-cli.ts +15 -4
- package/src/cli/where-cli.ts +22 -55
- package/src/code-edit/diff-render.ts +6 -32
- package/src/code-edit/source-delta-browser.ts +0 -1
- package/src/codex/models.ts +1 -1
- package/src/config.ts +8 -13
- package/src/connectors/event-ledger.ts +41 -0
- package/src/connectors/linear-projector.ts +88 -0
- package/src/connectors/linear.ts +143 -0
- package/src/connectors/types.ts +19 -0
- package/src/control-plane/lease-holder.ts +41 -0
- package/src/control-plane/ledger.ts +146 -0
- package/src/control-plane/light-member.ts +164 -0
- package/src/control-plane/member-tokens.ts +88 -0
- package/src/control-plane/member.ts +159 -0
- package/src/control-plane/port-lease-heartbeat.ts +101 -0
- package/src/control-plane/ports.ts +40 -0
- package/src/control-plane/primary.ts +169 -0
- package/src/control-plane/server.ts +216 -0
- package/src/dashboard/acp-boot.ts +14 -38
- package/src/dashboard/assistant-render-state-runtime.ts +2 -2
- package/src/dashboard/assistant-sample-runtime.ts +2 -2
- package/src/dashboard/auto-compact-runtime.ts +11 -16
- package/src/dashboard/browser-help-runtime.ts +2 -3
- package/src/dashboard/chat/acp-chat.ts +2 -5
- package/src/dashboard/code-edit-post-turn-runtime.ts +1 -2
- package/src/dashboard/compact-surface-assembly.ts +0 -14
- package/src/dashboard/compact-surface-dispatch.ts +1 -38
- package/src/dashboard/compact-surface-inventory.ts +0 -8
- package/src/dashboard/compact-surface-runtime.ts +0 -14
- package/src/dashboard/context-menu-provider-boot.ts +0 -9
- package/src/dashboard/context-window-runtime-boot.ts +0 -37
- package/src/dashboard/index.ts +331 -2562
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +0 -6
- package/src/dashboard/input/chat-main-slash-command.ts +2 -2
- package/src/dashboard/input/dashboard-priority-key-route.ts +1 -43
- package/src/dashboard/input/mouse-modal-surface-runtime.ts +1 -5
- package/src/dashboard/input/mouse-wiring.ts +2 -3
- package/src/dashboard/input/no-provider-reply.ts +13 -0
- package/src/dashboard/layout-display-runtime-registration.ts +0 -10
- package/src/dashboard/modals/pane-multi.ts +1 -1
- package/src/dashboard/replay-preview.ts +1 -1
- package/src/dashboard/runtime/approvers.ts +0 -1
- package/src/dashboard/runtime/state-snapshot.ts +0 -90
- package/src/dashboard/scenario-runtime-boot.ts +16 -16
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +134 -1456
- package/src/dashboard/slash-runtime/design-pick.ts +96 -0
- package/src/dashboard/slash-runtime/help-from-registry.ts +77 -0
- package/src/dashboard/slash-runtime/unknown-slash-reply.ts +78 -0
- package/src/dashboard/stale-install-check.ts +77 -0
- package/src/dashboard/surface-registry-wiring.ts +2 -15
- package/src/dashboard/turn-message-runtime.ts +0 -4
- package/src/dashboard/turn-preamble.ts +1 -1
- package/src/dashboard/turn-stream-formatter.ts +2 -2
- package/src/dashboard/turn-stream-runtime.ts +2 -2
- package/src/dashboard-pane-context-menu.ts +0 -14
- package/src/debug/log.ts +7 -0
- package/src/decide/boundary-shadow.ts +131 -0
- package/src/decisions/decision-ledger.ts +404 -0
- package/src/design/apply-direction.ts +209 -0
- package/src/design/css-root-tokens.ts +89 -0
- package/src/design/custom-system-create.ts +230 -0
- package/src/design/design-directions.ts +61 -41
- package/src/design/design-gate.ts +241 -0
- package/src/design/design-library.ts +57 -0
- package/src/design/design-previews.ts +138 -0
- package/src/design/design-systems.ts +61 -0
- package/src/design/lint-artifact-run.ts +46 -6
- package/src/design/lint-artifact.ts +5 -1
- package/src/design/open-design-client.ts +247 -0
- package/src/design/system-from-extract.ts +767 -0
- package/src/design/system-schema.ts +123 -0
- package/src/discord-slash-wire.ts +2 -1
- package/src/discord-test-runner.ts +2 -1
- package/src/discord-voice-wire.ts +2 -1
- package/src/discord.ts +1 -1
- package/src/dispatch/opportunistic-launcher.ts +24 -1
- package/src/domains/ops-status.ts +35 -2
- package/src/domains/outbound-alert.ts +24 -6
- package/src/domains/repeated-failure.ts +89 -0
- package/src/domains/schedule-manage-tool.ts +28 -8
- package/src/domains/schedule-migrate.ts +22 -4
- package/src/domains/schedule-registry.ts +88 -33
- package/src/domains/schedule-runs.ts +132 -0
- package/src/domains/schedule-state.ts +152 -0
- package/src/domains/telegram-kind-route.ts +21 -0
- package/src/element-registry/address.ts +1 -3
- package/src/execution-loop/dispatch-task.ts +139 -0
- package/src/execution-loop/gate-decision-summary.ts +29 -0
- package/src/execution-loop/gates.ts +197 -0
- package/src/git-fs/gh-cli.ts +47 -17
- package/src/git-fs/retry.ts +1 -0
- package/src/git-fs/runner.ts +1 -0
- package/src/git-fs/worktree.ts +6 -5
- package/src/github/pr-labels.ts +68 -0
- package/src/graph-kinds/installed-plugin-nodes.ts +95 -0
- package/src/graph-kinds/plugin-nodes.ts +68 -0
- package/src/graph-kinds/registry.ts +118 -0
- package/src/graph-runner/graph-cli.ts +103 -0
- package/src/graph-runner/graph-notify.ts +220 -0
- package/src/graph-runner/graph-tick.ts +119 -0
- package/src/graph-runner/release-manifest.ts +93 -0
- package/src/graph-runner/runner.ts +487 -0
- package/src/grok/credential.ts +158 -5
- package/src/grounding/ensure-grounding.ts +131 -0
- package/src/grounding/mirror-export.ts +89 -0
- package/src/grounding/mirror-manifest.ts +252 -0
- package/src/grounding/sources-cli.ts +209 -0
- package/src/grounding/sources.ts +333 -0
- package/src/grounding/token.ts +121 -0
- package/src/harness/harness-cli-command.ts +415 -23
- package/src/harness/harness-pod-dispatch.ts +116 -0
- package/src/harness/harness-stop.ts +260 -0
- package/src/harness/harness-substrate-default.ts +40 -0
- package/src/harness/harness-worktrees.ts +1 -1
- package/src/harness/harness-write-boundary.ts +2 -0
- package/src/harness/llm-decompose.ts +2 -1
- package/src/harness/self-send-decide.ts +233 -0
- package/src/harness/self-send-target.ts +22 -1
- package/src/harness/shell-relay.ts +5 -0
- package/src/harness/worktree-branch-prefix.ts +4 -3
- package/src/hooks/providers.ts +77 -0
- package/src/hooks/queue.ts +73 -0
- package/src/hooks/receiver.ts +133 -0
- package/src/index.ts +712 -3409
- package/src/input-core/dispatcher.ts +1 -1
- package/src/input-core/drag-esc-interceptor.ts +1 -1
- package/src/instance/current.ts +5 -5
- package/src/instance/leader.ts +10 -326
- package/src/instance/nexus-run-refusal.ts +27 -92
- package/src/instance/project-local-exclude.ts +27 -0
- package/src/instance/resolve.ts +46 -175
- package/src/intake-plane/capture.ts +14 -1
- package/src/intake-plane/check.ts +34 -14
- package/src/intake-plane/collect-github.ts +258 -0
- package/src/intake-plane/collect-pod.ts +100 -0
- package/src/intake-plane/collect-telegram-saved.ts +91 -0
- package/src/intake-plane/digest.ts +111 -0
- package/src/intake-plane/enrich-plugins.ts +1 -1
- package/src/intake-plane/front-classifier.ts +56 -0
- package/src/intake-plane/front-route-classifier.ts +80 -0
- package/src/intake-plane/front-route-rules.ts +152 -0
- package/src/intake-plane/grounding-docs.ts +185 -0
- package/src/intake-plane/harness-target.ts +20 -0
- package/src/intake-plane/intake-to-tasks.ts +303 -0
- package/src/intake-plane/items.ts +247 -0
- package/src/intake-plane/link-ledger.ts +27 -0
- package/src/intake-plane/route.ts +104 -0
- package/src/intake-plane/runtime-callables.ts +3 -1
- package/src/intake-plane/sketch-ledger.ts +34 -0
- package/src/intake-plane/slash.ts +30 -2
- package/src/intake-plane/submit-intake-work.ts +160 -0
- package/src/intake-plane/telegram-work.ts +56 -0
- package/src/iul/sidebar-shell.ts +0 -165
- package/src/launch-head/capability-check.ts +162 -0
- package/src/launch-head/launch-head-cli.ts +242 -0
- package/src/launch-head/load-balance.ts +81 -0
- package/src/live/detail-switch.ts +180 -0
- package/src/llm/provider-detect.ts +247 -0
- package/src/llm/provider-probe.ts +57 -0
- package/src/llm/usable-llm.ts +32 -0
- package/src/llm.ts +55 -23
- package/src/log-entry.ts +1 -1
- package/src/log-pane/attachment-popup.ts +1 -2
- package/src/loops/loop-cli.ts +37 -0
- package/src/loops/registry.ts +196 -0
- package/src/market/official-keys.ts +5 -0
- package/src/market/publish.ts +329 -0
- package/src/market/signed-index.ts +156 -0
- package/src/market/tgz.ts +121 -0
- package/src/mcp/client.ts +1 -1
- package/src/mcp/mcp-oauth.ts +40 -5
- package/src/mcp/server.ts +75 -7
- package/src/mcp-gateway/gateway.ts +128 -0
- package/src/mcp-gateway/pat-store.ts +124 -0
- package/src/mss/logging/log-store.ts +91 -2
- package/src/mss/logging/scoped-level.ts +5 -9
- package/src/native-tool-catalog.ts +66 -345
- package/src/nexus/api/connect-info.ts +23 -25
- package/src/nexus/api/context-url.ts +1 -1
- package/src/nexus/api/design-check.ts +90 -59
- package/src/nexus/api/design-previews-route.ts +182 -0
- package/src/nexus/api/design-system-create-route.ts +123 -0
- package/src/nexus/api/graph-approvals.ts +125 -0
- package/src/nexus/api/graph-kinds.ts +69 -0
- package/src/nexus/api/graphs-api.ts +221 -0
- package/src/nexus/api/harness-api.ts +31 -2
- package/src/nexus/api/health.ts +15 -0
- package/src/nexus/api/http-server.ts +328 -43
- package/src/nexus/api/image-generate.ts +3 -0
- package/src/nexus/api/ingest-token.ts +175 -0
- package/src/nexus/api/intake-ledger-api.ts +54 -0
- package/src/nexus/api/intake-route.ts +111 -0
- package/src/nexus/api/json-response.ts +33 -0
- package/src/nexus/api/live-detail.ts +47 -0
- package/src/nexus/api/live-shipped.ts +78 -0
- package/src/nexus/api/log-fabric.ts +42 -2
- package/src/nexus/api/markdown-publish.ts +3 -2
- package/src/nexus/api/mcp-http.ts +14 -9
- package/src/nexus/api/mcp-oauth-hint.ts +31 -0
- package/src/nexus/api/mcp-public-allowlist.ts +33 -0
- package/src/nexus/api/merge-approvals-gate.ts +79 -0
- package/src/nexus/api/merge-approvals.ts +307 -0
- package/src/nexus/api/meta-api.ts +18 -0
- package/src/nexus/api/next-fluent-wiring.ts +7 -9
- package/src/nexus/api/plugins-credentials-api.ts +47 -0
- package/src/nexus/api/plugins-market.ts +209 -0
- package/src/nexus/api/pod-credential-api.ts +187 -0
- package/src/nexus/api/public-routes.ts +87 -0
- package/src/nexus/api/rest-route-paths.ts +15 -0
- package/src/nexus/api/schedules-action.ts +12 -3
- package/src/nexus/api/schedules-read.ts +228 -0
- package/src/nexus/api/sessions-store.ts +8 -2
- package/src/nexus/api/setup-answer-priority.ts +130 -0
- package/src/nexus/api/setup-channel-bot.ts +56 -0
- package/src/nexus/api/setup-child-llm.ts +228 -0
- package/src/nexus/api/setup-obsidian-skills.ts +93 -0
- package/src/nexus/api/task-cards-api.ts +34 -0
- package/src/nexus/api/tasks-create.ts +136 -0
- package/src/nexus/api/telegram-trigger-bot.ts +3 -3
- package/src/nexus/api/terminals.ts +204 -18
- package/src/nexus/api/trace.ts +405 -0
- package/src/nexus/api/vault-api.ts +140 -7
- package/src/nexus/api/worktrees.ts +18 -2
- package/src/nexus/boot/register-mcp-clients.ts +135 -16
- package/src/nexus/daemon-endpoint.ts +85 -0
- package/src/nexus/default-port.ts +1 -0
- package/src/nexus/index.ts +362 -143
- package/src/nexus/onboarding/pwa-share-prompt.ts +31 -8
- package/src/nexus/onboarding/tailscale-probe.ts +9 -1
- package/src/nexus/outbound/router.ts +1 -1
- package/src/nexus/setup-status.ts +58 -0
- package/src/nexus/supervisor/lock.ts +8 -0
- package/src/nexus/webterm/pty.ts +15 -0
- package/src/oauth/codex-account-rotation.ts +122 -16
- package/src/oauth/codex-account-store.ts +88 -19
- package/src/oauth/codex-quota-policy.ts +55 -0
- package/src/oauth/store.ts +28 -25
- package/src/obsidian/default-vault.ts +17 -0
- package/src/obsidian/vault-write-guard.ts +46 -0
- package/src/onboarding/help/llm.md +2 -2
- package/src/onboarding.ts +27 -4
- package/src/panes/alt-skip-predicate.ts +4 -3
- package/src/panes/external-terminal-pane.ts +3 -4
- package/src/panes/factory.ts +1 -18
- package/src/panes/index.ts +1 -5
- package/src/panes/pane-cycle.ts +1 -1
- package/src/panes/types.ts +1 -1
- package/src/platform/env-literal.ts +4 -0
- package/src/plugin-hooks/dispatcher.ts +10 -4
- package/src/plugins/core/host.ts +108 -4
- package/src/plugins/core/manifest.ts +104 -7
- package/src/plugins/install/market-fetch.ts +250 -0
- package/src/plugins/install/plugin-credentials.ts +106 -0
- package/src/plugins/install/plugin-install.ts +518 -0
- package/src/policy/claude-subscription-guard.ts +25 -0
- package/src/preview/terminal.ts +24 -1
- package/src/preview-pane/mount.ts +1 -142
- package/src/prompt/references.ts +4 -51
- package/src/prompt-library/universal-preamble.ts +8 -2
- package/src/pty-shell/pty-control-ipc.ts +57 -3
- package/src/pty-shell/pty-mouse.ts +75 -0
- package/src/pty-shell/pty-recording.ts +108 -0
- package/src/pty-shell/registry.ts +53 -3
- package/src/python/resolve-python.ts +1 -1
- package/src/release-loop/checklist.ts +191 -0
- package/src/release-loop/manifest.ts +65 -0
- package/src/release-loop/release-note.ts +177 -0
- package/src/roles/lease-cas.ts +52 -0
- package/src/roles/machine-name.ts +48 -0
- package/src/roles/machine-profile.ts +65 -0
- package/src/roles/role-lease-read.ts +81 -0
- package/src/roles/role-lease.ts +63 -0
- package/src/roles/role-watch.ts +69 -0
- package/src/self-dev/ask-launch-flow.ts +39 -22
- package/src/self-dev/ask-launch-io.ts +1 -1
- package/src/self-dev/dev-cli.ts +290 -159
- package/src/self-dev/dev-pipeline.ts +157 -9
- package/src/self-dev/draft-sweep.ts +231 -0
- package/src/self-dev/draft-triage-rules.ts +42 -0
- package/src/self-dev/entrance-baseline.ts +156 -4
- package/src/self-dev/fabric-decompose-adapter.ts +10 -0
- package/src/self-dev/launch-preflight.ts +1 -1
- package/src/self-dev/orchestrate.ts +297 -20
- package/src/self-dev/repair-signals.ts +6 -0
- package/src/self-dev/run-store.ts +20 -5
- package/src/self-dev/run-supervisor.ts +43 -3
- package/src/self-implement/abandoned-classification.ts +15 -1
- package/src/self-implement/blocked-draft-policy.ts +6 -0
- package/src/self-implement/budget-gate.ts +236 -0
- package/src/self-implement/child-llm-preference.ts +84 -0
- package/src/self-implement/decision-events.ts +57 -0
- package/src/self-implement/decision-signal-press.ts +5 -2
- package/src/self-implement/dependency-change-gate.ts +90 -0
- package/src/self-implement/gate-baseline.ts +35 -2
- package/src/self-implement/gate-cli.ts +29 -7
- package/src/self-implement/gate-scope.ts +7 -1
- package/src/self-implement/goal-author-decompose.ts +22 -4
- package/src/self-implement/goal-author.ts +41 -3
- package/src/self-implement/goal-boundary.ts +65 -0
- package/src/self-implement/goal-clarification-escalation.ts +1 -0
- package/src/self-implement/goal-documents-dir.ts +6 -1
- package/src/self-implement/goal-execution-records.ts +58 -0
- package/src/self-implement/goal-run-store.ts +42 -24
- package/src/self-implement/graph-authority.ts +13 -28
- package/src/self-implement/graph-catalog.ts +48 -0
- package/src/self-implement/graph-run-contract.ts +127 -0
- package/src/self-implement/graph-templates.ts +14 -7
- package/src/self-implement/graph-yaml.ts +35 -6
- package/src/self-implement/harness-policy-gates.ts +42 -0
- package/src/self-implement/headless-elanous-driver.ts +30 -6
- package/src/self-implement/heal-triage.ts +229 -0
- package/src/self-implement/host-regate.ts +244 -0
- package/src/self-implement/non-git-consent.ts +23 -0
- package/src/self-implement/orchestrator.ts +488 -134
- package/src/self-implement/pipeline-shape.ts +1 -1
- package/src/self-implement/pr-evidence-artifact.ts +6 -19
- package/src/self-implement/prior-draft-findings.ts +128 -0
- package/src/self-implement/pwa-import-graph.ts +65 -0
- package/src/self-implement/repo-provision.ts +18 -21
- package/src/self-implement/report-origin.ts +39 -0
- package/src/self-implement/rework-policy.ts +21 -0
- package/src/self-implement/run-ledger-compact.ts +438 -0
- package/src/self-implement/run-ledger.ts +212 -29
- package/src/self-implement/run-report.ts +24 -0
- package/src/self-implement/run-status-mapping.ts +2 -0
- package/src/self-implement/running-runs.ts +112 -14
- package/src/self-implement/scoped-typecheck-config.ts +49 -0
- package/src/self-implement/seams.ts +207 -40
- package/src/self-implement/self-implement-cli.ts +17 -2
- package/src/self-implement/shadow-repo.ts +350 -0
- package/src/self-implement/supervision-vocabulary.ts +7 -0
- package/src/shell-runner/dispatch.ts +3 -0
- package/src/shell-runner/index.ts +0 -7
- package/src/skills/runner.ts +0 -69
- package/src/skills/tools/agent-room-slash.ts +2 -1
- package/src/skills/tools/agent-room.ts +8 -140
- package/src/skills/tools/agent.ts +5 -3
- package/src/skills/tools/context.ts +5 -140
- package/src/skills/tools/control.ts +4 -188
- package/src/skills/tools/dashboard-slash.ts +3 -11
- package/src/skills/tools/dashboard-state.ts +3 -5
- package/src/skills/tools/dev-harness.ts +45 -2
- package/src/skills/tools/omni-search.ts +29 -1
- package/src/skills/tools/shell.ts +11 -29
- package/src/skills/tools/spawn-coding-agent-headless.ts +6 -9
- package/src/ssh/ssh-picker-modal.ts +1 -1
- package/src/steward/directive.ts +99 -0
- package/src/steward/steward-cards.ts +45 -0
- package/src/steward/triage.ts +239 -0
- package/src/storage/cli-bin.ts +67 -0
- package/src/storage/object-store-visibility.ts +169 -0
- package/src/storage/object-store.ts +452 -0
- package/src/storage/s3.ts +53 -10
- package/src/storage/storage-detect.ts +337 -0
- package/src/surface/address.ts +3 -5
- package/src/surface/index.ts +0 -6
- package/src/surface/llm-tools.ts +1 -2
- package/src/surface/shell-runner-boot.ts +4 -89
- package/src/task-cards/card-cli.ts +64 -0
- package/src/task-cards/card-store.ts +241 -0
- package/src/task-orchestrator/boot.ts +27 -1
- package/src/task-orchestrator/dispatcher.ts +49 -7
- package/src/task-orchestrator/external-fingerprint.ts +10 -0
- package/src/task-orchestrator/external-policy.ts +86 -0
- package/src/task-orchestrator/feedback-loop.ts +4 -2
- package/src/task-orchestrator/graph.ts +18 -1
- package/src/task-orchestrator/runtimes/create.ts +128 -0
- package/src/task-orchestrator/store.ts +78 -18
- package/src/task-orchestrator/surface-registry.ts +5 -2
- package/src/task-orchestrator/surfaces/external-exec.ts +180 -0
- package/src/task-orchestrator/surfaces/idea-approval-pr.ts +118 -0
- package/src/task-orchestrator/surfaces/index.ts +4 -3
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +60 -5
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +194 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +369 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +207 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +128 -12
- package/src/task-orchestrator/surfaces/pod-skills.ts +11 -3
- package/src/task-orchestrator/surfaces/pod-source-bundle.ts +147 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +129 -0
- package/src/task-orchestrator/surfaces/pod-source-spec.ts +77 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +930 -45
- package/src/task-orchestrator/surfaces/self-implement.ts +8 -1
- package/src/task-orchestrator/tox-loop.ts +204 -0
- package/src/task-orchestrator/types.ts +21 -1
- package/src/telegram-commands.ts +8 -0
- package/src/telegram-report.ts +14 -7
- package/src/telegram-run.ts +18 -5
- package/src/telegram.ts +92 -22
- package/src/tool-runtime/acp-session-runtime.ts +28 -7
- package/src/tool-runtime/agent-runtime.ts +1 -0
- package/src/tool-runtime/context-runtime.ts +18 -35
- package/src/tool-runtime/control-runtime.ts +8 -21
- package/src/tool-runtime/dashboard-state-runtime.ts +1 -5
- package/src/tool-runtime/elanous-asana-runtimes.ts +205 -0
- package/src/tool-runtime/elanous-control-runtimes.ts +16 -2
- package/src/tool-runtime/elanous-task-submit-runtime.ts +124 -0
- package/src/tool-runtime/index.ts +4 -1
- package/src/tool-runtime/scenario-runtimes.ts +22 -21
- package/src/tool-runtime/scenario-target-mount.ts +6 -32
- package/src/tool-runtime/types.ts +8 -0
- package/src/tui/chat/attachment-summary.ts +4 -4
- package/src/tui-client/acp-transport-ws-client.ts +72 -5
- package/src/tui-client/headless-core-guard.ts +0 -1
- package/src/tui.ts +11 -7
- package/src/typecheck-ratchet.ts +15 -0
- package/src/ui/hover-presenter.ts +3 -7
- package/src/user-config.ts +453 -190
- package/src/util/spawn-sync-output.ts +15 -0
- package/src/version/code-revision.ts +34 -9
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/broll-agent.ts +102 -0
- package/src/video-pipeline/recipes/broll.ts +263 -0
- package/src/video-pipeline/walk-line.ts +2 -1
- package/src/views/scratch-image-size.ts +10 -0
- package/src/voice/channel-adapters/pwa-voice-adapter.ts +2 -18
- package/src/voice/channel-adapters/telegram-voice-adapter.ts +1 -6
- package/src/voice/voice-tts-singleton.ts +46 -8
- package/src/web-push/vapid-keys.ts +1 -1
- package/src/web-search/free.ts +77 -0
- package/src/web-search/index.ts +7 -5
- package/src/web-terminal/preview-tap-registry.ts +152 -43
- package/src/workflow-runtime/deps-bridge.ts +4 -3
- package/src/workflow-runtime/executor.ts +18 -22
- package/src/workflow-runtime/node-catalog.ts +20 -1
- package/src/workflow-runtime/nodes/bash.ts +1 -0
- package/src/workflow-runtime/nodes/task.ts +74 -0
- package/src/workflow-runtime/nodes/triggers.ts +24 -1
- package/src/workflow-runtime/plugin-kind-node.ts +166 -0
- package/src/workflow-runtime/schema.ts +98 -2
- package/src/workflow-runtime/triggers/webhook-router.ts +43 -3
- package/src/workflow-runtime/triggers/webhook-source.ts +19 -1
- package/src/workflow-runtime/types.ts +76 -5
- package/apps/pwa/out/_next/static/Ksn99fVf2HUWhSyV1-FC8/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1176-4943bd83b00e53a2.js +0 -25
- package/apps/pwa/out/_next/static/chunks/1380-9c652e1002032c86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1863-2ea170dfec26b88b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2091-2d6b7f4f16300f83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2347-366617ec73babe3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3089-e60cc8f5d35ee239.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3158-c77ed9ea34f9cc9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3607-f0b5c5ee18fcf56a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3659-05b2d5d971b42dbc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3736-b6a7bfdcb8f56ec6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3839-eebf298e89a7bb77.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4012.832a2824b978e7ee.js +0 -5
- package/apps/pwa/out/_next/static/chunks/4706-d85d7f3345f3ff91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/526-17a6a2e0e6dc4498.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5508-676ac75f2757ad40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5583-8a0317f4b8e68db9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6258-b58f722b10e8d31d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6820-32fd097e6186fdc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6852-983db7ca958634b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7235-e583e4a015e159b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7482-7b417330b24a996a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7701-99b7d4dedb955bf8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/77f1928d-bd3777589042d3ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8366-36956cafc5e33614.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8370-23d0de995be666f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8617-307421f3b0e8b2a2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8837-e45de46a9fedf1f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9058-0e8055a5ea3ebdd6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-84b84eca12acada4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1f23568c29e88f7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-bf6fc9aafd6135a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-3f8539ae4b719d2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d2900febb74ecf32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-e82dec647dd79c36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/dashboard/page-096ec743a8ee955a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-255c2ceded4b3493.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-84b84eca12acada4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2db61b2f9efba61f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-e11ee17f221aaa9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e075974e029ce4c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-ec5b68a9af3366a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-986c177afb4adae6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-a72781461af2f2a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-92781cbaafc487ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2c14d2a1f2930f33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-22ee4bf8070b2b4d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9c06e4a8297942a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d0cd32f6d373798f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0c1642018d87ebb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-93e5e97d614df487.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-84b84eca12acada4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b1ce871940d7393e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-ae154addf345febe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-90af3aa813d2053c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f3f962fda428a738.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-1c1f7cc1d5def06d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-09d4cbdaaacf06c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e877b8e8ca90b27f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-71d902f463dea526.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-40ea576cefa25fe6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a56a3f178c3831f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/bcc499d1-804a270d878e0842.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-b25b7c5501c59b6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-a9ec9da43387afff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-aa2c05954aaa6754.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-bb3768fb4b84aebb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-2820ba75b87b2f5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-58c73b145f189b1c.js +0 -1
- package/apps/pwa/out/_next/static/css/effec8adf767aa75.css +0 -1
- package/apps/pwa/out/dashboard/index.html +0 -1
- package/apps/pwa/out/dashboard/index.txt +0 -26
- package/src/acp/resident-shell.ts +0 -244
- package/src/agent/spawn-local-llm-in-vw.ts +0 -240
- package/src/dashboard/agent-spawn-tools-boot.ts +0 -14
- package/src/dashboard/dock-picker-inventory.ts +0 -41
- package/src/dashboard/goal-plan-hud-bridge.ts +0 -112
- package/src/dashboard/hud-mirror.ts +0 -207
- package/src/dashboard/input/mouse-dock-runtime.ts +0 -156
- package/src/dashboard/input/mouse-hover-runtime.ts +0 -46
- package/src/dashboard/input/mouse-pill-context-runtime.ts +0 -74
- package/src/dashboard/input/mouse-workspace-restore-runtime.ts +0 -64
- package/src/dashboard/input/scratch-actions.ts +0 -36
- package/src/dashboard/input/virtual-window-key-router.ts +0 -24
- package/src/dashboard/rich-scratch-viewers.ts +0 -77
- package/src/dashboard/scratch-slash-runtime.ts +0 -36
- package/src/dashboard/scratch-state-runtime.ts +0 -42
- package/src/dashboard/scratch-widget-runtime.ts +0 -37
- package/src/dashboard/sim-shell.ts +0 -313
- package/src/dashboard/virtual-window-control-runtime.ts +0 -57
- package/src/dashboard/virtual-window-help-runtime.ts +0 -113
- package/src/dashboard/virtual-window-input-runtime.ts +0 -99
- package/src/dashboard/virtual-window-mutation-runtime.ts +0 -102
- package/src/dashboard/virtual-window-split-runtime.ts +0 -70
- package/src/dashboard/vw-popup-openers.ts +0 -126
- package/src/dashboard/window-picker-popup.ts +0 -74
- package/src/dashboard/window-slash-runtime.ts +0 -108
- package/src/dashboard/windowing/companion-slash.ts +0 -78
- package/src/dashboard/windowing/fast-switch.ts +0 -138
- package/src/dashboard/windowing/lifecycle.ts +0 -185
- package/src/dashboard/windowing/virtual-windows.ts +0 -259
- package/src/dashboard/windowing/visibility-chord.ts +0 -77
- package/src/iul/resident-vw.ts +0 -55
- package/src/panes/content-adapter.ts +0 -162
- package/src/prompt/vw-reference.ts +0 -153
- package/src/shell-runner/external-terminal-pane.ts +0 -157
- package/src/sim/resident-vw.ts +0 -48
- package/src/skills/tools/spawn-coding-agent-vw.ts +0 -181
- package/src/skills/tools/virtual-windows.ts +0 -632
- package/src/surface/adapters/window-surface-adapter.ts +0 -141
- package/src/tool-runtime/layout-runtimes.ts +0 -81
- package/src/tool-runtime/scenario-window-mount.ts +0 -207
- package/src/views/ui-mode.ts +0 -100
- package/src/virtual-window-context-menu.ts +0 -97
- package/src/virtual-windows/addressing.ts +0 -195
- package/src/virtual-windows/benchmark-preset.ts +0 -119
- package/src/virtual-windows/event-bus.ts +0 -202
- package/src/virtual-windows/layout/apply-planner.ts +0 -189
- package/src/virtual-windows/layout/index.ts +0 -68
- package/src/virtual-windows/layout/layout-commands.ts +0 -186
- package/src/virtual-windows/layout/layout-tools.ts +0 -262
- package/src/virtual-windows/layout/persistence.ts +0 -219
- package/src/virtual-windows/layout/presets.ts +0 -114
- package/src/virtual-windows/layout/restore-planner.ts +0 -223
- package/src/virtual-windows/layout/serializer.ts +0 -197
- package/src/virtual-windows/layout/tree.ts +0 -147
- package/src/virtual-windows/layout/types.ts +0 -63
- package/src/virtual-windows/layout-tree.ts +0 -389
- package/src/virtual-windows/navigation.ts +0 -251
- package/src/virtual-windows/pane-capture.ts +0 -142
- package/src/virtual-windows/pane-content.ts +0 -611
- package/src/virtual-windows/pane-spawner.ts +0 -278
- package/src/virtual-windows/pty-tail-content.ts +0 -291
- package/src/virtual-windows/resident-window.ts +0 -59
- package/src/virtual-windows/secondary-action.ts +0 -25
- package/src/virtual-windows/terminal-slot-content.ts +0 -165
- package/src/virtual-windows/virtual-window.ts +0 -1301
- package/src/virtual-windows/vw-local-input-target-popup.ts +0 -110
- package/src/virtual-windows/vw-rename-modal.ts +0 -77
- package/src/virtual-windows/vw-selector-popup.ts +0 -177
- package/src/virtual-windows/window-registry.ts +0 -519
- package/src/voice/channel-adapters/discord-voice-adapter.ts +0 -202
- package/src/voice/voice-pwa-dispatch.ts +0 -245
- package/src/window-picker-modal.ts +0 -135
- /package/apps/pwa/out/_next/static/{Ksn99fVf2HUWhSyV1-FC8 → ktMqfrBbf8BMGac0jqLrb}/_ssgManifest.js +0 -0
- /package/src/dashboard/{companion-slash-runtime.ts → companion-messages-runtime.ts} +0 -0
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
// - 막히면 omni-crawl 자율 검색 → worktree 파일로 떨궈 codex 에 read 지시(TUI 멀티라인 회피)
|
|
8
8
|
// - 증거 게이트(doc 존재 / tsc 0 / test pass)로 완료 판정 후 commit
|
|
9
9
|
// 재사용: startPty(Bun 네이티브 PTY)·createWorktree·streamLLM·worktreeHasChanges·commitWorktree.
|
|
10
|
-
import { execFileSync, spawnSync } from 'node:child_process';
|
|
10
|
+
import { execFileSync, spawnSync, spawn as spawnChild } from 'node:child_process';
|
|
11
11
|
import { homedir } from 'node:os';
|
|
12
|
-
import { existsSync, writeFileSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
13
|
-
import {
|
|
12
|
+
import { existsSync, writeFileSync, mkdirSync, readdirSync, readFileSync, statSync, readlinkSync, realpathSync, lstatSync, unlinkSync } from 'node:fs';
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
import { join, relative, resolve, isAbsolute, sep } from 'node:path';
|
|
14
15
|
import { startPty, mintPtyId, onPtyEvent, type PtyHandle, type StartOpts } from '../pty-shell/registry.js';
|
|
15
16
|
import { withChildPtyIdentity } from '../agent/pty-identity.js';
|
|
16
17
|
import { NESTED_AGENT_ENV_BLOCKLIST } from '../agent/nested-agent-env.js';
|
|
@@ -19,6 +20,8 @@ import { configuredWorktreeRoot } from '../user-config.js';
|
|
|
19
20
|
import { worktreeHasChanges, commitWorktree, changedFiles } from '../self-implement/seams.js';
|
|
20
21
|
import { streamLLM, type LLMMessage } from '../llm.js';
|
|
21
22
|
import { debug } from '../debug/log.js';
|
|
23
|
+
import { emitDecision } from '../live/detail-switch.js';
|
|
24
|
+
import { resolvePtyWebAddress } from '../cli/pty-web-address.js';
|
|
22
25
|
import { reemitPtyUsage } from '../budget/pty-usage-reemit.js';
|
|
23
26
|
import { classifyAuthError } from '../oauth/codex.js';
|
|
24
27
|
import type { FallbackStep } from '../oauth/fallback-chain.js';
|
|
@@ -29,10 +32,17 @@ import { createLlmControlBrain, type StreamLLMFn } from '../autopilot/llm-contro
|
|
|
29
32
|
import { buildExecutorPtyRef, execSurfaceId } from '../self-implement/executor-contract.js';
|
|
30
33
|
import { runWithControlObserve } from '../capture/control-observe-adapter.js';
|
|
31
34
|
import { buildMissionProvision, sanitizeForPtyInput, type ProvisionRequest, type ProvisionResult } from './provision.js';
|
|
35
|
+
import { checkClaudeSubscription } from './claude-subscription.js';
|
|
36
|
+
import { handoffMission, waitForHumanLogin, type HandoffOperations } from './handoff.js';
|
|
37
|
+
import { dispatchOpenPullRequest } from '../tool-runtime/git-pr-runtime.js';
|
|
38
|
+
import { runClaudeHeadless } from './claude-headless.js';
|
|
39
|
+
import { installPluginInsideAgent, type PluginRequest, type PluginDeps } from './in-agent-plugin.js';
|
|
40
|
+
import { planMissionResources, type ResourceLadderDeps, type ResourcePlan } from './resource-ladder.js';
|
|
32
41
|
import { ensureRunId } from '../harness/harness-space.js';
|
|
33
42
|
import { recordHarnessWorktreeProvenance } from '../harness/harness-worktree-add.js';
|
|
34
43
|
import { resolveInstanceName } from '../instance-identity.js';
|
|
35
44
|
import { getChannelBus } from '../terminal-matrix/index.js';
|
|
45
|
+
import { envLiteral } from '../platform/env-literal.js';
|
|
36
46
|
import { publishSelfReportFrame } from '../capture/self-report-frame.js';
|
|
37
47
|
import { buildExecutorSelfReportFrame } from '../self-implement/executor-frame.js';
|
|
38
48
|
import { classifierFrameLines, classifyFrameState, type FrameState } from '../capture/frame-state-detect.js';
|
|
@@ -47,6 +57,52 @@ import type { IngestionEntry } from '../agent-substrate/execution/ingestion-poli
|
|
|
47
57
|
|
|
48
58
|
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
|
49
59
|
|
|
60
|
+
/** Terminate the PTY process and every descendant found before signalling it. */
|
|
61
|
+
export async function terminateMissionProcessTree(rootPid: number, deps: {
|
|
62
|
+
processTable?: () => string;
|
|
63
|
+
signal?: (pid: number, signal: NodeJS.Signals | 0) => void;
|
|
64
|
+
wait?: (ms: number) => Promise<void>;
|
|
65
|
+
} = {}): Promise<number[]> {
|
|
66
|
+
if (!Number.isSafeInteger(rootPid) || rootPid <= 0) return [];
|
|
67
|
+
const signal = deps.signal ?? ((pid, sig) => process.kill(pid, sig));
|
|
68
|
+
const processTable = deps.processTable ?? (() => execFileSync('ps', ['-eo', 'pid=,ppid='], { encoding: 'utf8' }));
|
|
69
|
+
const children = new Map<number, number[]>();
|
|
70
|
+
try {
|
|
71
|
+
for (const line of processTable().split('\n')) {
|
|
72
|
+
const match = line.trim().match(/^(\d+)\s+(\d+)$/);
|
|
73
|
+
if (!match) continue;
|
|
74
|
+
const pid = Number(match[1]);
|
|
75
|
+
const ppid = Number(match[2]);
|
|
76
|
+
if (!Number.isSafeInteger(pid) || !Number.isSafeInteger(ppid)) continue;
|
|
77
|
+
const siblings = children.get(ppid) ?? [];
|
|
78
|
+
siblings.push(pid);
|
|
79
|
+
children.set(ppid, siblings);
|
|
80
|
+
}
|
|
81
|
+
} catch (error) {
|
|
82
|
+
debug.log('agent-mission', 'process-tree-snapshot-failed', { rootPid, error: String(error) }, { level: 'warn' });
|
|
83
|
+
}
|
|
84
|
+
const visited = new Set<number>();
|
|
85
|
+
const order: number[] = [];
|
|
86
|
+
const collect = (pid: number): void => {
|
|
87
|
+
if (visited.has(pid)) return;
|
|
88
|
+
visited.add(pid);
|
|
89
|
+
for (const child of children.get(pid) ?? []) collect(child);
|
|
90
|
+
order.push(pid);
|
|
91
|
+
};
|
|
92
|
+
collect(rootPid);
|
|
93
|
+
for (const pid of order) {
|
|
94
|
+
try { signal(pid, 'SIGTERM'); } catch { /* The process may already have exited. */ }
|
|
95
|
+
}
|
|
96
|
+
await (deps.wait ?? sleep)(2000);
|
|
97
|
+
for (const pid of order) {
|
|
98
|
+
try {
|
|
99
|
+
signal(pid, 0);
|
|
100
|
+
signal(pid, 'SIGKILL');
|
|
101
|
+
} catch { /* The process has exited or is no longer accessible. */ }
|
|
102
|
+
}
|
|
103
|
+
return order;
|
|
104
|
+
}
|
|
105
|
+
|
|
50
106
|
/** Bounded classifier-compatible screen tail retained with each screen observation. */
|
|
51
107
|
export const SCREEN_LOG_TAIL_MAX_LINES = 10;
|
|
52
108
|
/** Maximum code points retained for each logged screen-tail line. */
|
|
@@ -119,15 +175,45 @@ export const codexBackend: AgentBackend = {
|
|
|
119
175
|
// ⚠️ "알려진 경로"까지의 보장 — CLI 가 새 과금 env 를 추가하면 추적 필요(flag/scrub drift 는 테스트로 감시).
|
|
120
176
|
|
|
121
177
|
/** claude Code 백엔드 — --dangerously-skip-permissions(권한 자동)·구독(oauth) 모드.
|
|
122
|
-
* scrub: API 키 + 대체 인증 토큰(ANTHROPIC_AUTH_TOKEN) + 프로바이더 스위치(Bedrock/Vertex) → oauth 로 좁힘.
|
|
123
|
-
* CLAUDE_CODE_USE_BEDROCK/VERTEX 가 unset 이면
|
|
178
|
+
* scrub: API 키 + 대체 인증 토큰(ANTHROPIC_AUTH_TOKEN) + 프로바이더 스위치(Bedrock/Vertex/Foundry) → oauth 로 좁힘.
|
|
179
|
+
* CLAUDE_CODE_USE_BEDROCK/VERTEX/FOUNDRY 가 unset 이면 다른 provider 의 creds 가 있어도 그 경로로 라우팅되지 않는다. */
|
|
124
180
|
export const claudeBackend: AgentBackend = {
|
|
125
181
|
name: 'claude',
|
|
126
182
|
cmd: 'claude',
|
|
127
183
|
args: ['--dangerously-skip-permissions'],
|
|
128
|
-
|
|
184
|
+
// CLAUDE_CODE_OAUTH_TOKEN: a launching Claude Code session exports its own token; the child must use the
|
|
185
|
+
// machine's stored login, never the parent session's (09-29 🅞: status read `oauth_token` → «api-key» · 대표 R2).
|
|
186
|
+
scrubEnv: ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'CLAUDE_CODE_OAUTH_TOKEN', 'CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_USE_FOUNDRY'],
|
|
187
|
+
// 🩸 09-29 S6: new worktree → «Accessing workspace … ❯ No, exit / Yes, I trust this folder». The default is «No», so
|
|
188
|
+
// the brain spent all 16 steps on this screen. Move to «Yes» (↓) then confirm (Enter) on the next observation —
|
|
189
|
+
// the worktree is an isolated tree elanous created (same reasoning as agy).
|
|
190
|
+
handleTrust: (screen, write) => {
|
|
191
|
+
const choice = claudeTrustChoice(screen);
|
|
192
|
+
if (choice === 'no-selected') { write('\x1b[B'); return true; }
|
|
193
|
+
if (choice === 'yes-selected') { write('\r'); return true; }
|
|
194
|
+
return false;
|
|
195
|
+
},
|
|
129
196
|
};
|
|
130
197
|
|
|
198
|
+
/** claude reads «text + Enter» arriving in one chunk as a paste, so the Enter becomes a newline and nothing is sent
|
|
199
|
+
* (09-29 실물: three brain inputs piled up in the input box). Send the text, then Enter on its own a moment later. */
|
|
200
|
+
export function submitSeparately(inject: (text: string) => boolean, delay: (fn: () => void) => void = (fn) => { setTimeout(fn, 250); }): (text: string) => boolean {
|
|
201
|
+
return (text) => {
|
|
202
|
+
if (text.length < 2 || !/\r$/.test(text)) return inject(text);
|
|
203
|
+
if (!inject(text.slice(0, -1))) return false;
|
|
204
|
+
delay(() => { inject('\r'); });
|
|
205
|
+
return true;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** claude 첫 화면의 폴더 신뢰 메뉴 — 어느 줄이 선택돼 있나(기본 선택 = «No, exit»). */
|
|
210
|
+
export function claudeTrustChoice(screen: string): 'no-selected' | 'yes-selected' | null {
|
|
211
|
+
if (!/Yes, I trust this folder/.test(screen) || !/(?:Accessing workspace|Quick safety check)/.test(screen)) return null;
|
|
212
|
+
if (/^\s*[❯>]\s*(?:\d+\.\s*)?Yes, I trust this folder/m.test(screen)) return 'yes-selected';
|
|
213
|
+
if (/^\s*[❯>]\s*(?:\d+\.\s*)?No, exit/m.test(screen)) return 'no-selected';
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
131
217
|
/** gemini 백엔드 — ⭐ 실행체는 **Antigravity CLI(`agy`)** 다(대표 2026-08-18 결정).
|
|
132
218
|
*
|
|
133
219
|
* ⛔⭐⭐⭐ 왜 `gemini` 가 아닌가 — ***그 CLI 는 «죽었다»***(2026-08-19 라이브 실측):
|
|
@@ -153,8 +239,20 @@ export const geminiBackend: AgentBackend = {
|
|
|
153
239
|
cmd: 'agy',
|
|
154
240
|
args: ['--dangerously-skip-permissions'],
|
|
155
241
|
scrubEnv: ['GEMINI_API_KEY', 'GOOGLE_API_KEY', 'GOOGLE_GENAI_USE_VERTEXAI', 'GOOGLE_APPLICATION_CREDENTIALS'],
|
|
242
|
+
// 🩸 09-27(agy 1.2.12): 새 워크트리마다 «Do you trust the contents of this project?» 메뉴가 먼저 뜨고 첫 줄이
|
|
243
|
+
// «> Yes, I trust this folder» 다. 처리가 없어 미션 문장이 이 메뉴로 들어가 사라졌고, 두뇌가 약 10분 뒤에야
|
|
244
|
+
// 다시 보냈다(탐침 run 06:03 → 06:13). 기본 선택(신뢰)을 Enter 로 고른다 — 워크트리는 elanous 가 만든 격리 트리다.
|
|
245
|
+
handleTrust: (screen, write) => {
|
|
246
|
+
if (agyNeedsTrust(screen)) { write('\r'); return true; }
|
|
247
|
+
return false;
|
|
248
|
+
},
|
|
156
249
|
};
|
|
157
250
|
|
|
251
|
+
/** agy 첫 화면의 폴더 신뢰 메뉴(기본 선택 = 신뢰). */
|
|
252
|
+
export function agyNeedsTrust(screen: string): boolean {
|
|
253
|
+
return /Do you trust the contents of this project\?/.test(screen) && /Yes, I trust this folder/.test(screen);
|
|
254
|
+
}
|
|
255
|
+
|
|
158
256
|
/** xAI grok Build CLI 백엔드 — --always-approve(전툴 자동승인)·구독(grok login) 모드.
|
|
159
257
|
* scrub: XAI/GROK API 키 전부 → 남는 인증 = ~/.grok/auth.json(grok login oauth).
|
|
160
258
|
* ⚠️ 바이너리는 xAI install.sh 가 ~/.grok/bin/grok 에 둔다 — cron/launchd 최소 PATH 에선 ensure-bin-path
|
|
@@ -339,8 +437,12 @@ export interface AgentMissionSpec {
|
|
|
339
437
|
mission: string;
|
|
340
438
|
/** repo 루트(기본: CWD 에서 resolveMainRepoRoot). */
|
|
341
439
|
repo?: string;
|
|
342
|
-
/** 새 worktree 브랜치명. */
|
|
343
|
-
branch
|
|
440
|
+
/** 새 worktree 브랜치명. workdir 모드에서는 관측 라벨(선택). */
|
|
441
|
+
branch?: string;
|
|
442
|
+
/** 저장소 worktree 대신 직접 실행할 비-git 작업 폴더. */
|
|
443
|
+
workdir?: string;
|
|
444
|
+
/** 호출자의 벽시계 마감/취소 신호. */
|
|
445
|
+
signal?: AbortSignal;
|
|
344
446
|
/** 분기 base(기본 HEAD). 이전 미션 산출 위에 쌓으려면 그 브랜치명. */
|
|
345
447
|
base?: string;
|
|
346
448
|
/** 완료 증거 판정. */
|
|
@@ -355,6 +457,16 @@ export interface AgentMissionSpec {
|
|
|
355
457
|
omniCrawlPath?: string;
|
|
356
458
|
/** 구동할 에이전트 backend(기본 codexBackend). claude/gemini/grok 확장점. */
|
|
357
459
|
agent?: AgentBackend;
|
|
460
|
+
/** Claude CLI 비대화형 stream-json 실행. 다른 backend 에서는 거부. */
|
|
461
|
+
headless?: boolean;
|
|
462
|
+
/** Install in the agent's own UI before sending the mission. */
|
|
463
|
+
plugin?: Pick<PluginRequest, 'plugin' | 'marketplace'>;
|
|
464
|
+
/** Pre-mission resource judgment; off skips it. */
|
|
465
|
+
resources?: 'on' | 'off';
|
|
466
|
+
/** Only the caller's explicit backend selection, not the resolved default. */
|
|
467
|
+
backendExplicit?: string;
|
|
468
|
+
/** Explicit backend sequence; transitions use the same handoff coordinator as brain decisions. */
|
|
469
|
+
chain?: readonly ('codex' | 'claude' | 'elanous')[];
|
|
358
470
|
/**
|
|
359
471
|
* ★ elanous 내부 프롬프트 인핸싱(가산·anti-drift) — 원문 verbatim 보존 + 커버리지 체크리스트 부착.
|
|
360
472
|
* 명시 override(undefined 면 entry 정책이 결정: elanous-apparatus→ON·external-verbatim→OFF·§6e capability 구동).
|
|
@@ -389,12 +501,17 @@ export type CodexMissionSpec = AgentMissionSpec;
|
|
|
389
501
|
export interface AgentMissionResult {
|
|
390
502
|
ok: boolean;
|
|
391
503
|
worktree: string;
|
|
392
|
-
branch: string;
|
|
504
|
+
branch: string | null;
|
|
505
|
+
reason?: 'aborted' | 'outside-write' | 'origin-not-github';
|
|
506
|
+
pr?: 'skipped';
|
|
507
|
+
paths?: string[];
|
|
393
508
|
rounds: number;
|
|
394
509
|
evidencePath: string | null;
|
|
395
510
|
committed: boolean;
|
|
396
511
|
usedOmniCrawl: boolean;
|
|
397
512
|
detail: string;
|
|
513
|
+
ptyId?: string;
|
|
514
|
+
webUrl?: string | null;
|
|
398
515
|
}
|
|
399
516
|
/** @deprecated codex 특정 이름 — AgentMissionResult 을 쓰라. */
|
|
400
517
|
export type CodexMissionResult = AgentMissionResult;
|
|
@@ -405,10 +522,40 @@ export interface AgentMissionDeps {
|
|
|
405
522
|
createWorktree?: typeof createWorktree;
|
|
406
523
|
recordWorktreeProvenance?: typeof recordHarnessWorktreeProvenance;
|
|
407
524
|
runControlLoop?: typeof runPtyControlLoop;
|
|
525
|
+
/** Inject controller responses while keeping the production control loop. */
|
|
526
|
+
controlStream?: StreamLLMFn;
|
|
527
|
+
resolvePtyWebAddress?: typeof resolvePtyWebAddress;
|
|
408
528
|
resolveRunFallback?: (input: { currentStep: FallbackStep; currentCredentialRateLimited: true }) => { action: string; backend?: string };
|
|
409
529
|
/** 재귀 재시도 사이에만 전달되는 런 로컬 폴백 진행 상태. */
|
|
410
530
|
runtimeFallback?: RuntimeFallbackContext;
|
|
411
531
|
reemitPtyUsage?: typeof reemitPtyUsage;
|
|
532
|
+
checkClaudeSubscription?: typeof checkClaudeSubscription;
|
|
533
|
+
runClaudeHeadless?: typeof runClaudeHeadless;
|
|
534
|
+
checkEvidence?: typeof checkEvidence;
|
|
535
|
+
commitWorktree?: typeof commitWorktree;
|
|
536
|
+
dispatchOpenPullRequest?: typeof dispatchOpenPullRequest;
|
|
537
|
+
terminateProcessTree?: typeof terminateMissionProcessTree;
|
|
538
|
+
repoStatus?: (repo: string) => string | Promise<string>;
|
|
539
|
+
emitDecision?: typeof emitDecision;
|
|
540
|
+
onPtyStarted?: (handle: PtyHandle, stop: () => void) => void;
|
|
541
|
+
onHeadlessStarted?: (pid: number, kill: () => void) => void;
|
|
542
|
+
isMissionAborted?: () => boolean;
|
|
543
|
+
awaitMission?: <T>(pending: Promise<T>) => Promise<T>;
|
|
544
|
+
onControlPending?: (pending: Promise<unknown>) => void;
|
|
545
|
+
onControlActive?: (pending: Promise<unknown>) => void;
|
|
546
|
+
/** Upper bound for waiting on control stages after cancel (default 10s). */
|
|
547
|
+
cancelDrainMs?: number;
|
|
548
|
+
handoffOperations?: Partial<HandoffOperations>;
|
|
549
|
+
/** Internal continuation: retain this exact worktree rather than calling createWorktree again. */
|
|
550
|
+
handoffWorktree?: { path: string; branch: string; base: string };
|
|
551
|
+
originalMission?: string;
|
|
552
|
+
/** The last controller reason from the previous backend (not a PTY transcript). */
|
|
553
|
+
previousSummary?: string;
|
|
554
|
+
initialTsc?: ReturnType<typeof collectTscDiagnostics> | null;
|
|
555
|
+
installPlugin?: typeof installPluginInsideAgent;
|
|
556
|
+
pluginDeps?: PluginDeps;
|
|
557
|
+
resourceLadder?: ResourceLadderDeps;
|
|
558
|
+
planMissionResources?: typeof planMissionResources;
|
|
412
559
|
}
|
|
413
560
|
|
|
414
561
|
const DEFAULT_OMNI = `${process.env.HOME}/.claude/skills/omni-crawl/scripts/main.ts`;
|
|
@@ -487,6 +634,13 @@ type EvidenceCheckDeps = {
|
|
|
487
634
|
readonly executeTsc?: TscExecutor;
|
|
488
635
|
readonly runTest?: (wt: string, testPath: string) => { ok: boolean; out: string };
|
|
489
636
|
readonly hasChanges?: (wt: string) => boolean;
|
|
637
|
+
/** Worktree-relative paths this mission changed (uncommitted · untracked · committed since fork). */
|
|
638
|
+
readonly changedPaths?: (wt: string) => readonly string[];
|
|
639
|
+
/** Non-git mission: compare against the files present before execution, not only mtime. */
|
|
640
|
+
readonly startedAt?: number;
|
|
641
|
+
readonly initialFiles?: ReadonlyMap<string, string>;
|
|
642
|
+
/** test mode: whether the worktree is a TypeScript project (default: tsconfig.json exists). */
|
|
643
|
+
readonly hasTsconfig?: boolean;
|
|
490
644
|
};
|
|
491
645
|
|
|
492
646
|
export function checkEvidence(
|
|
@@ -501,8 +655,26 @@ export function checkEvidence(
|
|
|
501
655
|
if (ev.kind === 'doc') {
|
|
502
656
|
const dir = join(wt, ev.dirRel);
|
|
503
657
|
if (!existsSync(dir)) return { ok: false, path: null, retry: `${ev.dirRel} 아래 문서가 아직 없다.` };
|
|
504
|
-
|
|
505
|
-
|
|
658
|
+
// Only a document this mission wrote counts: a matching file that was already in the
|
|
659
|
+
// worktree (e.g. an old PLAN-*.md) passed round 0 without any work (🅞 09-27).
|
|
660
|
+
const changed = deps.startedAt === undefined ? (deps.changedPaths ?? changedFiles)(wt) : [];
|
|
661
|
+
const dirPrefix = `${ev.dirRel.replace(/\/+$/, '')}/`;
|
|
662
|
+
const isChanged = (f: string) => {
|
|
663
|
+
if (deps.startedAt !== undefined) {
|
|
664
|
+
try {
|
|
665
|
+
const stat = statSync(join(dir, f));
|
|
666
|
+
return stat.isFile() && stat.mtimeMs >= deps.startedAt
|
|
667
|
+
&& (!deps.initialFiles || deps.initialFiles.get(f) !== fileFingerprint(join(dir, f)));
|
|
668
|
+
} catch { return false; }
|
|
669
|
+
}
|
|
670
|
+
return changed.some((c) => c === `${dirPrefix}${f}` || (c.endsWith('/') && `${dirPrefix}${f}`.startsWith(c)));
|
|
671
|
+
};
|
|
672
|
+
const matching = readdirSync(dir).filter((f) => ev.glob.test(f));
|
|
673
|
+
const hit = matching.find(isChanged);
|
|
674
|
+
if (hit) return { ok: true, path: join(dir, hit) };
|
|
675
|
+
return { ok: false, path: null, retry: matching.length
|
|
676
|
+
? `${ev.dirRel} 아래 이름이 맞는 문서는 있지만 이번 미션이 쓴 것이 아니다 — 새로 작성하거나 고쳐라.`
|
|
677
|
+
: `${ev.dirRel} 아래 대상 문서가 아직 없다.` };
|
|
506
678
|
}
|
|
507
679
|
if (!hasChanges(wt)) return { ok: false, path: null, retry: '아직 변경사항이 없다. 실제 파일을 작성하라.' };
|
|
508
680
|
if (ev.kind === 'tsc') {
|
|
@@ -516,7 +688,10 @@ export function checkEvidence(
|
|
|
516
688
|
// 없으면 비파싱 원시 출력의 **끝** 1500자(out.slice(-1500))를 쓴다. output.slice(0,1500)(앞부분)로
|
|
517
689
|
// 바꾸면 종전 문구와 어긋나 수용기준을 위반한다.
|
|
518
690
|
if (ev.fileRel && !existsSync(join(wt, ev.fileRel))) return { ok: false, path: null, retry: `${ev.fileRel} 가 아직 없다.` };
|
|
519
|
-
|
|
691
|
+
// 🩸 09-29 S6(retry-demo): without a tsconfig.json tsc prints its help and exits 1, so a mission whose tests passed
|
|
692
|
+
// 2/2 was sent «tsc 실패» with the help text as the error. The test is the evidence the caller asked for — the
|
|
693
|
+
// tsc pre-check only applies to a TypeScript project.
|
|
694
|
+
const tsc: ReturnType<TscExecutor> = deps.hasTsconfig ?? existsSync(join(wt, 'tsconfig.json')) ? executeTsc(wt) : { ran: true, diagnostics: [] };
|
|
520
695
|
if (!tsc.ran || tsc.diagnostics.length > 0) {
|
|
521
696
|
const parsed = tsc.diagnostics.map((diagnostic) => diagnostic.line);
|
|
522
697
|
const errors = parsed.slice(0, 25).join('\n') || (tsc.output ?? tsc.failure ?? '').slice(-1500);
|
|
@@ -652,6 +827,9 @@ export interface MissionControlBrainOpts {
|
|
|
652
827
|
* 행동은 no-op(wait)로 폴백 = 무회귀. 반환 detail 을 자식에 input 으로 전달(설치됨/거부 안내). */
|
|
653
828
|
readonly provision?: (req: ProvisionRequest) => Promise<ProvisionResult>;
|
|
654
829
|
readonly stream?: StreamLLMFn;
|
|
830
|
+
readonly handoffEnabled?: boolean;
|
|
831
|
+
/** Screen-grounded brain summary for the next backend, never the raw PTY screen. */
|
|
832
|
+
readonly onSummary?: (summary: string) => void;
|
|
655
833
|
}
|
|
656
834
|
|
|
657
835
|
/** 기존 5-action mission 판단을 canonical PTY control-loop 결정으로 축소한다. search는 이 경계에서만
|
|
@@ -678,7 +856,9 @@ export function createMissionControlBrain(opts: MissionControlBrainOpts): RunSup
|
|
|
678
856
|
- "wait": ${backendName} 가 아직 작업 중(도구 실행/생성)이면 대기.
|
|
679
857
|
- "verify": ${backendName} 가 MISSION-COMPLETE/완료를 주장하면 증거 게이트(내가 실행)로 검증. 완료주장 시 이걸 우선.
|
|
680
858
|
- "send": ${backendName} 가 멈추거나 계속 진행이 필요하면 짧고 명확한 지시(text).
|
|
681
|
-
- "search": ${backendName} 가 정보/라이브러리/문법/외부자원에 막혔으면 omni-crawl 로 조사(query). ⭐외부 힌트 없이 스스로
|
|
859
|
+
- "search": ${backendName} 가 정보/라이브러리/문법/외부자원에 막혔으면 omni-crawl 로 조사(query). ⭐외부 힌트 없이 스스로 판단.
|
|
860
|
+
${opts.handoffEnabled ? ` - "handoff": 다른 담당자로 넘길 때 to(codex/claude/elanous), mission(다음 지시), carry(diff/summary 선택). carry=summary 면 reason 에 화면에서 확인한 리뷰 지적을 구체적으로 요약하라(다음 backend 에 전달된다). claude 리뷰 뒤 지적은 codex 에 summary 로 되돌려라. elanous 는 증거 게이트와 PR.
|
|
861
|
+
- "ask-human": 화면에 로그인 URL/장치 코드가 보이면 reason, url/code(보이는 것만). 토큰·자격파일을 열지 마라.` : ''}${opts.provision ? `
|
|
682
862
|
- "provision": ${backendName} 가 **없는 Node 패키지**에 막혔으면(예: "Cannot find module 'X'"·"Module not found: X") 격리 worktree 에 자율 설치(spec=**npm 패키지명**, layer="pkg"). ⚠️Node 패키지만 — 파이썬/시스템 도구(pip·apt·brew)는 아직 미지원이니 provision 하지 말고 다른 방법(search·send)으로. 내가 설치 후 재시도를 지시한다.` : ''}
|
|
683
863
|
증거상태: ${opts.evidenceReady() ? '충족(완료 가능)' : '아직'}.
|
|
684
864
|
JSON 만: {"action":"...","text":"...","query":"...","spec":"...","layer":"pkg","reason":"..."}`;
|
|
@@ -691,7 +871,11 @@ export function createMissionControlBrain(opts: MissionControlBrainOpts): RunSup
|
|
|
691
871
|
decisionFromRaw: async (raw, obs): Promise<ControlDecision> => {
|
|
692
872
|
const decision = parseBrainDecision(raw);
|
|
693
873
|
history.push(`s${obs.step}:${decision.action}`);
|
|
694
|
-
debug.log('agent-mission', 'brain', { step: obs.step, action: decision.action,
|
|
874
|
+
debug.log('agent-mission', 'brain', { step: obs.step, action: decision.action,
|
|
875
|
+
...(decision.action === 'ask-human' ? {} : { reason: decision.reason.slice(0, 120) }) });
|
|
876
|
+
if (decision.reason && decision.action !== 'ask-human') opts.onSummary?.(decision.reason.slice(0, 2000));
|
|
877
|
+
if (decision.action === 'handoff' && decision.to && decision.mission) return { action: 'handoff', to: decision.to, mission: decision.mission, ...(decision.carry ? { carry: decision.carry } : {}) };
|
|
878
|
+
if (decision.action === 'ask-human') return { action: 'ask-human', reason: decision.reason, ...(decision.url ? { url: decision.url } : {}), ...(decision.code ? { code: decision.code } : {}) };
|
|
695
879
|
if (decision.action === 'send') return { action: 'input', text: `${decision.text || 'continue'}\r` };
|
|
696
880
|
if (decision.action === 'verify' || decision.action === 'done') return { action: 'done', reason: decision.reason || 'agent completed' };
|
|
697
881
|
if (decision.action === 'search') {
|
|
@@ -838,7 +1022,7 @@ export function buildMissionWorktreeRequest(
|
|
|
838
1022
|
ctx: { repoRoot: string; worktreeRoot: string },
|
|
839
1023
|
): CreateWorktreeOpts {
|
|
840
1024
|
return {
|
|
841
|
-
repoRoot: ctx.repoRoot, branch: spec.branch
|
|
1025
|
+
repoRoot: ctx.repoRoot, branch: spec.branch!, worktreeRoot: ctx.worktreeRoot, resetExisting: true,
|
|
842
1026
|
...(spec.base ? { base: spec.base } : {}),
|
|
843
1027
|
...(spec.reuseOwnedWorktree === true ? { reuseOwnedWorktree: true } : {}),
|
|
844
1028
|
};
|
|
@@ -868,10 +1052,334 @@ export function recordMissionWorktreeProvenance(
|
|
|
868
1052
|
}
|
|
869
1053
|
|
|
870
1054
|
// ══════════════════ 메인 ══════════════════
|
|
1055
|
+
export const AGENT_MISSION_TAKEOVER_WAIT_MS = 1_800_000;
|
|
1056
|
+
|
|
1057
|
+
function containingGitRepo(dir: string): string | null {
|
|
1058
|
+
const probe = spawnSync('git', ['-C', dir, 'rev-parse', '--show-toplevel'], { encoding: 'utf8' });
|
|
1059
|
+
return probe.status === 0 && probe.stdout.trim() ? probe.stdout.trim() : null;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
function missionRepoStatus(repo: string): Promise<string> {
|
|
1063
|
+
return new Promise((resolve, reject) => {
|
|
1064
|
+
const child = spawnChild('git', ['status', '--porcelain', '-z', '--untracked-files=all'], { cwd: repo });
|
|
1065
|
+
let out = '', err = '';
|
|
1066
|
+
child.stdout.setEncoding('utf8').on('data', (chunk: string) => { out += chunk; });
|
|
1067
|
+
child.stderr.setEncoding('utf8').on('data', (chunk: string) => { err += chunk; });
|
|
1068
|
+
child.on('error', reject);
|
|
1069
|
+
child.on('close', (code) => code === 0 ? resolve(out) : reject(new Error(`git status failed (${code}): ${err}`)));
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
function statusEntries(status: string): Map<string, string> {
|
|
1074
|
+
const nulDelimited = status.includes('\0');
|
|
1075
|
+
const entries = nulDelimited ? status.split('\0') : status.split('\n');
|
|
1076
|
+
const paths = new Map<string, string>();
|
|
1077
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1078
|
+
const entry = entries[i]!;
|
|
1079
|
+
if (!entry) continue;
|
|
1080
|
+
// Porcelain -z lists the source of a rename in the following entry; its path is literal.
|
|
1081
|
+
if (nulDelimited && /[RC]/.test(entry.slice(0, 2))) i++;
|
|
1082
|
+
const raw = nulDelimited ? entry.slice(3) : entry.slice(3).replace(/^.* -> /, '');
|
|
1083
|
+
if (raw) paths.set(raw, entry.slice(0, 2));
|
|
1084
|
+
}
|
|
1085
|
+
return paths;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
function insideWorkdir(repo: string, workdir: string, path: string): boolean {
|
|
1089
|
+
const root = realpathSync(repo);
|
|
1090
|
+
const folder = realpathSync(workdir);
|
|
1091
|
+
const candidate = resolve(root, path);
|
|
1092
|
+
const rel = relative(folder, candidate);
|
|
1093
|
+
return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function initialEvidenceFiles(workdir: string, evidence: Extract<EvidenceMode, { kind: 'doc' }>): Map<string, string> {
|
|
1097
|
+
const dir = join(workdir, evidence.dirRel);
|
|
1098
|
+
const files = new Map<string, string>();
|
|
1099
|
+
if (existsSync(dir)) for (const name of readdirSync(dir)) {
|
|
1100
|
+
if (!evidence.glob.test(name)) continue;
|
|
1101
|
+
const fingerprint = fileFingerprint(join(dir, name));
|
|
1102
|
+
if (fingerprint !== null) files.set(name, fingerprint);
|
|
1103
|
+
}
|
|
1104
|
+
return files;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
function fileFingerprint(path: string): string | null {
|
|
1108
|
+
try {
|
|
1109
|
+
const stat = statSync(path);
|
|
1110
|
+
if (!stat.isFile()) return null;
|
|
1111
|
+
return createHash('sha256').update(readFileSync(path)).digest('hex');
|
|
1112
|
+
} catch { return null; }
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
function linkedTargetFingerprint(path: string, seen: Set<string> = new Set()): string | null {
|
|
1116
|
+
try {
|
|
1117
|
+
const real = realpathSync(path);
|
|
1118
|
+
// A link cycle is hashed as a marker; the content was already hashed on the first visit.
|
|
1119
|
+
if (seen.has(real)) return 'cycle';
|
|
1120
|
+
const stat = statSync(real);
|
|
1121
|
+
if (stat.isFile()) return fileFingerprint(real);
|
|
1122
|
+
if (!stat.isDirectory()) return null;
|
|
1123
|
+
seen.add(real);
|
|
1124
|
+
const hash = createHash('sha256');
|
|
1125
|
+
for (const entry of readdirSync(real, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
1126
|
+
const child = join(real, entry.name);
|
|
1127
|
+
// Follow nested links too: writing through `link/nested` changes the nested target, not the link text.
|
|
1128
|
+
const content = linkedTargetFingerprint(child, seen) ?? 'missing';
|
|
1129
|
+
hash.update(entry.name).update(entry.isSymbolicLink() ? `link:${readlinkSync(child)}:${content}` : content);
|
|
1130
|
+
}
|
|
1131
|
+
return hash.digest('hex');
|
|
1132
|
+
} catch { return null; }
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// Git control files change what git and its hooks execute. Objects, the index and refs churn during
|
|
1136
|
+
// ordinary reads and sibling worktrees, so they are not compared.
|
|
1137
|
+
const GIT_CONTROL_ENTRIES = ['config', 'config.worktree', 'hooks', 'info'];
|
|
1138
|
+
|
|
1139
|
+
function gitControlFingerprints(root: string, add: (label: string, hash: string | null) => void): void {
|
|
1140
|
+
const dotGit = join(root, '.git');
|
|
1141
|
+
const dirs: Array<{ dir: string; label: string }> = [];
|
|
1142
|
+
try {
|
|
1143
|
+
const stat = lstatSync(dotGit);
|
|
1144
|
+
if (stat.isDirectory()) dirs.push({ dir: dotGit, label: '.git' });
|
|
1145
|
+
else if (stat.isFile()) {
|
|
1146
|
+
add('.git', fileFingerprint(dotGit));
|
|
1147
|
+
const gitdir = /^gitdir:\s*(.+)$/m.exec(readFileSync(dotGit, 'utf8'))?.[1]?.trim();
|
|
1148
|
+
if (gitdir) {
|
|
1149
|
+
const dir = resolve(root, gitdir);
|
|
1150
|
+
dirs.push({ dir, label: '.git:gitdir' });
|
|
1151
|
+
const common = existsSync(join(dir, 'commondir')) ? readFileSync(join(dir, 'commondir'), 'utf8').trim() : '';
|
|
1152
|
+
if (common) dirs.push({ dir: resolve(dir, common), label: '.git:common' });
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
} catch { return; }
|
|
1156
|
+
const walk = (absolute: string, label: string): void => {
|
|
1157
|
+
try {
|
|
1158
|
+
const stat = lstatSync(absolute);
|
|
1159
|
+
if (stat.isDirectory()) {
|
|
1160
|
+
for (const name of readdirSync(absolute).sort()) walk(join(absolute, name), `${label}/${name}`);
|
|
1161
|
+
} else add(label, stat.isSymbolicLink() ? `link:${readlinkSync(absolute)}:${linkedTargetFingerprint(absolute)}` : fileFingerprint(absolute));
|
|
1162
|
+
} catch { /* Absent control files are compared as absent. */ }
|
|
1163
|
+
};
|
|
1164
|
+
for (const { dir, label } of dirs) for (const name of GIT_CONTROL_ENTRIES) walk(join(dir, name), `${label}/${name}`);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
function externalLinks(dir: string, workdir: string, label: (path: string) => string): Map<string, string | null> {
|
|
1168
|
+
const links = new Map<string, string | null>();
|
|
1169
|
+
const folder = realpathSync(workdir);
|
|
1170
|
+
const visit = (current: string): void => {
|
|
1171
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
1172
|
+
if (entry.name === '.git' && entry.isDirectory()) continue;
|
|
1173
|
+
const path = join(current, entry.name);
|
|
1174
|
+
if (entry.isDirectory()) visit(path);
|
|
1175
|
+
else if (entry.isSymbolicLink()) {
|
|
1176
|
+
try {
|
|
1177
|
+
const target = realpathSync(path);
|
|
1178
|
+
const rel = relative(folder, target);
|
|
1179
|
+
if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
|
|
1180
|
+
links.set(label(path), linkedTargetFingerprint(target));
|
|
1181
|
+
}
|
|
1182
|
+
} catch { /* A broken link cannot be used to write an existing target. */ }
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
visit(dir);
|
|
1187
|
+
return links;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
function repoFingerprints(repo: string, workdir: string, paths: readonly string[]): Map<string, string | null> {
|
|
1191
|
+
const fingerprints = new Map<string, string | null>();
|
|
1192
|
+
const root = realpathSync(repo);
|
|
1193
|
+
const folder = realpathSync(workdir);
|
|
1194
|
+
const inside = (absolute: string): boolean => {
|
|
1195
|
+
const rel = relative(folder, absolute);
|
|
1196
|
+
return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
|
|
1197
|
+
};
|
|
1198
|
+
const visit = (dir: string): void => {
|
|
1199
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1200
|
+
if (dir === root && entry.name === '.git') continue;
|
|
1201
|
+
const absolute = join(dir, entry.name);
|
|
1202
|
+
if (inside(absolute)) continue;
|
|
1203
|
+
const path = relative(root, absolute);
|
|
1204
|
+
if (entry.isDirectory()) visit(absolute);
|
|
1205
|
+
else if (entry.isSymbolicLink()) {
|
|
1206
|
+
fingerprints.set(path, `link:${readlinkSync(absolute)}`);
|
|
1207
|
+
try {
|
|
1208
|
+
const target = realpathSync(absolute);
|
|
1209
|
+
if (!target.startsWith(`${root}${sep}`) && target !== root) {
|
|
1210
|
+
fingerprints.set(path, `link:${readlinkSync(absolute)}:${linkedTargetFingerprint(target)}`);
|
|
1211
|
+
}
|
|
1212
|
+
} catch { /* Broken link. */ }
|
|
1213
|
+
}
|
|
1214
|
+
else fingerprints.set(path, fileFingerprint(absolute));
|
|
1215
|
+
}
|
|
1216
|
+
};
|
|
1217
|
+
// Include ignored files as well as tracked/untracked paths: git status alone cannot see them.
|
|
1218
|
+
visit(root);
|
|
1219
|
+
gitControlFingerprints(root, (label, hash) => fingerprints.set(label, hash));
|
|
1220
|
+
for (const path of paths) {
|
|
1221
|
+
if (insideWorkdir(repo, workdir, path) || fingerprints.has(path)) continue;
|
|
1222
|
+
fingerprints.set(path, fileFingerprint(resolve(root, path)));
|
|
1223
|
+
}
|
|
1224
|
+
return fingerprints;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/** Abort owns the PTY tree even while the control brain or an external tool is awaiting. */
|
|
871
1228
|
export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMissionDeps = {}): Promise<AgentMissionResult> {
|
|
872
|
-
|
|
1229
|
+
if (spec.signal?.aborted) {
|
|
1230
|
+
debug.log('agent-mission', 'aborted', { workdir: spec.workdir, pids: [], reason: 'aborted' });
|
|
1231
|
+
return { ok: false, reason: 'aborted', worktree: spec.workdir ?? '', branch: spec.workdir ? null : spec.branch ?? null,
|
|
1232
|
+
rounds: 0, evidencePath: null, committed: false, usedOmniCrawl: false, detail: 'aborted' };
|
|
1233
|
+
}
|
|
1234
|
+
if (spec.workdir && spec.evidence.kind !== 'doc') throw new Error('workdir 모드는 doc 증거만');
|
|
1235
|
+
const workdir = spec.workdir;
|
|
1236
|
+
const status = deps.repoStatus ?? missionRepoStatus;
|
|
1237
|
+
// Compare the repository that contains the workdir, not the launcher's cwd: a workdir outside any repository
|
|
1238
|
+
// (e.g. a media folder) must not be failed by unrelated writes in the launcher's tree, such as its own logs.
|
|
1239
|
+
const repo = workdir ? (spec.repo ?? containingGitRepo(workdir)) : null;
|
|
1240
|
+
if (workdir && !repo) debug.log('agent-mission', 'workdir-outside-repo', { workdir, pids: [], reason: 'links-only' });
|
|
1241
|
+
const signal = spec.signal;
|
|
1242
|
+
let before = '';
|
|
1243
|
+
let beforeFingerprints = new Map<string, string | null>();
|
|
1244
|
+
let beforeLinks = new Map<string, string | null>();
|
|
1245
|
+
if (workdir) {
|
|
1246
|
+
let stopWaiting!: () => void;
|
|
1247
|
+
const interrupted = new Promise<never>((_resolve, reject) => { stopWaiting = () => reject(new Error('MISSION_ABORTED')); });
|
|
1248
|
+
signal?.addEventListener('abort', stopWaiting, { once: true });
|
|
1249
|
+
try {
|
|
1250
|
+
if (repo) {
|
|
1251
|
+
before = await Promise.race([status(repo), interrupted]);
|
|
1252
|
+
beforeFingerprints = repoFingerprints(repo, workdir, [...statusEntries(before).keys()]);
|
|
1253
|
+
}
|
|
1254
|
+
beforeLinks = externalLinks(workdir, workdir, (path) => path);
|
|
1255
|
+
} catch (error) {
|
|
1256
|
+
if (!signal?.aborted) throw error;
|
|
1257
|
+
debug.log('agent-mission', 'aborted', { workdir, pids: [], reason: 'aborted' });
|
|
1258
|
+
return { ok: false, reason: 'aborted', worktree: workdir, branch: null,
|
|
1259
|
+
rounds: 0, evidencePath: null, committed: false, usedOmniCrawl: false, detail: 'aborted' };
|
|
1260
|
+
} finally { signal?.removeEventListener('abort', stopWaiting); }
|
|
1261
|
+
}
|
|
1262
|
+
const startedAt = Date.now();
|
|
1263
|
+
const initialFiles = workdir && spec.evidence.kind === 'doc' ? initialEvidenceFiles(workdir, spec.evidence) : undefined;
|
|
1264
|
+
let handle: PtyHandle | undefined;
|
|
1265
|
+
let childPid: number | undefined;
|
|
1266
|
+
let killChild: (() => void) | undefined;
|
|
1267
|
+
let stopPty: (() => void) | undefined;
|
|
1268
|
+
let abort!: () => void;
|
|
1269
|
+
let cancelled = false;
|
|
1270
|
+
let controlPending: Promise<unknown> | undefined;
|
|
1271
|
+
let controlSettled = false;
|
|
1272
|
+
let activeControl: Promise<unknown> | undefined;
|
|
1273
|
+
let activeSettled = false;
|
|
1274
|
+
const aborted = new Promise<never>((_resolve, reject) => {
|
|
1275
|
+
abort = () => {
|
|
1276
|
+
if (cancelled) return;
|
|
1277
|
+
cancelled = true;
|
|
1278
|
+
debug.log('agent-mission', 'aborted', { workdir, pids: childPid ? [childPid] : handle?.pid ? [handle.pid] : [], reason: 'aborted' });
|
|
1279
|
+
void (async () => {
|
|
1280
|
+
stopPty?.();
|
|
1281
|
+
const pid = childPid ?? handle?.pid;
|
|
1282
|
+
try {
|
|
1283
|
+
if (pid) {
|
|
1284
|
+
const pids = await (deps.terminateProcessTree ?? terminateMissionProcessTree)(pid);
|
|
1285
|
+
debug.log('agent-mission', 'tree-killed', { workdir, pids, reason: 'aborted' });
|
|
1286
|
+
}
|
|
1287
|
+
} finally {
|
|
1288
|
+
if (handle) try { handle.kill(); } catch { /* Already exited. */ }
|
|
1289
|
+
killChild?.();
|
|
1290
|
+
}
|
|
1291
|
+
})().then(() => reject(new Error('MISSION_ABORTED')), reject);
|
|
1292
|
+
};
|
|
1293
|
+
});
|
|
1294
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
1295
|
+
if (signal?.aborted) abort();
|
|
1296
|
+
let result: AgentMissionResult;
|
|
1297
|
+
try {
|
|
1298
|
+
if (cancelled) await aborted;
|
|
1299
|
+
const body = runAgentMissionBody(spec, { ...deps, onControlActive: (pending) => {
|
|
1300
|
+
activeSettled = false;
|
|
1301
|
+
activeControl = pending.then(() => { activeSettled = true; }, () => { activeSettled = true; });
|
|
1302
|
+
}, onControlPending: (pending) => {
|
|
1303
|
+
controlSettled = false;
|
|
1304
|
+
controlPending = pending.then(() => { controlSettled = true; }, () => { controlSettled = true; });
|
|
1305
|
+
}, awaitMission: (pending) => Promise.race([pending, aborted]), isMissionAborted: () => cancelled, onPtyStarted: (h, stop) => { handle = h; stopPty = stop; deps.onPtyStarted?.(h, stop); if (signal?.aborted) abort(); }, onHeadlessStarted: (pid, kill) => { childPid = pid; killChild = kill; deps.onHeadlessStarted?.(pid, kill); if (signal?.aborted) abort(); } }, startedAt, initialFiles);
|
|
1306
|
+
if (signal) {
|
|
1307
|
+
try { result = await Promise.race([body, aborted]); }
|
|
1308
|
+
catch (error) {
|
|
1309
|
+
if (cancelled) {
|
|
1310
|
+
// The tree is already terminated by abort; a stage not tied to cancellation (e.g. ownership wait)
|
|
1311
|
+
// must not hold the return forever, so the drain is bounded.
|
|
1312
|
+
const drain = (async () => {
|
|
1313
|
+
await body.catch(() => {});
|
|
1314
|
+
if (activeControl && !activeSettled) await activeControl;
|
|
1315
|
+
if (controlPending && !controlSettled) await controlPending;
|
|
1316
|
+
})();
|
|
1317
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1318
|
+
const drained = await Promise.race([drain.then(() => true), new Promise<false>((done) => { timer = setTimeout(() => done(false), deps.cancelDrainMs ?? 10_000); })]);
|
|
1319
|
+
clearTimeout(timer);
|
|
1320
|
+
if (!drained) debug.log('agent-mission', 'cancel-drain-timeout', { workdir, pids: childPid ? [childPid] : handle?.pid ? [handle.pid] : [], reason: 'aborted' });
|
|
1321
|
+
}
|
|
1322
|
+
throw error;
|
|
1323
|
+
}
|
|
1324
|
+
} else result = await body;
|
|
1325
|
+
if (cancelled) await aborted;
|
|
1326
|
+
} catch (error) {
|
|
1327
|
+
if (!cancelled) throw error;
|
|
1328
|
+
result = { ok: false, reason: 'aborted', worktree: workdir ?? '', branch: workdir ? null : spec.branch ?? null,
|
|
1329
|
+
rounds: 0, evidencePath: null, committed: false, usedOmniCrawl: false, detail: 'aborted' };
|
|
1330
|
+
} finally {
|
|
1331
|
+
signal?.removeEventListener('abort', abort);
|
|
1332
|
+
}
|
|
1333
|
+
if (workdir) {
|
|
1334
|
+
let after = '';
|
|
1335
|
+
if (repo) {
|
|
1336
|
+
let stopWaiting!: () => void;
|
|
1337
|
+
const interrupted = new Promise<never>((_resolve, reject) => { stopWaiting = () => reject(new Error('MISSION_ABORTED')); });
|
|
1338
|
+
signal?.addEventListener('abort', stopWaiting, { once: true });
|
|
1339
|
+
try { after = await Promise.race([status(repo), interrupted]); }
|
|
1340
|
+
catch (error) {
|
|
1341
|
+
if (!signal?.aborted) throw error;
|
|
1342
|
+
after = await status(repo);
|
|
1343
|
+
} finally { signal?.removeEventListener('abort', stopWaiting); }
|
|
1344
|
+
}
|
|
1345
|
+
// A cancel that lands during the final inspection still cancels the mission; it never reports success.
|
|
1346
|
+
if (signal?.aborted && result.reason !== 'aborted') {
|
|
1347
|
+
debug.log('agent-mission', 'aborted', { workdir, pids: [], reason: 'aborted-during-final-inspection' });
|
|
1348
|
+
result = { ...result, ok: false, reason: 'aborted', committed: false, detail: 'aborted' };
|
|
1349
|
+
}
|
|
1350
|
+
const afterEntries = statusEntries(after);
|
|
1351
|
+
const beforeEntries = statusEntries(before);
|
|
1352
|
+
const afterFingerprints = repo
|
|
1353
|
+
? repoFingerprints(repo, workdir, [...new Set([...beforeFingerprints.keys(), ...afterEntries.keys()])])
|
|
1354
|
+
: new Map<string, string | null>();
|
|
1355
|
+
const paths = [...afterFingerprints].filter(([path, hash]) =>
|
|
1356
|
+
(beforeFingerprints.has(path) && beforeFingerprints.get(path) !== hash)
|
|
1357
|
+
|| (!beforeFingerprints.has(path) && hash !== null)
|
|
1358
|
+
|| (afterEntries.has(path) && beforeEntries.get(path) !== afterEntries.get(path)))
|
|
1359
|
+
.map(([path]) => path);
|
|
1360
|
+
for (const [link, hash] of externalLinks(workdir, workdir, (path) => path)) {
|
|
1361
|
+
if (beforeLinks.get(link) !== hash && !paths.includes(link)) paths.push(link);
|
|
1362
|
+
}
|
|
1363
|
+
paths.sort();
|
|
1364
|
+
if (paths.length) {
|
|
1365
|
+
debug.log('agent-mission', 'outside-write', { workdir, pids: [], reason: paths.join(', ') });
|
|
1366
|
+
(deps.emitDecision ?? emitDecision)({ kind: 'ESCALATE', what: '작업 폴더 밖 쓰기', reason: paths.join(', '), purpose: '사람이 확인한다', target: 'human' });
|
|
1367
|
+
return { ...result, ok: false, reason: 'outside-write', paths, committed: false };
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
return result;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
async function runAgentMissionBody(spec: AgentMissionSpec, deps: AgentMissionDeps, startedAt: number, initialFiles?: ReadonlyMap<string, string>): Promise<AgentMissionResult> {
|
|
1374
|
+
const backend = spec.agent ?? (spec.chain?.[0] && spec.chain[0] !== 'elanous' ? resolveBackend(spec.chain[0]) : resolveDefaultBackend());
|
|
1375
|
+
if (spec.chain && (spec.chain[0] !== backend.name || !['codex,claude,elanous', 'codex,claude,codex,elanous'].some((allowed) => allowed === spec.chain!.join(',') || (deps.handoffWorktree && allowed.endsWith(`,${spec.chain!.join(',')}`))))) throw new Error('invalid agent mission chain');
|
|
1376
|
+
if (spec.chain && spec.commit === false && spec.chain.includes('elanous')) throw new Error('elanous PR handoff requires commit authorization');
|
|
1377
|
+
if (spec.headless && spec.chain) throw new Error('--headless cannot run a PTY handoff chain');
|
|
1378
|
+
if (spec.headless && backend.name !== 'claude') throw new Error('--headless 는 --backend claude 전용입니다');
|
|
1379
|
+
if (spec.plugin && (spec.headless || (backend.name !== 'codex' && backend.name !== 'claude'))) throw new Error('--plugin 은 codex/claude PTY 전용입니다');
|
|
1380
|
+
if (spec.workdir && spec.chain) throw new Error('workdir 모드는 넘기기 사슬을 쓰지 않는다');
|
|
873
1381
|
const runtimeFallback = deps.runtimeFallback ?? {
|
|
874
|
-
fallbackEligible: spec.agent === undefined,
|
|
1382
|
+
fallbackEligible: spec.agent === undefined && !spec.chain,
|
|
875
1383
|
attemptedSteps: new Set<FallbackStep>([backend.name === 'grok' ? 'grok' : 'codex-rotate']),
|
|
876
1384
|
descents: 0,
|
|
877
1385
|
maxDescents: backend.name === 'codex' ? 1 : 0,
|
|
@@ -880,6 +1388,7 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
880
1388
|
const createMissionWorktree = deps.createWorktree ?? createWorktree;
|
|
881
1389
|
const recordWorktreeProvenance = deps.recordWorktreeProvenance ?? recordHarnessWorktreeProvenance;
|
|
882
1390
|
const repoRoot = spec.repo ?? resolveMainRepoRoot(process.cwd()) ?? process.cwd();
|
|
1391
|
+
if (!spec.workdir && !spec.branch) throw new Error('branch is required without workdir');
|
|
883
1392
|
const maxRounds = spec.maxRounds ?? 16;
|
|
884
1393
|
const omniPath = spec.omniCrawlPath ?? DEFAULT_OMNI;
|
|
885
1394
|
const screensDir = spec.screensDir ?? join(process.env.TMPDIR || '/tmp', `agent-mission-${backend.name}-${spec.branch}`);
|
|
@@ -903,32 +1412,124 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
903
1412
|
role: 'controller', executor: describeRole({ role: 'executor', executorKind: 'agent', agentBackend: backend.name }),
|
|
904
1413
|
entry: missionEntry, capabilities: [...caps.active], enhanceActive,
|
|
905
1414
|
});
|
|
906
|
-
// ⭐ 이 자리는 «별칭»(createMissionWorktree)이라 소스 스캔이 못 찾았고 타입 검사가 찾았다
|
|
907
|
-
// — 리뷰 3R must-fix ② 가 경고한 그 형태다(별칭·래퍼는 정규식으로 못 센다).
|
|
908
|
-
const wt = createMissionWorktree(buildMissionWorktreeRequest(spec, { repoRoot, worktreeRoot: configuredWorktreeRoot() }));
|
|
909
|
-
recordMissionWorktreeProvenance(wt.path, buildMissionWorktreeProvenance(spec.branch), recordWorktreeProvenance);
|
|
910
|
-
debug.log('agent-mission', 'worktree', { path: wt.path, branch: wt.branch, base: wt.base });
|
|
911
|
-
const baselineTsc = spec.evidence.kind === 'tsc' ? collectTscDiagnostics(wt.path) : null;
|
|
912
|
-
const evidenceCheck: typeof checkEvidence = (worktree, evidence) => evidence.kind === 'tsc' && baselineTsc
|
|
913
|
-
? checkEvidence(worktree, evidence, { baseline: baselineTsc.diagnostics, executeTsc: baselineTsc.ran ? collectTscDiagnostics : () => baselineTsc })
|
|
914
|
-
: checkEvidence(worktree, evidence);
|
|
915
|
-
|
|
916
1415
|
// 구독 모드 — backend 지정 env 키 스크럽 후 강제 env까지 적용해 cmd·args·env를 순수 seam으로 구성한다.
|
|
917
1416
|
// forcedEnv 이름의 후속 로깅은 이 착지의 의도적 경계이며, spawn에는 같은 seam의 env가 그대로 흐른다.
|
|
918
1417
|
const spawnParams = resolveBackendSpawn(backend, process.env);
|
|
919
1418
|
const env = spawnParams.env;
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1419
|
+
if (backend.name === 'claude') {
|
|
1420
|
+
const status = (deps.checkClaudeSubscription ?? checkClaudeSubscription)({ env });
|
|
1421
|
+
debug.log('agent-mission.claude-subscription', 'status', {
|
|
1422
|
+
ok: status.ok, authMethod: status.authMethod, apiProvider: status.apiProvider, reason: status.reason,
|
|
1423
|
+
});
|
|
1424
|
+
if (!status.ok) {
|
|
1425
|
+
const action = status.reason === 'logged-out'
|
|
1426
|
+
? 'Run `claude login` to authenticate a Claude subscription, then retry.'
|
|
1427
|
+
: status.reason === 'api-key'
|
|
1428
|
+
? 'Claude is using API-key/provider authentication rather than a Claude subscription. Run `claude login` with a subscription account, then retry.'
|
|
1429
|
+
: 'Run `claude auth status --json` and check the Claude CLI/login, then retry.';
|
|
1430
|
+
return {
|
|
1431
|
+
ok: false, worktree: spec.workdir ?? '', branch: spec.branch ?? null, rounds: 0,
|
|
1432
|
+
evidencePath: null, committed: false, usedOmniCrawl: false,
|
|
1433
|
+
detail: `Claude subscription check failed (${status.reason}). ${action}`,
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
// ⭐ 이 자리는 «별칭»(createMissionWorktree)이라 소스 스캔이 못 찾았고 타입 검사가 찾았다
|
|
1438
|
+
// — 리뷰 3R must-fix ② 가 경고한 그 형태다(별칭·래퍼는 정규식으로 못 센다).
|
|
1439
|
+
if (deps.isMissionAborted?.()) throw new Error('MISSION_ABORTED');
|
|
1440
|
+
const wt = spec.workdir
|
|
1441
|
+
? { path: spec.workdir, branch: spec.branch ?? null, base: null }
|
|
1442
|
+
: deps.handoffWorktree ?? createMissionWorktree(buildMissionWorktreeRequest(spec, { repoRoot, worktreeRoot: configuredWorktreeRoot() }));
|
|
1443
|
+
if (spec.workdir) debug.log('agent-mission', 'workdir-mode', { workdir: wt.path, pids: [], reason: 'non-git' });
|
|
1444
|
+
else {
|
|
1445
|
+
if (!deps.handoffWorktree) recordMissionWorktreeProvenance(wt.path, buildMissionWorktreeProvenance(spec.branch!), recordWorktreeProvenance);
|
|
1446
|
+
debug.log('agent-mission', 'worktree', { path: wt.path, branch: wt.branch, base: wt.base });
|
|
1447
|
+
}
|
|
1448
|
+
const baselineTsc = spec.evidence.kind === 'tsc' ? (deps.initialTsc ?? collectTscDiagnostics(wt.path)) : null;
|
|
1449
|
+
const evidenceCheck: typeof checkEvidence = (worktree, evidence) => evidence.kind === 'tsc' && baselineTsc
|
|
1450
|
+
? checkEvidence(worktree, evidence, { baseline: baselineTsc.diagnostics, executeTsc: baselineTsc.ran ? collectTscDiagnostics : () => baselineTsc })
|
|
1451
|
+
: checkEvidence(worktree, evidence, spec.workdir ? { startedAt, initialFiles } : {});
|
|
1452
|
+
const verifyEvidence: typeof checkEvidence = spec.workdir ? evidenceCheck : deps.checkEvidence ?? evidenceCheck;
|
|
1453
|
+
// Resolve identity before either child path; both receive the same run ID through env.
|
|
1454
|
+
if (deps.isMissionAborted?.()) throw new Error('MISSION_ABORTED');
|
|
923
1455
|
const runId = ensureRunId();
|
|
924
1456
|
env.ELANOUS_RUN_ID = runId;
|
|
1457
|
+
if (spec.headless === true) {
|
|
1458
|
+
// The non-interactive child receives the mission on stdin, never via a PTY or argv.
|
|
1459
|
+
// Keep the same enhancement and additive memory policy as the interactive mission.
|
|
1460
|
+
let prompt = spec.mission;
|
|
1461
|
+
let checklist: string[] = [];
|
|
1462
|
+
if (enhanceActive) {
|
|
1463
|
+
const { enhancePrompt } = await import('../prompt-enhance/enhance.js');
|
|
1464
|
+
const enhanced = await enhancePrompt(spec.mission, {
|
|
1465
|
+
...(spec.deliverableHint ? { deliverableHint: spec.deliverableHint } : {}),
|
|
1466
|
+
});
|
|
1467
|
+
prompt = enhanced.enhanced;
|
|
1468
|
+
checklist = enhanced.checklist;
|
|
1469
|
+
debug.log('agent-mission', 'enhance', {
|
|
1470
|
+
checklist: checklist.length, enhancedBy: enhanced.enhancedBy,
|
|
1471
|
+
origChars: enhanced.original.length, enhancedChars: prompt.length, verbatimPreserved: enhanced.verbatimPreserved,
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
if (spec.memory !== false) {
|
|
1475
|
+
const { recallMemoryContext } = await import('../agent-substrate/execution/memory-context.js');
|
|
1476
|
+
const mem = await recallMemoryContext(spec.mission.slice(0, 300), { limit: 5 });
|
|
1477
|
+
if (mem) { prompt = `${prompt}\n\n${mem}`; debug.log('agent-mission', 'memory', { injected: true, chars: mem.length }); }
|
|
1478
|
+
else debug.log('agent-mission', 'memory', { injected: false });
|
|
1479
|
+
}
|
|
1480
|
+
if (deps.isMissionAborted?.()) throw new Error('MISSION_ABORTED');
|
|
1481
|
+
const headlessRun = (deps.runClaudeHeadless ?? runClaudeHeadless)({ cwd: wt.path, prompt, env: envLiteral(env), maxTurns: maxRounds, onSpawn: deps.onHeadlessStarted });
|
|
1482
|
+
const result = await (deps.awaitMission ? deps.awaitMission(headlessRun) : headlessRun);
|
|
1483
|
+
debug.log('agent-mission', 'headless-result', {
|
|
1484
|
+
ok: result.ok, reason: result.reason, exitCode: result.exitCode,
|
|
1485
|
+
sessionId: result.sessionId, numTurns: result.numTurns, toolEvents: result.toolEvents,
|
|
1486
|
+
malformedLines: result.malformedLines, durationMs: result.durationMs,
|
|
1487
|
+
});
|
|
1488
|
+
if (!result.ok) return {
|
|
1489
|
+
ok: false, worktree: wt.path, branch: wt.branch, rounds: result.numTurns ?? 0,
|
|
1490
|
+
evidencePath: null, committed: false, usedOmniCrawl: false,
|
|
1491
|
+
detail: `Claude headless failed (${result.reason}; exit ${result.exitCode ?? 'unknown'}). Check the Claude CLI and retry.`,
|
|
1492
|
+
};
|
|
1493
|
+
if (deps.isMissionAborted?.()) return { ok: false, reason: 'aborted', worktree: wt.path, branch: wt.branch,
|
|
1494
|
+
rounds: result.numTurns ?? 0, evidencePath: null, committed: false, usedOmniCrawl: false, detail: 'aborted' };
|
|
1495
|
+
const finalEv = verifyEvidence(wt.path, spec.evidence);
|
|
1496
|
+
if (!finalEv.ok) return {
|
|
1497
|
+
ok: false, worktree: wt.path, branch: wt.branch, rounds: result.numTurns ?? 0,
|
|
1498
|
+
evidencePath: null, committed: false, usedOmniCrawl: false,
|
|
1499
|
+
detail: `미완(증거 부족): ${finalEv.retry ?? '증거가 아직 부족하다.'}`,
|
|
1500
|
+
};
|
|
1501
|
+
if (checklist.length) {
|
|
1502
|
+
const { verifyCoverage } = await import('../prompt-enhance/coverage.js');
|
|
1503
|
+
const coverage = await verifyCoverage(gatherArtifactText(wt.path, finalEv.path), checklist, {});
|
|
1504
|
+
debug.log('agent-mission', 'coverage', { covered: coverage.covered.length, missing: coverage.missing.length,
|
|
1505
|
+
ratio: Number(coverage.ratio.toFixed(2)), method: coverage.method, coverageRetries: 0 });
|
|
1506
|
+
if (coverage.missing.length) debug.log('agent-mission', 'coverage-exhausted', { missing: coverage.missing.length });
|
|
1507
|
+
}
|
|
1508
|
+
let committed = false;
|
|
1509
|
+
if (!deps.isMissionAborted?.() && !spec.workdir && (spec.commit ?? true)) {
|
|
1510
|
+
const c = (deps.commitWorktree ?? commitWorktree)(wt.path, `chore(agent-mission): ${spec.branch} — claude-in-elanous headless 산출`);
|
|
1511
|
+
committed = c.ok;
|
|
1512
|
+
debug.log('agent-mission', 'commit', { ok: c.ok, out: c.out.slice(0, 120) });
|
|
1513
|
+
if (!c.ok) {
|
|
1514
|
+
debug.log('agent-mission', 'result', { ok: false, rounds: result.numTurns ?? 0, evidencePath: finalEv.path, committed: false, usedOmni: false });
|
|
1515
|
+
return { ok: false, worktree: wt.path, branch: wt.branch, rounds: result.numTurns ?? 0,
|
|
1516
|
+
evidencePath: finalEv.path, committed: false, usedOmniCrawl: false,
|
|
1517
|
+
detail: `미완(자동 커밋 실패): ${c.out.slice(0, 120)}` };
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
debug.log('agent-mission', 'result', { ok: true, rounds: result.numTurns ?? 0, evidencePath: finalEv.path, committed, usedOmni: false });
|
|
1521
|
+
return { ok: true, worktree: wt.path, branch: wt.branch, rounds: result.numTurns ?? 0,
|
|
1522
|
+
evidencePath: finalEv.path, committed, usedOmniCrawl: false, detail: '완료(증거 충족)' };
|
|
1523
|
+
}
|
|
1524
|
+
env.TERM = 'xterm-256color';
|
|
1525
|
+
// ⭐run-identity — runId was resolved before either headless or PTY spawn.
|
|
925
1526
|
debug.log('agent-mission', 'spawn', { agent: backend.name, cmd: `${spawnParams.cmd} ${spawnParams.args.join(' ')}`, scrubbed: backend.scrubEnv ?? [], nestedEnvRemovedCount: spawnParams.nestedEnvRemovedCount, runId });
|
|
926
1527
|
// PTY 정체성 — kind(=backend)·nickname(goto 로 나중 접근)·accessMode='auto'(헤드리스 자율·brain 이 write 소유).
|
|
927
1528
|
const ptyOpts = buildAgentMissionPtySpawnOptions({
|
|
928
1529
|
backend,
|
|
929
1530
|
spawn: { cmd: spawnParams.cmd, args: spawnParams.args, env, unsetEnv: spawnParams.unsetEnv },
|
|
930
1531
|
workdir: wt.path,
|
|
931
|
-
nickname: spec.nickname ?? spec.branch,
|
|
1532
|
+
nickname: spec.nickname ?? spec.branch ?? backend.name,
|
|
932
1533
|
});
|
|
933
1534
|
const childStartedAt = Date.now();
|
|
934
1535
|
let liveDirty = false, liveChunks = 0;
|
|
@@ -970,8 +1571,12 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
970
1571
|
}
|
|
971
1572
|
});
|
|
972
1573
|
let h: PtyHandle;
|
|
1574
|
+
if (deps.isMissionAborted?.()) { offLive(); throw new Error('MISSION_ABORTED'); }
|
|
973
1575
|
try { h = spawnPty(ptyOpts); }
|
|
974
1576
|
catch (error) { offLive(); throw error; }
|
|
1577
|
+
deps.onPtyStarted?.(h, () => { if (liveTimer) clearInterval(liveTimer); offLive(); });
|
|
1578
|
+
if (deps.isMissionAborted?.()) return { ok: false, reason: 'aborted', worktree: wt.path, branch: wt.branch,
|
|
1579
|
+
rounds: 0, evidencePath: null, committed: false, usedOmniCrawl: false, detail: 'aborted' };
|
|
975
1580
|
const executorRef = buildExecutorPtyRef({
|
|
976
1581
|
ptyId: h.id,
|
|
977
1582
|
backend: backend.name,
|
|
@@ -980,6 +1585,9 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
980
1585
|
instance: resolveInstanceName(),
|
|
981
1586
|
});
|
|
982
1587
|
debug.log('agent-mission', 'pty', { id: h.id, kind: h.kind, nickname: h.nickname, accessMode: h.accessMode, executorRef });
|
|
1588
|
+
const webAddress = (deps.resolvePtyWebAddress ?? resolvePtyWebAddress)(h.id);
|
|
1589
|
+
process.stderr.write(`[agent-mission] pty=${h.id} watch=${webAddress.webUrl ?? `(web unavailable: ${webAddress.pwaUnavailableReason ?? 'not-resolved'})`}\n`);
|
|
1590
|
+
debug.log('agent-mission', 'pty-link', { id: h.id, webUrl: webAddress.webUrl, webUrlSource: webAddress.webUrlSource });
|
|
983
1591
|
|
|
984
1592
|
// ⭐P2 arbiter: the child is accessMode='auto' (brain-owned), so the driver —
|
|
985
1593
|
// the autonomous brain — must write as 'agent' or the arbiter denies it. This
|
|
@@ -987,10 +1595,10 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
987
1595
|
// inject unless they takeover (auto→write, needs 'open' policy). `h['write']`
|
|
988
1596
|
// form so the drive helper isn't caught by the h.write→drive rewrite.
|
|
989
1597
|
//
|
|
990
|
-
//
|
|
991
|
-
//
|
|
992
|
-
// (사람이 제어를 가져갔으니 자율 구동 멈춤 = HITL 로 넘어감). 관측 남김.
|
|
1598
|
+
// 초기 미션 전송 중 소유권을 잃으면 write 를 시도하지 않는다. 제어 루프에 들어간 뒤의
|
|
1599
|
+
// takeover 는 awaitOwnership 으로 기다리며, 사람이 release 하면 미션을 재개한다.
|
|
993
1600
|
const drive = (s: string): void => {
|
|
1601
|
+
if (deps.isMissionAborted?.()) return;
|
|
994
1602
|
// ⭐공용 seam(P2b P-a′) — 판정은 `pty-control-stance` 한 곳. 집행(throw)은 종전 그대로다(무회귀).
|
|
995
1603
|
const stance = probeControlStance(h, 'agent', (e) =>
|
|
996
1604
|
debug.log('agent-mission', 'hascontrol-error', { id: h.id, error: (e as Error)?.message ?? String(e) }));
|
|
@@ -1033,11 +1641,69 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
1033
1641
|
const stopLive = (): void => { if (liveTimer) clearInterval(liveTimer); offLive(); };
|
|
1034
1642
|
|
|
1035
1643
|
// ready + trust — backend 별 신뢰/권한 프롬프트 처리(codex=1, 이후 백엔드는 자체 handler).
|
|
1036
|
-
await waitForQuiet(h, 1500, 20000);
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1644
|
+
await (deps.awaitMission ? deps.awaitMission(waitForQuiet(h, 1500, 20000)) : waitForQuiet(h, 1500, 20000));
|
|
1645
|
+
if (deps.isMissionAborted?.()) throw new Error('MISSION_ABORTED');
|
|
1646
|
+
let screen = await (deps.awaitMission ? deps.awaitMission(capture('ready')) : capture('ready'));
|
|
1647
|
+
if (deps.isMissionAborted?.()) throw new Error('MISSION_ABORTED');
|
|
1648
|
+
// A trust menu can need more than one key (claude: ↓ to «Yes», then Enter) — answer until it is gone, at most 3 times.
|
|
1649
|
+
// 🩸 09-29: one pass sent only ↓, the mission text went into the menu and its Enter confirmed «Yes» instead of
|
|
1650
|
+
// submitting the mission, which then sat unsent in the input box.
|
|
1651
|
+
for (let pass = 0; pass < 3 && backend.handleTrust?.(screen, (s) => drive(s)); pass++) {
|
|
1652
|
+
debug.log('agent-mission', 'trust', { agent: backend.name, action: 'handled', pass });
|
|
1653
|
+
const trusted = (async () => { await waitForQuiet(h, 1500, 15000); return capture('trusted'); })();
|
|
1654
|
+
screen = await (deps.awaitMission ? deps.awaitMission(trusted) : trusted);
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
let resourcePlan: ResourcePlan | undefined;
|
|
1658
|
+
// Only an explicit `on` runs the ladder (the CLI passes `on` by default). Library callers and fake-PTY
|
|
1659
|
+
// tests that leave it unset keep the pre-ladder behaviour — 09-29 #21849 made them wait on a real LLM.
|
|
1660
|
+
if (spec.resources === 'on') {
|
|
1661
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1662
|
+
try {
|
|
1663
|
+
resourcePlan = await Promise.race([
|
|
1664
|
+
(deps.planMissionResources ?? planMissionResources)(spec.mission, deps.resourceLadder ?? {}, {
|
|
1665
|
+
backend: spec.backendExplicit,
|
|
1666
|
+
plugin: spec.plugin ? `${spec.plugin.plugin}@${spec.plugin.marketplace}` : undefined,
|
|
1667
|
+
resources: spec.resources,
|
|
1668
|
+
deadlineMs: 20_000,
|
|
1669
|
+
}),
|
|
1670
|
+
new Promise<never>((_resolve, reject) => { timer = setTimeout(() => reject(new Error('resource ladder timeout (20s)')), 20_000); }),
|
|
1671
|
+
]);
|
|
1672
|
+
debug.log('agent-mission.resources', 'planned', {
|
|
1673
|
+
have: resourcePlan.have.length, gaps: resourcePlan.gaps.length,
|
|
1674
|
+
suggestedPlugin: resourcePlan.plugin?.plugin, suggestedBackend: resourcePlan.backend?.name,
|
|
1675
|
+
executedBackend: backend.name,
|
|
1676
|
+
});
|
|
1677
|
+
} catch (error) {
|
|
1678
|
+
debug.log('agent-mission.resources', 'plan-failed', { reason: error instanceof Error ? error.message : String(error) }, { level: 'warn' });
|
|
1679
|
+
} finally { if (timer) clearTimeout(timer); }
|
|
1680
|
+
}
|
|
1681
|
+
const suggestedPlugin = resourcePlan?.plugin?.source === 'official-index' && !spec.plugin
|
|
1682
|
+
&& !spec.headless && (backend.name === 'codex' || backend.name === 'claude')
|
|
1683
|
+
&& resourcePlan.plugin.marketplace === 'elanous'
|
|
1684
|
+
&& /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(resourcePlan.plugin.plugin)
|
|
1685
|
+
? { plugin: resourcePlan.plugin.plugin, marketplace: resourcePlan.plugin.marketplace } : undefined;
|
|
1686
|
+
const requestedPlugin = spec.plugin ?? suggestedPlugin;
|
|
1687
|
+
let installedPlugin: typeof requestedPlugin;
|
|
1688
|
+
if (requestedPlugin) {
|
|
1689
|
+
try {
|
|
1690
|
+
const plugin = await (deps.installPlugin ?? installPluginInsideAgent)(
|
|
1691
|
+
{ agent: backend.name as 'codex' | 'claude', ...requestedPlugin }, h,
|
|
1692
|
+
{ ...(backend.handleTrust ? { handleTrust: backend.handleTrust } : {}), ...deps.pluginDeps, write: drive },
|
|
1693
|
+
);
|
|
1694
|
+
if (plugin.outcome !== 'installed') {
|
|
1695
|
+
if (spec.plugin) {
|
|
1696
|
+
stopLive();
|
|
1697
|
+
try { h.kill(); } catch { /* already exited */ }
|
|
1698
|
+
return { ok: false, worktree: wt.path, branch: wt.branch, rounds: 0, evidencePath: null,
|
|
1699
|
+
committed: false, usedOmniCrawl: false, detail: `플러그인 설치 ESCALATE (${plugin.reason}) — 미션은 전송하지 않았다` };
|
|
1700
|
+
}
|
|
1701
|
+
debug.log('agent-mission.resources', 'install-failed', { plugin: requestedPlugin.plugin, reason: plugin.reason }, { level: 'warn' });
|
|
1702
|
+
} else installedPlugin = requestedPlugin;
|
|
1703
|
+
} catch (error) {
|
|
1704
|
+
if (spec.plugin) throw error;
|
|
1705
|
+
debug.log('agent-mission.resources', 'install-failed', { plugin: requestedPlugin.plugin, reason: 'installer-error' }, { level: 'warn' });
|
|
1706
|
+
}
|
|
1041
1707
|
}
|
|
1042
1708
|
|
|
1043
1709
|
// ★ elanous 내부 인핸싱(opt-in) — 원문 verbatim 보존 + 커버리지 체크리스트 부착(anti-drift).
|
|
@@ -1066,6 +1732,16 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
1066
1732
|
else debug.log('agent-mission', 'memory', { injected: false });
|
|
1067
1733
|
}
|
|
1068
1734
|
|
|
1735
|
+
if (installedPlugin) missionText = `${missionText}\n\n설치된 ${installedPlugin.plugin} 플러그인에서 실제 스킬을 확인하고 ${installedPlugin.plugin}:<skill> 형식으로 해당 스킬을 사용하라.`;
|
|
1736
|
+
if (resourcePlan) {
|
|
1737
|
+
const safeName = (name: string) => sanitizeForPtyInput(name, 80)
|
|
1738
|
+
.replace(/\b(?:bearer|secret|password|token|api.?key|authorization)\s*[:=]\s*\S+|(?:sk-[\w-]+|gh[pousr]_[\w-]+|github_pat_[\w-]+|AIza[\w-]+|xox[baprs]-[\w-]+)/gi, '[redacted]')
|
|
1739
|
+
.replace(/https?:\/\/\S+/gi, '[redacted]');
|
|
1740
|
+
const have = resourcePlan.have.slice(0, 5).map(safeName);
|
|
1741
|
+
const gaps = resourcePlan.gaps.slice(0, 5).map(gap => safeName(gap.need));
|
|
1742
|
+
missionText = `${missionText}\n\n[elanous 자원]\n보유: ${have.join(', ') || '없음'}\n설치: ${installedPlugin ? `${installedPlugin.plugin}@${installedPlugin.marketplace}` : '없음'}\n미충족: ${gaps.join(', ') || '없음'}`;
|
|
1743
|
+
}
|
|
1744
|
+
if (deps.isMissionAborted?.()) throw new Error('MISSION_ABORTED');
|
|
1069
1745
|
// 미션 전송 — 인핸싱/기억으로 가공됐으면(멀티라인) 파일로 떨궈 read 지시(TUI 멀티라인 위험·verbatim 보존).
|
|
1070
1746
|
// 원문 그대로면(단문) 타이핑.
|
|
1071
1747
|
if (missionText !== spec.mission) {
|
|
@@ -1082,12 +1758,17 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
1082
1758
|
}
|
|
1083
1759
|
|
|
1084
1760
|
let usedOmni = false;
|
|
1761
|
+
let controllerSummary = deps.previousSummary ?? '';
|
|
1762
|
+
let reviewSummary = '';
|
|
1085
1763
|
let coverageRetries = enhanceActive && checklist.length ? 2 : 0;
|
|
1086
1764
|
const search = createMissionSearch({ worktree: wt.path, omniPath });
|
|
1087
1765
|
const brain = createMissionControlBrain({
|
|
1088
1766
|
mission: spec.mission,
|
|
1089
1767
|
backend,
|
|
1090
|
-
|
|
1768
|
+
stream: deps.controlStream,
|
|
1769
|
+
handoffEnabled: true,
|
|
1770
|
+
onSummary: (summary) => { controllerSummary = summary; },
|
|
1771
|
+
evidenceReady: () => spec.chain && spec.chain.length > 1 ? true : verifyEvidence(wt.path, spec.evidence).ok,
|
|
1091
1772
|
search: async (query, step) => {
|
|
1092
1773
|
usedOmni = true;
|
|
1093
1774
|
await search(query, step);
|
|
@@ -1098,12 +1779,84 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
1098
1779
|
// buildMissionProvision 팩토리로 배선(wt.path→cwd 를 DI 로 행동검증 가능·소스 tripwire 불요).
|
|
1099
1780
|
provision: buildMissionProvision(wt.path),
|
|
1100
1781
|
});
|
|
1782
|
+
// A trust/permission prompt can appear after the first screen (09-29 S6: codex 0.157 showed «Folder access»
|
|
1783
|
+
// 70 s after launch, after the one-shot check). Answer it at every step with the backend's own bytes
|
|
1784
|
+
// before asking the LLM — otherwise the mission text is typed into the prompt and the run stalls.
|
|
1785
|
+
const trustAwareBrain: RunSupervisor = {
|
|
1786
|
+
decide: (obs, signal) => {
|
|
1787
|
+
let answer: string | undefined;
|
|
1788
|
+
if (backend.handleTrust?.(obs.screen, (bytes) => { answer = bytes; }) && answer !== undefined) {
|
|
1789
|
+
debug.log('agent-mission', 'trust', { agent: backend.name, action: 'handled-in-loop', step: obs.step });
|
|
1790
|
+
emitDecision({ kind: 'ROUTE', what: `${backend.name} 폴더 신뢰 화면 → 계속`, reason: '시작 뒤 늦게 뜬 신뢰 확인', purpose: '미션을 이어 간다', target: backend.name, phase: 'implement' });
|
|
1791
|
+
return { action: 'input', text: answer };
|
|
1792
|
+
}
|
|
1793
|
+
return brain.decide(obs, signal);
|
|
1794
|
+
},
|
|
1795
|
+
};
|
|
1796
|
+
let pendingHandoff: { to: 'codex' | 'claude'; mission: string; summary: string } | undefined;
|
|
1797
|
+
let gatedHandoff = false;
|
|
1798
|
+
let handoffPrSkipped = false;
|
|
1799
|
+
let transitionFailure: string | undefined;
|
|
1800
|
+
const handoffOps: HandoffOperations = {
|
|
1801
|
+
start: async (to, mission) => { pendingHandoff = { to, mission, summary: controllerSummary }; },
|
|
1802
|
+
claudeLoggedIn: () => (deps.checkClaudeSubscription ?? checkClaudeSubscription)({ env: resolveBackendSpawn(claudeBackend, process.env).env }).ok,
|
|
1803
|
+
screen: () => h.renderScreen(),
|
|
1804
|
+
alive: () => h.isAlive(),
|
|
1805
|
+
login: async (worktree) => {
|
|
1806
|
+
const loginSpawn = resolveBackendSpawn(claudeBackend, process.env);
|
|
1807
|
+
const handle = spawnPty(buildAgentMissionPtySpawnOptions({
|
|
1808
|
+
backend: claudeBackend,
|
|
1809
|
+
spawn: { cmd: loginSpawn.cmd, args: ['login'], env: { ...loginSpawn.env, TERM: 'xterm-256color' }, unsetEnv: loginSpawn.unsetEnv },
|
|
1810
|
+
workdir: worktree,
|
|
1811
|
+
nickname: `${spec.branch}-login`,
|
|
1812
|
+
}));
|
|
1813
|
+
return { screen: () => handle.renderScreen(), alive: () => handle.isAlive(), close: () => handle.kill() };
|
|
1814
|
+
},
|
|
1815
|
+
sleep: async (ms) => { await sleep(ms); },
|
|
1816
|
+
notify: async (card) => {
|
|
1817
|
+
const { sendOutbound } = await import('../domains/outbound-alert.js');
|
|
1818
|
+
if (!sendOutbound([card.text, card.url, card.code].filter(Boolean).join('\n'), 'agent-mission')) {
|
|
1819
|
+
throw new Error('agent mission login card delivery failed');
|
|
1820
|
+
}
|
|
1821
|
+
},
|
|
1822
|
+
gateAndPr: async (worktree) => {
|
|
1823
|
+
if (spec.commit === false) throw new Error('elanous PR handoff requires commit authorization');
|
|
1824
|
+
const ev = (deps.checkEvidence ?? evidenceCheck)(worktree, spec.evidence);
|
|
1825
|
+
if (!ev.ok) throw new Error(`handoff evidence gate failed: ${ev.retry ?? 'missing evidence'}`);
|
|
1826
|
+
const promptFile = join(worktree, '.mission-prompt.md');
|
|
1827
|
+
let promptExisted = false;
|
|
1828
|
+
try { lstatSync(promptFile); promptExisted = true; } catch (error) {
|
|
1829
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
1830
|
+
}
|
|
1831
|
+
if (promptExisted) unlinkSync(promptFile);
|
|
1832
|
+
debug.log('agent-mission', 'handoff-prompt-file-removed', { existed: promptExisted });
|
|
1833
|
+
const stagedPrompt = execFileSync('git', ['ls-files', '--cached', '--', '.mission-prompt.md'], { cwd: worktree, encoding: 'utf8' });
|
|
1834
|
+
if (stagedPrompt.trim()) {
|
|
1835
|
+
execFileSync('git', ['rm', '-f', '--cached', '--', '.mission-prompt.md'], { cwd: worktree, encoding: 'utf8' });
|
|
1836
|
+
}
|
|
1837
|
+
if (execFileSync('git', ['ls-files', '--cached', '--', '.mission-prompt.md'], { cwd: worktree, encoding: 'utf8' }).trim()) {
|
|
1838
|
+
throw new Error('handoff prompt file remains in commit index');
|
|
1839
|
+
}
|
|
1840
|
+
const commit = (deps.commitWorktree ?? commitWorktree)(worktree, `chore(agent-mission): ${spec.branch} handoff`);
|
|
1841
|
+
if (!commit.ok) throw new Error(`handoff commit failed: ${commit.out}`);
|
|
1842
|
+
execFileSync('git', ['push', '-u', 'origin', `HEAD:${spec.branch}`], { cwd: worktree, encoding: 'utf8', timeout: 120_000 });
|
|
1843
|
+
const pushUrls = execFileSync('git', ['remote', 'get-url', '--push', '--all', 'origin'], { cwd: worktree, encoding: 'utf8' }).trim().split('\n');
|
|
1844
|
+
if (!pushUrls.length || !pushUrls.every((url) => /^(?:https:\/\/github\.com\/|ssh:\/\/git@github\.com\/|git@github\.com:)[^/]+\/[^/]+\/?$/i.test(url))) {
|
|
1845
|
+
handoffPrSkipped = true;
|
|
1846
|
+
debug.log('agent-mission', 'handoff-pr-skipped', { reason: 'origin-not-github' });
|
|
1847
|
+
} else {
|
|
1848
|
+
(deps.dispatchOpenPullRequest ?? dispatchOpenPullRequest)({ title: `agent-mission: ${spec.branch}`, body: deps.originalMission ?? spec.mission, head: spec.branch, base: spec.base ?? 'main' }, { cwd: worktree });
|
|
1849
|
+
}
|
|
1850
|
+
gatedHandoff = true;
|
|
1851
|
+
},
|
|
1852
|
+
...deps.handoffOperations,
|
|
1853
|
+
};
|
|
1101
1854
|
const verifyDone = createMissionVerifyDone({
|
|
1102
1855
|
worktree: wt.path,
|
|
1103
1856
|
evidence: spec.evidence,
|
|
1104
1857
|
checklist,
|
|
1105
1858
|
coverageRetries,
|
|
1106
|
-
checkEvidence:
|
|
1859
|
+
checkEvidence: verifyEvidence,
|
|
1107
1860
|
});
|
|
1108
1861
|
// ★ P3b-2 observe 어댑터(2026-07-25) — EMIT-side(makeMissionObserveStep)가 프레임 버스에 흘리는 executor
|
|
1109
1862
|
// 화면을 **구조화 진행 다이제스트**(state+요약·throttle)로 압축해 observe 서피스(로그 패브릭)에 노출한다.
|
|
@@ -1114,24 +1867,99 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
1114
1867
|
// ★ 동일 버스 인스턴스 보장(리뷰 should-fix) — observe 구독과 EMIT(makeMissionObserveStep)이 **같은** 버스를
|
|
1115
1868
|
// 봐야 프레임이 흐른다. getChannelBus() 를 두 번 부르지 말고 지역 캐시로 구조적 보장.
|
|
1116
1869
|
const bus = getChannelBus();
|
|
1117
|
-
const
|
|
1870
|
+
const observeStep = makeMissionObserveStep({
|
|
1871
|
+
capture,
|
|
1872
|
+
renderPng: () => h.renderScreenPng(),
|
|
1873
|
+
bus,
|
|
1874
|
+
ident: { ptyId: h.id, instance: resolveInstanceName(), runId },
|
|
1875
|
+
});
|
|
1876
|
+
debug.log('agent-mission', 'takeover-wait', { id: h.id, maxWaitMs: AGENT_MISSION_TAKEOVER_WAIT_MS });
|
|
1877
|
+
const controlRun = runWithControlObserve(
|
|
1118
1878
|
bus, execSurfaceId(h.id),
|
|
1119
1879
|
(d) => debug.log('agent-mission.observe', 'progress', { surfaceId: d.surfaceId, state: d.state, summary: d.summary, unknownInput: d.unknownInput, frame: d.frameCount, runId: d.runId }),
|
|
1120
|
-
() =>
|
|
1121
|
-
|
|
1122
|
-
|
|
1880
|
+
() => {
|
|
1881
|
+
const handleDeps = controlDepsForHandle(h);
|
|
1882
|
+
const pending = (deps.runControlLoop ?? runPtyControlLoop)(trustAwareBrain, {
|
|
1883
|
+
...handleDeps,
|
|
1884
|
+
...(backend.name === 'claude' ? { inject: submitSeparately(handleDeps.inject) } : {}),
|
|
1885
|
+
...(deps.isMissionAborted ? {
|
|
1886
|
+
controlStance: () => deps.isMissionAborted!() ? 'unknown' as const : probeControlStance(h, 'agent', (e) =>
|
|
1887
|
+
debug.log('agent-mission', 'hascontrol-error', { id: h.id, error: (e as Error)?.message ?? String(e) })),
|
|
1888
|
+
} : {}),
|
|
1889
|
+
awaitOwnership: { maxWaitMs: AGENT_MISSION_TAKEOVER_WAIT_MS },
|
|
1890
|
+
settle: async () => {
|
|
1891
|
+
const quiet = waitForQuiet(h, 6000, 360000);
|
|
1892
|
+
await (deps.awaitMission ? deps.awaitMission(quiet) : quiet);
|
|
1893
|
+
},
|
|
1123
1894
|
// ★ U5 — 제어스텝 관측: 프레임 버스 발행(PTY 감독 계열 통일 합류·headless #5379 와 동일 seam) + 화면 전사.
|
|
1124
1895
|
// 발행 먼저·내부 fail-soft(관측이 미션 안 깸)·capture 는 예외 전파(원 semantics). 배선=makeMissionObserveStep.
|
|
1125
|
-
onStep:
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1896
|
+
onStep: async (obs, decision) => {
|
|
1897
|
+
await observeStep(obs, decision);
|
|
1898
|
+
if (backend.name === 'claude') {
|
|
1899
|
+
// Keep only review findings, not authentication screens or a raw PTY transcript.
|
|
1900
|
+
const finding = obs.screen.match(/(?:review findings?|finding|issues?|지적|문제)\s*[::]\s*([^\r\n]+)/i)?.[1]?.trim();
|
|
1901
|
+
if (finding && !/login|log in|sign in|https?:\/\/|token|cookie|password|장치 코드|로그인/i.test(finding)) {
|
|
1902
|
+
reviewSummary = `${reviewSummary}\n${finding}`.trim().slice(-3500);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
},
|
|
1906
|
+
verifyDone: spec.chain && spec.chain.length > 1 ? async () => ({ ok: true as const }) : verifyDone,
|
|
1907
|
+
handoff: async (decision, obs) => {
|
|
1908
|
+
try {
|
|
1909
|
+
if (spec.chain && decision.to !== spec.chain[1]) throw new Error(`chain order violation: expected ${spec.chain[1] ?? 'completion'}, got ${decision.to}`);
|
|
1910
|
+
if (await handoffMission(decision, wt.path, handoffOps, reviewSummary || controllerSummary) === 'gated') gatedHandoff = true;
|
|
1911
|
+
} catch (error) {
|
|
1912
|
+
transitionFailure = error instanceof Error ? error.message : String(error);
|
|
1913
|
+
throw error;
|
|
1914
|
+
}
|
|
1915
|
+
},
|
|
1916
|
+
askHuman: async (decision) => {
|
|
1917
|
+
try {
|
|
1918
|
+
await waitForHumanLogin(decision, handoffOps);
|
|
1919
|
+
} catch (error) {
|
|
1920
|
+
transitionFailure = error instanceof Error ? error.message : String(error);
|
|
1921
|
+
throw error;
|
|
1922
|
+
}
|
|
1923
|
+
},
|
|
1924
|
+
}, { maxSteps: maxRounds });
|
|
1925
|
+
deps.onControlActive?.(pending);
|
|
1926
|
+
return pending;
|
|
1927
|
+
},
|
|
1133
1928
|
{ onSettled: (digestCount) => debug.log('agent-mission.observe', 'summary', { digestCount }), observeOpts: { expectRunId: runId } },
|
|
1134
1929
|
);
|
|
1930
|
+
deps.onControlPending?.(controlRun);
|
|
1931
|
+
const control = await (deps.awaitMission ? deps.awaitMission(controlRun) : controlRun);
|
|
1932
|
+
if (deps.isMissionAborted?.()) throw new Error('MISSION_ABORTED');
|
|
1933
|
+
if (control.termination.kind === 'success' && !control.handoff && spec.chain && spec.chain.length > 1) {
|
|
1934
|
+
const to = spec.chain[1]!;
|
|
1935
|
+
try {
|
|
1936
|
+
if (await handoffMission({ action: 'handoff', to, mission: to === 'claude' ? 'Review changes and report findings; do not rewrite the original mission.' : to === 'codex' ? `Address the review findings and finish the original mission.\nOriginal mission:\n${deps.originalMission ?? spec.mission}` : deps.originalMission ?? spec.mission, carry: to === 'claude' ? 'diff' : 'summary' }, wt.path, handoffOps, reviewSummary || controllerSummary) === 'gated') gatedHandoff = true;
|
|
1937
|
+
} catch (error) {
|
|
1938
|
+
stopLive();
|
|
1939
|
+
try { h.kill(); } catch { /* noop */ }
|
|
1940
|
+
throw error;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
const nextChain = spec.chain?.slice(1);
|
|
1944
|
+
if (transitionFailure || (control.termination.kind !== 'success' && pendingHandoff)) {
|
|
1945
|
+
stopLive();
|
|
1946
|
+
try { h.kill(); } catch { /* noop */ }
|
|
1947
|
+
throw new Error(transitionFailure ?? 'handoff was requested but the PTY control loop did not finish successfully');
|
|
1948
|
+
}
|
|
1949
|
+
if (pendingHandoff) {
|
|
1950
|
+
stopLive();
|
|
1951
|
+
try { h.kill(); } catch { /* noop */ }
|
|
1952
|
+
const next = pendingHandoff;
|
|
1953
|
+
return runAgentMission({ ...spec, plugin: undefined, agent: resolveBackend(next.to), mission: next.mission, chain: nextChain && nextChain.length > 1 ? nextChain : undefined, enhance: false, memory: false }, { ...deps, handoffWorktree: { path: wt.path, branch: wt.branch!, base: wt.base! }, originalMission: deps.originalMission ?? spec.mission, previousSummary: next.summary, initialTsc: baselineTsc, runtimeFallback: { ...runtimeFallback, fallbackEligible: false } });
|
|
1954
|
+
}
|
|
1955
|
+
// A gate/PR handoff only counts as success when the control loop itself did not end in error.
|
|
1956
|
+
if (gatedHandoff && control.termination.kind !== 'error') {
|
|
1957
|
+
stopLive();
|
|
1958
|
+
try { h.kill(); } catch { /* noop */ }
|
|
1959
|
+
return { ok: true, worktree: wt.path, branch: wt.branch, rounds: control.steps, evidencePath: wt.path, committed: true, usedOmniCrawl: usedOmni,
|
|
1960
|
+
...(handoffPrSkipped ? { pr: 'skipped' as const, reason: 'origin-not-github' as const } : {}),
|
|
1961
|
+
detail: handoffPrSkipped ? '완료(증거 게이트·push·PR 생략)' : '완료(증거 게이트·PR)' };
|
|
1962
|
+
}
|
|
1135
1963
|
const done = control.termination.kind === 'success';
|
|
1136
1964
|
const round = control.steps;
|
|
1137
1965
|
if (control.termination.kind === 'error') {
|
|
@@ -1156,46 +1984,49 @@ export async function runAgentMission(spec: AgentMissionSpec, deps: AgentMission
|
|
|
1156
1984
|
descents: runtimeFallback.descents,
|
|
1157
1985
|
maxFallbackDescents: runtimeFallback.maxDescents,
|
|
1158
1986
|
});
|
|
1159
|
-
if (nextBackend) {
|
|
1987
|
+
if (nextBackend && !deps.isMissionAborted?.()) {
|
|
1160
1988
|
const nextStep: FallbackStep = nextBackend.name === 'grok' ? 'grok' : 'codex-rotate';
|
|
1161
1989
|
stopLive();
|
|
1990
|
+
if (h.pid) await (deps.terminateProcessTree ?? terminateMissionProcessTree)(h.pid);
|
|
1162
1991
|
try { h.kill(); } catch { /* noop */ }
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
runtimeFallback
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
descents: runtimeFallback.descents + 1,
|
|
1171
|
-
},
|
|
1992
|
+
const nextSpec = { ...spec, agent: nextBackend, reuseOwnedWorktree: true };
|
|
1993
|
+
const nextDeps = {
|
|
1994
|
+
...deps,
|
|
1995
|
+
runtimeFallback: {
|
|
1996
|
+
...runtimeFallback,
|
|
1997
|
+
attemptedSteps: new Set([...runtimeFallback.attemptedSteps, nextStep]),
|
|
1998
|
+
descents: runtimeFallback.descents + 1,
|
|
1172
1999
|
},
|
|
1173
|
-
|
|
2000
|
+
};
|
|
2001
|
+
// Keep the original signal owner and outside-write baseline across a replacement PTY.
|
|
2002
|
+
return spec.signal || spec.workdir ? runAgentMissionBody(nextSpec, nextDeps, startedAt, initialFiles) : runAgentMission(nextSpec, nextDeps);
|
|
1174
2003
|
}
|
|
1175
2004
|
}
|
|
1176
2005
|
debug.log('agent-mission', 'control-result', { termination: control.termination.kind, steps: control.steps });
|
|
1177
2006
|
if (control.termination.kind === 'cancelled') {
|
|
1178
2007
|
stopLive();
|
|
1179
|
-
try { h.kill(); } catch { /* noop */ }
|
|
1180
2008
|
throw new Error('AGENT_YIELDED: PTY 제어가 사람에게 이양됨(takeover) — 자율 미션 중단');
|
|
1181
2009
|
}
|
|
1182
2010
|
|
|
1183
|
-
|
|
2011
|
+
if (deps.isMissionAborted?.()) return { ok: false, reason: 'aborted', worktree: wt.path, branch: wt.branch,
|
|
2012
|
+
rounds: round, evidencePath: null, committed: false, usedOmniCrawl: usedOmni, detail: 'aborted' };
|
|
2013
|
+
const finalEv = verifyEvidence(wt.path, spec.evidence);
|
|
1184
2014
|
const evidencePath = finalEv.ok ? finalEv.path : null;
|
|
1185
2015
|
let committed = false;
|
|
1186
|
-
if (finalEv.ok && (spec.commit ?? true)) {
|
|
1187
|
-
const c = commitWorktree(wt.path, `chore(agent-mission): ${spec.branch} — ${backend.name}-in-elanous PTY RFC 산출`);
|
|
2016
|
+
if (!deps.isMissionAborted?.() && !spec.workdir && finalEv.ok && (spec.commit ?? true)) {
|
|
2017
|
+
const c = (deps.commitWorktree ?? commitWorktree)(wt.path, `chore(agent-mission): ${spec.branch} — ${backend.name}-in-elanous PTY RFC 산출`);
|
|
1188
2018
|
committed = c.ok;
|
|
1189
2019
|
debug.log('agent-mission', 'commit', { ok: c.ok, out: c.out.slice(0, 120) });
|
|
1190
2020
|
}
|
|
1191
2021
|
debug.log('agent-mission', 'result', { ok: finalEv.ok, rounds: round, evidencePath, committed, usedOmni });
|
|
1192
2022
|
stopLive();
|
|
2023
|
+
if (h.pid) await terminateMissionProcessTree(h.pid);
|
|
1193
2024
|
try { h.kill(); } catch { /* noop */ }
|
|
1194
|
-
await sleep(400);
|
|
1195
2025
|
|
|
1196
2026
|
return {
|
|
1197
2027
|
ok: finalEv.ok, worktree: wt.path, branch: wt.branch, rounds: round,
|
|
1198
2028
|
evidencePath, committed, usedOmniCrawl: usedOmni,
|
|
2029
|
+
ptyId: h.id, webUrl: webAddress.webUrl,
|
|
1199
2030
|
detail: done ? '완료(증거 충족)' : (finalEv.ok ? '증거 충족(루프 종료)' : '미완(증거 부족)'),
|
|
1200
2031
|
};
|
|
1201
2032
|
}
|