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